]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/vt/vt.c
exec(2): fix prototypes
[plan9front.git] / sys / src / cmd / vt / vt.c
1 /*
2  * Known bugs:
3  *
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.
7  *
8  * 2. We don't handle tabstops past nelem(tabcol) columns.
9  *
10  * 3. We don't respect requests to do reverse video for the whole screen.
11  *
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.
14  *
15  * 5. Cursor key sequences aren't selected by keypad application mode.
16  *
17  * 6. "VT220" mode (-2) currently just switches the default cursor key
18  *      functions (same as -a); it's still just a VT100 emulation.
19  *
20  * 7. VT52 mode and a few other rarely used features are not implemented.
21  */
22
23 #include <u.h>
24 #include <libc.h>
25 #include <draw.h>
26 #include <bio.h>
27 #include <ctype.h>
28 #include "cons.h"
29
30 int     wraparound = 1;
31 int     originrelative = 0;
32
33 int     tabcol[200];
34
35 struct funckey vt100fk[NKEYS] = {
36         { "up key",             "\033OA", },
37         { "down key",           "\033OB", },
38         { "left key",           "\033OD", },
39         { "right key",          "\033OC", },
40 };
41
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", },
47         { "F1",                 "\033OP", },
48         { "F2",                 "\033OQ", },
49         { "F3",                 "\033OR", },
50         { "F4",                 "\033OS", },
51         { "F5",                 "\033OT", },
52         { "F6",                 "\033OU", },
53         { "F7",                 "\033OV", },
54         { "F8",                 "\033OW", },
55         { "F9",                 "\033OX", },
56         { "F10",                "\033OY", },
57         { "F11",                "\033OZ", },
58         { "F12",                "\033O1", },
59 };
60
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", },
66 };
67
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",                 "\033OP", },
76         { "F2",                 "\033OQ", },
77         { "F3",                 "\033OR", },
78         { "F4",                 "\033OS", },
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~", },
87 };
88
89 char gmap[256] = {
90         ['_']   ' ',    /* blank */
91         ['\\']  '*',    /* diamond */
92         ['a']   'X',    /* checkerboard */
93         ['b']   '\t',   /* HT */
94         ['c']   '\x0C', /* FF */
95         ['d']   '\r',   /* CR */
96         ['e']   '\n',   /* LF */
97         ['f']   'o',    /* degree */
98         ['g']   '+',    /* plus/minus */
99         ['h']   '\n',   /* NL, but close enough */
100         ['i']   '\v',   /* VT */
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 */
111         ['t']   '+',    /* |-   */
112         ['u']   '+',    /* -| */
113         ['v']   '+',    /* upside down T */
114         ['w']   '+',    /* rightside up T */
115         ['x']   '|',    /* vertical bar */
116         ['y']   '<',    /* less/equal */
117         ['z']   '>',    /* gtr/equal */
118         ['{']   'p',    /* pi */
119         ['|']   '!',    /* not equal */
120         ['}']   'L',    /* pound symbol */
121         ['~']   '.',    /* centered dot: ยท */
122 };
123
124 static void setattr(int argc, int *argv);
125 static void osc(void);
126
127 void
128 fixops(int *operand)
129 {
130         if(operand[0] < 1)
131                 operand[0] = 1;
132 }
133
134 void
135 emulate(void)
136 {
137         Rune buf[BUFS+1];
138         int i;
139         int n;
140         int c;
141         int operand[10];
142         int noperand;
143         int savex, savey, saveattr, saveisgraphics;
144         int isgraphics;
145         int g0set, g1set;
146         int dch;
147
148         isgraphics = 0;
149         g0set = 'B';    /* US ASCII */
150         g1set = 'B';    /* US ASCII */
151         savex = savey = 0;
152         yscrmin = 0;
153         yscrmax = ymax;
154         saveattr = 0;
155         saveisgraphics = 0;
156         /* set initial tab stops to DEC-standard 8-column spacing */
157         for(c=0; (c+=8)<nelem(tabcol);)
158                 tabcol[c] = 1;
159
160         for (;;) {
161                 if (y > ymax) {
162                         x = 0;
163                         newline();
164                 }
165                 buf[0] = get_next_char();
166                 buf[1] = '\0';
167                 switch(buf[0]) {
168
169                 case '\000':
170                 case '\001':
171                 case '\002':
172                 case '\003':
173                 case '\004':
174                 case '\005':
175                 case '\006':
176                         goto Default;
177
178                 case '\007':            /* bell */
179                         ringbell();
180                         break;
181
182                 case '\010':            /* backspace */
183                         if (x > 0)
184                                 --x;
185                         break;
186
187                 case '\011':            /* tab to next tab stop; if none, to right margin */
188                         for(c=x+1; c<nelem(tabcol) && !tabcol[c]; c++)
189                                 ;
190                         if(c < nelem(tabcol))
191                                 x = c;
192                         else
193                                 x = xmax;
194                         break;
195
196                 case '\012':            /* linefeed */
197                 case '\013':
198                 case '\014':
199                         newline();
200                         if (ttystate[cs->raw].nlcr)
201                                 x = 0;
202                         break;
203
204                 case '\015':            /* carriage return */
205                         x = 0;
206                         if (ttystate[cs->raw].crnl)
207                                 newline();
208                         break;
209
210                 case '\016':    /* SO: invoke G1 char set */
211                         isgraphics = (isdigit(g1set));
212                         break;
213                 case '\017':    /* SI: invoke G0 char set */
214                         isgraphics = (isdigit(g0set));
215                         break;
216
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 */
228                         goto Default;
229 ;
230                 /* ESC, \033, is handled below */
231                 case '\034':    /* FS */
232                 case '\035':    /* GS */
233                 case '\036':    /* RS */
234                 case '\037':    /* US */
235                         break;
236                 case '\177':    /* delete: ignored */
237                         break;
238
239                 case '\033':
240                         switch(dch = get_next_char()){
241                         /*
242                          * 1 - graphic processor option on (no-op; not installed)
243                          */
244                         case '1':
245                                 break;
246
247                         /*
248                          * 2 - graphic processor option off (no-op; not installed)
249                          */
250                         case '2':
251                                 break;
252
253                         /*
254                          * 7 - save cursor position.
255                          */
256                         case '7':
257 //print("save\n");
258                                 savex = x;
259                                 savey = y;
260                                 saveattr = attr;
261                                 saveisgraphics = isgraphics;
262                                 break;
263
264                         /*
265                          * 8 - restore cursor position.
266                          */
267                         case '8':
268 //print("restore\n");
269                                 x = savex;
270                                 y = savey;
271                                 attr = saveattr;
272                                 isgraphics = saveisgraphics;
273                                 break;
274
275                         /*
276                          * c - Reset terminal.
277                          */
278                         case 'c':
279 print("resetterminal\n");
280                                 cursoron = 1;
281                                 ttystate[cs->raw].nlcr = 0;
282                                 break;
283
284                         /*
285                          * D - active position down a line, scroll if at bottom margin.
286                          * (Original VT100 had a bug: tracked new-line/line-feed mode.)
287                          */
288                         case 'D':
289                                 if(++y > yscrmax) {
290                                         y = yscrmax;
291                                         scroll(yscrmin+1, yscrmax+1, yscrmin, yscrmax);
292                                 }
293                                 break;
294
295                         /*
296                          * E - active position to start of next line, scroll if at bottom margin.
297                          */
298                         case 'E':
299                                 x = 0;
300                                 if(++y > yscrmax) {
301                                         y = yscrmax;
302                                         scroll(yscrmin+1, yscrmax+1, yscrmin, yscrmax);
303                                 }
304                                 break;
305
306                         /*
307                          * H - set tab stop at current column.
308                          * (This is cursor home in VT52 mode (not implemented).)
309                          */
310                         case 'H':
311                                 if(x < nelem(tabcol))
312                                         tabcol[x] = 1;
313                                 break;
314
315                         /*
316                          * M - active position up a line, scroll if at top margin..
317                          */
318                         case 'M':
319                                 if(--y < yscrmin) {
320                                         y = yscrmin;
321                                         scroll(yscrmin, yscrmax, yscrmin+1, yscrmin);
322                                 }
323                                 break;
324
325                         /*
326                          * Z - identification.  the terminal
327                          * emulator will return the response
328                          * code for a generic VT100.
329                          */
330                         case 'Z':
331                         Ident:
332                                 sendnchars(7, "\033[?1;2c");    /* VT100 with AVO option */
333 //                              sendnchars(5, "\033[?6c");      /* VT102 (insert/delete-char, etc.) */
334                                 break;
335
336                         /*
337                          * < - enter ANSI mode
338                          */
339                         case '<':
340                                 break;
341
342                         /*
343                          * > - set numeric keypad mode on (not implemented)
344                          */
345                         case '>':
346                                 break;
347
348                         /*
349                          * = - set numeric keypad mode off (not implemented)
350                          */
351                         case '=':
352                                 break;
353
354                         /*
355                          * # - Takes a one-digit argument
356                          */
357                         case '#':
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 */
365                                         break;
366                                 }
367                                 break;
368
369                         /*
370                          * ( - switch G0 character set
371                          */
372                         case '(':
373                                 g0set = get_next_char();
374                                 break;
375
376                         /*
377                          * - switch G1 character set
378                          */
379                         case ')':
380                                 g1set = get_next_char();
381                                 break;
382
383                         /*
384                          * Received left bracket.
385                          */
386                         case '[':
387                                 /*
388                                  * A semi-colon or ? delimits arguments.
389                                  */
390                                 memset(operand, 0, sizeof(operand));
391                                 operand[0] = number(buf, &i);
392                                 noperand = 1;
393                                 while(buf[0] == ';' || buf[0] == '?'){
394                                         if(noperand < nelem(operand)){
395                                                 noperand++;
396                                                 operand[noperand-1] = number(buf, nil);
397                                         } else
398                                                 number(buf, nil);
399                                 }
400
401                                 /*
402                                  * do escape2 stuff
403                                  */
404                                 switch(dch = buf[0]){
405                                         /*
406                                          * c - same as ESC Z: what are you?
407                                          */
408                                         case 'c':
409                                                 goto Ident;
410
411                                         /*
412                                          * g - various tabstop manipulation
413                                          */
414                                         case 'g':
415                                                 switch(operand[0]){
416                                                 case 0: /* clear tab at current column */
417                                                         if(x < nelem(tabcol))
418                                                                 tabcol[x] = 0;
419                                                         break;
420                                                 case 3: /* clear all tabs */
421                                                         memset(tabcol, 0, sizeof tabcol);
422                                                         break;
423                                                 }
424                                                 break;
425
426                                         /*
427                                          * l - clear various options.
428                                          */
429                                         case 'l':
430                                                 if(noperand == 1){
431                                                         switch(operand[0]){     
432                                                         case 20:        /* set line feed mode */
433                                                                 ttystate[cs->raw].nlcr = 1;
434                                                                 break;
435                                                         case 30:        /* screen invisible (? not supported through VT220) */
436                                                                 break;
437                                                         }
438                                                 }else while(--noperand > 0){
439                                                         switch(operand[noperand]){
440                                                         case 1: /* set cursor keys to send ANSI functions: ESC [ A..D */
441                                                                 break;
442                                                         case 2: /* set VT52 mode (not implemented) */
443                                                                 break;
444                                                         case 3: /* set 80 columns */
445                                                                 setdim(-1, 80);
446                                                                 break;
447                                                         case 4: /* set jump scrolling */
448                                                                 break;
449                                                         case 5: /* set normal video on screen */
450                                                                 break;
451                                                         case 6: /* set origin to absolute */
452                                                                 originrelative = 0;
453                                                                 x = y = 0;
454                                                                 break;
455                                                         case 7: /* reset auto-wrap mode */
456                                                                 wraparound = 0;
457                                                                 break;
458                                                         case 8: /* reset auto-repeat mode */
459                                                                 break;
460                                                         case 9: /* reset interlacing mode */
461                                                                 break;
462                                                         case 25:        /* text cursor off (VT220) */
463                                                                 cursoron = 0;
464                                                                 break;
465                                                         }
466                                                 }
467                                                 break;
468
469                                         /*
470                                         * s - some dec private stuff. actually [ ? num s, but we can't detect it.
471                                         */
472                                         case 's':
473                                                 break;
474
475                                         /*
476                                          * h - set various options.
477                                          */
478                                         case 'h':
479                                                 if(noperand == 1){
480                                                         switch(operand[0]){
481                                                         default:
482                                                                 break;
483                                                         case 20:        /* set newline mode */
484                                                                 ttystate[cs->raw].nlcr = 0;
485                                                                 break;
486                                                         case 30:        /* screen visible (? not supported through VT220) */
487                                                                 break;
488                                                         }
489                                                 }else while(--noperand > 0){
490                                                         switch(operand[noperand]){
491                                                         default:
492                                                                 break;
493                                                         case 1: /* set cursor keys to send application function: ESC O A..D */
494                                                                 break;
495                                                         case 2: /* set ANSI */
496                                                                 break;
497                                                         case 3: /* set 132 columns */
498                                                                 setdim(-1, 132);
499                                                                 break;
500                                                         case 4: /* set smooth scrolling */
501                                                                 break;
502                                                         case 5: /* set screen to reverse video (not implemented) */
503                                                                 break;
504                                                         case 6: /* set origin to relative */
505                                                                 originrelative = 1;
506                                                                 x = 0;
507                                                                 y = yscrmin;
508                                                                 break;
509                                                         case 7: /* set auto-wrap mode */
510                                                                 wraparound = 1;
511                                                                 break;
512                                                         case 8: /* set auto-repeat mode */
513                                                                 break;
514                                                         case 9: /* set interlacing mode */
515                                                                 break;
516                                                         case 25:        /* text cursor on (VT220) */
517                                                                 cursoron = 1;
518                                                                 break;
519                                                         }
520                                                 }
521                                                 break;
522
523                                         /*
524                                          * m - change character attrs.
525                                          */
526                                         case 'm':
527                                                 setattr(noperand, operand);
528                                                 break;
529
530                                         /*
531                                          * n - request various reports
532                                          */
533                                         case 'n':
534                                                 switch(operand[0]){
535                                                 case 5: /* status */
536                                                         sendnchars(4, "\033[0n");       /* terminal ok */
537                                                         break;
538                                                 case 6: /* cursor position */
539                                                         sendnchars(sprint((char*)buf, "\033[%d;%dR",
540                                                                 originrelative ? y+1 - yscrmin : y+1, x+1), (char*)buf);
541                                                         break;
542                                                 }
543                                                 break;
544
545                                         /*
546                                          * q - turn on list of LEDs; turn off others.
547                                          */
548                                         case 'q':
549                                                 break;
550
551                                         /*
552                                          * r - change scrolling region.  operand[0] is
553                                          * min scrolling region and operand[1] is max
554                                          * scrolling region.
555                                          */
556                                         case 'r':
557                                                 yscrmin = 0;
558                                                 yscrmax = ymax;
559                                                 switch(noperand){
560                                                 case 2:
561                                                         yscrmax = operand[1]-1;
562                                                         if(yscrmax > ymax)
563                                                                 yscrmax = ymax;
564                                                 case 1:
565                                                         yscrmin = operand[0]-1;
566                                                         if(yscrmin < 0)
567                                                                 yscrmin = 0;
568                                                 }
569                                                 x = 0;
570                                                 y = yscrmin;
571                                                 break;
572
573                                         /*
574                                          * x - report terminal parameters
575                                          */
576                                         case 'x':
577                                                 sendnchars(20, "\033[3;1;1;120;120;1;0x");
578                                                 break;
579
580                                         /*
581                                          * y - invoke confidence test
582                                          */
583                                         case 'y':
584                                                 break;
585
586                                         /*
587                                          * z - line spacing
588                                          */
589                                         case 'z':
590                                                 break;
591
592                                         /*
593                                          * A - cursor up.
594                                          */
595                                         case 'e':
596                                         case 'A':
597                                                 fixops(operand);
598                                                 y -= operand[0];
599                                                 if(y < yscrmin)
600                                                         y = yscrmin;
601                                                 olines -= operand[0];
602                                                 if(olines < 0)
603                                                         olines = 0;
604                                                 break;
605
606                                         /*
607                                          * B - cursor down
608                                          */
609                                         case 'B':
610                                                 fixops(operand);
611                                                 y += operand[0];
612                                                 if(y > yscrmax)
613                                                         y=yscrmax;
614                                                 break;
615                                         
616                                         /*
617                                          * C - cursor right
618                                          */
619                                         case 'a':
620                                         case 'C':
621                                                 fixops(operand);
622                                                 x += operand[0];
623                                                 /*
624                                                  * VT-100-UG says not to go past the
625                                                  * right margin.
626                                                  */
627                                                 if(x > xmax)
628                                                         x = xmax;
629                                                 break;
630
631                                         /*
632                                          * D - cursor left
633                                          */
634                                         case 'D':
635                                                 fixops(operand);
636                                                 x -= operand[0];
637                                                 if(x < 0)
638                                                         x = 0;
639                                                 break;
640
641                                         /*
642                                          *      G - cursor to column
643                                          */
644                                         case '\'':
645                                         case 'G':
646                                                 fixops(operand);
647                                                 x = operand[0] - 1;
648                                                 if(x > xmax)
649                                                         x = xmax;
650                                                 break;
651
652                                         /*
653                                          * H and f - cursor motion.  operand[0] is row and
654                                          * operand[1] is column, origin 1.
655                                          */
656                                         case 'H':
657                                         case 'f':
658                                                 fixops(operand+1);
659                                                 x = operand[1] - 1;
660                                                 if(x > xmax)
661                                                         x = xmax;
662
663                                                 /* fallthrough */
664
665                                         /*
666                                          * d - cursor to line n (xterm)
667                                          */
668                                         case 'd':
669                                                 fixops(operand);
670                                                 y = operand[0] - 1;
671                                                 if(originrelative){
672                                                         y += yscrmin;
673                                                         if(y > yscrmax)
674                                                                 y = yscrmax;
675                                                 }else{
676                                                         if(y > ymax)
677                                                                 y = ymax;
678                                                 }
679                                                 break;
680
681                                         /*
682                                          * J - clear some or all of the display.
683                                          */
684                                         case 'J':
685                                                 switch (operand[0]) {
686                                                         /*
687                                                          * operand 2:  whole screen.
688                                                          */
689                                                         case 2:
690                                                                 clear(Rpt(pt(0, 0), pt(xmax+1, ymax+1)));
691                                                                 break;
692                                                         /*
693                                                          * operand 1: start of screen to active position, inclusive.
694                                                          */
695                                                         case 1:
696                                                                 clear(Rpt(pt(0, 0), pt(xmax+1, y)));
697                                                                 clear(Rpt(pt(0, y), pt(x+1, y+1)));
698                                                                 break;
699                                                         /*
700                                                          * Default:  active position to end of screen, inclusive.
701                                                          */
702                                                         default:
703                                                                 clear(Rpt(pt(x, y), pt(xmax+1, y+1)));
704                                                                 clear(Rpt(pt(0, y+1), pt(xmax+1, ymax+1)));
705                                                                 break;
706                                                 }
707                                                 break;
708
709                                         /*
710                                          * K - clear some or all of the line.
711                                          */
712                                         case 'K':
713                                                 switch (operand[0]) {
714                                                         /*
715                                                          * operand 2: whole line.
716                                                          */
717                                                         case 2:
718                                                                 clear(Rpt(pt(0, y), pt(xmax+1, y+1)));
719                                                                 break;
720                                                         /*
721                                                          * operand 1: start of line to active position, inclusive.
722                                                          */
723                                                         case 1:
724                                                                 clear(Rpt(pt(0, y), pt(x+1, y+1)));
725                                                                 break;
726                                                         /*
727                                                          * Default: active position to end of line, inclusive.
728                                                          */
729                                                         default:
730                                                                 clear(Rpt(pt(x, y), pt(xmax+1, y+1)));
731                                                                 break;
732                                                 }
733                                                 break;
734
735                                         /*
736                                          *      P - delete character(s) from right of cursor (xterm)
737                                          */
738                                         case 'P':
739                                                 fixops(operand);
740                                                 i = x + operand[0];
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)));
743                                                 break;
744
745                                         /*
746                                          *      @ - insert blank(s) to right of cursor (xterm)
747                                          */
748                                         case '@':
749                                                 fixops(operand);
750                                                 i = x + operand[0];
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)));
753                                                 break;
754
755
756                                         /*
757                                          *      X - erase character(s) at cursor and to the right (xterm)
758                                          */
759                                         case 'X':
760                                                 fixops(operand);
761                                                 i = x + operand[0];
762                                                 clear(Rpt(pt(x, y), pt(i, y+1)));
763                                                 break;
764
765                                         /*
766                                          * L - insert a line at cursor position (VT102 and later)
767                                          */
768                                         case 'L':
769                                                 fixops(operand);
770                                                 for(i = 0; i < operand[0]; ++i)
771                                                         scroll(y, yscrmax, y+1, y);
772                                                 break;
773
774                                         /*
775                                          * M - delete a line at cursor position (VT102 and later)
776                                          */
777                                         case 'M':
778                                                 fixops(operand);
779                                                 for(i = 0; i < operand[0]; ++i)
780                                                         scroll(y+1, yscrmax+1, y, yscrmax);
781                                                 break;
782
783                                         /*
784                                          * S,T - scroll up/down (xterm)
785                                          */
786                                         case 'T':
787                                                 fixops(operand);
788                                                 for(i = 0; i < operand[0]; ++i)
789                                                         scroll(yscrmin, yscrmax, yscrmin+1, yscrmin);
790                                                 break;
791
792                                         case 'S':
793                                                 fixops(operand);
794                                                 for(i = 0; i < operand[0]; ++i)
795                                                         scroll(yscrmin+1, yscrmax+1, yscrmin, yscrmin);
796                                                 break;
797
798                                         case '=':       /* ? not supported through VT220 */
799                                                 number(buf, nil);
800                                                 switch(buf[0]) {
801                                                 case 'h':
802                                                 case 'l':
803                                                         break;
804                                                 }
805                                                 break;
806
807                                         /*
808                                          * Anything else we ignore for now...
809                                          */
810                                         default:
811 print("unknown escape2 '%c' (0x%x)\n", dch, dch);
812                                                 break;
813                                 }
814
815                                 break;
816
817                         /*
818                          * Collapse multiple '\033' to one.
819                          */
820                         case '\033':
821                                 peekc = '\033';
822                                 break;
823
824                         /* OSC escape */
825                         case ']':
826                                 osc();
827                                 break;
828
829                         /*
830                          * Ignore other commands.
831                          */
832                         default:
833 print("unknown command '%c' (0x%x)\n", dch, dch);
834                                 break;
835
836                         }
837                         break;
838
839                 default:                /* ordinary char */
840 Default:
841                         if(isgraphics && buf[0] < nelem(gmap) && gmap[buf[0]])
842                                 buf[0] = gmap[buf[0]];
843
844                         /* line wrap */
845                         if (x > xmax){
846                                 if(wraparound){
847                                         x = 0;
848                                         newline();
849                                 }else{
850                                         continue;
851                                 }
852                         }
853                         n = 1;
854                         c = 0;
855                         while (!cs->raw && host_avail() && x+n<=xmax && n<BUFS
856                             && (c = get_next_char())>=' ' && c<'\177') {
857                                 buf[n++] = c;
858                                 c = 0;
859                         }
860                         buf[n] = 0;
861                         drawstring(pt(x, y), buf, attr);
862                         x += n;
863                         peekc = c;
864                         break;
865                 }
866         }
867 }
868
869 static void
870 setattr(int argc, int *argv)
871 {
872         int i;
873
874         for(i=0; i<argc; i++) {
875                 switch(argv[i]) {
876                 case 0:
877                         attr = defattr;
878                         fgcolor = fgdefault;
879                         bgcolor = bgdefault;
880                         break;
881                 case 1:
882                         attr |= THighIntensity;
883                         break;          
884                 case 4:
885                         attr |= TUnderline;
886                         break;          
887                 case 5:
888                         attr |= TBlink;
889                         break;
890                 case 7:
891                         attr |= TReverse;
892                         break;
893                 case 8:
894                         attr |= TInvisible;
895                         break;
896                 case 22:
897                         attr &= ~THighIntensity;
898                         break;          
899                 case 24:
900                         attr &= ~TUnderline;
901                         break;          
902                 case 25:
903                         attr &= ~TBlink;
904                         break;
905                 case 27:
906                         attr &= ~TReverse;
907                         break;
908                 case 28:
909                         attr &= ~TInvisible;
910                         break;
911                 case 30:        /* black */
912                 case 31:        /* red */
913                 case 32:        /* green */
914                 case 33:        /* brown */
915                 case 34:        /* blue */
916                 case 35:        /* purple */
917                 case 36:        /* cyan */
918                 case 37:        /* white */
919                         fgcolor = (nocolor? fgdefault: colors[argv[i]-30]);
920                         break;
921                 case 39:
922                         fgcolor = fgdefault;
923                         break;
924                 case 40:        /* black */
925                 case 41:        /* red */
926                 case 42:        /* green */
927                 case 43:        /* brown */
928                 case 44:        /* blue */
929                 case 45:        /* purple */
930                 case 46:        /* cyan */
931                 case 47:        /* white */
932                         bgcolor = (nocolor? bgdefault: colors[argv[i]-40]);
933                         break;
934                 case 49:
935                         bgcolor = bgdefault;
936                         break;
937                 }
938         }
939 }
940
941 // handle ESC], Operating System Command
942 static void
943 osc(void)
944 {
945         Rune ch, buf[BUFS+1];
946         int fd, osc, got, i;
947         osc = number(&ch, &got);
948
949         if(got) {
950                 switch(osc) {
951                 case 0:
952                 case 1:
953                 case 2:
954                         // set title
955                         i = 0;
956
957                         while((ch = get_next_char()) != '\a') {
958                                 if(i < nelem(buf) - 1) {
959                                         buf[i++] = ch;
960                                 }
961                         }
962                         buf[i] = 0;
963                         if((fd = open("/dev/label", OWRITE)) >= 0) {
964                                 fprint(fd, "%S", buf);
965                                 close(fd);
966                         }
967                         break;
968                 default:
969                         fprint(2, "unknown osc escape %d\n", osc);
970                         break;
971                 }
972         }
973 }