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.
32 int originrelative = 0;
36 struct funckey ansifk[] = {
37 { "up key", "\033[A", },
38 { "down key", "\033[B", },
39 { "left key", "\033[D", },
40 { "right key", "\033[C", },
56 struct funckey ansiappfk[] = {
57 { "up key", "\033OA", },
58 { "down key", "\033OB", },
59 { "left key", "\033OD", },
60 { "right key", "\033OC", },
65 struct funckey vt220fk[] = {
66 { "insert", "\033[2~", },
67 { "delete", "\033[3~", },
68 { "home", "\033[1~", },
69 { "end", "\033[4~", },
70 { "page up", "\033[5~", },
71 { "page down", "\033[6~", },
73 { "up key", "\033[A", },
74 { "down key", "\033[B", },
75 { "left key", "\033[D", },
76 { "right key", "\033[C", },
82 { "F5", "\033[15~", },
83 { "F6", "\033[17~", },
84 { "F7", "\033[18~", },
85 { "F8", "\033[19~", },
86 { "F9", "\033[20~", },
87 { "F10", "\033[21~", },
88 { "F11", "\033[23~", },
89 { "F12", "\033[24~", },
95 ['_'] ' ', /* blank */
96 ['\\'] '*', /* diamond */
97 ['a'] 'X', /* checkerboard */
99 ['c'] '\x0C', /* FF */
102 ['f'] 'o', /* degree */
103 ['g'] '+', /* plus/minus */
104 ['h'] '\n', /* NL, but close enough */
106 ['j'] '+', /* lower right corner */
107 ['k'] '+', /* upper right corner */
108 ['l'] '+', /* upper left corner */
109 ['m'] '+', /* lower left corner */
110 ['n'] '+', /* crossing lines */
111 ['o'] '-', /* horiz line - scan 1 */
112 ['p'] '-', /* horiz line - scan 3 */
113 ['q'] '-', /* horiz line - scan 5 */
114 ['r'] '-', /* horiz line - scan 7 */
115 ['s'] '-', /* horiz line - scan 9 */
118 ['v'] '+', /* upside down T */
119 ['w'] '+', /* rightside up T */
120 ['x'] '|', /* vertical bar */
121 ['y'] '<', /* less/equal */
122 ['z'] '>', /* gtr/equal */
124 ['|'] '!', /* not equal */
125 ['}'] 'L', /* pound symbol */
126 ['~'] '.', /* centered dot: ยท */
129 static void setattr(int argc, int *argv);
130 static void osc(void);
148 int savex, savey, saveattr, saveisgraphics;
153 g0set = 'B'; /* US ASCII */
154 g1set = 'B'; /* US ASCII */
160 /* set initial tab stops to DEC-standard 8-column spacing */
161 for(c=0; (c+=8)<nelem(tabcol);)
169 buf[0] = get_next_char();
182 case '\007': /* bell */
186 case '\010': /* backspace */
191 case '\011': /* tab to next tab stop; if none, to right margin */
192 for(c=x+1; c<nelem(tabcol) && !tabcol[c]; c++)
194 if(c < nelem(tabcol))
200 case '\012': /* linefeed */
204 if (ttystate[cs->raw].nlcr)
208 case '\015': /* carriage return */
210 if (ttystate[cs->raw].crnl)
214 case '\016': /* SO: invoke G1 char set */
215 isgraphics = (isdigit(g1set));
217 case '\017': /* SI: invoke G0 char set */
218 isgraphics = (isdigit(g0set));
221 case '\020': /* DLE */
222 case '\021': /* DC1 */
223 case '\022': /* XON */
224 case '\023': /* DC3 */
225 case '\024': /* XOFF */
226 case '\025': /* NAK */
227 case '\026': /* SYN */
228 case '\027': /* ETB */
229 case '\030': /* CAN: cancel escape sequence, display checkerboard (not implemented) */
230 case '\031': /* EM */
231 case '\032': /* SUB: same as CAN */
234 /* ESC, \033, is handled below */
235 case '\034': /* FS */
236 case '\035': /* GS */
237 case '\036': /* RS */
238 case '\037': /* US */
240 case '\177': /* delete: ignored */
244 switch(get_next_char()){
246 * 1 - graphic processor option on (no-op; not installed)
252 * 2 - graphic processor option off (no-op; not installed)
258 * 7 - save cursor position.
264 saveisgraphics = isgraphics;
268 * 8 - restore cursor position.
274 isgraphics = saveisgraphics;
278 * c - Reset terminal.
282 ttystate[cs->raw].nlcr = 0;
286 * D - active position down a line, scroll if at bottom margin.
287 * (Original VT100 had a bug: tracked new-line/line-feed mode.)
292 scroll(yscrmin+1, yscrmax+1, yscrmin, yscrmax);
297 * E - active position to start of next line, scroll if at bottom margin.
303 scroll(yscrmin+1, yscrmax+1, yscrmin, yscrmax);
308 * H - set tab stop at current column.
309 * (This is cursor home in VT52 mode (not implemented).)
312 if(x < nelem(tabcol))
317 * M - active position up a line, scroll if at top margin..
322 scroll(yscrmin, yscrmax, yscrmin+1, yscrmin);
327 * Z - identification. the terminal
328 * emulator will return the response
329 * code for a generic VT100.
333 sendnchars(7, "\033[?1;2c"); /* VT100 with AVO option */
337 * < - enter ANSI mode
343 * > - set numeric keypad mode on (not implemented)
349 * = - set numeric keypad mode off (not implemented)
355 * # - Takes a one-digit argument
358 switch(get_next_char()){
359 case '3': /* Top half of double-height line */
360 case '4': /* Bottom half of double-height line */
361 case '5': /* Single-width single-height line */
362 case '6': /* Double-width line */
363 case '7': /* Screen print */
364 case '8': /* Fill screen with E's */
370 * ( - switch G0 character set
373 g0set = get_next_char();
377 * - switch G1 character set
380 g1set = get_next_char();
384 * Received left bracket.
388 * A semi-colon or ? delimits arguments.
390 memset(operand, 0, sizeof(operand));
391 operand[0] = number(buf, &i);
393 while(buf[0] == ';' || buf[0] == '?'){
394 if(noperand < nelem(operand)){
396 operand[noperand-1] = number(buf, nil);
406 * c - same as ESC Z: what are you?
412 * g - various tabstop manipulation
416 case 0: /* clear tab at current column */
417 if(x < nelem(tabcol))
420 case 3: /* clear all tabs */
421 memset(tabcol, 0, sizeof tabcol);
427 * l - clear various options.
432 case 20: /* set line feed mode */
433 ttystate[cs->raw].nlcr = 1;
435 case 30: /* screen invisible (? not supported through VT220) */
438 }else while(--noperand > 0){
439 switch(operand[noperand]){
440 case 1: /* set cursor keys to send ANSI functions: ESC [ A..D */
443 case 2: /* set VT52 mode (not implemented) */
445 case 3: /* set 80 columns */
448 case 4: /* set jump scrolling */
450 case 5: /* set normal video on screen */
452 case 6: /* set origin to absolute */
456 case 7: /* reset auto-wrap mode */
459 case 8: /* reset auto-repeat mode */
461 case 9: /* reset interlacing mode */
463 case 25: /* text cursor off (VT220) */
471 * s - some dec private stuff. actually [ ? num s, but we can't detect it.
477 * h - set various options.
484 case 20: /* set newline mode */
485 ttystate[cs->raw].nlcr = 0;
487 case 30: /* screen visible (? not supported through VT220) */
490 }else while(--noperand > 0){
491 switch(operand[noperand]){
494 case 1: /* set cursor keys to send application function: ESC O A..D */
497 case 2: /* set ANSI */
499 case 3: /* set 132 columns */
502 case 4: /* set smooth scrolling */
504 case 5: /* set screen to reverse video (not implemented) */
506 case 6: /* set origin to relative */
511 case 7: /* set auto-wrap mode */
514 case 8: /* set auto-repeat mode */
516 case 9: /* set interlacing mode */
518 case 25: /* text cursor on (VT220) */
526 * m - change character attrs.
529 setattr(noperand, operand);
533 * n - request various reports
538 sendnchars(4, "\033[0n"); /* terminal ok */
540 case 6: /* cursor position */
541 sendnchars(sprint((char*)buf, "\033[%d;%dR",
542 originrelative ? y+1 - yscrmin : y+1, x+1), (char*)buf);
548 * q - turn on list of LEDs; turn off others.
554 * r - change scrolling region. operand[0] is
555 * min scrolling region and operand[1] is max
563 yscrmax = operand[1]-1;
567 yscrmin = operand[0]-1;
576 * x - report terminal parameters
579 sendnchars(20, "\033[3;1;1;120;120;1;0x");
583 * y - invoke confidence test
603 olines -= operand[0];
626 * VT-100-UG says not to go past the
644 * G - cursor to column
655 * H and f - cursor motion. operand[0] is row and
656 * operand[1] is column, origin 1.
668 * d - cursor to line n (xterm)
684 * J - clear some or all of the display.
687 switch (operand[0]) {
689 * operand 2: whole screen.
692 clear(0, 0, xmax+1, ymax+1);
695 * operand 1: start of screen to active position, inclusive.
698 clear(0, 0, xmax+1, y);
699 clear(0, y, x+1, y+1);
702 * Default: active position to end of screen, inclusive.
705 clear(x, y, xmax+1, y+1);
706 clear(0, y+1, xmax+1, ymax+1);
712 * K - clear some or all of the line.
715 switch (operand[0]) {
717 * operand 2: whole line.
720 clear(0, y, xmax+1, y+1);
723 * operand 1: start of line to active position, inclusive.
726 clear(0, y, x+1, y+1);
729 * Default: active position to end of line, inclusive.
732 clear(x, y, xmax+1, y+1);
738 * P - delete character(s) from right of cursor (xterm)
743 shift(x, y, i, xmax+1 - i);
744 clear(xmax-operand[0], y, xmax+1, y+1);
748 * @ - insert blank(s) to right of cursor (xterm)
753 shift(i, y, x, xmax+1 - i);
759 * X - erase character(s) at cursor and to the right (xterm)
768 * L - insert a line at cursor position (VT102 and later)
772 for(i = 0; i < operand[0]; ++i)
773 scroll(y, yscrmax, y+1, y);
777 * M - delete a line at cursor position (VT102 and later)
781 for(i = 0; i < operand[0]; ++i)
782 scroll(y+1, yscrmax+1, y, yscrmax);
786 * S,T - scroll up/down (xterm)
790 for(i = 0; i < operand[0]; ++i)
791 scroll(yscrmin, yscrmax, yscrmin+1, yscrmin);
796 for(i = 0; i < operand[0]; ++i)
797 scroll(yscrmin+1, yscrmax+1, yscrmin, yscrmin);
800 case '=': /* ? not supported through VT220 */
813 * Collapse multiple '\033' to one.
826 default: /* ordinary char */
828 if(isgraphics && buf[0] < nelem(gmap) && gmap[buf[0]])
829 buf[0] = gmap[buf[0]];
842 while (!cs->raw && host_avail() && x+n<=xmax && n<BUFS
843 && (c = get_next_char())>=' ' && c<'\177') {
857 setattr(int argc, int *argv)
861 for(i=0; i<argc; i++) {
867 attr |= THighIntensity;
882 attr &= ~THighIntensity;
901 case 35: /* purple */
904 attr = (attr & ~0xF000) | 0x1000 | (argv[i]-30)<<13;
906 case 39: /* default */
914 case 45: /* purple */
917 attr = (attr & ~0x0F00) | 0x0100 | (argv[i]-40)<<9;
919 case 49: /* default */
926 // handle ESC], Operating System Command
930 Rune ch, buf[BUFS+1];
932 osc = number(&ch, &got);
942 while((ch = get_next_char()) != '\a') {
943 if(i < nelem(buf) - 1) {
948 if((fd = open("/dev/label", OWRITE)) >= 0) {
949 fprint(fd, "%S", buf);