top = def(esc_args[0], 1) - 1; if (top < 0) top = 0; bot = (esc_nargs <= 1 || esc_args[1] == 0 ? rows : def(esc_args[1], rows)) - 1;
if (esc_args[0] <= 0) { top=0; bot=rows-1; } else { top = def(esc_args[0], 1) - 1; bot = (esc_nargs <= 1 || esc_args[1] == 0 ? rows : def(esc_args[1], rows)) - 1; }
void term_out(void) {    int c;    while ( (c = inbuf_getc()) != -1) {        /*         * Optionally log the session traffic to a file. Useful for         * debugging and possibly also useful for actual logging.         */	if (logfile) {	    static FILE *fp = NULL;	    if (!fp) fp = fopen(logfile, "wb");	    if (fp) fputc (c, fp);	}	if( termstate < DO_CTRLS && (c&0x60) == 0 ) {	    switch (c) {	      case '\005':	       /* terminal type query */		ldisc->send ("PuTTY\r", 6);		break;	      case '\007':		beep();		disptop = scrtop;		break;	      case '\b':		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':		cset = 1;		break;	      case '\017':		cset = 0;		break;	      case '\033':		termstate = SEEN_ESC;		break;	      case 0233:		termstate = SEEN_CSI;		esc_nargs = 1;		esc_args[0] = ARG_DEFAULT;		esc_query = FALSE;		break;	      case 0235:		termstate = SEEN_OSC;		esc_args[0] = 0;		break;	      case '\r':		curs_x = 0;		wrapnext = FALSE;		fix_cpos;		seen_disp_event = TRUE;		break;	      case '\013':	      case '\014':	      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;		nl_count++;		break;	      case '\t':		do {		    curs_x++;		} while (curs_x < cols-1 && !tabs[curs_x]);		if (curs_x >= cols)		    curs_x = cols-1;		{		    unsigned long *old_cpos = cpos;		    fix_cpos;		    check_selection (old_cpos, cpos);		}		seen_disp_event = TRUE;		break;	    }	}	else switch (termstate) {	  case TOPLEVEL:	  /* Only graphic characters get this far, ctrls are stripped above */	    if (wrapnext) {		cpos[1] = ATTR_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;		nl_count++;	    }	    if (insert)		insch (1);	    check_selection (cpos, cpos+1);	    *cpos++ = xlat_tty2scr((unsigned char)c) | curr_attr |		(c <= 0x7F ? cset_attr[cset] : ATTR_ASCII);	    curs_x++;	    if (curs_x == cols) {		cpos--;		curs_x--;		wrapnext = wrap;	    }	    seen_disp_event = 1;	    break;	  case IGNORE_NEXT:	    termstate = TOPLEVEL;	    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:	    termstate = TOPLEVEL;	    switch (c) {	      case ' ':		       /* some weird sequence? */		termstate = IGNORE_NEXT;		break;	      case '[':		       /* enter CSI mode */		termstate = SEEN_CSI;		esc_nargs = 1;		esc_args[0] = ARG_DEFAULT;		esc_query = FALSE;		break;	      case ']':		       /* xterm escape sequences */		termstate = SEEN_OSC;		esc_args[0] = 0;		break;	      case '(':		       /* should set GL */		termstate = SET_GL;		break;	      case ')':		       /* should set GR */		termstate = SET_GR;		break;	      case '7':		       /* save cursor */		save_cursor (TRUE);		break;	      case '8':		       /* restore cursor */		save_cursor (FALSE);		seen_disp_event = TRUE;		break;	      case '=':		app_keypad_keys = TRUE;		break;	      case '>':		app_keypad_keys = FALSE;		break;	      case 'D':		       /* exactly equivalent to LF */		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;		nl_count++;		break;	      case 'E':		       /* exactly equivalent to CR-LF */		curs_x = 0;		wrapnext = FALSE;		if (curs_y == marg_b)		    scroll (marg_t, marg_b, 1, TRUE);		else if (curs_y < rows-1)		    curs_y++;		fix_cpos;		wrapnext = FALSE;		nl_count++;		seen_disp_event = TRUE;		break;	      case 'M':		       /* reverse index - backwards LF */		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 */		ldisc->send ("\033[?6c", 5);		break;	      case 'c':		       /* restore power-on settings */		power_on();		fix_cpos;		disptop = scrtop;		seen_disp_event = TRUE;		break;	      case '#':		       /* ESC # 8 fills screen with Es :-) */		termstate = SEEN_ESCHASH;		break;	      case 'H':		       /* set a tab */		tabs[curs_x] = TRUE;		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 'B': case 'e':      /* move down N lines */		move (curs_x, curs_y + def(esc_args[0], 1), 1);		seen_disp_event = TRUE;		break;	      case 'C': case 'a':      /* move right N cols */		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 */		move (0, curs_y + def(esc_args[0], 1), 1);		seen_disp_event = TRUE;		break;	      case 'F':		       /* move up N lines and CR */		move (0, curs_y - def(esc_args[0], 1), 1);		seen_disp_event = TRUE;		break;	      case 'G': case '`':      /* set horizontal posn */		move (def(esc_args[0], 1) - 1, curs_y, 0);		seen_disp_event = TRUE;		break;	      case 'd':		       /* set vertical posn */		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 = scrtop;		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 */		if (curs_y <= marg_b)		    scroll (curs_y, marg_b, -def(esc_args[0], 1), FALSE);		seen_disp_event = TRUE;		break;	      case 'M':		       /* delete lines */		if (curs_y <= marg_b)		    scroll (curs_y, marg_b, def(esc_args[0], 1), TRUE);		seen_disp_event = TRUE;		break;	      case '@':		       /* insert chars */		insch (def(esc_args[0], 1));		seen_disp_event = TRUE;		break;	      case 'P':		       /* delete chars */		insch (-def(esc_args[0], 1));		seen_disp_event = TRUE;		break;	      case 'c':		       /* terminal type query */		ldisc->send ("\033[?6c", 5);		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));		}		break;	      case 'h':		       /* toggle a mode to high */	      case ANSI_QUE('h'):		toggle_mode (esc_args[0], esc_query, TRUE);		break;	      case 'l':		       /* toggle a mode to low */	      case ANSI_QUE('l'):		toggle_mode (esc_args[0], esc_query, FALSE);		break;	      case 'g':		       /* clear tabs */		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 */		if (esc_nargs <= 2) {		    int top, bot;		    top = def(esc_args[0], 1) - 1;		    if (top < 0)			top = 0;		    bot = (esc_nargs <= 1 || esc_args[1] == 0 ? rows :			   def(esc_args[1], rows)) - 1;		    if (bot >= rows)			bot = rows-1;		    if (top <= bot) {			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.			 */			curs_y = 0;			fix_cpos;			seen_disp_event = TRUE;		    }		}		break;	      case 'm':		       /* set graphics rendition */		{		    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 */			    curr_attr |= ATTR_BOLD; break;			  case 4:      /* enable underline */			  case 21:     /* (enable double underline) */			    curr_attr |= ATTR_UNDER; break;			  case 7:      /* enable reverse video */			    curr_attr |= ATTR_REVERSE; break;			  case 22:     /* disable bold */			    curr_attr &= ~ATTR_BOLD; break;			  case 24:     /* disable underline */			    curr_attr &= ~ATTR_UNDER; break;			  case 27:     /* disable reverse video */			    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;			}		    }		}		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 */		request_resize (cols, def(esc_args[0], 24));		deselect();		break;	      case 'X':		       /* write N spaces w/o moving cursor */		{		    int n = def(esc_args[0], 1);		    unsigned long *p = cpos;		    if (n > cols - curs_x)			n = cols - curs_x;		    check_selection (cpos, cpos+n);		    while (n--)			*p++ = ERASE_CHAR;		    seen_disp_event = TRUE;		}		break;	      case 'x':		       /* report terminal characteristics */		{		    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;	    }	    break;	  case SET_GL:	  case SET_GR:	    switch (c) {	      case 'A':		cset_attr[termstate == SET_GL ? 0 : 1] = ATTR_GBCHR;		break;	      case '0':		cset_attr[termstate == SET_GL ? 0 : 1] = ATTR_LINEDRW;		break;	      default:		       /* specifically, 'B' */		cset_attr[termstate == SET_GL ? 0 : 1] = ATTR_ASCII;		break;	    }	    if( c != '%' )	        termstate = TOPLEVEL;	    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;		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 SEEN_ESCHASH:	    if (c == '8') {		unsigned long *p = scrtop;		int n = rows * (cols+1);		while (n--)		    *p++ = ATTR_DEFAULT | 'E';		disptop = scrtop;		seen_disp_event = TRUE;		check_selection (scrtop, scrtop + rows * (cols+1));	    }	    termstate = TOPLEVEL;	    break;	}	check_selection (cpos, cpos+1);    }	    if (nl_count > MAXNL)	term_update();}