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