if (line_codepage != CP_UTF8) utf = 0;
utf = 0;
void term_out(void){    int c, inbuf_reap;    for (inbuf_reap = 0; inbuf_reap < inbuf_head; inbuf_reap++) {	c = inbuf[inbuf_reap];	/*	 * Optionally log the session traffic to a file. Useful for	 * debugging and possibly also useful for actual logging.	 */	logtraffic((unsigned char) c, LGTYP_DEBUG);	/* 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.	 */	/* First see about all those translations. */	if (termstate == TOPLEVEL) {	    if (utf)		switch (utf_state) {		  case 0:		    if (c < 0x80) {			/* I know; gotos are evil. This one is really bad!			 * But before you try removing it follow the path of the			 * sequence "0x5F 0xC0 0x71" with UTF and VTGraphics on.			 */			/*			   if (cfg.no_vt_graph_with_utf8) break;			 */			goto evil_jump;		    } else if ((c & 0xe0) == 0xc0) {			utf_size = utf_state = 1;			utf_char = (c & 0x1f);		    } else if ((c & 0xf0) == 0xe0) {			utf_size = utf_state = 2;			utf_char = (c & 0x0f);		    } else if ((c & 0xf8) == 0xf0) {			utf_size = utf_state = 3;			utf_char = (c & 0x07);		    } else if ((c & 0xfc) == 0xf8) {			utf_size = utf_state = 4;			utf_char = (c & 0x03);		    } else if ((c & 0xfe) == 0xfc) {			utf_size = utf_state = 5;			utf_char = (c & 0x01);		    } else {			c = UCSERR;			break;		    }		    continue;		  case 1:		  case 2:		  case 3:		  case 4:		  case 5:		    if ((c & 0xC0) != 0x80) {			inbuf_reap--;  /* This causes the faulting character */			c = UCSERR;    /* to be logged twice - not really a */			utf_state = 0; /* serious problem. */			break;		    }		    utf_char = (utf_char << 6) | (c & 0x3f);		    if (--utf_state)			continue;		    c = utf_char;		    /* Is somebody trying to be evil! */		    if (c < 0x80 ||			(c < 0x800 && utf_size >= 2) ||			(c < 0x10000 && utf_size >= 3) ||			(c < 0x200000 && utf_size >= 4) ||			(c < 0x4000000 && 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;		    /* Oops this is a 16bit implementation */		    if (c >= 0x10000)			c = 0xFFFD;		    break;	    }	    /* Are we in the nasty ACS mode? Note: no sco in utf mode. */	    else if(sco_acs && 		    (c!='\033' && c!='\n' && c!='\r' && c!='\b'))	    {	       if (sco_acs == 2) c ^= 0x80;	       c |= ATTR_SCOACS;	    } else {	      evil_jump:;		switch (cset_attr[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 ATTR_LINEDRW:		    if (unitab_ctrl[c] != 0xFF)			c = unitab_ctrl[c];		    else			c = ((unsigned char) c) | ATTR_LINEDRW;		    break;		  case ATTR_GBCHR:		    /* If UK-ASCII, make the '#' a LineDraw Pound */		    if (c == '#') {			c = '}' | ATTR_LINEDRW;			break;		    }		  /*FALLTHROUGH*/ case ATTR_ASCII:		    if (unitab_ctrl[c] != 0xFF)			c = unitab_ctrl[c];		    else			c = ((unsigned char) c) | ATTR_ASCII;		    break;		case ATTR_SCOACS:		    if (c>=' ') c = ((unsigned char)c) | ATTR_SCOACS;		    break;		}	    }	}	/* How about C1 controls ? */	if ((c & -32) == 0x80 && termstate < DO_CTRLS && !vt52_mode &&	    has_compat(VT220)) {	    termstate = SEEN_ESC;	    esc_query = FALSE;	    c = '@' + (c & 0x1F);	}	/* Or the GL control. */	if (c == '\177' && termstate < DO_CTRLS && has_compat(OTHER)) {	    if (curs.x && !wrapnext)		curs.x--;	    wrapnext = FALSE;	    fix_cpos;	    *cpos = (' ' | curr_attr | ATTR_ASCII);	} else	    /* Or normal C0 controls. */	if ((c & -32) == 0 && termstate < DO_CTRLS) {	    switch (c) {	      case '\005':	       /* 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);		{		    char abuf[256], *s, *d;		    int state = 0;		    for (s = 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(CP_ACP, abuf, d - abuf);		}		break;	      case '\007':		{		    struct beeptime *newbeep;		    long ticks;		    ticks = GetTickCount();		    if (!beep_overloaded) {			newbeep = smalloc(sizeof(struct beeptime));			newbeep->ticks = ticks;			newbeep->next = NULL;			if (!beephead)			    beephead = newbeep;			else			    beeptail->next = newbeep;			beeptail = newbeep;			nbeeps++;		    }		    /*		     * Throw out any beeps that happened more than		     * t seconds ago.		     */		    while (beephead &&			   beephead->ticks < ticks - cfg.bellovl_t) {			struct beeptime *tmp = beephead;			beephead = tmp->next;			sfree(tmp);			if (!beephead)			    beeptail = NULL;			nbeeps--;		    }		    if (cfg.bellovl && beep_overloaded &&			ticks - lastbeep >= cfg.bellovl_s) {			/*			 * If we're currently overloaded and the			 * last beep was more than s seconds ago,			 * leave overload mode.			 */			beep_overloaded = FALSE;		    } else if (cfg.bellovl && !beep_overloaded &&			       nbeeps >= cfg.bellovl_n) {			/*			 * Now, if we have n or more beeps			 * remaining in the queue, go into overload			 * mode.			 */			beep_overloaded = TRUE;		    }		    lastbeep = ticks;		    /*		     * Perform an actual beep if we're not overloaded.		     */		    if (!cfg.bellovl || !beep_overloaded) {			beep(cfg.beep);			if (cfg.beep == BELL_VISUAL) {			    in_vbell = TRUE;			    vbell_timeout = ticks + VBELL_TIMEOUT;			    term_update();			}		    }		    disptop = 0;		}		break;	      case '\b':		if (curs.x == 0 && (curs.y == 0 || wrap == 0));		else if (curs.x == 0 && curs.y > 0)		    curs.x = cols - 1, curs.y--;		else if (wrapnext)		    wrapnext = FALSE;		else		    curs.x--;		fix_cpos;		seen_disp_event = TRUE;		break;	      case '\016':		compatibility(VT100);		cset = 1;		break;	      case '\017':		compatibility(VT100);		cset = 0;		break;	      case '\033':		if (vt52_mode)		    termstate = VT52_ESC;		else {		    compatibility(ANSIMIN);		    termstate = SEEN_ESC;		    esc_query = FALSE;		}		break;	      case '\r':		curs.x = 0;		wrapnext = FALSE;		fix_cpos;		seen_disp_event = TRUE;		paste_hold = 0;		logtraffic((unsigned char) c, LGTYP_ASCII);		break;	      case '\014':		if (has_compat(SCOANSI)) {		    move(0, 0, 0);		    erase_lots(FALSE, FALSE, TRUE);		    disptop = 0;		    wrapnext = FALSE;		    seen_disp_event = 1;		    break;		}	      case '\013':		compatibility(VT100);	      case '\n':		if (curs.y == marg_b)		    scroll(marg_t, marg_b, 1, TRUE);		else if (curs.y < rows - 1)		    curs.y++;		if (cfg.lfhascr)		    curs.x = 0;		fix_cpos;		wrapnext = FALSE;		seen_disp_event = 1;		paste_hold = 0;		logtraffic((unsigned char) c, LGTYP_ASCII);		break;	      case '\t':		{		    pos old_curs = curs;		    unsigned long *ldata = lineptr(curs.y);		    do {			curs.x++;		    } while (curs.x < cols - 1 && !tabs[curs.x]);		    if ((ldata[cols] & LATTR_MODE) != LATTR_NORM) {			if (curs.x >= cols / 2)			    curs.x = cols / 2 - 1;		    } else {			if (curs.x >= cols)			    curs.x = cols - 1;		    }		    fix_cpos;		    check_selection(old_curs, curs);		}		seen_disp_event = TRUE;		break;	    }	} else	    switch (termstate) {	      case TOPLEVEL:		/* Only graphic characters get this far, ctrls are stripped above */		if (wrapnext && wrap) {		    cpos[1] |= LATTR_WRAPPED;		    if (curs.y == marg_b)			scroll(marg_t, marg_b, 1, TRUE);		    else if (curs.y < rows - 1)			curs.y++;		    curs.x = 0;		    fix_cpos;		    wrapnext = FALSE;		}		if (insert)		    insch(1);		if (selstate != NO_SELECTION) {		    pos cursplus = curs;		    incpos(cursplus);		    check_selection(curs, cursplus);		}		if ((c & CSET_MASK) == ATTR_ASCII || (c & CSET_MASK) == 0)		    logtraffic((unsigned char) c, LGTYP_ASCII);		{		    extern int wcwidth(wchar_t ucs);		    int width = 0;		    if (DIRECT_CHAR(c))			width = 1;		    if (!width)			width = wcwidth((wchar_t) c);		    switch (width) {		      case 2:			if (curs.x + 1 != cols) {			    *cpos++ = c | ATTR_WIDE | curr_attr;			    *cpos++ = UCSWIDE | curr_attr;			    curs.x++;			    break;			}		      case 1:			*cpos++ = c | curr_attr;			break;		      default:			continue;		    }		}		curs.x++;		if (curs.x == cols) {		    cpos--;		    curs.x--;		    wrapnext = TRUE;		    if (wrap && vt52_mode) {			cpos[1] |= LATTR_WRAPPED;			if (curs.y == marg_b)			    scroll(marg_t, marg_b, 1, TRUE);			else if (curs.y < rows - 1)			    curs.y++;			curs.x = 0;			fix_cpos;			wrapnext = FALSE;		    }		}		seen_disp_event = 1;		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();		    termstate = TOPLEVEL;		    break;		}		/* else fall through */	      case SEEN_ESC:		if (c >= ' ' && c <= '/') {		    if (esc_query)			esc_query = -1;		    else			esc_query = c;		    break;		}		termstate = TOPLEVEL;		switch (ANSI(c, esc_query)) {		  case '[':	       /* enter CSI mode */		    termstate = SEEN_CSI;		    esc_nargs = 1;		    esc_args[0] = ARG_DEFAULT;		    esc_query = FALSE;		    break;		  case ']':	       /* xterm escape sequences */		    /* Compatibility is nasty here, xterm, linux, decterm yuk! */		    compatibility(OTHER);		    termstate = SEEN_OSC;		    esc_args[0] = 0;		    break;		  case '7':	       /* save cursor */		    compatibility(VT100);		    save_cursor(TRUE);		    break;		  case '8':	       /* restore cursor */		    compatibility(VT100);		    save_cursor(FALSE);		    seen_disp_event = TRUE;		    break;		  case '=':		    compatibility(VT100);		    app_keypad_keys = TRUE;		    break;		  case '>':		    compatibility(VT100);		    app_keypad_keys = FALSE;		    break;		  case 'D':	       /* exactly equivalent to LF */		    compatibility(VT100);		    if (curs.y == marg_b)			scroll(marg_t, marg_b, 1, TRUE);		    else if (curs.y < rows - 1)			curs.y++;		    fix_cpos;		    wrapnext = FALSE;		    seen_disp_event = TRUE;		    break;		  case 'E':	       /* exactly equivalent to CR-LF */		    compatibility(VT100);		    curs.x = 0;		    if (curs.y == marg_b)			scroll(marg_t, marg_b, 1, TRUE);		    else if (curs.y < rows - 1)			curs.y++;		    fix_cpos;		    wrapnext = FALSE;		    seen_disp_event = TRUE;		    break;		  case 'M':	       /* reverse index - backwards LF */		    compatibility(VT100);		    if (curs.y == marg_t)			scroll(marg_t, marg_b, -1, TRUE);		    else if (curs.y > 0)			curs.y--;		    fix_cpos;		    wrapnext = FALSE;		    seen_disp_event = TRUE;		    break;		  case 'Z':	       /* terminal type query */		    compatibility(VT100);		    ldisc_send(id_string, strlen(id_string));		    break;		  case 'c':	       /* restore power-on settings */		    compatibility(VT100);		    power_on();		    if (reset_132) {			request_resize(80, rows, 1);			reset_132 = 0;		    }		    fix_cpos;		    disptop = 0;		    seen_disp_event = TRUE;		    break;		  case 'H':	       /* set a tab */		    compatibility(VT100);		    tabs[curs.x] = TRUE;		    break;		  case ANSI('8', '#'):	/* ESC # 8 fills screen with Es :-) */		    compatibility(VT100);		    {			unsigned long *ldata;			int i, j;			pos scrtop, scrbot;			for (i = 0; i < rows; i++) {			    ldata = lineptr(i);			    for (j = 0; j < cols; j++)				ldata[j] = ATTR_DEFAULT | 'E';			    ldata[cols] = 0;			}			disptop = 0;			seen_disp_event = TRUE;			scrtop.x = scrtop.y = 0;			scrbot.x = 0;			scrbot.y = rows;			check_selection(scrtop, scrbot);		    }		    break;		  case ANSI('3', '#'):		  case ANSI('4', '#'):		  case ANSI('5', '#'):		  case ANSI('6', '#'):		    compatibility(VT100);		    {			unsigned long nlattr;			unsigned long *ldata;			switch (ANSI(c, esc_query)) {			  case ANSI('3', '#'):			    nlattr = LATTR_TOP;			    break;			  case ANSI('4', '#'):			    nlattr = LATTR_BOT;			    break;			  case ANSI('5', '#'):			    nlattr = LATTR_NORM;			    break;			  default: /* spiritually case ANSI('6', '#'): */			    nlattr = LATTR_WIDE;			    break;			}			ldata = lineptr(curs.y);			ldata[cols] &= ~LATTR_MODE;			ldata[cols] |= nlattr;		    }		    break;		  case ANSI('A', '('):		    compatibility(VT100);		    cset_attr[0] = ATTR_GBCHR;		    break;		  case ANSI('B', '('):		    compatibility(VT100);		    cset_attr[0] = ATTR_ASCII;		    break;		  case ANSI('0', '('):		    compatibility(VT100);		    cset_attr[0] = ATTR_LINEDRW;		    break;		  case ANSI('U', '('): 		    compatibility(OTHER);		    cset_attr[0] = ATTR_SCOACS; 		    break;		  case ANSI('A', ')'):		    compatibility(VT100);		    cset_attr[1] = ATTR_GBCHR;		    break;		  case ANSI('B', ')'):		    compatibility(VT100);		    cset_attr[1] = ATTR_ASCII;		    break;		  case ANSI('0', ')'):		    compatibility(VT100);		    cset_attr[1] = ATTR_LINEDRW;		    break;		  case ANSI('U', ')'): 		    compatibility(OTHER);		    cset_attr[1] = ATTR_SCOACS; 		    break;		  case ANSI('8', '%'):	/* Old Linux code */		  case ANSI('G', '%'):		    compatibility(OTHER);		    utf = 1;		    break;		  case ANSI('@', '%'):		    compatibility(OTHER);		    if (line_codepage != CP_UTF8)			utf = 0;		    break;		}		break;	      case SEEN_CSI:		termstate = TOPLEVEL;  /* default */		if (isdigit(c)) {		    if (esc_nargs <= ARGS_MAX) {			if (esc_args[esc_nargs - 1] == ARG_DEFAULT)			    esc_args[esc_nargs - 1] = 0;			esc_args[esc_nargs - 1] =			    10 * esc_args[esc_nargs - 1] + c - '0';		    }		    termstate = SEEN_CSI;		} else if (c == ';') {		    if (++esc_nargs <= ARGS_MAX)			esc_args[esc_nargs - 1] = ARG_DEFAULT;		    termstate = SEEN_CSI;		} else if (c < '@') {		    if (esc_query)			esc_query = -1;		    else if (c == '?')			esc_query = TRUE;		    else			esc_query = c;		    termstate = SEEN_CSI;		} else		    switch (ANSI(c, esc_query)) {		      case 'A':       /* move up N lines */			move(curs.x, curs.y - def(esc_args[0], 1), 1);			seen_disp_event = TRUE;			break;		      case 'e':       /* move down N lines */			compatibility(ANSI);			/* FALLTHROUGH */		      case 'B':			move(curs.x, curs.y + def(esc_args[0], 1), 1);			seen_disp_event = TRUE;			break;		      case ANSI('c', '>'):	/* report xterm version */			compatibility(OTHER);			/* this reports xterm version 136 so that VIM can			   use the drag messages from the mouse reporting */			ldisc_send("\033[>0;136;0c", 11);			break;		      case 'a':       /* move right N cols */			compatibility(ANSI);			/* FALLTHROUGH */		      case 'C':			move(curs.x + def(esc_args[0], 1), curs.y, 1);			seen_disp_event = TRUE;			break;		      case 'D':       /* move left N cols */			move(curs.x - def(esc_args[0], 1), curs.y, 1);			seen_disp_event = TRUE;			break;		      case 'E':       /* move down N lines and CR */			compatibility(ANSI);			move(0, curs.y + def(esc_args[0], 1), 1);			seen_disp_event = TRUE;			break;		      case 'F':       /* move up N lines and CR */			compatibility(ANSI);			move(0, curs.y - def(esc_args[0], 1), 1);			seen_disp_event = TRUE;			break;		      case 'G':		      case '`':       /* set horizontal posn */			compatibility(ANSI);			move(def(esc_args[0], 1) - 1, curs.y, 0);			seen_disp_event = TRUE;			break;		      case 'd':       /* set vertical posn */			compatibility(ANSI);			move(curs.x,			     (dec_om ? marg_t : 0) + def(esc_args[0],							 1) - 1,			     (dec_om ? 2 : 0));			seen_disp_event = TRUE;			break;		      case 'H':		      case 'f':       /* set horz and vert posns at once */			if (esc_nargs < 2)			    esc_args[1] = ARG_DEFAULT;			move(def(esc_args[1], 1) - 1,			     (dec_om ? marg_t : 0) + def(esc_args[0],							 1) - 1,			     (dec_om ? 2 : 0));			seen_disp_event = TRUE;			break;		      case 'J':       /* erase screen or parts of it */			{			    unsigned int i = def(esc_args[0], 0) + 1;			    if (i > 3)				i = 0;			    erase_lots(FALSE, !!(i & 2), !!(i & 1));			}			disptop = 0;			seen_disp_event = TRUE;			break;		      case 'K':       /* erase line or parts of it */			{			    unsigned int i = def(esc_args[0], 0) + 1;			    if (i > 3)				i = 0;			    erase_lots(TRUE, !!(i & 2), !!(i & 1));			}			seen_disp_event = TRUE;			break;		      case 'L':       /* insert lines */			compatibility(VT102);			if (curs.y <= marg_b)			    scroll(curs.y, marg_b, -def(esc_args[0], 1),				   FALSE);			fix_cpos;			seen_disp_event = TRUE;			break;		      case 'M':       /* delete lines */			compatibility(VT102);			if (curs.y <= marg_b)			    scroll(curs.y, marg_b, def(esc_args[0], 1),				   TRUE);			fix_cpos;			seen_disp_event = TRUE;			break;		      case '@':       /* insert chars */			/* XXX VTTEST says this is vt220, vt510 manual says vt102 */			compatibility(VT102);			insch(def(esc_args[0], 1));			seen_disp_event = TRUE;			break;		      case 'P':       /* delete chars */			compatibility(VT102);			insch(-def(esc_args[0], 1));			seen_disp_event = TRUE;			break;		      case 'c':       /* terminal type query */			compatibility(VT100);			/* This is the response for a VT102 */			ldisc_send(id_string, strlen(id_string));			break;		      case 'n':       /* cursor position query */			if (esc_args[0] == 6) {			    char buf[32];			    sprintf(buf, "\033[%d;%dR", curs.y + 1,				    curs.x + 1);			    ldisc_send(buf, strlen(buf));			} else if (esc_args[0] == 5) {			    ldisc_send("\033[0n", 4);			}			break;		      case 'h':       /* toggle modes to high */		      case ANSI_QUE('h'):			compatibility(VT100);			{			    int i;			    for (i = 0; i < esc_nargs; i++)				toggle_mode(esc_args[i], esc_query, TRUE);			}			break;		      case 'l':       /* toggle modes to low */		      case ANSI_QUE('l'):			compatibility(VT100);			{			    int i;			    for (i = 0; i < esc_nargs; i++)				toggle_mode(esc_args[i], esc_query, FALSE);			}			break;		      case 'g':       /* clear tabs */			compatibility(VT100);			if (esc_nargs == 1) {			    if (esc_args[0] == 0) {				tabs[curs.x] = FALSE;			    } else if (esc_args[0] == 3) {				int i;				for (i = 0; i < cols; i++)				    tabs[i] = FALSE;			    }			}			break;		      case 'r':       /* set scroll margins */			compatibility(VT100);			if (esc_nargs <= 2) {			    int top, bot;			    top = def(esc_args[0], 1) - 1;			    bot = (esc_nargs <= 1				   || esc_args[1] ==				   0 ? rows : def(esc_args[1], rows)) - 1;			    if (bot >= rows)				bot = rows - 1;			    /* VTTEST Bug 9 - if region is less than 2 lines			     * don't change region.			     */			    if (bot - top > 0) {				marg_t = top;				marg_b = bot;				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				 */				curs.y = (dec_om ? marg_t : 0);				fix_cpos;				seen_disp_event = TRUE;			    }			}			break;		      case 'm':       /* 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 < esc_nargs; i++) {				switch (def(esc_args[i], 0)) {				  case 0:	/* restore defaults */				    curr_attr = ATTR_DEFAULT;				    break;				  case 1:	/* enable bold */				    compatibility(VT100AVO);				    curr_attr |= ATTR_BOLD;				    break;				  case 21:	/* (enable double underline) */				    compatibility(OTHER);				  case 4:	/* enable underline */				    compatibility(VT100AVO);				    curr_attr |= ATTR_UNDER;				    break;				  case 5:	/* enable blink */				    compatibility(VT100AVO);				    curr_attr |= ATTR_BLINK;				    break;				  case 7:	/* enable reverse video */				    curr_attr |= ATTR_REVERSE;				    break;				  case 10:      /* SCO acs off */				    compatibility(SCOANSI);				    sco_acs = 0; break;				  case 11:      /* SCO acs on */				    compatibility(SCOANSI);				    sco_acs = 1; break;				  case 12:      /* SCO acs on flipped */				    compatibility(SCOANSI);				    sco_acs = 2; break;				  case 22:	/* disable bold */				    compatibility2(OTHER, VT220);				    curr_attr &= ~ATTR_BOLD;				    break;				  case 24:	/* disable underline */				    compatibility2(OTHER, VT220);				    curr_attr &= ~ATTR_UNDER;				    break;				  case 25:	/* disable blink */				    compatibility2(OTHER, VT220);				    curr_attr &= ~ATTR_BLINK;				    break;				  case 27:	/* disable reverse video */				    compatibility2(OTHER, VT220);				    curr_attr &= ~ATTR_REVERSE;				    break;				  case 30:				  case 31:				  case 32:				  case 33:				  case 34:				  case 35:				  case 36:				  case 37:				    /* foreground */				    curr_attr &= ~ATTR_FGMASK;				    curr_attr |=					(esc_args[i] - 30) << ATTR_FGSHIFT;				    break;				  case 39:	/* default-foreground */				    curr_attr &= ~ATTR_FGMASK;				    curr_attr |= ATTR_DEFFG;				    break;				  case 40:				  case 41:				  case 42:				  case 43:				  case 44:				  case 45:				  case 46:				  case 47:				    /* background */				    curr_attr &= ~ATTR_BGMASK;				    curr_attr |=					(esc_args[i] - 40) << ATTR_BGSHIFT;				    break;				  case 49:	/* default-background */				    curr_attr &= ~ATTR_BGMASK;				    curr_attr |= ATTR_DEFBG;				    break;				}			    }			    if (use_bce)				erase_char =				    (' ' |				     (curr_attr &				      (ATTR_FGMASK | ATTR_BGMASK |				       ATTR_BLINK)));			}			break;		      case 's':       /* save cursor */			save_cursor(TRUE);			break;		      case 'u':       /* restore cursor */			save_cursor(FALSE);			seen_disp_event = TRUE;			break;		      case 't':       /* 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.			 */			compatibility(VT340TEXT);			if (esc_nargs <= 1			    && (esc_args[0] < 1 || esc_args[0] >= 24)) {			    request_resize(cols, def(esc_args[0], 24), 0);			    deselect();			}			break;		      case 'S':			compatibility(SCOANSI);			scroll(marg_t, marg_b, def(esc_args[0], 1), TRUE);			fix_cpos;			wrapnext = FALSE;			seen_disp_event = TRUE;			break;		      case 'T':			compatibility(SCOANSI);			scroll(marg_t, marg_b, -def(esc_args[0], 1), TRUE);			fix_cpos;			wrapnext = FALSE;			seen_disp_event = TRUE;			break;		      case ANSI('|', '*'):			/* VT420 sequence 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 (esc_nargs == 1 && esc_args[0] > 0) {			    request_resize(cols,					   def(esc_args[0], cfg.height),					   0);			    deselect();			}			break;		      case ANSI('|', '$'):			/* VT340/VT420 sequence DECSCPP			 * Set number of columns per page			 * Docs imply range is only 80 or 132, but I'll allow any.			 */			compatibility(VT340TEXT);			if (esc_nargs <= 1) {			    request_resize(def(esc_args[0], cfg.width),					   rows, 0);			    deselect();			}			break;		      case 'X':       /* write N spaces w/o moving cursor */			/* XXX VTTEST says this is vt220, vt510 manual says vt100 */			compatibility(ANSIMIN);			{			    int n = def(esc_args[0], 1);			    pos cursplus;			    unsigned long *p = cpos;			    if (n > cols - curs.x)				n = cols - curs.x;			    cursplus = curs;			    cursplus.x += n;			    check_selection(curs, cursplus);			    while (n--)				*p++ = erase_char;			    seen_disp_event = TRUE;			}			break;		      case 'x':       /* report terminal characteristics */			compatibility(VT100);			{			    char buf[32];			    int i = def(esc_args[0], 0);			    if (i == 0 || i == 1) {				strcpy(buf, "\033[2;1;1;112;112;1;0x");				buf[2] += i;				ldisc_send(buf, 20);			    }			}			break;		      case ANSI('L', '='):			compatibility(OTHER);			use_bce = (esc_args[0] <= 0);			erase_char = ERASE_CHAR;			if (use_bce)			    erase_char =				(' ' |				 (curr_attr &				  (ATTR_FGMASK | ATTR_BGMASK)));			break;		      case ANSI('E', '='):			compatibility(OTHER);			blink_is_real = (esc_args[0] >= 1);			break;		      case ANSI('p', '"'):			/* 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 (esc_args[0]) {			  case 61:			    compatibility_level &= ~TM_VTXXX;			    compatibility_level |= TM_VT102;			    break;			  case 62:			    compatibility_level &= ~TM_VTXXX;			    compatibility_level |= TM_VT220;			    break;			  default:			    if (esc_args[0] > 60 && esc_args[0] < 70)				compatibility_level |= TM_VTXXX;			    break;			  case 40:			    compatibility_level &= TM_VTXXX;			    break;			  case 41:			    compatibility_level = TM_PUTTY;			    break;			  case 42:			    compatibility_level = TM_SCOANSI;			    break;			  case ARG_DEFAULT:			    compatibility_level = TM_PUTTY;			    break;			  case 50:			    break;			}			/* Change the response to CSI c */			if (esc_args[0] == 50) {			    int i;			    char lbuf[64];			    strcpy(id_string, "\033[?");			    for (i = 1; i < esc_nargs; i++) {				if (i != 1)				    strcat(id_string, ";");				sprintf(lbuf, "%d", esc_args[i]);				strcat(id_string, lbuf);			    }			    strcat(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 (reset_132)				request_resize(132, 24, 1);			    else				request_resize(80, 24, 1);			}#endif			break;		    }		break;	      case SEEN_OSC:		osc_w = FALSE;		switch (c) {		  case 'P':	       /* Linux palette sequence */		    termstate = SEEN_OSC_P;		    osc_strlen = 0;		    break;		  case 'R':	       /* Linux palette reset */		    palette_reset();		    term_invalidate();		    termstate = TOPLEVEL;		    break;		  case 'W':	       /* word-set */		    termstate = SEEN_OSC_W;		    osc_w = TRUE;		    break;		  case '0':		  case '1':		  case '2':		  case '3':		  case '4':		  case '5':		  case '6':		  case '7':		  case '8':		  case '9':		    esc_args[0] = 10 * esc_args[0] + c - '0';		    break;		  case 'L':		    /*		     * Grotty hack to support xterm and DECterm title		     * sequences concurrently.		     */		    if (esc_args[0] == 2) {			esc_args[0] = 1;			break;		    }		    /* else fall through */		  default:		    termstate = OSC_STRING;		    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 == '\n' || c == '\r') {		    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();		    termstate = TOPLEVEL;		} else if (c == '\033')		    termstate = OSC_MAYBE_ST;		else if (osc_strlen < OSC_STR_MAX)		    osc_string[osc_strlen++] = c;		break;	      case SEEN_OSC_P:		{		    int max = (osc_strlen == 0 ? 21 : 16);		    int val;		    if (c >= '0' && c <= '9')			val = c - '0';		    else if (c >= 'A' && c <= 'A' + max - 10)			val = c - 'A' + 10;		    else if (c >= 'a' && c <= 'a' + max - 10)			val = c - 'a' + 10;		    else {			termstate = TOPLEVEL;			break;		    }		    osc_string[osc_strlen++] = val;		    if (osc_strlen >= 7) {			palette_set(osc_string[0],				    osc_string[1] * 16 + osc_string[2],				    osc_string[3] * 16 + osc_string[4],				    osc_string[5] * 16 + osc_string[6]);			term_invalidate();			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':		    esc_args[0] = 10 * esc_args[0] + c - '0';		    break;		  default:		    termstate = OSC_STRING;		    osc_strlen = 0;		}		break;	      case VT52_ESC:		termstate = TOPLEVEL;		seen_disp_event = TRUE;		switch (c) {		  case 'A':		    move(curs.x, curs.y - 1, 1);		    break;		  case 'B':		    move(curs.x, curs.y + 1, 1);		    break;		  case 'C':		    move(curs.x + 1, curs.y, 1);		    break;		  case 'D':		    move(curs.x - 1, 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':		    cset_attr[cset = 0] = ATTR_LINEDRW;		    break;		  case 'G':		    cset_attr[cset = 0] = ATTR_ASCII;		    break;		  case 'H':		    move(0, 0, 0);		    break;		  case 'I':		    if (curs.y == 0)			scroll(0, rows - 1, -1, TRUE);		    else if (curs.y > 0)			curs.y--;		    fix_cpos;		    wrapnext = FALSE;		    break;		  case 'J':		    erase_lots(FALSE, FALSE, TRUE);		    disptop = 0;		    break;		  case 'K':		    erase_lots(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':		    termstate = VT52_Y1;		    break;		  case 'Z':		    ldisc_send("\033/Z", 3);		    break;		  case '=':		    app_keypad_keys = TRUE;		    break;		  case '>':		    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.		     */		    vt52_mode = FALSE;		    blink_is_real = cfg.blinktext;		    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(0, 0, 0);		    erase_lots(FALSE, FALSE, TRUE);		    disptop = 0;		    break;		  case 'L':		    /* compatibility(ATARI) */		    if (curs.y <= marg_b)			scroll(curs.y, marg_b, -1, FALSE);		    break;		  case 'M':		    /* compatibility(ATARI) */		    if (curs.y <= marg_b)			scroll(curs.y, marg_b, 1, TRUE);		    break;		  case 'b':		    /* compatibility(ATARI) */		    termstate = VT52_FG;		    break;		  case 'c':		    /* compatibility(ATARI) */		    termstate = VT52_BG;		    break;		  case 'd':		    /* compatibility(ATARI) */		    erase_lots(FALSE, TRUE, FALSE);		    disptop = 0;		    break;		  case 'e':		    /* compatibility(ATARI) */		    cursor_on = TRUE;		    break;		  case 'f':		    /* compatibility(ATARI) */		    cursor_on = FALSE;		    break;		    /* case 'j': Save cursor position - broken on ST */		    /* case 'k': Restore cursor position */		  case 'l':		    /* compatibility(ATARI) */		    erase_lots(TRUE, TRUE, TRUE);		    curs.x = 0;		    wrapnext = FALSE;		    fix_cpos;		    break;		  case 'o':		    /* compatibility(ATARI) */		    erase_lots(TRUE, TRUE, FALSE);		    break;		  case 'p':		    /* compatibility(ATARI) */		    curr_attr |= ATTR_REVERSE;		    break;		  case 'q':		    /* compatibility(ATARI) */		    curr_attr &= ~ATTR_REVERSE;		    break;		  case 'v':	       /* wrap Autowrap on - Wyse style */		    /* compatibility(ATARI) */		    wrap = 1;		    break;		  case 'w':	       /* Autowrap off */		    /* compatibility(ATARI) */		    wrap = 0;		    break;		  case 'R':		    /* compatibility(OTHER) */		    vt52_bold = FALSE;		    curr_attr = ATTR_DEFAULT;		    if (use_bce)			erase_char = (' ' |				      (curr_attr &				       (ATTR_FGMASK | ATTR_BGMASK |					ATTR_BLINK)));		    break;		  case 'S':		    /* compatibility(VI50) */		    curr_attr |= ATTR_UNDER;		    break;		  case 'W':		    /* compatibility(VI50) */		    curr_attr &= ~ATTR_UNDER;		    break;		  case 'U':		    /* compatibility(VI50) */		    vt52_bold = TRUE;		    curr_attr |= ATTR_BOLD;		    break;		  case 'T':		    /* compatibility(VI50) */		    vt52_bold = FALSE;		    curr_attr &= ~ATTR_BOLD;		    break;#endif		}		break;	      case VT52_Y1:		termstate = VT52_Y2;		move(curs.x, c - ' ', 0);		break;	      case VT52_Y2:		termstate = TOPLEVEL;		move(c - ' ', curs.y, 0);		break;#ifdef VT52_PLUS	      case VT52_FG:		termstate = TOPLEVEL;		curr_attr &= ~ATTR_FGMASK;		curr_attr &= ~ATTR_BOLD;		curr_attr |= (c & 0x7) << ATTR_FGSHIFT;		if ((c & 0x8) || vt52_bold)		    curr_attr |= ATTR_BOLD;		if (use_bce)		    erase_char = (' ' |				  (curr_attr &				   (ATTR_FGMASK | ATTR_BGMASK |				    ATTR_BLINK)));		break;	      case VT52_BG:		termstate = TOPLEVEL;		curr_attr &= ~ATTR_BGMASK;		curr_attr &= ~ATTR_BLINK;		curr_attr |= (c & 0x7) << ATTR_BGSHIFT;		/* Note: bold background */		if (c & 0x8)		    curr_attr |= ATTR_BLINK;		if (use_bce)		    erase_char = (' ' |				  (curr_attr &				   (ATTR_FGMASK | ATTR_BGMASK |				    ATTR_BLINK)));		break;#endif	      default: break;	       /* placate gcc warning about enum use */	    }	if (selstate != NO_SELECTION) {	    pos cursplus = curs;	    incpos(cursplus);	    check_selection(curs, cursplus);	}    }    inbuf_head = 0;}