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", },
75 { "F1", "\033[11~", },
76 { "F2", "\033[12~", },
77 { "F3", "\033[13~", },
78 { "F4", "\033[14~", },
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[22~", },
86 { "F12", "\033[23~", },
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);
142 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(dch = 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.
260 saveisgraphics = isgraphics;
264 * 8 - restore cursor position.
267 //print("restore\n");
271 isgraphics = saveisgraphics;
275 * c - Reset terminal.
278 print("resetterminal\n");
280 ttystate[cs->raw].nlcr = 0;
284 * D - active position down a line, scroll if at bottom margin.
285 * (Original VT100 had a bug: tracked new-line/line-feed mode.)
290 scroll(yscrmin+1, yscrmax+1, yscrmin, yscrmax);
295 * E - active position to start of next line, scroll if at bottom margin.
301 scroll(yscrmin+1, yscrmax+1, yscrmin, yscrmax);
306 * H - set tab stop at current column.
307 * (This is cursor home in VT52 mode (not implemented).)
310 if(x < nelem(tabcol))
315 * M - active position up a line, scroll if at top margin..
320 scroll(yscrmin, yscrmax, yscrmin+1, yscrmin);
325 * Z - identification. the terminal
326 * emulator will return the response
327 * code for a generic VT100.
331 sendnchars2(7, "\033[?1;2c"); /* VT100 with AVO option */
332 // sendnchars2(5, "\033[?6c"); /* VT102 (insert/delete-char, etc.) */
336 * < - enter ANSI mode
342 * > - set numeric keypad mode on (not implemented)
348 * = - set numeric keypad mode off (not implemented)
354 * # - Takes a one-digit argument
357 switch(get_next_char()){
358 case '3': /* Top half of double-height line */
359 case '4': /* Bottom half of double-height line */
360 case '5': /* Single-width single-height line */
361 case '6': /* Double-width line */
362 case '7': /* Screen print */
363 case '8': /* Fill screen with E's */
369 * ( - switch G0 character set
372 g0set = get_next_char();
376 * - switch G1 character set
379 g1set = get_next_char();
383 * Received left bracket.
387 * A semi-colon or ? delimits arguments.
389 memset(operand, 0, sizeof(operand));
390 operand[0] = number(buf, &i);
392 while(buf[0] == ';' || buf[0] == '?'){
393 if(noperand < nelem(operand)){
395 operand[noperand-1] = number(buf, nil);
403 switch(dch = buf[0]){
405 * c - same as ESC Z: what are you?
411 * g - various tabstop manipulation
415 case 0: /* clear tab at current column */
416 if(x < nelem(tabcol))
419 case 3: /* clear all tabs */
420 memset(tabcol, 0, sizeof tabcol);
426 * l - clear various options.
431 case 20: /* set line feed mode */
432 ttystate[cs->raw].nlcr = 1;
434 case 30: /* screen invisible (? not supported through VT220) */
437 }else while(--noperand > 0){
438 switch(operand[noperand]){
439 case 1: /* set cursor keys to send ANSI functions: ESC [ A..D */
441 case 2: /* set VT52 mode (not implemented) */
443 case 3: /* set 80 columns */
446 case 4: /* set jump scrolling */
448 case 5: /* set normal video on screen */
450 case 6: /* set origin to absolute */
454 case 7: /* reset auto-wrap mode */
457 case 8: /* reset auto-repeat mode */
459 case 9: /* reset interlacing mode */
461 case 25: /* text cursor off (VT220) */
469 * s - some dec private stuff. actually [ ? num s, but we can't detect it.
475 * h - set various options.
482 case 20: /* set newline mode */
483 ttystate[cs->raw].nlcr = 0;
485 case 30: /* screen visible (? not supported through VT220) */
488 }else while(--noperand > 0){
489 switch(operand[noperand]){
492 case 1: /* set cursor keys to send application function: ESC O A..D */
494 case 2: /* set ANSI */
496 case 3: /* set 132 columns */
499 case 4: /* set smooth scrolling */
501 case 5: /* set screen to reverse video (not implemented) */
503 case 6: /* set origin to relative */
508 case 7: /* set auto-wrap mode */
511 case 8: /* set auto-repeat mode */
513 case 9: /* set interlacing mode */
515 case 25: /* text cursor on (VT220) */
523 * m - change character attrs.
526 setattr(noperand, operand);
530 * n - request various reports
535 sendnchars2(4, "\033[0n"); /* terminal ok */
537 case 6: /* cursor position */
538 sendnchars2(sprint(buf, "\033[%d;%dR",
539 originrelative ? y+1 - yscrmin : y+1, x+1), buf);
545 * q - turn on list of LEDs; turn off others.
551 * r - change scrolling region. operand[0] is
552 * min scrolling region and operand[1] is max
560 yscrmax = operand[1]-1;
564 yscrmin = operand[0]-1;
573 * x - report terminal parameters
576 sendnchars2(20, "\033[3;1;1;120;120;1;0x");
580 * y - invoke confidence test
600 olines -= operand[0];
623 * VT-100-UG says not to go past the
641 * G - cursor to column
652 * H and f - cursor motion. operand[0] is row and
653 * operand[1] is column, origin 1.
665 * d - cursor to line n (xterm)
681 * J - clear some or all of the display.
684 switch (operand[0]) {
686 * operand 2: whole screen.
689 clear(Rpt(pt(0, 0), pt(xmax+1, ymax+1)));
692 * operand 1: start of screen to active position, inclusive.
695 clear(Rpt(pt(0, 0), pt(xmax+1, y)));
696 clear(Rpt(pt(0, y), pt(x+1, y+1)));
699 * Default: active position to end of screen, inclusive.
702 clear(Rpt(pt(x, y), pt(xmax+1, y+1)));
703 clear(Rpt(pt(0, y+1), pt(xmax+1, ymax+1)));
709 * K - clear some or all of the line.
712 switch (operand[0]) {
714 * operand 2: whole line.
717 clear(Rpt(pt(0, y), pt(xmax+1, y+1)));
720 * operand 1: start of line to active position, inclusive.
723 clear(Rpt(pt(0, y), pt(x+1, y+1)));
726 * Default: active position to end of line, inclusive.
729 clear(Rpt(pt(x, y), pt(xmax+1, y+1)));
735 * P - delete character(s) from right of cursor (xterm)
740 draw(screen, Rpt(pt(x, y), pt(xmax+1, y+1)), screen, nil, pt(i, y));
741 clear(Rpt(pt(xmax-operand[0], y), pt(xmax+1, y+1)));
745 * @ - insert blank(s) to right of cursor (xterm)
750 draw(screen, Rpt(pt(i, y), pt(xmax+1, y+1)), screen, nil, pt(x, y));
751 clear(Rpt(pt(x, y), pt(i, y+1)));
756 * X - erase character(s) at cursor and to the right (xterm)
761 clear(Rpt(pt(x, y), pt(i, y+1)));
765 * L - insert a line at cursor position (VT102 and later)
769 for(i = 0; i < operand[0]; ++i)
770 scroll(y, yscrmax, y+1, y);
774 * M - delete a line at cursor position (VT102 and later)
778 for(i = 0; i < operand[0]; ++i)
779 scroll(y+1, yscrmax+1, y, yscrmax);
783 * S,T - scroll up/down (xterm)
787 for(i = 0; i < operand[0]; ++i)
788 scroll(yscrmin, yscrmax, yscrmin+1, yscrmin);
793 for(i = 0; i < operand[0]; ++i)
794 scroll(yscrmin+1, yscrmax+1, yscrmin, yscrmin);
797 case '=': /* ? not supported through VT220 */
807 * Anything else we ignore for now...
810 print("unknown escape2 '%c' (0x%x)\n", dch, dch);
817 * Collapse multiple '\033' to one.
824 case ']': /* it's actually <esc> ] num ; title <bel> */
829 while((ch = get_next_char()) != '\a')
832 fd = open("/dev/label", OWRITE);
839 * Ignore other commands.
842 print("unknown command '%c' (0x%x)\n", dch, dch);
848 default: /* ordinary char */
850 if(isgraphics && gmap[(uchar) buf[0]])
851 buf[0] = gmap[(uchar) buf[0]];
864 while (!cs->raw && host_avail() && x+n<=xmax && n<BUFS
865 && (c = get_next_char())>=' ' && c<'\177') {
870 // clear(Rpt(pt(x,y), pt(x+n, y+1)));
871 drawstring(pt(x, y), buf, attr);
880 setattr(int argc, int *argv)
884 for(i=0; i<argc; i++) {
892 attr |= THighIntensity;
907 attr &= ~THighIntensity;
926 case 35: /* purple */
929 fgcolor = (nocolor? fgdefault: colors[argv[i]-30]);
939 case 45: /* purple */
942 bgcolor = (nocolor? bgdefault: colors[argv[i]-40]);