#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
+#include <limits.h>
#include <time.h>
#include <assert.h>
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);
termline *ldata;
/* Validate input coordinates, just in case. */
- if (x == 0 || x > term->cols)
+ if (x <= 0 || x > term->cols)
return;
ldata = scrlineptr(y);
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 == ';') {
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);
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);
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);
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),
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),
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)
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);
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),
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;
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 ?
}
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);
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);
/* 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;
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;
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)) <<
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)) <<
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':
/*
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;
}
term_print_flush(term);
- if (term->logflush)
+ if (term->logflush && term->logctx)
logflush(term->logctx);
}
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);
} 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;
}
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 &&
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? */