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", "\033[A", },
72 { "down key", "\033[B", },
73 { "left key", "\033[D", },
74 { "right key", "\033[C", },
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;
149 g0set = 'B'; /* US ASCII */
150 g1set = 'B'; /* US ASCII */
156 /* set initial tab stops to DEC-standard 8-column spacing */
157 for(c=0; (c+=8)<nelem(tabcol);)
165 buf[0] = get_next_char();
178 case '\007': /* bell */
182 case '\010': /* backspace */
187 case '\011': /* tab to next tab stop; if none, to right margin */
188 for(c=x+1; c<nelem(tabcol) && !tabcol[c]; c++)
190 if(c < nelem(tabcol))
196 case '\012': /* linefeed */
200 if (ttystate[cs->raw].nlcr)
204 case '\015': /* carriage return */
206 if (ttystate[cs->raw].crnl)
210 case '\016': /* SO: invoke G1 char set */
211 isgraphics = (isdigit(g1set));
213 case '\017': /* SI: invoke G0 char set */
214 isgraphics = (isdigit(g0set));
217 case '\020': /* DLE */
218 case '\021': /* DC1 */
219 case '\022': /* XON */
220 case '\023': /* DC3 */
221 case '\024': /* XOFF */
222 case '\025': /* NAK */
223 case '\026': /* SYN */
224 case '\027': /* ETB */
225 case '\030': /* CAN: cancel escape sequence, display checkerboard (not implemented) */
226 case '\031': /* EM */
227 case '\032': /* SUB: same as CAN */
230 /* ESC, \033, is handled below */
231 case '\034': /* FS */
232 case '\035': /* GS */
233 case '\036': /* RS */
234 case '\037': /* US */
236 case '\177': /* delete: ignored */
240 switch(dch = get_next_char()){
242 * 1 - graphic processor option on (no-op; not installed)
248 * 2 - graphic processor option off (no-op; not installed)
254 * 7 - save cursor position.
261 saveisgraphics = isgraphics;
265 * 8 - restore cursor position.
268 //print("restore\n");
272 isgraphics = saveisgraphics;
276 * c - Reset terminal.
279 print("resetterminal\n");
281 ttystate[cs->raw].nlcr = 0;
285 * D - active position down a line, scroll if at bottom margin.
286 * (Original VT100 had a bug: tracked new-line/line-feed mode.)
291 scroll(yscrmin+1, yscrmax+1, yscrmin, yscrmax);
296 * E - active position to start of next line, scroll if at bottom margin.
302 scroll(yscrmin+1, yscrmax+1, yscrmin, yscrmax);
307 * H - set tab stop at current column.
308 * (This is cursor home in VT52 mode (not implemented).)
311 if(x < nelem(tabcol))
316 * M - active position up a line, scroll if at top margin..
321 scroll(yscrmin, yscrmax, yscrmin+1, yscrmin);
326 * Z - identification. the terminal
327 * emulator will return the response
328 * code for a generic VT100.
332 sendnchars(7, "\033[?1;2c"); /* VT100 with AVO option */
333 // sendnchars(5, "\033[?6c"); /* VT102 (insert/delete-char, etc.) */
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);
404 switch(dch = buf[0]){
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 */
442 case 2: /* set VT52 mode (not implemented) */
444 case 3: /* set 80 columns */
447 case 4: /* set jump scrolling */
449 case 5: /* set normal video on screen */
451 case 6: /* set origin to absolute */
455 case 7: /* reset auto-wrap mode */
458 case 8: /* reset auto-repeat mode */
460 case 9: /* reset interlacing mode */
462 case 25: /* text cursor off (VT220) */
470 * s - some dec private stuff. actually [ ? num s, but we can't detect it.
476 * h - set various options.
483 case 20: /* set newline mode */
484 ttystate[cs->raw].nlcr = 0;
486 case 30: /* screen visible (? not supported through VT220) */
489 }else while(--noperand > 0){
490 switch(operand[noperand]){
493 case 1: /* set cursor keys to send application function: ESC O A..D */
495 case 2: /* set ANSI */
497 case 3: /* set 132 columns */
500 case 4: /* set smooth scrolling */
502 case 5: /* set screen to reverse video (not implemented) */
504 case 6: /* set origin to relative */
509 case 7: /* set auto-wrap mode */
512 case 8: /* set auto-repeat mode */
514 case 9: /* set interlacing mode */
516 case 25: /* text cursor on (VT220) */
524 * m - change character attrs.
527 setattr(noperand, operand);
531 * n - request various reports
536 sendnchars(4, "\033[0n"); /* terminal ok */
538 case 6: /* cursor position */
539 sendnchars(sprint((char*)buf, "\033[%d;%dR",
540 originrelative ? y+1 - yscrmin : y+1, x+1), (char*)buf);
546 * q - turn on list of LEDs; turn off others.
552 * r - change scrolling region. operand[0] is
553 * min scrolling region and operand[1] is max
561 yscrmax = operand[1]-1;
565 yscrmin = operand[0]-1;
574 * x - report terminal parameters
577 sendnchars(20, "\033[3;1;1;120;120;1;0x");
581 * y - invoke confidence test
601 olines -= operand[0];
624 * VT-100-UG says not to go past the
642 * G - cursor to column
653 * H and f - cursor motion. operand[0] is row and
654 * operand[1] is column, origin 1.
666 * d - cursor to line n (xterm)
682 * J - clear some or all of the display.
685 switch (operand[0]) {
687 * operand 2: whole screen.
690 clear(Rpt(pt(0, 0), pt(xmax+1, ymax+1)));
693 * operand 1: start of screen to active position, inclusive.
696 clear(Rpt(pt(0, 0), pt(xmax+1, y)));
697 clear(Rpt(pt(0, y), pt(x+1, y+1)));
700 * Default: active position to end of screen, inclusive.
703 clear(Rpt(pt(x, y), pt(xmax+1, y+1)));
704 clear(Rpt(pt(0, y+1), pt(xmax+1, ymax+1)));
710 * K - clear some or all of the line.
713 switch (operand[0]) {
715 * operand 2: whole line.
718 clear(Rpt(pt(0, y), pt(xmax+1, y+1)));
721 * operand 1: start of line to active position, inclusive.
724 clear(Rpt(pt(0, y), pt(x+1, y+1)));
727 * Default: active position to end of line, inclusive.
730 clear(Rpt(pt(x, y), pt(xmax+1, y+1)));
736 * P - delete character(s) from right of cursor (xterm)
741 draw(screen, Rpt(pt(x, y), pt(xmax+1, y+1)), screen, nil, pt(i, y));
742 clear(Rpt(pt(xmax-operand[0], y), pt(xmax+1, y+1)));
746 * @ - insert blank(s) to right of cursor (xterm)
751 draw(screen, Rpt(pt(i, y), pt(xmax+1, y+1)), screen, nil, pt(x, y));
752 clear(Rpt(pt(x, y), pt(i, y+1)));
757 * X - erase character(s) at cursor and to the right (xterm)
762 clear(Rpt(pt(x, y), pt(i, y+1)));
766 * L - insert a line at cursor position (VT102 and later)
770 for(i = 0; i < operand[0]; ++i)
771 scroll(y, yscrmax, y+1, y);
775 * M - delete a line at cursor position (VT102 and later)
779 for(i = 0; i < operand[0]; ++i)
780 scroll(y+1, yscrmax+1, y, yscrmax);
784 * S,T - scroll up/down (xterm)
788 for(i = 0; i < operand[0]; ++i)
789 scroll(yscrmin, yscrmax, yscrmin+1, yscrmin);
794 for(i = 0; i < operand[0]; ++i)
795 scroll(yscrmin+1, yscrmax+1, yscrmin, yscrmin);
798 case '=': /* ? not supported through VT220 */
808 * Anything else we ignore for now...
811 print("unknown escape2 '%c' (0x%x)\n", dch, dch);
818 * Collapse multiple '\033' to one.
830 * Ignore other commands.
833 print("unknown command '%c' (0x%x)\n", dch, dch);
839 default: /* ordinary char */
841 if(isgraphics && buf[0] < nelem(gmap) && gmap[buf[0]])
842 buf[0] = gmap[buf[0]];
855 while (!cs->raw && host_avail() && x+n<=xmax && n<BUFS
856 && (c = get_next_char())>=' ' && c<'\177') {
861 drawstring(pt(x, y), buf, attr);
870 setattr(int argc, int *argv)
874 for(i=0; i<argc; i++) {
882 attr |= THighIntensity;
897 attr &= ~THighIntensity;
916 case 35: /* purple */
919 fgcolor = (nocolor? fgdefault: colors[argv[i]-30]);
929 case 45: /* purple */
932 bgcolor = (nocolor? bgdefault: colors[argv[i]-40]);
941 // handle ESC], Operating System Command
945 Rune ch, buf[BUFS+1];
947 osc = number(&ch, &got);
957 while((ch = get_next_char()) != '\a') {
958 if(i < nelem(buf) - 1) {
963 if((fd = open("/dev/label", OWRITE)) >= 0) {
964 fprint(fd, "%S", buf);
969 fprint(2, "unknown osc escape %d\n", osc);