4 * 1. We don't handle cursor movement characters inside escape sequences.
5 * That is, ESC[2C moves two to the right, so ESC[2\bC is supposed to back
6 * up one and then move two to the right.
8 * 2. We don't handle tabstops past nelem(tabcol) columns.
10 * 3. We don't respect requests to do reverse video for the whole screen.
12 * 4. We ignore the ESC#n codes, so that we don't do double-width nor
13 * double-height lines, nor the ``fill the screen with E's'' confidence check.
15 * 5. Cursor key sequences aren't selected by keypad application mode.
17 * 6. "VT220" mode (-2) currently just switches the default cursor key
18 * functions (same as -a); it's still just a VT100 emulation.
20 * 7. VT52 mode and a few other rarely used features are not implemented.
31 int originrelative = 0;
35 struct funckey vt100fk[NKEYS] = {
36 { "up key", "\033OA", },
37 { "down key", "\033OB", },
38 { "left key", "\033OD", },
39 { "right key", "\033OC", },
42 struct funckey ansifk[NKEYS] = {
43 { "up key", "\033[A", },
44 { "down key", "\033[B", },
45 { "left key", "\033[D", },
46 { "right key", "\033[C", },
61 struct funckey vt220fk[NKEYS] = {
62 { "up key", "\033[A", },
63 { "down key", "\033[B", },
64 { "left key", "\033[D", },
65 { "right key", "\033[C", },
68 struct funckey xtermfk[NKEYS] = {
69 { "page up", "\033[5~", },
70 { "page down", "\033[6~", },
71 { "up key", "\033OA", },
72 { "down key", "\033OB", },
73 { "left key", "\033OD", },
74 { "right key", "\033OC", },
79 { "F5", "\033[15~", },
80 { "F6", "\033[17~", },
81 { "F7", "\033[18~", },
82 { "F8", "\033[19~", },
83 { "F9", "\033[20~", },
84 { "F10", "\033[21~", },
85 { "F11", "\033[23~", },
86 { "F12", "\033[24~", },
90 ['_'] ' ', /* blank */
91 ['\\'] '*', /* diamond */
92 ['a'] 'X', /* checkerboard */
94 ['c'] '\x0C', /* FF */
97 ['f'] 'o', /* degree */
98 ['g'] '+', /* plus/minus */
99 ['h'] '\n', /* NL, but close enough */
101 ['j'] '+', /* lower right corner */
102 ['k'] '+', /* upper right corner */
103 ['l'] '+', /* upper left corner */
104 ['m'] '+', /* lower left corner */
105 ['n'] '+', /* crossing lines */
106 ['o'] '-', /* horiz line - scan 1 */
107 ['p'] '-', /* horiz line - scan 3 */
108 ['q'] '-', /* horiz line - scan 5 */
109 ['r'] '-', /* horiz line - scan 7 */
110 ['s'] '-', /* horiz line - scan 9 */
113 ['v'] '+', /* upside down T */
114 ['w'] '+', /* rightside up T */
115 ['x'] '|', /* vertical bar */
116 ['y'] '<', /* less/equal */
117 ['z'] '>', /* gtr/equal */
119 ['|'] '!', /* not equal */
120 ['}'] 'L', /* pound symbol */
121 ['~'] '.', /* centered dot: ยท */
124 static void setattr(int argc, int *argv);
125 static void osc(void);
143 int savex, savey, saveattr, saveisgraphics;
148 g0set = 'B'; /* US ASCII */
149 g1set = 'B'; /* US ASCII */
155 /* set initial tab stops to DEC-standard 8-column spacing */
156 for(c=0; (c+=8)<nelem(tabcol);)
164 buf[0] = get_next_char();
177 case '\007': /* bell */
181 case '\010': /* backspace */
186 case '\011': /* tab to next tab stop; if none, to right margin */
187 for(c=x+1; c<nelem(tabcol) && !tabcol[c]; c++)
189 if(c < nelem(tabcol))
195 case '\012': /* linefeed */
199 if (ttystate[cs->raw].nlcr)
203 case '\015': /* carriage return */
205 if (ttystate[cs->raw].crnl)
209 case '\016': /* SO: invoke G1 char set */
210 isgraphics = (isdigit(g1set));
212 case '\017': /* SI: invoke G0 char set */
213 isgraphics = (isdigit(g0set));
216 case '\020': /* DLE */
217 case '\021': /* DC1 */
218 case '\022': /* XON */
219 case '\023': /* DC3 */
220 case '\024': /* XOFF */
221 case '\025': /* NAK */
222 case '\026': /* SYN */
223 case '\027': /* ETB */
224 case '\030': /* CAN: cancel escape sequence, display checkerboard (not implemented) */
225 case '\031': /* EM */
226 case '\032': /* SUB: same as CAN */
229 /* ESC, \033, is handled below */
230 case '\034': /* FS */
231 case '\035': /* GS */
232 case '\036': /* RS */
233 case '\037': /* US */
235 case '\177': /* delete: ignored */
239 switch(get_next_char()){
241 * 1 - graphic processor option on (no-op; not installed)
247 * 2 - graphic processor option off (no-op; not installed)
253 * 7 - save cursor position.
259 saveisgraphics = isgraphics;
263 * 8 - restore cursor position.
269 isgraphics = saveisgraphics;
273 * c - Reset terminal.
277 ttystate[cs->raw].nlcr = 0;
281 * D - active position down a line, scroll if at bottom margin.
282 * (Original VT100 had a bug: tracked new-line/line-feed mode.)
287 scroll(yscrmin+1, yscrmax+1, yscrmin, yscrmax);
292 * E - active position to start of next line, scroll if at bottom margin.
298 scroll(yscrmin+1, yscrmax+1, yscrmin, yscrmax);
303 * H - set tab stop at current column.
304 * (This is cursor home in VT52 mode (not implemented).)
307 if(x < nelem(tabcol))
312 * M - active position up a line, scroll if at top margin..
317 scroll(yscrmin, yscrmax, yscrmin+1, yscrmin);
322 * Z - identification. the terminal
323 * emulator will return the response
324 * code for a generic VT100.
328 sendnchars(7, "\033[?1;2c"); /* VT100 with AVO option */
332 * < - enter ANSI mode
338 * > - set numeric keypad mode on (not implemented)
344 * = - set numeric keypad mode off (not implemented)
350 * # - Takes a one-digit argument
353 switch(get_next_char()){
354 case '3': /* Top half of double-height line */
355 case '4': /* Bottom half of double-height line */
356 case '5': /* Single-width single-height line */
357 case '6': /* Double-width line */
358 case '7': /* Screen print */
359 case '8': /* Fill screen with E's */
365 * ( - switch G0 character set
368 g0set = get_next_char();
372 * - switch G1 character set
375 g1set = get_next_char();
379 * Received left bracket.
383 * A semi-colon or ? delimits arguments.
385 memset(operand, 0, sizeof(operand));
386 operand[0] = number(buf, &i);
388 while(buf[0] == ';' || buf[0] == '?'){
389 if(noperand < nelem(operand)){
391 operand[noperand-1] = number(buf, nil);
401 * c - same as ESC Z: what are you?
407 * g - various tabstop manipulation
411 case 0: /* clear tab at current column */
412 if(x < nelem(tabcol))
415 case 3: /* clear all tabs */
416 memset(tabcol, 0, sizeof tabcol);
422 * l - clear various options.
427 case 20: /* set line feed mode */
428 ttystate[cs->raw].nlcr = 1;
430 case 30: /* screen invisible (? not supported through VT220) */
433 }else while(--noperand > 0){
434 switch(operand[noperand]){
435 case 1: /* set cursor keys to send ANSI functions: ESC [ A..D */
437 case 2: /* set VT52 mode (not implemented) */
439 case 3: /* set 80 columns */
442 case 4: /* set jump scrolling */
444 case 5: /* set normal video on screen */
446 case 6: /* set origin to absolute */
450 case 7: /* reset auto-wrap mode */
453 case 8: /* reset auto-repeat mode */
455 case 9: /* reset interlacing mode */
457 case 25: /* text cursor off (VT220) */
465 * s - some dec private stuff. actually [ ? num s, but we can't detect it.
471 * h - set various options.
478 case 20: /* set newline mode */
479 ttystate[cs->raw].nlcr = 0;
481 case 30: /* screen visible (? not supported through VT220) */
484 }else while(--noperand > 0){
485 switch(operand[noperand]){
488 case 1: /* set cursor keys to send application function: ESC O A..D */
490 case 2: /* set ANSI */
492 case 3: /* set 132 columns */
495 case 4: /* set smooth scrolling */
497 case 5: /* set screen to reverse video (not implemented) */
499 case 6: /* set origin to relative */
504 case 7: /* set auto-wrap mode */
507 case 8: /* set auto-repeat mode */
509 case 9: /* set interlacing mode */
511 case 25: /* text cursor on (VT220) */
519 * m - change character attrs.
522 setattr(noperand, operand);
526 * n - request various reports
531 sendnchars(4, "\033[0n"); /* terminal ok */
533 case 6: /* cursor position */
534 sendnchars(sprint((char*)buf, "\033[%d;%dR",
535 originrelative ? y+1 - yscrmin : y+1, x+1), (char*)buf);
541 * q - turn on list of LEDs; turn off others.
547 * r - change scrolling region. operand[0] is
548 * min scrolling region and operand[1] is max
556 yscrmax = operand[1]-1;
560 yscrmin = operand[0]-1;
569 * x - report terminal parameters
572 sendnchars(20, "\033[3;1;1;120;120;1;0x");
576 * y - invoke confidence test
596 olines -= operand[0];
619 * VT-100-UG says not to go past the
637 * G - cursor to column
648 * H and f - cursor motion. operand[0] is row and
649 * operand[1] is column, origin 1.
661 * d - cursor to line n (xterm)
677 * J - clear some or all of the display.
680 switch (operand[0]) {
682 * operand 2: whole screen.
685 clear(0, 0, xmax+1, ymax+1);
688 * operand 1: start of screen to active position, inclusive.
691 clear(0, 0, xmax+1, y);
692 clear(0, y, x+1, y+1);
695 * Default: active position to end of screen, inclusive.
698 clear(x, y, xmax+1, y+1);
699 clear(0, y+1, xmax+1, ymax+1);
705 * K - clear some or all of the line.
708 switch (operand[0]) {
710 * operand 2: whole line.
713 clear(0, y, xmax+1, y+1);
716 * operand 1: start of line to active position, inclusive.
719 clear(0, y, x+1, y+1);
722 * Default: active position to end of line, inclusive.
725 clear(x, y, xmax+1, y+1);
731 * P - delete character(s) from right of cursor (xterm)
736 shift(x, y, i, xmax+1 - i);
737 clear(xmax-operand[0], y, xmax+1, y+1);
741 * @ - insert blank(s) to right of cursor (xterm)
746 shift(i, y, x, xmax+1 - i);
752 * X - erase character(s) at cursor and to the right (xterm)
761 * L - insert a line at cursor position (VT102 and later)
765 for(i = 0; i < operand[0]; ++i)
766 scroll(y, yscrmax, y+1, y);
770 * M - delete a line at cursor position (VT102 and later)
774 for(i = 0; i < operand[0]; ++i)
775 scroll(y+1, yscrmax+1, y, yscrmax);
779 * S,T - scroll up/down (xterm)
783 for(i = 0; i < operand[0]; ++i)
784 scroll(yscrmin, yscrmax, yscrmin+1, yscrmin);
789 for(i = 0; i < operand[0]; ++i)
790 scroll(yscrmin+1, yscrmax+1, yscrmin, yscrmin);
793 case '=': /* ? not supported through VT220 */
806 * Collapse multiple '\033' to one.
819 default: /* ordinary char */
821 if(isgraphics && buf[0] < nelem(gmap) && gmap[buf[0]])
822 buf[0] = gmap[buf[0]];
835 while (!cs->raw && host_avail() && x+n<=xmax && n<BUFS
836 && (c = get_next_char())>=' ' && c<'\177') {
850 setattr(int argc, int *argv)
854 for(i=0; i<argc; i++) {
860 attr |= THighIntensity;
875 attr &= ~THighIntensity;
894 case 35: /* purple */
897 attr = (attr & ~0xF000) | 0x1000 | (argv[i]-30)<<13;
899 case 39: /* default */
907 case 45: /* purple */
910 attr = (attr & ~0x0F00) | 0x0100 | (argv[i]-40)<<9;
912 case 49: /* default */
919 // handle ESC], Operating System Command
923 Rune ch, buf[BUFS+1];
925 osc = number(&ch, &got);
935 while((ch = get_next_char()) != '\a') {
936 if(i < nelem(buf) - 1) {
941 if((fd = open("/dev/label", OWRITE)) >= 0) {
942 fprint(fd, "%S", buf);