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