/* 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++; } }
/* * 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(); }