X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=blobdiff_plain;f=terminal.c;h=c79944cda889cb8822be342b4557bebc38de85a9;hb=bec33b23119d9363854a2d0b4f4ca0fe893827aa;hp=7570a63b16743fd54b5b8f17cda4c0466ce6c10b;hpb=23208779e78024a004f5e51c189874cb50c29af0;p=PuTTY.git diff --git a/terminal.c b/terminal.c index 7570a63b..c79944cd 100644 --- a/terminal.c +++ b/terminal.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -65,7 +66,7 @@ #define has_compat(x) ( ((CL_##x)&term->compatibility_level) != 0 ) -char *EMPTY_WINDOW_TITLE = ""; +const char *EMPTY_WINDOW_TITLE = ""; const char sco2ansicolour[] = { 0, 4, 2, 6, 1, 5, 3, 7 }; @@ -1402,6 +1403,7 @@ void term_copy_stuff_from_conf(Terminal *term) term->no_remote_charset = conf_get_int(term->conf, CONF_no_remote_charset); term->no_remote_resize = conf_get_int(term->conf, CONF_no_remote_resize); term->no_remote_wintitle = conf_get_int(term->conf, CONF_no_remote_wintitle); + term->no_remote_clearscroll = conf_get_int(term->conf, CONF_no_remote_clearscroll); term->rawcnp = conf_get_int(term->conf, CONF_rawcnp); term->rect_select = conf_get_int(term->conf, CONF_rect_select); term->remote_qtitle_action = conf_get_int(term->conf, CONF_remote_qtitle_action); @@ -2343,7 +2345,7 @@ static void check_boundary(Terminal *term, int x, int y) termline *ldata; /* Validate input coordinates, just in case. */ - if (x == 0 || x > term->cols) + if (x <= 0 || x > term->cols) return; ldata = scrlineptr(y); @@ -3493,8 +3495,15 @@ static void term_out(Terminal *term) if (term->esc_nargs <= ARGS_MAX) { if (term->esc_args[term->esc_nargs - 1] == ARG_DEFAULT) term->esc_args[term->esc_nargs - 1] = 0; - term->esc_args[term->esc_nargs - 1] = - 10 * term->esc_args[term->esc_nargs - 1] + c - '0'; + if (term->esc_args[term->esc_nargs - 1] <= + UINT_MAX / 10 && + term->esc_args[term->esc_nargs - 1] * 10 <= + UINT_MAX - c - '0') + term->esc_args[term->esc_nargs - 1] = + 10 * term->esc_args[term->esc_nargs - 1] + + c - '0'; + else + term->esc_args[term->esc_nargs - 1] = UINT_MAX; } term->termstate = SEEN_CSI; } else if (c == ';') { @@ -3510,8 +3519,10 @@ static void term_out(Terminal *term) term->esc_query = c; term->termstate = SEEN_CSI; } else +#define CLAMP(arg, lim) ((arg) = ((arg) > (lim)) ? (lim) : (arg)) switch (ANSI(c, term->esc_query)) { case 'A': /* CUU: move up N lines */ + CLAMP(term->esc_args[0], term->rows); move(term, term->curs.x, term->curs.y - def(term->esc_args[0], 1), 1); seen_disp_event(term); @@ -3520,6 +3531,7 @@ static void term_out(Terminal *term) compatibility(ANSI); /* FALLTHROUGH */ case 'B': /* CUD: Cursor down */ + CLAMP(term->esc_args[0], term->rows); move(term, term->curs.x, term->curs.y + def(term->esc_args[0], 1), 1); seen_disp_event(term); @@ -3535,23 +3547,27 @@ static void term_out(Terminal *term) compatibility(ANSI); /* FALLTHROUGH */ case 'C': /* CUF: Cursor right */ + CLAMP(term->esc_args[0], term->cols); move(term, term->curs.x + def(term->esc_args[0], 1), term->curs.y, 1); seen_disp_event(term); break; case 'D': /* CUB: move left N cols */ + CLAMP(term->esc_args[0], term->cols); move(term, term->curs.x - def(term->esc_args[0], 1), term->curs.y, 1); seen_disp_event(term); break; case 'E': /* CNL: move down N lines and CR */ compatibility(ANSI); + CLAMP(term->esc_args[0], term->rows); move(term, 0, term->curs.y + def(term->esc_args[0], 1), 1); seen_disp_event(term); break; case 'F': /* CPL: move up N lines and CR */ compatibility(ANSI); + CLAMP(term->esc_args[0], term->rows); move(term, 0, term->curs.y - def(term->esc_args[0], 1), 1); seen_disp_event(term); @@ -3559,12 +3575,14 @@ static void term_out(Terminal *term) case 'G': /* CHA */ case '`': /* HPA: set horizontal posn */ compatibility(ANSI); + CLAMP(term->esc_args[0], term->cols); move(term, def(term->esc_args[0], 1) - 1, term->curs.y, 0); seen_disp_event(term); break; case 'd': /* VPA: set vertical posn */ compatibility(ANSI); + CLAMP(term->esc_args[0], term->rows); move(term, term->curs.x, ((term->dec_om ? term->marg_t : 0) + def(term->esc_args[0], 1) - 1), @@ -3575,6 +3593,8 @@ static void term_out(Terminal *term) case 'f': /* HVP: set horz and vert posns at once */ if (term->esc_nargs < 2) term->esc_args[1] = ARG_DEFAULT; + CLAMP(term->esc_args[0], term->rows); + CLAMP(term->esc_args[1], term->cols); move(term, def(term->esc_args[1], 1) - 1, ((term->dec_om ? term->marg_t : 0) + def(term->esc_args[0], 1) - 1), @@ -3587,7 +3607,8 @@ static void term_out(Terminal *term) if (i == 3) { /* Erase Saved Lines (xterm) * This follows Thomas Dickey's xterm. */ - term_clrsb(term); + if (!term->no_remote_clearscroll) + term_clrsb(term); } else { i++; if (i > 3) @@ -3610,6 +3631,7 @@ static void term_out(Terminal *term) break; case 'L': /* IL: insert lines */ compatibility(VT102); + CLAMP(term->esc_args[0], term->rows); if (term->curs.y <= term->marg_b) scroll(term, term->curs.y, term->marg_b, -def(term->esc_args[0], 1), FALSE); @@ -3617,6 +3639,7 @@ static void term_out(Terminal *term) break; case 'M': /* DL: delete lines */ compatibility(VT102); + CLAMP(term->esc_args[0], term->rows); if (term->curs.y <= term->marg_b) scroll(term, term->curs.y, term->marg_b, def(term->esc_args[0], 1), @@ -3626,11 +3649,13 @@ static void term_out(Terminal *term) case '@': /* ICH: insert chars */ /* XXX VTTEST says this is vt220, vt510 manual says vt102 */ compatibility(VT102); + CLAMP(term->esc_args[0], term->cols); insch(term, def(term->esc_args[0], 1)); seen_disp_event(term); break; case 'P': /* DCH: delete chars */ compatibility(VT102); + CLAMP(term->esc_args[0], term->cols); insch(term, -def(term->esc_args[0], 1)); seen_disp_event(term); break; @@ -3708,6 +3733,8 @@ static void term_out(Terminal *term) compatibility(VT100); if (term->esc_nargs <= 2) { int top, bot; + CLAMP(term->esc_args[0], term->rows); + CLAMP(term->esc_args[1], term->rows); top = def(term->esc_args[0], 1) - 1; bot = (term->esc_nargs <= 1 || term->esc_args[1] == 0 ? @@ -3940,7 +3967,8 @@ static void term_out(Terminal *term) switch (term->esc_args[0]) { int x, y, len; - char buf[80], *p; + char buf[80]; + const char *p; case 1: set_iconic(term->frontend, FALSE); break; @@ -3995,7 +4023,9 @@ static void term_out(Terminal *term) case 13: if (term->ldisc) { get_window_pos(term->frontend, &x, &y); - len = sprintf(buf, "\033[3;%d;%dt", x, y); + len = sprintf(buf, "\033[3;%u;%ut", + (unsigned)x, + (unsigned)y); ldisc_send(term->ldisc, buf, len, 0); } break; @@ -4060,6 +4090,7 @@ static void term_out(Terminal *term) } break; case 'S': /* SU: Scroll up */ + CLAMP(term->esc_args[0], term->rows); compatibility(SCOANSI); scroll(term, term->marg_t, term->marg_b, def(term->esc_args[0], 1), TRUE); @@ -4067,6 +4098,7 @@ static void term_out(Terminal *term) seen_disp_event(term); break; case 'T': /* SD: Scroll down */ + CLAMP(term->esc_args[0], term->rows); compatibility(SCOANSI); scroll(term, term->marg_t, term->marg_b, -def(term->esc_args[0], 1), TRUE); @@ -4109,6 +4141,7 @@ static void term_out(Terminal *term) /* XXX VTTEST says this is vt220, vt510 manual * says vt100 */ compatibility(ANSIMIN); + CLAMP(term->esc_args[0], term->cols); { int n = def(term->esc_args[0], 1); pos cursplus; @@ -4142,6 +4175,7 @@ static void term_out(Terminal *term) break; case 'Z': /* CBT */ compatibility(OTHER); + CLAMP(term->esc_args[0], term->cols); { int i = def(term->esc_args[0], 1); pos old_curs = term->curs; @@ -4202,7 +4236,7 @@ static void term_out(Terminal *term) break; case ANSI('F', '='): /* set normal foreground */ compatibility(SCOANSI); - if (term->esc_args[0] >= 0 && term->esc_args[0] < 16) { + if (term->esc_args[0] < 16) { long colour = (sco2ansicolour[term->esc_args[0] & 0x7] | (term->esc_args[0] & 0x8)) << @@ -4216,7 +4250,7 @@ static void term_out(Terminal *term) break; case ANSI('G', '='): /* set normal background */ compatibility(SCOANSI); - if (term->esc_args[0] >= 0 && term->esc_args[0] < 16) { + if (term->esc_args[0] < 16) { long colour = (sco2ansicolour[term->esc_args[0] & 0x7] | (term->esc_args[0] & 0x8)) << @@ -4340,7 +4374,11 @@ static void term_out(Terminal *term) case '7': case '8': case '9': - term->esc_args[0] = 10 * term->esc_args[0] + c - '0'; + if (term->esc_args[0] <= UINT_MAX / 10 && + term->esc_args[0] * 10 <= UINT_MAX - c - '0') + term->esc_args[0] = 10 * term->esc_args[0] + c - '0'; + else + term->esc_args[0] = UINT_MAX; break; case 'L': /* @@ -4422,7 +4460,11 @@ static void term_out(Terminal *term) case '7': case '8': case '9': - term->esc_args[0] = 10 * term->esc_args[0] + c - '0'; + if (term->esc_args[0] <= UINT_MAX / 10 && + term->esc_args[0] * 10 <= UINT_MAX - c - '0') + term->esc_args[0] = 10 * term->esc_args[0] + c - '0'; + else + term->esc_args[0] = UINT_MAX; break; default: term->termstate = OSC_STRING; @@ -4685,7 +4727,7 @@ static void term_out(Terminal *term) } term_print_flush(term); - if (term->logflush) + if (term->logflush && term->logctx) logflush(term->logctx); } @@ -5405,7 +5447,7 @@ typedef struct { static void clip_addchar(clip_workbuf *b, wchar_t chr, int attr) { if (b->bufpos >= b->buflen) { - b->buflen += 128; + b->buflen *= 2; b->textbuf = sresize(b->textbuf, b->buflen, wchar_t); b->textptr = b->textbuf + b->bufpos; b->attrbuf = sresize(b->attrbuf, b->buflen, int); @@ -6040,7 +6082,8 @@ void term_mouse(Terminal *term, Mouse_Button braw, Mouse_Button bcooked, } else if (c <= 223 && r <= 223) { len = sprintf(abuf, "\033[M%c%c%c", encstate + 32, c + 32, r + 32); } - ldisc_send(term->ldisc, abuf, len, 0); + if (len > 0) + ldisc_send(term->ldisc, abuf, len, 0); } return; } @@ -6074,6 +6117,19 @@ void term_mouse(Terminal *term, Mouse_Button braw, Mouse_Button bcooked, sel_spread(term); } else if ((bcooked == MBT_SELECT && a == MA_DRAG) || (bcooked == MBT_EXTEND && a != MA_RELEASE)) { + if (a == MA_DRAG && + (term->selstate == NO_SELECTION || term->selstate == SELECTED)) { + /* + * This can happen if a front end has passed us a MA_DRAG + * without a prior MA_CLICK. OS X GTK does so, for + * example, if the initial button press was eaten by the + * WM when it activated the window in the first place. The + * nicest thing to do in this situation is to ignore + * further drags, and wait for the user to click in the + * window again properly if they want to select. + */ + return; + } if (term->selstate == ABOUT_TO && poseq(term->selanchor, selpoint)) return; if (bcooked == MBT_EXTEND && a != MA_DRAG && @@ -6317,9 +6373,11 @@ void term_set_focus(Terminal *term, int has_focus) */ char *term_get_ttymode(Terminal *term, const char *mode) { - char *val = NULL; + const char *val = NULL; if (strcmp(mode, "ERASE") == 0) { val = term->bksp_is_delete ? "^?" : "^H"; + } else if (strcmp(mode, "IUTF8") == 0) { + val = frontend_is_utf8(term->frontend) ? "yes" : "no"; } /* FIXME: perhaps we should set ONLCR based on lfhascr as well? */ /* FIXME: or ECHO and friends based on local echo state? */ @@ -6337,7 +6395,7 @@ struct term_userpass_state { * input. */ int term_get_userpass_input(Terminal *term, prompts_t *p, - unsigned char *in, int inlen) + const unsigned char *in, int inlen) { struct term_userpass_state *s = (struct term_userpass_state *)p->data; if (!s) {