term->termstate = SEEN_ESC; term->esc_query = FALSE; c = '@' + (c & 0x1F);
if (c == 0x9a) c = 0; else { term->termstate = SEEN_ESC; term->esc_query = FALSE; c = '@' + (c & 0x1F); }
static void term_out(Terminal *term){    unsigned long c;    int unget;    unsigned char localbuf[256], *chars;    int nchars = 0;    unget = -1;    chars = NULL;		       /* placate compiler warnings */    while (nchars > 0 || bufchain_size(&term->inbuf) > 0) {	if (unget == -1) {	    if (nchars == 0) {		void *ret;		bufchain_prefix(&term->inbuf, &ret, &nchars);		if (nchars > sizeof(localbuf))		    nchars = sizeof(localbuf);		memcpy(localbuf, ret, nchars);		bufchain_consume(&term->inbuf, nchars);		chars = localbuf;		assert(chars != NULL);	    }	    c = *chars++;	    nchars--;	    /*	     * Optionally log the session traffic to a file. Useful for	     * debugging and possibly also useful for actual logging.	     */	    if (term->cfg.logtype == LGTYP_DEBUG && term->logctx)		logtraffic(term->logctx, (unsigned char) c, LGTYP_DEBUG);	} else {	    c = unget;	    unget = -1;	}	/* Note only VT220+ are 8-bit VT102 is seven bit, it shouldn't even	 * be able to display 8-bit characters, but I'll let that go 'cause	 * of i18n.	 */	/*	 * If we're printing, add the character to the printer	 * buffer.	 */	if (term->printing) {	    bufchain_add(&term->printer_buf, &c, 1);	    /*	     * If we're in print-only mode, we use a much simpler	     * state machine designed only to recognise the ESC[4i	     * termination sequence.	     */	    if (term->only_printing) {		if (c == '\033')		    term->print_state = 1;		else if (c == (unsigned char)'\233')		    term->print_state = 2;		else if (c == '[' && term->print_state == 1)		    term->print_state = 2;		else if (c == '4' && term->print_state == 2)		    term->print_state = 3;		else if (c == 'i' && term->print_state == 3)		    term->print_state = 4;		else		    term->print_state = 0;		if (term->print_state == 4) {		    term_print_finish(term);		}		continue;	    }	}	/* First see about all those translations. */	if (term->termstate == TOPLEVEL) {	    if (in_utf(term))		switch (term->utf_state) {		  case 0:		    if (c < 0x80) {			/* UTF-8 must be stateless so we ignore iso2022. */			if (term->ucsdata->unitab_ctrl[c] != 0xFF) 			     c = term->ucsdata->unitab_ctrl[c];			else c = ((unsigned char)c) | CSET_ASCII;			break;		    } else if ((c & 0xe0) == 0xc0) {			term->utf_size = term->utf_state = 1;			term->utf_char = (c & 0x1f);		    } else if ((c & 0xf0) == 0xe0) {			term->utf_size = term->utf_state = 2;			term->utf_char = (c & 0x0f);		    } else if ((c & 0xf8) == 0xf0) {			term->utf_size = term->utf_state = 3;			term->utf_char = (c & 0x07);		    } else if ((c & 0xfc) == 0xf8) {			term->utf_size = term->utf_state = 4;			term->utf_char = (c & 0x03);		    } else if ((c & 0xfe) == 0xfc) {			term->utf_size = term->utf_state = 5;			term->utf_char = (c & 0x01);		    } else {			c = UCSERR;			break;		    }		    continue;		  case 1:		  case 2:		  case 3:		  case 4:		  case 5:		    if ((c & 0xC0) != 0x80) {			unget = c;			c = UCSERR;			term->utf_state = 0;			break;		    }		    term->utf_char = (term->utf_char << 6) | (c & 0x3f);		    if (--term->utf_state)			continue;		    c = term->utf_char;		    /* Is somebody trying to be evil! */		    if (c < 0x80 ||			(c < 0x800 && term->utf_size >= 2) ||			(c < 0x10000 && term->utf_size >= 3) ||			(c < 0x200000 && term->utf_size >= 4) ||			(c < 0x4000000 && term->utf_size >= 5))			c = UCSERR;		    /* Unicode line separator and paragraph separator are CR-LF */		    if (c == 0x2028 || c == 0x2029)			c = 0x85;		    /* High controls are probably a Baaad idea too. */		    if (c < 0xA0)			c = 0xFFFD;		    /* The UTF-16 surrogates are not nice either. */		    /*       The standard give the option of decoding these: 		     *       I don't want to! */		    if (c >= 0xD800 && c < 0xE000)			c = UCSERR;		    /* ISO 10646 characters now limited to UTF-16 range. */		    if (c > 0x10FFFF)			c = UCSERR;		    /* This is currently a TagPhobic application.. */		    if (c >= 0xE0000 && c <= 0xE007F)			continue;		    /* U+FEFF is best seen as a null. */		    if (c == 0xFEFF)			continue;		    /* But U+FFFE is an error. */		    if (c == 0xFFFE || c == 0xFFFF)			c = UCSERR;		    break;	    }	    /* Are we in the nasty ACS mode? Note: no sco in utf mode. */	    else if(term->sco_acs && 		    (c!='\033' && c!='\012' && c!='\015' && c!='\b'))	    {	       if (term->sco_acs == 2) c |= 0x80;	       c |= CSET_SCOACS;	    } else {		switch (term->cset_attr[term->cset]) {		    /* 		     * Linedraw characters are different from 'ESC ( B'		     * only for a small range. For ones outside that		     * range, make sure we use the same font as well as		     * the same encoding.		     */		  case CSET_LINEDRW:		    if (term->ucsdata->unitab_ctrl[c] != 0xFF)			c = term->ucsdata->unitab_ctrl[c];		    else			c = ((unsigned char) c) | CSET_LINEDRW;		    break;		  case CSET_GBCHR:		    /* If UK-ASCII, make the '#' a LineDraw Pound */		    if (c == '#') {			c = '}' | CSET_LINEDRW;			break;		    }		  /*FALLTHROUGH*/ case CSET_ASCII:		    if (term->ucsdata->unitab_ctrl[c] != 0xFF)			c = term->ucsdata->unitab_ctrl[c];		    else			c = ((unsigned char) c) | CSET_ASCII;		    break;		case CSET_SCOACS:		    if (c>=' ') c = ((unsigned char)c) | CSET_SCOACS;		    break;		}	    }	}	/* How about C1 controls ? */	if ((c & -32) == 0x80 && term->termstate < DO_CTRLS &&	    !term->vt52_mode && has_compat(VT220)) {	    term->termstate = SEEN_ESC;	    term->esc_query = FALSE;	    c = '@' + (c & 0x1F);	}	/* Or the GL control. */	if (c == '\177' && term->termstate < DO_CTRLS && has_compat(OTHER)) {	    if (term->curs.x && !term->wrapnext)		term->curs.x--;	    term->wrapnext = FALSE;	    /* destructive backspace might be disabled */	    if (!term->cfg.no_dbackspace) {		check_boundary(term, term->curs.x, term->curs.y);		check_boundary(term, term->curs.x+1, term->curs.y);		copy_termchar(scrlineptr(term->curs.y),			      term->curs.x, &term->erase_char);	    }	} else	    /* Or normal C0 controls. */	if ((c & ~0x1F) == 0 && term->termstate < DO_CTRLS) {	    switch (c) {	      case '\005':	       /* ENQ: terminal type query */		/* Strictly speaking this is VT100 but a VT100 defaults to		 * no response. Other terminals respond at their option.		 *		 * Don't put a CR in the default string as this tends to		 * upset some weird software.		 *		 * An xterm returns "xterm" (5 characters)		 */		compatibility(ANSIMIN);		if (term->ldisc) {		    char abuf[256], *s, *d;		    int state = 0;		    for (s = term->cfg.answerback, d = abuf; *s; s++) {			if (state) {			    if (*s >= 'a' && *s <= 'z')				*d++ = (*s - ('a' - 1));			    else if ((*s >= '@' && *s <= '_') ||				     *s == '?' || (*s & 0x80))				*d++ = ('@' ^ *s);			    else if (*s == '~')				*d++ = '^';			    state = 0;			} else if (*s == '^') {			    state = 1;			} else			    *d++ = *s;		    }		    lpage_send(term->ldisc, DEFAULT_CODEPAGE,			       abuf, d - abuf, 0);		}		break;	      case '\007':	      /* BEL: Bell */		{		    struct beeptime *newbeep;		    unsigned long ticks;		    ticks = GETTICKCOUNT();		    if (!term->beep_overloaded) {			newbeep = snew(struct beeptime);			newbeep->ticks = ticks;			newbeep->next = NULL;			if (!term->beephead)			    term->beephead = newbeep;			else			    term->beeptail->next = newbeep;			term->beeptail = newbeep;			term->nbeeps++;		    }		    /*		     * Throw out any beeps that happened more than		     * t seconds ago.		     */		    while (term->beephead &&			   term->beephead->ticks < ticks - term->cfg.bellovl_t) {			struct beeptime *tmp = term->beephead;			term->beephead = tmp->next;			sfree(tmp);			if (!term->beephead)			    term->beeptail = NULL;			term->nbeeps--;		    }		    if (term->cfg.bellovl && term->beep_overloaded &&			ticks - term->lastbeep >= (unsigned)term->cfg.bellovl_s) {			/*			 * If we're currently overloaded and the			 * last beep was more than s seconds ago,			 * leave overload mode.			 */			term->beep_overloaded = FALSE;		    } else if (term->cfg.bellovl && !term->beep_overloaded &&			       term->nbeeps >= term->cfg.bellovl_n) {			/*			 * Now, if we have n or more beeps			 * remaining in the queue, go into overload			 * mode.			 */			term->beep_overloaded = TRUE;		    }		    term->lastbeep = ticks;		    /*		     * Perform an actual beep if we're not overloaded.		     */		    if (!term->cfg.bellovl || !term->beep_overloaded) {			beep(term->frontend, term->cfg.beep);			if (term->cfg.beep == BELL_VISUAL) {			    term_schedule_vbell(term, FALSE, 0);			}		    }		    seen_disp_event(term);		}		break;	      case '\b':	      /* BS: Back space */		if (term->curs.x == 0 &&		    (term->curs.y == 0 || term->wrap == 0))		    /* do nothing */ ;		else if (term->curs.x == 0 && term->curs.y > 0)		    term->curs.x = term->cols - 1, term->curs.y--;		else if (term->wrapnext)		    term->wrapnext = FALSE;		else		    term->curs.x--;		seen_disp_event(term);		break;	      case '\016':	      /* LS1: Locking-shift one */		compatibility(VT100);		term->cset = 1;		break;	      case '\017':	      /* LS0: Locking-shift zero */		compatibility(VT100);		term->cset = 0;		break;	      case '\033':	      /* ESC: Escape */		if (term->vt52_mode)		    term->termstate = VT52_ESC;		else {		    compatibility(ANSIMIN);		    term->termstate = SEEN_ESC;		    term->esc_query = FALSE;		}		break;	      case '\015':	      /* CR: Carriage return */		term->curs.x = 0;		term->wrapnext = FALSE;		seen_disp_event(term);		term->paste_hold = 0;		if (term->logctx)		    logtraffic(term->logctx, (unsigned char) c, LGTYP_ASCII);		break;	      case '\014':	      /* FF: Form feed */		if (has_compat(SCOANSI)) {		    move(term, 0, 0, 0);		    erase_lots(term, FALSE, FALSE, TRUE);		    term->disptop = 0;		    term->wrapnext = FALSE;		    seen_disp_event(term);		    break;		}	      case '\013':	      /* VT: Line tabulation */		compatibility(VT100);	      case '\012':	      /* LF: Line feed */		if (term->curs.y == term->marg_b)		    scroll(term, term->marg_t, term->marg_b, 1, TRUE);		else if (term->curs.y < term->rows - 1)		    term->curs.y++;		if (term->cfg.lfhascr)		    term->curs.x = 0;		term->wrapnext = FALSE;		seen_disp_event(term);		term->paste_hold = 0;		if (term->logctx)		    logtraffic(term->logctx, (unsigned char) c, LGTYP_ASCII);		break;	      case '\t':	      /* HT: Character tabulation */		{		    pos old_curs = term->curs;		    termline *ldata = scrlineptr(term->curs.y);		    do {			term->curs.x++;		    } while (term->curs.x < term->cols - 1 &&			     !term->tabs[term->curs.x]);		    if ((ldata->lattr & LATTR_MODE) != LATTR_NORM) {			if (term->curs.x >= term->cols / 2)			    term->curs.x = term->cols / 2 - 1;		    } else {			if (term->curs.x >= term->cols)			    term->curs.x = term->cols - 1;		    }		    check_selection(term, old_curs, term->curs);		}		seen_disp_event(term);		break;	    }	} else	    switch (term->termstate) {	      case TOPLEVEL:		/* Only graphic characters get this far;		 * ctrls are stripped above */		{		    termline *cline = scrlineptr(term->curs.y);		    int width = 0;		    if (DIRECT_CHAR(c))			width = 1;		    if (!width)			width = wcwidth((wchar_t) c);		    if (term->wrapnext && term->wrap && width > 0) {			cline->lattr |= LATTR_WRAPPED;			if (term->curs.y == term->marg_b)			    scroll(term, term->marg_t, term->marg_b, 1, TRUE);			else if (term->curs.y < term->rows - 1)			    term->curs.y++;			term->curs.x = 0;			term->wrapnext = FALSE;			cline = scrlineptr(term->curs.y);		    }		    if (term->insert && width > 0)			insch(term, width);		    if (term->selstate != NO_SELECTION) {			pos cursplus = term->curs;			incpos(cursplus);			check_selection(term, term->curs, cursplus);		    }		    if (((c & CSET_MASK) == CSET_ASCII ||			 (c & CSET_MASK) == 0) &&			term->logctx)			logtraffic(term->logctx, (unsigned char) c,				   LGTYP_ASCII);		    switch (width) {		      case 2:			/*			 * If we're about to display a double-width			 * character starting in the rightmost			 * column, then we do something special			 * instead. We must print a space in the			 * last column of the screen, then wrap;			 * and we also set LATTR_WRAPPED2 which			 * instructs subsequent cut-and-pasting not			 * only to splice this line to the one			 * after it, but to ignore the space in the			 * last character position as well.			 * (Because what was actually output to the			 * terminal was presumably just a sequence			 * of CJK characters, and we don't want a			 * space to be pasted in the middle of			 * those just because they had the			 * misfortune to start in the wrong parity			 * column. xterm concurs.)			 */			check_boundary(term, term->curs.x, term->curs.y);			check_boundary(term, term->curs.x+2, term->curs.y);			if (term->curs.x == term->cols-1) {			    copy_termchar(cline, term->curs.x,					  &term->erase_char);			    cline->lattr |= LATTR_WRAPPED | LATTR_WRAPPED2;			    if (term->curs.y == term->marg_b)				scroll(term, term->marg_t, term->marg_b,				       1, TRUE);			    else if (term->curs.y < term->rows - 1)				term->curs.y++;			    term->curs.x = 0;			    cline = scrlineptr(term->curs.y);			    /* Now we must check_boundary again, of course. */			    check_boundary(term, term->curs.x, term->curs.y);			    check_boundary(term, term->curs.x+2, term->curs.y);			}			/* FULL-TERMCHAR */			clear_cc(cline, term->curs.x);			cline->chars[term->curs.x].chr = c;			cline->chars[term->curs.x].attr = term->curr_attr;			term->curs.x++;			/* FULL-TERMCHAR */			clear_cc(cline, term->curs.x);			cline->chars[term->curs.x].chr = UCSWIDE;			cline->chars[term->curs.x].attr = term->curr_attr;			break;		      case 1:			check_boundary(term, term->curs.x, term->curs.y);			check_boundary(term, term->curs.x+1, term->curs.y);			/* FULL-TERMCHAR */			clear_cc(cline, term->curs.x);			cline->chars[term->curs.x].chr = c;			cline->chars[term->curs.x].attr = term->curr_attr;			break;		      case 0:			if (term->curs.x > 0) {			    int x = term->curs.x - 1;			    /* If we're in wrapnext state, the character			     * to combine with is _here_, not to our left. */			    if (term->wrapnext)				x++;			    /*			     * If the previous character is			     * UCSWIDE, back up another one.			     */			    if (cline->chars[x].chr == UCSWIDE) {				assert(x > 0);				x--;			    }			    add_cc(cline, x, c);			    seen_disp_event(term);			}			continue;		      default:			continue;		    }		    term->curs.x++;		    if (term->curs.x == term->cols) {			term->curs.x--;			term->wrapnext = TRUE;			if (term->wrap && term->vt52_mode) {			    cline->lattr |= LATTR_WRAPPED;			    if (term->curs.y == term->marg_b)				scroll(term, term->marg_t, term->marg_b, 1, TRUE);			    else if (term->curs.y < term->rows - 1)				term->curs.y++;			    term->curs.x = 0;			    term->wrapnext = FALSE;			}		    }		    seen_disp_event(term);		}		break;	      case OSC_MAYBE_ST:		/*		 * This state is virtually identical to SEEN_ESC, with the		 * exception that we have an OSC sequence in the pipeline,		 * and _if_ we see a backslash, we process it.		 */		if (c == '\\') {		    do_osc(term);		    term->termstate = TOPLEVEL;		    break;		}		/* else fall through */	      case SEEN_ESC:		if (c >= ' ' && c <= '/') {		    if (term->esc_query)			term->esc_query = -1;		    else			term->esc_query = c;		    break;		}		term->termstate = TOPLEVEL;		switch (ANSI(c, term->esc_query)) {		  case '[':		/* enter CSI mode */		    term->termstate = SEEN_CSI;		    term->esc_nargs = 1;		    term->esc_args[0] = ARG_DEFAULT;		    term->esc_query = FALSE;		    break;		  case ']':		/* OSC: xterm escape sequences */		    /* Compatibility is nasty here, xterm, linux, decterm yuk! */		    compatibility(OTHER);		    term->termstate = SEEN_OSC;		    term->esc_args[0] = 0;		    break;		  case '7':		/* DECSC: save cursor */		    compatibility(VT100);		    save_cursor(term, TRUE);		    break;		  case '8':	 	/* DECRC: restore cursor */		    compatibility(VT100);		    save_cursor(term, FALSE);		    seen_disp_event(term);		    break;		  case '=':		/* DECKPAM: Keypad application mode */		    compatibility(VT100);		    term->app_keypad_keys = TRUE;		    break;		  case '>':		/* DECKPNM: Keypad numeric mode */		    compatibility(VT100);		    term->app_keypad_keys = FALSE;		    break;		  case 'D':	       /* IND: exactly equivalent to LF */		    compatibility(VT100);		    if (term->curs.y == term->marg_b)			scroll(term, term->marg_t, term->marg_b, 1, TRUE);		    else if (term->curs.y < term->rows - 1)			term->curs.y++;		    term->wrapnext = FALSE;		    seen_disp_event(term);		    break;		  case 'E':	       /* NEL: exactly equivalent to CR-LF */		    compatibility(VT100);		    term->curs.x = 0;		    if (term->curs.y == term->marg_b)			scroll(term, term->marg_t, term->marg_b, 1, TRUE);		    else if (term->curs.y < term->rows - 1)			term->curs.y++;		    term->wrapnext = FALSE;		    seen_disp_event(term);		    break;		  case 'M':	       /* RI: reverse index - backwards LF */		    compatibility(VT100);		    if (term->curs.y == term->marg_t)			scroll(term, term->marg_t, term->marg_b, -1, TRUE);		    else if (term->curs.y > 0)			term->curs.y--;		    term->wrapnext = FALSE;		    seen_disp_event(term);		    break;		  case 'Z':	       /* DECID: terminal type query */		    compatibility(VT100);		    if (term->ldisc)			ldisc_send(term->ldisc, term->id_string,				   strlen(term->id_string), 0);		    break;		  case 'c':	       /* RIS: restore power-on settings */		    compatibility(VT100);		    power_on(term);		    if (term->ldisc)   /* cause ldisc to notice changes */			ldisc_send(term->ldisc, NULL, 0, 0);		    if (term->reset_132) {			if (!term->cfg.no_remote_resize)			    request_resize(term->frontend, 80, term->rows);			term->reset_132 = 0;		    }		    term->disptop = 0;		    seen_disp_event(term);		    break;		  case 'H':	       /* HTS: set a tab */		    compatibility(VT100);		    term->tabs[term->curs.x] = TRUE;		    break;		  case ANSI('8', '#'):	/* DECALN: fills screen with Es :-) */		    compatibility(VT100);		    {			termline *ldata;			int i, j;			pos scrtop, scrbot;			for (i = 0; i < term->rows; i++) {			    ldata = scrlineptr(i);			    for (j = 0; j < term->cols; j++) {				copy_termchar(ldata, j,					      &term->basic_erase_char);				ldata->chars[j].chr = 'E';			    }			    ldata->lattr = LATTR_NORM;			}			term->disptop = 0;			seen_disp_event(term);			scrtop.x = scrtop.y = 0;			scrbot.x = 0;			scrbot.y = term->rows;			check_selection(term, scrtop, scrbot);		    }		    break;		  case ANSI('3', '#'):		  case ANSI('4', '#'):		  case ANSI('5', '#'):		  case ANSI('6', '#'):		    compatibility(VT100);		    {			int nlattr;			switch (ANSI(c, term->esc_query)) {			  case ANSI('3', '#'): /* DECDHL: 2*height, top */			    nlattr = LATTR_TOP;			    break;			  case ANSI('4', '#'): /* DECDHL: 2*height, bottom */			    nlattr = LATTR_BOT;			    break;			  case ANSI('5', '#'): /* DECSWL: normal */			    nlattr = LATTR_NORM;			    break;			  default: /* case ANSI('6', '#'): DECDWL: 2*width */			    nlattr = LATTR_WIDE;			    break;			}			scrlineptr(term->curs.y)->lattr = nlattr;		    }		    break;		  /* GZD4: G0 designate 94-set */		  case ANSI('A', '('):		    compatibility(VT100);		    if (!term->cfg.no_remote_charset)			term->cset_attr[0] = CSET_GBCHR;		    break;		  case ANSI('B', '('):		    compatibility(VT100);		    if (!term->cfg.no_remote_charset)			term->cset_attr[0] = CSET_ASCII;		    break;		  case ANSI('0', '('):		    compatibility(VT100);		    if (!term->cfg.no_remote_charset)			term->cset_attr[0] = CSET_LINEDRW;		    break;		  case ANSI('U', '('): 		    compatibility(OTHER);		    if (!term->cfg.no_remote_charset)			term->cset_attr[0] = CSET_SCOACS; 		    break;		  /* G1D4: G1-designate 94-set */		  case ANSI('A', ')'):		    compatibility(VT100);		    if (!term->cfg.no_remote_charset)			term->cset_attr[1] = CSET_GBCHR;		    break;		  case ANSI('B', ')'):		    compatibility(VT100);		    if (!term->cfg.no_remote_charset)			term->cset_attr[1] = CSET_ASCII;		    break;		  case ANSI('0', ')'):		    compatibility(VT100);		    if (!term->cfg.no_remote_charset)			term->cset_attr[1] = CSET_LINEDRW;		    break;		  case ANSI('U', ')'): 		    compatibility(OTHER);		    if (!term->cfg.no_remote_charset)			term->cset_attr[1] = CSET_SCOACS; 		    break;		  /* DOCS: Designate other coding system */		  case ANSI('8', '%'):	/* Old Linux code */		  case ANSI('G', '%'):		    compatibility(OTHER);		    if (!term->cfg.no_remote_charset)			term->utf = 1;		    break;		  case ANSI('@', '%'):		    compatibility(OTHER);		    if (!term->cfg.no_remote_charset)			term->utf = 0;		    break;		}		break;	      case SEEN_CSI:		term->termstate = TOPLEVEL;  /* default */		if (isdigit(c)) {		    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';		    }		    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);			seen_disp_event(term);			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);			seen_disp_event(term);			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);			seen_disp_event(term);			break;		      case 'D':       /* CUB: move left N 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);			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);			move(term, 0,			     term->curs.y - def(term->esc_args[0], 1), 1);			seen_disp_event(term);			break;		      case 'G':	      /* CHA */		      case '`':       /* HPA: set horizontal posn */			compatibility(ANSI);			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);			move(term, term->curs.x,			     ((term->dec_om ? term->marg_t : 0) +			      def(term->esc_args[0], 1) - 1),			     (term->dec_om ? 2 : 0));			seen_disp_event(term);			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));			seen_disp_event(term);			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;			seen_disp_event(term);			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));			}			seen_disp_event(term);			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);			seen_disp_event(term);			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);			seen_disp_event(term);			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));			seen_disp_event(term);			break;		      case 'P':       /* DCH: delete chars */			compatibility(VT102);			insch(term, -def(term->esc_args[0], 1));			seen_disp_event(term);			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);				seen_disp_event(term);			    }			}			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;				    term_schedule_tblink(term);				    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 + 8)                                         << 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 + 8)                                         << ATTR_BGSHIFT);				    break;				  case 49:	/* default-background */				    term->curr_attr &= ~ATTR_BGMASK;				    term->curr_attr |= ATTR_DEFBG;				    break;				  case 38:   /* xterm 256-colour mode */				    if (i+2 < term->esc_nargs &&					term->esc_args[i+1] == 5) {					term->curr_attr &= ~ATTR_FGMASK;					term->curr_attr |=					    ((term->esc_args[i+2] & 0xFF)					     << ATTR_FGSHIFT);					i += 2;				    }				    break;				  case 48:   /* xterm 256-colour mode */				    if (i+2 < term->esc_nargs &&					term->esc_args[i+1] == 5) {					term->curr_attr &= ~ATTR_BGMASK;					term->curr_attr |=					    ((term->esc_args[i+2] & 0xFF)					     << ATTR_BGSHIFT);					i += 2;				    }				    break;				}			    }			    set_erase_char(term);			}			break;		      case 's':       /* save cursor */			save_cursor(term, TRUE);			break;		      case 'u':       /* restore cursor */			save_cursor(term, FALSE);			seen_disp_event(term);			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);			    switch (term->esc_args[0]) {				int x, y, len;				char buf[80], *p;			      case 1:				set_iconic(term->frontend, FALSE);				break;			      case 2:				set_iconic(term->frontend, TRUE);				break;			      case 3:				if (term->esc_nargs >= 3) {				    if (!term->cfg.no_remote_resize)					move_window(term->frontend,						    def(term->esc_args[1], 0),						    def(term->esc_args[2], 0));				}				break;			      case 4:				/* We should resize the window to a given				 * size in pixels here, but currently our				 * resizing code isn't healthy enough to				 * manage it. */				break;			      case 5:				/* move to top */				set_zorder(term->frontend, TRUE);				break;			      case 6:				/* move to bottom */				set_zorder(term->frontend, FALSE);				break;			      case 7:				refresh_window(term->frontend);				break;			      case 8:				if (term->esc_nargs >= 3) {				    if (!term->cfg.no_remote_resize)					request_resize(term->frontend,						       def(term->esc_args[2], term->cfg.width),						       def(term->esc_args[1], term->cfg.height));				}				break;			      case 9:				if (term->esc_nargs >= 2)				    set_zoomed(term->frontend,					       term->esc_args[1] ?					       TRUE : FALSE);				break;			      case 11:				if (term->ldisc)				    ldisc_send(term->ldisc,					       is_iconic(term->frontend) ?					       "\033[1t" : "\033[2t", 4, 0);				break;			      case 13:				if (term->ldisc) {				    get_window_pos(term->frontend, &x, &y);				    len = sprintf(buf, "\033[3;%d;%dt", x, y);				    ldisc_send(term->ldisc, buf, len, 0);				}				break;			      case 14:				if (term->ldisc) {				    get_window_pixels(term->frontend, &x, &y);				    len = sprintf(buf, "\033[4;%d;%dt", x, y);				    ldisc_send(term->ldisc, buf, len, 0);				}				break;			      case 18:				if (term->ldisc) {				    len = sprintf(buf, "\033[8;%d;%dt",						  term->rows, term->cols);				    ldisc_send(term->ldisc, buf, len, 0);				}				break;			      case 19:				/*				 * Hmmm. Strictly speaking we				 * should return `the size of the				 * screen in characters', but				 * that's not easy: (a) window				 * furniture being what it is it's				 * hard to compute, and (b) in				 * resize-font mode maximising the				 * window wouldn't change the				 * number of characters. *shrug*. I				 * think we'll ignore it for the				 * moment and see if anyone				 * complains, and then ask them				 * what they would like it to do.				 */				break;			      case 20:				if (term->ldisc &&				    !term->cfg.no_remote_qtitle) {				    p = get_window_title(term->frontend, TRUE);				    len = strlen(p);				    ldisc_send(term->ldisc, "\033]L", 3, 0);				    ldisc_send(term->ldisc, p, len, 0);				    ldisc_send(term->ldisc, "\033\\", 2, 0);				}				break;			      case 21:				if (term->ldisc &&				    !term->cfg.no_remote_qtitle) {				    p = get_window_title(term->frontend,FALSE);				    len = strlen(p);				    ldisc_send(term->ldisc, "\033]l", 3, 0);				    ldisc_send(term->ldisc, p, len, 0);				    ldisc_send(term->ldisc, "\033\\", 2, 0);				}				break;			    }			}			break;		      case 'S':		/* SU: Scroll up */			compatibility(SCOANSI);			scroll(term, term->marg_t, term->marg_b,			       def(term->esc_args[0], 1), TRUE);			term->wrapnext = FALSE;			seen_disp_event(term);			break;		      case 'T':		/* SD: Scroll down */			compatibility(SCOANSI);			scroll(term, term->marg_t, term->marg_b,			       -def(term->esc_args[0], 1), TRUE);			term->wrapnext = FALSE;			seen_disp_event(term);			break;		      case ANSI('|', '*'): /* DECSNLS */			/* 			 * Set number of lines on screen			 * VT420 uses VGA like hardware and can			 * support any size in reasonable range			 * (24..49 AIUI) with no default specified.			 */			compatibility(VT420);			if (term->esc_nargs == 1 && term->esc_args[0] > 0) {			    if (!term->cfg.no_remote_resize)				request_resize(term->frontend, term->cols,					       def(term->esc_args[0],						   term->cfg.height));			    deselect(term);			}			break;		      case ANSI('|', '$'): /* DECSCPP */			/*			 * Set number of columns per page			 * Docs imply range is only 80 or 132, but			 * I'll allow any.			 */			compatibility(VT340TEXT);			if (term->esc_nargs <= 1) {			    if (!term->cfg.no_remote_resize)				request_resize(term->frontend,					       def(term->esc_args[0],						   term->cfg.width), term->rows);			    deselect(term);			}			break;		      case 'X':     /* ECH: write N spaces w/o moving cursor */			/* XXX VTTEST says this is vt220, vt510 manual			 * says vt100 */			compatibility(ANSIMIN);			{			    int n = def(term->esc_args[0], 1);			    pos cursplus;			    int p = term->curs.x;			    termline *cline = scrlineptr(term->curs.y);			    if (n > term->cols - term->curs.x)				n = term->cols - term->curs.x;			    cursplus = term->curs;			    cursplus.x += n;			    check_boundary(term, term->curs.x, term->curs.y);			    check_boundary(term, term->curs.x+n, term->curs.y);			    check_selection(term, term->curs, cursplus);			    while (n--)				copy_termchar(cline, p++,					      &term->erase_char);			    seen_disp_event(term);			}			break;		      case 'x':       /* DECREQTPARM: report terminal characteristics */			compatibility(VT100);			if (term->ldisc) {			    char buf[32];			    int i = def(term->esc_args[0], 0);			    if (i == 0 || i == 1) {				strcpy(buf, "\033[2;1;1;112;112;1;0x");				buf[2] += i;				ldisc_send(term->ldisc, buf, 20, 0);			    }			}			break;		      case 'Z':		/* CBT: BackTab for xterm */			compatibility(OTHER);			{			    int i = def(term->esc_args[0], 1);			    pos old_curs = term->curs;			    for(;i>0 && term->curs.x>0; i--) {				do {				    term->curs.x--;				} while (term->curs.x >0 &&					 !term->tabs[term->curs.x]);			    }			    check_selection(term, old_curs, term->curs);			}			break;		      case ANSI('c', '='):      /* Hide or Show Cursor */			compatibility(SCOANSI);			switch(term->esc_args[0]) {			  case 0:  /* hide cursor */			    term->cursor_on = FALSE;			    break;			  case 1:  /* restore cursor */			    term->big_cursor = FALSE;			    term->cursor_on = TRUE;			    break;			  case 2:  /* block cursor */			    term->big_cursor = TRUE;			    term->cursor_on = TRUE;			    break;			}			break;		      case ANSI('C', '='):			/*			 * set cursor start on scanline esc_args[0] and			 * end on scanline esc_args[1].If you set			 * the bottom scan line to a value less than			 * the top scan line, the cursor will disappear.			 */			compatibility(SCOANSI);			if (term->esc_nargs >= 2) {			    if (term->esc_args[0] > term->esc_args[1])				term->cursor_on = FALSE;			    else				term->cursor_on = TRUE;			}			break;		      case ANSI('D', '='):			compatibility(SCOANSI);			term->blink_is_real = FALSE;			term_schedule_tblink(term);			if (term->esc_args[0]>=1)			    term->curr_attr |= ATTR_BLINK;			else			    term->curr_attr &= ~ATTR_BLINK;			break;		      case ANSI('E', '='):			compatibility(SCOANSI);			term->blink_is_real = (term->esc_args[0] >= 1);			term_schedule_tblink(term);			break;		      case ANSI('F', '='):      /* set normal foreground */			compatibility(SCOANSI);			if (term->esc_args[0] >= 0 && term->esc_args[0] < 16) {			    long colour = 				(sco2ansicolour[term->esc_args[0] & 0x7] |				 (term->esc_args[0] & 0x8)) <<				ATTR_FGSHIFT;			    term->curr_attr &= ~ATTR_FGMASK;			    term->curr_attr |= colour;			    term->default_attr &= ~ATTR_FGMASK;			    term->default_attr |= colour;			}			break;		      case ANSI('G', '='):      /* set normal background */			compatibility(SCOANSI);			if (term->esc_args[0] >= 0 && term->esc_args[0] < 16) {			    long colour = 				(sco2ansicolour[term->esc_args[0] & 0x7] |				 (term->esc_args[0] & 0x8)) <<				ATTR_BGSHIFT;			    term->curr_attr &= ~ATTR_BGMASK;			    term->curr_attr |= colour;			    term->default_attr &= ~ATTR_BGMASK;			    term->default_attr |= colour;			}			break;		      case ANSI('L', '='):			compatibility(SCOANSI);			term->use_bce = (term->esc_args[0] <= 0);			set_erase_char(term);			break;		      case ANSI('p', '"'): /* DECSCL: set compat level */			/*			 * Allow the host to make this emulator a			 * 'perfect' VT102. This first appeared in			 * the VT220, but we do need to get back to			 * PuTTY mode so I won't check it.			 *			 * The arg in 40..42,50 are a PuTTY extension.			 * The 2nd arg, 8bit vs 7bit is not checked.			 *			 * Setting VT102 mode should also change			 * the Fkeys to generate PF* codes as a			 * real VT102 has no Fkeys. The VT220 does			 * this, F11..F13 become ESC,BS,LF other			 * Fkeys send nothing.			 *			 * Note ESC c will NOT change this!			 */			switch (term->esc_args[0]) {			  case 61:			    term->compatibility_level &= ~TM_VTXXX;			    term->compatibility_level |= TM_VT102;			    break;			  case 62:			    term->compatibility_level &= ~TM_VTXXX;			    term->compatibility_level |= TM_VT220;			    break;			  default:			    if (term->esc_args[0] > 60 &&				term->esc_args[0] < 70)				term->compatibility_level |= TM_VTXXX;			    break;			  case 40:			    term->compatibility_level &= TM_VTXXX;			    break;			  case 41:			    term->compatibility_level = TM_PUTTY;			    break;			  case 42:			    term->compatibility_level = TM_SCOANSI;			    break;			  case ARG_DEFAULT:			    term->compatibility_level = TM_PUTTY;			    break;			  case 50:			    break;			}			/* Change the response to CSI c */			if (term->esc_args[0] == 50) {			    int i;			    char lbuf[64];			    strcpy(term->id_string, "\033[?");			    for (i = 1; i < term->esc_nargs; i++) {				if (i != 1)				    strcat(term->id_string, ";");				sprintf(lbuf, "%d", term->esc_args[i]);				strcat(term->id_string, lbuf);			    }			    strcat(term->id_string, "c");			}#if 0			/* Is this a good idea ? 			 * Well we should do a soft reset at this point ...			 */			if (!has_compat(VT420) && has_compat(VT100)) {			    if (!term->cfg.no_remote_resize) {				if (term->reset_132)				    request_resize(132, 24);				else				    request_resize(80, 24);			    }			}#endif			break;		    }		break;	      case SEEN_OSC:		term->osc_w = FALSE;		switch (c) {		  case 'P':	       /* Linux palette sequence */		    term->termstate = SEEN_OSC_P;		    term->osc_strlen = 0;		    break;		  case 'R':	       /* Linux palette reset */		    palette_reset(term->frontend);		    term_invalidate(term);		    term->termstate = TOPLEVEL;		    break;		  case 'W':	       /* word-set */		    term->termstate = SEEN_OSC_W;		    term->osc_w = TRUE;		    break;		  case '0':		  case '1':		  case '2':		  case '3':		  case '4':		  case '5':		  case '6':		  case '7':		  case '8':		  case '9':		    term->esc_args[0] = 10 * term->esc_args[0] + c - '0';		    break;		  case 'L':		    /*		     * Grotty hack to support xterm and DECterm title		     * sequences concurrently.		     */		    if (term->esc_args[0] == 2) {			term->esc_args[0] = 1;			break;		    }		    /* else fall through */		  default:		    term->termstate = OSC_STRING;		    term->osc_strlen = 0;		}		break;	      case OSC_STRING:		/*		 * This OSC stuff is EVIL. It takes just one character to get into		 * sysline mode and it's not initially obvious how to get out.		 * So I've added CR and LF as string aborts.		 * This shouldn't effect compatibility as I believe embedded 		 * control characters are supposed to be interpreted (maybe?) 		 * and they don't display anything useful anyway.		 *		 * -- RDB		 */		if (c == '\012' || c == '\015') {		    term->termstate = TOPLEVEL;		} else if (c == 0234 || c == '\007') {		    /*		     * These characters terminate the string; ST and BEL		     * terminate the sequence and trigger instant		     * processing of it, whereas ESC goes back to SEEN_ESC		     * mode unless it is followed by \, in which case it is		     * synonymous with ST in the first place.		     */		    do_osc(term);		    term->termstate = TOPLEVEL;		} else if (c == '\033')		    term->termstate = OSC_MAYBE_ST;		else if (term->osc_strlen < OSC_STR_MAX)		    term->osc_string[term->osc_strlen++] = (char)c;		break;	      case SEEN_OSC_P:		{		    int max = (term->osc_strlen == 0 ? 21 : 16);		    int val;		    if ((int)c >= '0' && (int)c <= '9')			val = c - '0';		    else if ((int)c >= 'A' && (int)c <= 'A' + max - 10)			val = c - 'A' + 10;		    else if ((int)c >= 'a' && (int)c <= 'a' + max - 10)			val = c - 'a' + 10;		    else {			term->termstate = TOPLEVEL;			break;		    }		    term->osc_string[term->osc_strlen++] = val;		    if (term->osc_strlen >= 7) {			palette_set(term->frontend, term->osc_string[0],				    term->osc_string[1] * 16 + term->osc_string[2],				    term->osc_string[3] * 16 + term->osc_string[4],				    term->osc_string[5] * 16 + term->osc_string[6]);			term_invalidate(term);			term->termstate = TOPLEVEL;		    }		}		break;	      case SEEN_OSC_W:		switch (c) {		  case '0':		  case '1':		  case '2':		  case '3':		  case '4':		  case '5':		  case '6':		  case '7':		  case '8':		  case '9':		    term->esc_args[0] = 10 * term->esc_args[0] + c - '0';		    break;		  default:		    term->termstate = OSC_STRING;		    term->osc_strlen = 0;		}		break;	      case VT52_ESC:		term->termstate = TOPLEVEL;		seen_disp_event(term);		switch (c) {		  case 'A':		    move(term, term->curs.x, term->curs.y - 1, 1);		    break;		  case 'B':		    move(term, term->curs.x, term->curs.y + 1, 1);		    break;		  case 'C':		    move(term, term->curs.x + 1, term->curs.y, 1);		    break;		  case 'D':		    move(term, term->curs.x - 1, term->curs.y, 1);		    break;		    /*		     * From the VT100 Manual		     * NOTE: The special graphics characters in the VT100		     *       are different from those in the VT52		     *		     * From VT102 manual:		     *       137 _  Blank             - Same		     *       140 `  Reserved          - Humm.		     *       141 a  Solid rectangle   - Similar		     *       142 b  1/                - Top half of fraction for the		     *       143 c  3/                - subscript numbers below.		     *       144 d  5/		     *       145 e  7/		     *       146 f  Degrees           - Same		     *       147 g  Plus or minus     - Same		     *       150 h  Right arrow		     *       151 i  Ellipsis (dots)		     *       152 j  Divide by		     *       153 k  Down arrow		     *       154 l  Bar at scan 0		     *       155 m  Bar at scan 1		     *       156 n  Bar at scan 2		     *       157 o  Bar at scan 3     - Similar		     *       160 p  Bar at scan 4     - Similar		     *       161 q  Bar at scan 5     - Similar		     *       162 r  Bar at scan 6     - Same		     *       163 s  Bar at scan 7     - Similar		     *       164 t  Subscript 0		     *       165 u  Subscript 1		     *       166 v  Subscript 2		     *       167 w  Subscript 3		     *       170 x  Subscript 4		     *       171 y  Subscript 5		     *       172 z  Subscript 6		     *       173 {  Subscript 7		     *       174 |  Subscript 8		     *       175 }  Subscript 9		     *       176 ~  Paragraph		     *		     */		  case 'F':		    term->cset_attr[term->cset = 0] = CSET_LINEDRW;		    break;		  case 'G':		    term->cset_attr[term->cset = 0] = CSET_ASCII;		    break;		  case 'H':		    move(term, 0, 0, 0);		    break;		  case 'I':		    if (term->curs.y == 0)			scroll(term, 0, term->rows - 1, -1, TRUE);		    else if (term->curs.y > 0)			term->curs.y--;		    term->wrapnext = FALSE;		    break;		  case 'J':		    erase_lots(term, FALSE, FALSE, TRUE);		    term->disptop = 0;		    break;		  case 'K':		    erase_lots(term, TRUE, FALSE, TRUE);		    break;#if 0		  case 'V':		    /* XXX Print cursor line */		    break;		  case 'W':		    /* XXX Start controller mode */		    break;		  case 'X':		    /* XXX Stop controller mode */		    break;#endif		  case 'Y':		    term->termstate = VT52_Y1;		    break;		  case 'Z':		    if (term->ldisc)			ldisc_send(term->ldisc, "\033/Z", 3, 0);		    break;		  case '=':		    term->app_keypad_keys = TRUE;		    break;		  case '>':		    term->app_keypad_keys = FALSE;		    break;		  case '<':		    /* XXX This should switch to VT100 mode not current or default		     *     VT mode. But this will only have effect in a VT220+		     *     emulation.		     */		    term->vt52_mode = FALSE;		    term->blink_is_real = term->cfg.blinktext;		    term_schedule_tblink(term);		    break;#if 0		  case '^':		    /* XXX Enter auto print mode */		    break;		  case '_':		    /* XXX Exit auto print mode */		    break;		  case ']':		    /* XXX Print screen */		    break;#endif#ifdef VT52_PLUS		  case 'E':		    /* compatibility(ATARI) */		    move(term, 0, 0, 0);		    erase_lots(term, FALSE, FALSE, TRUE);		    term->disptop = 0;		    break;		  case 'L':		    /* compatibility(ATARI) */		    if (term->curs.y <= term->marg_b)			scroll(term, term->curs.y, term->marg_b, -1, FALSE);		    break;		  case 'M':		    /* compatibility(ATARI) */		    if (term->curs.y <= term->marg_b)			scroll(term, term->curs.y, term->marg_b, 1, TRUE);		    break;		  case 'b':		    /* compatibility(ATARI) */		    term->termstate = VT52_FG;		    break;		  case 'c':		    /* compatibility(ATARI) */		    term->termstate = VT52_BG;		    break;		  case 'd':		    /* compatibility(ATARI) */		    erase_lots(term, FALSE, TRUE, FALSE);		    term->disptop = 0;		    break;		  case 'e':		    /* compatibility(ATARI) */		    term->cursor_on = TRUE;		    break;		  case 'f':		    /* compatibility(ATARI) */		    term->cursor_on = FALSE;		    break;		    /* case 'j': Save cursor position - broken on ST */		    /* case 'k': Restore cursor position */		  case 'l':		    /* compatibility(ATARI) */		    erase_lots(term, TRUE, TRUE, TRUE);		    term->curs.x = 0;		    term->wrapnext = FALSE;		    break;		  case 'o':		    /* compatibility(ATARI) */		    erase_lots(term, TRUE, TRUE, FALSE);		    break;		  case 'p':		    /* compatibility(ATARI) */		    term->curr_attr |= ATTR_REVERSE;		    break;		  case 'q':		    /* compatibility(ATARI) */		    term->curr_attr &= ~ATTR_REVERSE;		    break;		  case 'v':	       /* wrap Autowrap on - Wyse style */		    /* compatibility(ATARI) */		    term->wrap = 1;		    break;		  case 'w':	       /* Autowrap off */		    /* compatibility(ATARI) */		    term->wrap = 0;		    break;		  case 'R':		    /* compatibility(OTHER) */		    term->vt52_bold = FALSE;		    term->curr_attr = ATTR_DEFAULT;		    set_erase_char(term);		    break;		  case 'S':		    /* compatibility(VI50) */		    term->curr_attr |= ATTR_UNDER;		    break;		  case 'W':		    /* compatibility(VI50) */		    term->curr_attr &= ~ATTR_UNDER;		    break;		  case 'U':		    /* compatibility(VI50) */		    term->vt52_bold = TRUE;		    term->curr_attr |= ATTR_BOLD;		    break;		  case 'T':		    /* compatibility(VI50) */		    term->vt52_bold = FALSE;		    term->curr_attr &= ~ATTR_BOLD;		    break;#endif		}		break;	      case VT52_Y1:		term->termstate = VT52_Y2;		move(term, term->curs.x, c - ' ', 0);		break;	      case VT52_Y2:		term->termstate = TOPLEVEL;		move(term, c - ' ', term->curs.y, 0);		break;#ifdef VT52_PLUS	      case VT52_FG:		term->termstate = TOPLEVEL;		term->curr_attr &= ~ATTR_FGMASK;		term->curr_attr &= ~ATTR_BOLD;		term->curr_attr |= (c & 0xF) << ATTR_FGSHIFT;		set_erase_char(term);		break;	      case VT52_BG:		term->termstate = TOPLEVEL;		term->curr_attr &= ~ATTR_BGMASK;		term->curr_attr &= ~ATTR_BLINK;		term->curr_attr |= (c & 0xF) << ATTR_BGSHIFT;		set_erase_char(term);		break;#endif	      default: break;	       /* placate gcc warning about enum use */	    }	if (term->selstate != NO_SELECTION) {	    pos cursplus = term->curs;	    incpos(cursplus);	    check_selection(term, term->curs, cursplus);	}    }    term_print_flush(term);    if (term->cfg.logflush)	logflush(term->logctx);}