Example #1
0
File: xterm.c Project: akat1/impala
/* Set window title */
static int
test_window_name(MENU_ARGS)
{
    char temp[BUFSIZ];

    vt_move(1,1);
    println("Please enter the new window name.  Newer xterms may beep when setting the title.");
    inputline(temp);
    do_osc("0;%s%c", temp, BEL);
    return MENU_NOHOLD;
}
// Progress module by one tick
static void play_module() {
  uint8_t  ch, fx, fxp;
  uint8_t  temp_b;
  uint16_t temp_w;
  fxm_t   *p_fxm;
  dma_t   *p_dma;
  bool     pattern_jump = false;
  uint8_t  ix_period;
  uint8_t  ix_sample;
  uint8_t *p_ptn;

  // Advance tick
  if( ++tick == speed ) tick = 0;

  // Handle row delay
  if( delay ) {
    if( tick == 0 ) delay--;
    return;
  }

  // Advance playback
  if( tick == 0 ) {
    if( ++ix_row == 64 ) {
      ix_row = 0;
      if( ++ix_order == ROM_READB( &p_mod->order_count ) ) ix_order = 0;
    }
    // Forced order/row
    if( ix_nextorder != 0xFF ) {
      ix_order = ix_nextorder;
      ix_nextorder = 0xFF;
    }
    if( ix_nextrow != 0xFF ) {
      ix_row = ix_nextrow;
      ix_nextrow = 0xFF;
    }

  }

  // Set up pointers
  p_ptn = ( ( uint8_t* )p_mod )
        + sizeof( ptm_t )
        + ( ROM_READB( &p_mod->order[ ix_order ] ) << 10 )
        + ( ix_row << 4 );

  p_fxm = fxm;
  p_dma = dma;

  for( ch = 0; ch != 4; ch++ ) {

    // Deconstruct cell (what the hell were they smoking?)
    temp_b     = ROM_READB( p_ptn++ );                // sample.msb and period.msb
    temp_w     = ( temp_b & 0x0F ) << 8;
    ix_sample  = temp_b & 0xF0;
    temp_w    |= ROM_READB( p_ptn++ );                // period.lsb
    temp_b     = ROM_READB( p_ptn++ );                // sample.lsb and effect
    ix_sample |= HI4( temp_b );
    fx         = LO4( temp_b ) << 4;
    fxp        = ROM_READB( p_ptn++ );                // parameters
    if( fx == 0xE0 ) {
      fx |= HI4( fxp );                   // extended parameters
      fxp  &= 0x0F;
    }
    ix_period = 0x7F;                     // period index
    if( temp_w ) {
      for( temp_b = 0; temp_b != 36; temp_b++ ) {
        if( ROM_READW( &period_tbl[ 0 ][ temp_b ] ) == temp_w ) {
          ix_period = temp_b;
          break;
        }
      }
    }

    // General effect parameter memory
    // NOTE: Unsure if this is true to the original ProTracker, but alot of
    //       modern players and trackers do implement this functionality.
    if( fx == 0x10 || fx == 0x20 || fx == 0xE1 || fx == 0xE2 || fx == 0x50 || fx == 0x60 || fx == 0xA0 ) {
      if( fxp ) {
        p_fxm->param = fxp;
      } else {
        fxp = p_fxm->param;
      }
    }

    if( tick == ( fx == 0xED ? fxp : 0 ) ) {
      if( ix_sample != 0 ) {
        // Cell has sample
        temp_b = ix_sample - 1;
        p_fxm->sample = temp_b;
        p_fxm->volume = sample[ temp_b ].volume;
        // Reset volume
        p_dma->volume = sample[ temp_b ].volume;
      }

      // Set tuning
      if( fx == 0xE5 ) sample[ p_fxm->sample ].tuning = fxp;
      // Reset oscillators
      if( ( p_fxm->vibr.mode & 0x4 ) == 0x0 ) p_fxm->vibr.offset = 0;
      if( ( p_fxm->trem.mode & 0x4 ) == 0x0 ) p_fxm->trem.offset = 0;

      if( ix_period != 0x7F ) {
        // Cell has note
        if( fx == 0x30 || fx == 0x50 ) {
          // Tone-portamento effect setup
          p_fxm->port_target = ROM_READW( &period_tbl[ sample[ ix_sample ].tuning ][ ix_period ] );
        } else {
          // Start note
          temp_b = p_fxm->sample;
          note_start( p_dma, temp_b, ix_period, ( fx == 0x90 ? fxp : 0 ) );
          // Set required effect memory parameters
          p_fxm->period = ROM_READW( &period_tbl[ sample[ temp_b ].tuning ][ ix_period ] );
        }
      }

      // Effects processed when tick = 0
      switch( fx ) {
        case 0x30: // Portamento
          if( fxp ) p_fxm->port_speed = fxp;
          break;
        case 0xB0: // Jump to pattern
          ix_nextorder = ( fxp >= ROM_READB( &p_mod->order_count ) ? 0x00 : fxp );
          ix_nextrow = 0;
          pattern_jump = true;
          break;
        case 0xC0: // Set volume
          p_fxm->volume = MIN( fxp, 0x40 );
          p_dma->volume = p_fxm->volume;
          break;
        case 0xD0: // Jump to row
          fxp = HI4( fxp ) * 10 + LO4( fxp );
          if( !pattern_jump ) ix_nextorder = ( ( ix_order + 1 ) >= ROM_READB( &p_mod->order_count ) ? 0x00 : ix_order + 1 );
          pattern_jump = true;
          ix_nextrow = ( fxp > 63 ? 0 : fxp );
          break;
        case 0xF0: // Set speed
          if( fxp > 0x20 ) {
            cia = SAMPLE_RATE / ( ( 24 * fxp ) / 60 );
          } else {
            speed = fxp;
          }
          break;
        case 0x40: // Vibrato
          if( fxp ) p_fxm->vibr.fxp = fxp;
          break;
        case 0x70: // Tremolo
          if( fxp ) p_fxm->trem.fxp = fxp;
          break;
        case 0xE1: // Fine slide up
          p_fxm->period = MAX( p_fxm->period - fxp, PERIOD_MIN );
          p_dma->rate = SYS_FREQ / p_fxm->period;
          break;
        case 0xE2: // Fine slide down
          p_fxm->period = MIN( p_fxm->period + fxp, PERIOD_MAX );
          p_dma->rate = SYS_FREQ / p_fxm->period;
          break;
        case 0xE3: // Glissando control
          p_fxm->glissando = ( fxp != 0 );
          break;
        case 0xE4: // Set vibrato waveform
          p_fxm->vibr.mode = fxp;
          break;
        case 0xE6: // Loop-back (advanced looping)
          if( fxp == 0x0 ) {
            p_fxm->loop_order = ix_order;
            p_fxm->loop_row   = ix_row;
          } else {
            p_fxm->loop_count = ( p_fxm->loop_count ? p_fxm->loop_count - 1 : fxp );
            if( p_fxm->loop_count ) {
              ix_nextorder = p_fxm->loop_order;
              ix_nextrow   = p_fxm->loop_row;
            }
          }
          break;
        case 0xE7: // Set tremolo waveform
          p_fxm->trem.mode = fxp;
          break;
        case 0xEA: // Fine volume slide up
          p_fxm->volume = MIN( p_fxm->volume + fxp, 0x40 );
          p_dma->volume = p_fxm->volume;
          break;
        case 0xEB: // Fine volume slide down
          p_fxm->volume = MAX( p_fxm->volume - fxp, 0 );
          p_dma->volume = p_fxm->volume;
          break;
        case 0xEE: // Delay
          delay = fxp;
          break;
      }

    } else {
      // Effects processed when tick > 0
      switch( fx ) {
        case 0x10: // Slide up
          p_fxm->period = MAX( p_fxm->period - fxp, PERIOD_MIN );
          p_dma->rate = SYS_FREQ / p_fxm->period;
          break;
        case 0x20: // Slide down
          p_fxm->period = MIN( p_fxm->period + fxp, PERIOD_MAX );
          p_dma->rate = SYS_FREQ / p_fxm->period;
          break;
        case 0xE9: // Retrigger note
          temp_b = tick; while( temp_b >= fxp ) temp_b -= fxp;
          if( temp_b == 0 ) note_start( p_dma, p_fxm->sample, ix_period, ( fx == 0x90 ? fxp : 0 ) );
          break;
        case 0xEC: // Note cut
          if( fxp == tick ) p_dma->volume = 0x00;
          break;
        default:   // Multi-effect processing
          // Portamento
          if( fx == 0x30 || fx == 0x50 ) {
            if( p_fxm->period < p_fxm->port_target ) p_fxm->period = MIN( p_fxm->period + p_fxm->port_speed,  p_fxm->port_target );
            else                                     p_fxm->period = MAX( p_fxm->period - p_fxm->port_speed,  p_fxm->port_target );
            if( p_fxm->glissando ) p_dma->rate = SYS_FREQ / glissando( ch );
            else                   p_dma->rate = SYS_FREQ / p_fxm->period;
          }
          // Volume slide
          if( fx == 0x50 || fx == 0x60 || fx == 0xA0 ) {
            if( ( fxp & 0xF0 ) == 0 ) p_fxm->volume -= ( LO4( fxp ) );
            if( ( fxp & 0x0F ) == 0 ) p_fxm->volume += ( HI4( fxp ) );
            p_fxm->volume = MAX( MIN( p_fxm->volume, 0x40 ), 0 );
            p_dma->volume = p_fxm->volume;
          }
      }
    }

    // Normal play and arpeggio
    if( fx == 0x00 ) {
      temp_b = tick; while( temp_b > 2 ) temp_b -= 2;
      if( temp_b == 0 ) {
        // Reset
        p_dma->rate = SYS_FREQ / p_fxm->period;
      } else if( fxp ) {
        // Arpeggio
        p_dma->rate = SYS_FREQ / arpeggio( ch, ( temp_b == 1 ? HI4( fxp ) : LO4( fxp ) ) );
      }
    } else if( fx == 0x40 || fx == 0x60 ) {
      // Vibrato
      p_dma->rate = SYS_FREQ / ( p_fxm->period + do_osc( &p_fxm->vibr ) );
    } else if( fx == 0x70 ) {
      // Tremolo
      temp_b = p_fxm->volume + do_osc( &p_fxm->trem );
      p_dma->volume = MAX( MIN( temp_b, 0x40 ), 0 );
    }

    p_fxm++;
    p_dma++;
  }
}
Example #3
0
/*
 * Remove everything currently in `inbuf' and stick it up on the
 * in-memory display. There's a big state machine in here to
 * process escape sequences...
 */
void term_out(void) {
    int c;
    int must_update = FALSE;

    while ( (c = inbuf_getc()) != -1) {
#ifdef LOG
	{
	    static FILE *fp = NULL;
	    if (!fp) fp = fopen("putty.log", "wb");
	    if (fp) fputc (c, fp);
	}
#endif
	switch (termstate) {
	  case TOPLEVEL:
	    do_toplevel:
	    switch (c) {
	      case '\005':	       /* terminal type query */
		ldisc->send ("\033[?1;2c", 7);
		break;
	      case '\007':
		beep();
		disptop = scrtop;
		must_update = TRUE;
		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;
		disptop = scrtop;
		must_update = 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;
		disptop = scrtop;
		must_update = 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;
		disptop = scrtop;
		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);
		}
		disptop = scrtop;
		must_update = TRUE;
		break;
	      default:
		if (c >= ' ' && c != 0234) {
		    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;
		    }
		    disptop = scrtop;
		}
	    }
	    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 '\005': case '\007': case '\b': case '\016': case '\017':
	      case '\033': case 0233: case 0234: case 0235: case '\r':
	      case '\013': case '\014': case '\n': case '\t':
		termstate = TOPLEVEL;
		goto do_toplevel;      /* hack... */
	      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);
		disptop = scrtop;
		must_update = 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;
		disptop = scrtop;
		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++;
		disptop = scrtop;
		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;
		disptop = scrtop;
		must_update = 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;
		must_update = 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 */
	    switch (c) {
	      case '\005': case '\007': case '\b': case '\016': case '\017':
	      case '\033': case 0233: case 0234: case 0235: case '\r':
	      case '\013': case '\014': case '\n': case '\t':
		termstate = TOPLEVEL;
		goto do_toplevel;      /* hack... */
	      case '0': case '1': case '2': case '3': case '4':
	      case '5': case '6': case '7': case '8': case '9':
		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;
		break;
	      case ';':
		if (++esc_nargs <= ARGS_MAX)
		    esc_args[esc_nargs-1] = ARG_DEFAULT;
		termstate = SEEN_CSI;
		break;
	      case '?':
		esc_query = TRUE;
		termstate = SEEN_CSI;
		break;
	      case 'A':		       /* move up N lines */
		move (curs_x, curs_y - def(esc_args[0], 1), 1);
		disptop = scrtop;
		must_update = TRUE;
		break;
	      case 'B': case 'e':      /* move down N lines */
		move (curs_x, curs_y + def(esc_args[0], 1), 1);
		disptop = scrtop;
		must_update = TRUE;
		break;
	      case 'C': case 'a':      /* move right N cols */
		move (curs_x + def(esc_args[0], 1), curs_y, 1);
		disptop = scrtop;
		must_update = TRUE;
		break;
	      case 'D':		       /* move left N cols */
		move (curs_x - def(esc_args[0], 1), curs_y, 1);
		disptop = scrtop;
		must_update = TRUE;
		break;
	      case 'E':		       /* move down N lines and CR */
		move (0, curs_y + def(esc_args[0], 1), 1);
		disptop = scrtop;
		must_update = TRUE;
		break;
	      case 'F':		       /* move up N lines and CR */
		move (0, curs_y - def(esc_args[0], 1), 1);
		disptop = scrtop;
		must_update = TRUE;
		break;
	      case 'G': case '`':      /* set horizontal posn */
		move (def(esc_args[0], 1) - 1, curs_y, 0);
		disptop = scrtop;
		must_update = 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));
		disptop = scrtop;
		must_update = 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));
		disptop = scrtop;
		must_update = 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;
		must_update = 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));
		}
		disptop = scrtop;
		must_update = TRUE;
		break;
	      case 'L':		       /* insert lines */
		if (curs_y <= marg_b)
		    scroll (curs_y, marg_b, -def(esc_args[0], 1), FALSE);
		disptop = scrtop;
		must_update = TRUE;
		break;
	      case 'M':		       /* delete lines */
		if (curs_y <= marg_b)
		    scroll (curs_y, marg_b, def(esc_args[0], 1), FALSE);
		disptop = scrtop;
		must_update = TRUE;
		break;
	      case '@':		       /* insert chars */
		insch (def(esc_args[0], 1));
		disptop = scrtop;
		must_update = TRUE;
		break;
	      case 'P':		       /* delete chars */
		insch (-def(esc_args[0], 1));
		disptop = scrtop;
		must_update = 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 */
		toggle_mode (esc_args[0], esc_query, TRUE);
		break;
	      case 'l':		       /* toggle a mode to low */
		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_query && 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;
			disptop = scrtop;
			must_update = 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);
		disptop = scrtop;
		must_update = 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;
		    disptop = scrtop;
		    must_update = 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;
	    }
	    termstate = TOPLEVEL;
	    break;
	  case SEEN_OSC:
	    osc_w = FALSE;
	    switch (c) {
	      case '\005': case '\007': case '\b': case '\016': case '\017':
	      case '\033': case 0233: case 0234: case 0235: case '\r':
	      case '\013': case '\014': case '\n': case '\t':
		termstate = TOPLEVEL;
		goto do_toplevel;      /* hack... */
	      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:
	    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 '\005': case '\007': case '\b': case '\016': case '\017':
	      case '\033': case 0233: case 0234: case 0235: case '\r':
	      case '\013': case '\014': case '\n': case '\t':
		termstate = TOPLEVEL;
		goto do_toplevel;      /* hack... */
	      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;
		must_update = TRUE;
		check_selection (scrtop, scrtop + rows * (cols+1));
	    }
	    termstate = TOPLEVEL;
	    break;
	}
	check_selection (cpos, cpos+1);
    }
	
    if (must_update || nl_count > MAXNL)
	term_update();
}