+ term->termstate = SEEN_CSI;
+ } else if (c == ';') {
+ if (++term->esc_nargs <= ARGS_MAX)
+ term->esc_args[term->esc_nargs - 1] = ARG_DEFAULT;
+ term->termstate = SEEN_CSI;
+ } else if (c < '@') {
+ if (term->esc_query)
+ term->esc_query = -1;
+ else if (c == '?')
+ term->esc_query = TRUE;
+ else
+ term->esc_query = c;
+ term->termstate = SEEN_CSI;
+ } else
+ switch (ANSI(c, term->esc_query)) {
+ case 'A': /* CUU: move up N lines */
+ move(term, term->curs.x,
+ term->curs.y - def(term->esc_args[0], 1), 1);
+ term->seen_disp_event = TRUE;
+ break;
+ case 'e': /* VPR: move down N lines */
+ compatibility(ANSI);
+ /* FALLTHROUGH */
+ case 'B': /* CUD: Cursor down */
+ move(term, term->curs.x,
+ term->curs.y + def(term->esc_args[0], 1), 1);
+ term->seen_disp_event = TRUE;
+ break;
+ case ANSI('c', '>'): /* DA: report xterm version */
+ compatibility(OTHER);
+ /* this reports xterm version 136 so that VIM can
+ use the drag messages from the mouse reporting */
+ if (term->ldisc)
+ ldisc_send(term->ldisc, "\033[>0;136;0c", 11, 0);
+ break;
+ case 'a': /* HPR: move right N cols */
+ compatibility(ANSI);
+ /* FALLTHROUGH */
+ case 'C': /* CUF: Cursor right */
+ move(term, term->curs.x + def(term->esc_args[0], 1),
+ term->curs.y, 1);
+ term->seen_disp_event = TRUE;
+ break;
+ case 'D': /* CUB: move left N cols */
+ move(term, term->curs.x - def(term->esc_args[0], 1),
+ term->curs.y, 1);
+ term->seen_disp_event = TRUE;
+ break;
+ case 'E': /* CNL: move down N lines and CR */
+ compatibility(ANSI);
+ move(term, 0,
+ term->curs.y + def(term->esc_args[0], 1), 1);
+ term->seen_disp_event = TRUE;
+ break;
+ case 'F': /* CPL: move up N lines and CR */
+ compatibility(ANSI);
+ move(term, 0,
+ term->curs.y - def(term->esc_args[0], 1), 1);
+ term->seen_disp_event = TRUE;
+ break;
+ case 'G': /* CHA */
+ case '`': /* HPA: set horizontal posn */
+ compatibility(ANSI);
+ move(term, def(term->esc_args[0], 1) - 1,
+ term->curs.y, 0);
+ term->seen_disp_event = TRUE;
+ break;
+ case 'd': /* VPA: set vertical posn */
+ compatibility(ANSI);
+ move(term, term->curs.x,
+ ((term->dec_om ? term->marg_t : 0) +
+ def(term->esc_args[0], 1) - 1),
+ (term->dec_om ? 2 : 0));
+ term->seen_disp_event = TRUE;
+ break;
+ case 'H': /* CUP */
+ case 'f': /* HVP: set horz and vert posns at once */
+ if (term->esc_nargs < 2)
+ term->esc_args[1] = ARG_DEFAULT;
+ move(term, def(term->esc_args[1], 1) - 1,
+ ((term->dec_om ? term->marg_t : 0) +
+ def(term->esc_args[0], 1) - 1),
+ (term->dec_om ? 2 : 0));
+ term->seen_disp_event = TRUE;
+ break;
+ case 'J': /* ED: erase screen or parts of it */
+ {
+ unsigned int i = def(term->esc_args[0], 0) + 1;
+ if (i > 3)
+ i = 0;
+ erase_lots(term, FALSE, !!(i & 2), !!(i & 1));
+ }
+ term->disptop = 0;
+ term->seen_disp_event = TRUE;
+ break;
+ case 'K': /* EL: erase line or parts of it */
+ {
+ unsigned int i = def(term->esc_args[0], 0) + 1;
+ if (i > 3)
+ i = 0;
+ erase_lots(term, TRUE, !!(i & 2), !!(i & 1));
+ }
+ term->seen_disp_event = TRUE;
+ break;
+ case 'L': /* IL: insert lines */
+ compatibility(VT102);
+ if (term->curs.y <= term->marg_b)
+ scroll(term, term->curs.y, term->marg_b,
+ -def(term->esc_args[0], 1), FALSE);
+ fix_cpos;
+ term->seen_disp_event = TRUE;
+ break;
+ case 'M': /* DL: delete lines */
+ compatibility(VT102);
+ if (term->curs.y <= term->marg_b)
+ scroll(term, term->curs.y, term->marg_b,
+ def(term->esc_args[0], 1),
+ TRUE);
+ fix_cpos;
+ term->seen_disp_event = TRUE;
+ break;
+ case '@': /* ICH: insert chars */
+ /* XXX VTTEST says this is vt220, vt510 manual says vt102 */
+ compatibility(VT102);
+ insch(term, def(term->esc_args[0], 1));
+ term->seen_disp_event = TRUE;
+ break;
+ case 'P': /* DCH: delete chars */
+ compatibility(VT102);
+ insch(term, -def(term->esc_args[0], 1));
+ term->seen_disp_event = TRUE;
+ break;
+ case 'c': /* DA: terminal type query */
+ compatibility(VT100);
+ /* This is the response for a VT102 */
+ if (term->ldisc)
+ ldisc_send(term->ldisc, term->id_string,
+ strlen(term->id_string), 0);
+ break;
+ case 'n': /* DSR: cursor position query */
+ if (term->ldisc) {
+ if (term->esc_args[0] == 6) {
+ char buf[32];
+ sprintf(buf, "\033[%d;%dR", term->curs.y + 1,
+ term->curs.x + 1);
+ ldisc_send(term->ldisc, buf, strlen(buf), 0);
+ } else if (term->esc_args[0] == 5) {
+ ldisc_send(term->ldisc, "\033[0n", 4, 0);
+ }
+ }
+ break;
+ case 'h': /* SM: toggle modes to high */
+ case ANSI_QUE('h'):
+ compatibility(VT100);
+ {
+ int i;
+ for (i = 0; i < term->esc_nargs; i++)
+ toggle_mode(term, term->esc_args[i],
+ term->esc_query, TRUE);
+ }
+ break;
+ case 'i': /* MC: Media copy */
+ case ANSI_QUE('i'):
+ compatibility(VT100);
+ {
+ if (term->esc_nargs != 1) break;
+ if (term->esc_args[0] == 5 && *term->cfg.printer) {
+ term->printing = TRUE;
+ term->only_printing = !term->esc_query;
+ term->print_state = 0;
+ term_print_setup(term);
+ } else if (term->esc_args[0] == 4 &&
+ term->printing) {
+ term_print_finish(term);
+ }
+ }
+ break;
+ case 'l': /* RM: toggle modes to low */
+ case ANSI_QUE('l'):
+ compatibility(VT100);
+ {
+ int i;
+ for (i = 0; i < term->esc_nargs; i++)
+ toggle_mode(term, term->esc_args[i],
+ term->esc_query, FALSE);
+ }
+ break;
+ case 'g': /* TBC: clear tabs */
+ compatibility(VT100);
+ if (term->esc_nargs == 1) {
+ if (term->esc_args[0] == 0) {
+ term->tabs[term->curs.x] = FALSE;
+ } else if (term->esc_args[0] == 3) {
+ int i;
+ for (i = 0; i < term->cols; i++)
+ term->tabs[i] = FALSE;
+ }
+ }
+ break;
+ case 'r': /* DECSTBM: set scroll margins */
+ compatibility(VT100);
+ if (term->esc_nargs <= 2) {
+ int top, bot;
+ top = def(term->esc_args[0], 1) - 1;
+ bot = (term->esc_nargs <= 1
+ || term->esc_args[1] == 0 ?
+ term->rows :
+ def(term->esc_args[1], term->rows)) - 1;
+ if (bot >= term->rows)
+ bot = term->rows - 1;
+ /* VTTEST Bug 9 - if region is less than 2 lines
+ * don't change region.
+ */
+ if (bot - top > 0) {
+ term->marg_t = top;
+ term->marg_b = bot;
+ term->curs.x = 0;
+ /*
+ * I used to think the cursor should be
+ * placed at the top of the newly marginned
+ * area. Apparently not: VMS TPU falls over
+ * if so.
+ *
+ * Well actually it should for
+ * Origin mode - RDB
+ */
+ term->curs.y = (term->dec_om ?
+ term->marg_t : 0);
+ fix_cpos;
+ term->seen_disp_event = TRUE;
+ }
+ }
+ break;
+ case 'm': /* SGR: set graphics rendition */
+ {
+ /*
+ * A VT100 without the AVO only had one
+ * attribute, either underline or
+ * reverse video depending on the
+ * cursor type, this was selected by
+ * CSI 7m.
+ *
+ * case 2:
+ * This is sometimes DIM, eg on the
+ * GIGI and Linux
+ * case 8:
+ * This is sometimes INVIS various ANSI.
+ * case 21:
+ * This like 22 disables BOLD, DIM and INVIS
+ *
+ * The ANSI colours appear on any
+ * terminal that has colour (obviously)
+ * but the interaction between sgr0 and
+ * the colours varies but is usually
+ * related to the background colour
+ * erase item. The interaction between
+ * colour attributes and the mono ones
+ * is also very implementation
+ * dependent.
+ *
+ * The 39 and 49 attributes are likely
+ * to be unimplemented.
+ */
+ int i;
+ for (i = 0; i < term->esc_nargs; i++) {
+ switch (def(term->esc_args[i], 0)) {
+ case 0: /* restore defaults */
+ term->curr_attr = term->default_attr;
+ break;
+ case 1: /* enable bold */
+ compatibility(VT100AVO);
+ term->curr_attr |= ATTR_BOLD;
+ break;
+ case 21: /* (enable double underline) */
+ compatibility(OTHER);
+ case 4: /* enable underline */
+ compatibility(VT100AVO);
+ term->curr_attr |= ATTR_UNDER;
+ break;
+ case 5: /* enable blink */
+ compatibility(VT100AVO);
+ term->curr_attr |= ATTR_BLINK;
+ break;
+ case 6: /* SCO light bkgrd */
+ compatibility(SCOANSI);
+ term->blink_is_real = FALSE;
+ term->curr_attr |= ATTR_BLINK;
+ break;
+ case 7: /* enable reverse video */
+ term->curr_attr |= ATTR_REVERSE;
+ break;
+ case 10: /* SCO acs off */
+ compatibility(SCOANSI);
+ if (term->cfg.no_remote_charset) break;
+ term->sco_acs = 0; break;
+ case 11: /* SCO acs on */
+ compatibility(SCOANSI);
+ if (term->cfg.no_remote_charset) break;
+ term->sco_acs = 1; break;
+ case 12: /* SCO acs on, |0x80 */
+ compatibility(SCOANSI);
+ if (term->cfg.no_remote_charset) break;
+ term->sco_acs = 2; break;
+ case 22: /* disable bold */
+ compatibility2(OTHER, VT220);
+ term->curr_attr &= ~ATTR_BOLD;
+ break;
+ case 24: /* disable underline */
+ compatibility2(OTHER, VT220);
+ term->curr_attr &= ~ATTR_UNDER;
+ break;
+ case 25: /* disable blink */
+ compatibility2(OTHER, VT220);
+ term->curr_attr &= ~ATTR_BLINK;
+ break;
+ case 27: /* disable reverse video */
+ compatibility2(OTHER, VT220);
+ term->curr_attr &= ~ATTR_REVERSE;
+ break;
+ case 30:
+ case 31:
+ case 32:
+ case 33:
+ case 34:
+ case 35:
+ case 36:
+ case 37:
+ /* foreground */
+ term->curr_attr &= ~ATTR_FGMASK;
+ term->curr_attr |=
+ (term->esc_args[i] - 30)<<ATTR_FGSHIFT;
+ break;
+ case 90:
+ case 91:
+ case 92:
+ case 93:
+ case 94:
+ case 95:
+ case 96:
+ case 97:
+ /* xterm-style bright foreground */
+ term->curr_attr &= ~ATTR_FGMASK;
+ term->curr_attr |=
+ ((term->esc_args[i] - 90 + 16)
+ << ATTR_FGSHIFT);
+ break;
+ case 39: /* default-foreground */
+ term->curr_attr &= ~ATTR_FGMASK;
+ term->curr_attr |= ATTR_DEFFG;
+ break;
+ case 40:
+ case 41:
+ case 42:
+ case 43:
+ case 44:
+ case 45:
+ case 46:
+ case 47:
+ /* background */
+ term->curr_attr &= ~ATTR_BGMASK;
+ term->curr_attr |=
+ (term->esc_args[i] - 40)<<ATTR_BGSHIFT;
+ break;
+ case 100:
+ case 101:
+ case 102:
+ case 103:
+ case 104:
+ case 105:
+ case 106:
+ case 107:
+ /* xterm-style bright background */
+ term->curr_attr &= ~ATTR_BGMASK;
+ term->curr_attr |=
+ ((term->esc_args[i] - 100 + 16)
+ << ATTR_BGSHIFT);
+ break;
+ case 49: /* default-background */
+ term->curr_attr &= ~ATTR_BGMASK;
+ term->curr_attr |= ATTR_DEFBG;
+ break;
+ }
+ }
+ if (term->use_bce)
+ term->erase_char = (' ' | ATTR_ASCII |
+ (term->curr_attr &
+ (ATTR_FGMASK |
+ ATTR_BGMASK)));
+ }
+ break;
+ case 's': /* save cursor */
+ save_cursor(term, TRUE);
+ break;
+ case 'u': /* restore cursor */
+ save_cursor(term, FALSE);
+ term->seen_disp_event = TRUE;
+ break;
+ case 't': /* DECSLPP: set page size - ie window height */
+ /*
+ * VT340/VT420 sequence DECSLPP, DEC only allows values
+ * 24/25/36/48/72/144 other emulators (eg dtterm) use
+ * illegal values (eg first arg 1..9) for window changing
+ * and reports.
+ */
+ if (term->esc_nargs <= 1
+ && (term->esc_args[0] < 1 ||
+ term->esc_args[0] >= 24)) {
+ compatibility(VT340TEXT);
+ if (!term->cfg.no_remote_resize)
+ request_resize(term->frontend, term->cols,
+ def(term->esc_args[0], 24));
+ deselect(term);
+ } else if (term->esc_nargs >= 1 &&
+ term->esc_args[0] >= 1 &&
+ term->esc_args[0] < 24) {
+ compatibility(OTHER);