xref: /netbsd-src/sys/dev/wscons/wsemul_vt100_subr.c (revision dc306354b0b29af51801a7632f1e95265a68cd81)
1 /* $NetBSD: wsemul_vt100_subr.c,v 1.5 1999/01/10 00:28:21 augustss Exp $ */
2 
3 /*
4  * Copyright (c) 1998
5  *	Matthias Drochner.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed for the NetBSD Project
18  *	by Matthias Drochner.
19  * 4. The name of the author may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  */
34 
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 
38 #include <dev/wscons/wsksymvar.h>
39 #include <dev/wscons/wsdisplayvar.h>
40 #include <dev/wscons/wsemulvar.h>
41 #include <dev/wscons/wsemul_vt100var.h>
42 
43 static int vt100_selectattribute __P((struct wsemul_vt100_emuldata *,
44 				      int, int, int, long *));
45 static int vt100_ansimode __P((struct wsemul_vt100_emuldata *, int, int));
46 static int vt100_decmode __P((struct wsemul_vt100_emuldata *, int, int));
47 #define VTMODE_SET 33
48 #define VTMODE_RESET 44
49 #define VTMODE_REPORT 55
50 
51 /*
52  * scroll up within scrolling region
53  */
54 void
55 wsemul_vt100_scrollup(edp, n)
56 	struct wsemul_vt100_emuldata *edp;
57 	int n;
58 {
59 	int help;
60 
61 	if (n > edp->scrreg_nrows)
62 		n = edp->scrreg_nrows;
63 
64 	help = edp->scrreg_nrows - n;
65 	if (help > 0) {
66 		(*edp->emulops->copyrows)(edp->emulcookie,
67 					  edp->scrreg_startrow + n,
68 					  edp->scrreg_startrow,
69 					  help);
70 		if (edp->dblwid)
71 			memmove(&edp->dblwid[edp->scrreg_startrow],
72 				&edp->dblwid[edp->scrreg_startrow + n],
73 				help);
74 	}
75 	(*edp->emulops->eraserows)(edp->emulcookie,
76 				   edp->scrreg_startrow + help, n,
77 				   edp->defattr);
78 	if (edp->dblwid)
79 		memset(&edp->dblwid[edp->scrreg_startrow + help], 0, n);
80 	CHECK_DW;
81 }
82 
83 /*
84  * scroll down within scrolling region
85  */
86 void
87 wsemul_vt100_scrolldown(edp, n)
88 	struct wsemul_vt100_emuldata *edp;
89 	int n;
90 {
91 	int help;
92 
93 	if (n > edp->scrreg_nrows)
94 		n = edp->scrreg_nrows;
95 
96 	help = edp->scrreg_nrows - n;
97 	if (help > 0) {
98 		(*edp->emulops->copyrows)(edp->emulcookie,
99 					  edp->scrreg_startrow,
100 					  edp->scrreg_startrow + n,
101 					  help);
102 		if (edp->dblwid)
103 			memmove(&edp->dblwid[edp->scrreg_startrow + n],
104 				&edp->dblwid[edp->scrreg_startrow],
105 				help);
106 	}
107 	(*edp->emulops->eraserows)(edp->emulcookie,
108 				   edp->scrreg_startrow, n,
109 				   edp->defattr);
110 	if (edp->dblwid)
111 		memset(&edp->dblwid[edp->scrreg_startrow], 0, n);
112 	CHECK_DW;
113 }
114 
115 /*
116  * erase in display
117  */
118 void
119 wsemul_vt100_ed(edp, arg)
120 	struct wsemul_vt100_emuldata *edp;
121 	int arg;
122 {
123 	int n;
124 
125 	switch (arg) {
126 	    case 0: /* cursor to end */
127 		ERASECOLS(edp->ccol, COLS_LEFT + 1, edp->defattr);
128 		n = edp->nrows - edp->crow - 1;
129 		if (n > 0) {
130 			(*edp->emulops->eraserows)(edp->emulcookie,
131 						   edp->crow + 1, n,
132 						   edp->defattr);
133 			if (edp->dblwid)
134 				memset(&edp->dblwid[edp->crow + 1], 0, n);
135 		}
136 		break;
137 	    case 1: /* beginning to cursor */
138 		if (edp->crow > 0) {
139 			(*edp->emulops->eraserows)(edp->emulcookie,
140 						   0, edp->crow,
141 						   edp->defattr);
142 			if (edp->dblwid)
143 				memset(&edp->dblwid[0], 0, edp->crow);
144 		}
145 		ERASECOLS(0, edp->ccol + 1, edp->defattr);
146 		break;
147 	    case 2: /* complete display */
148 		(*edp->emulops->eraserows)(edp->emulcookie,
149 					   0, edp->nrows,
150 					   edp->defattr);
151 		if (edp->dblwid)
152 			memset(&edp->dblwid[0], 0, edp->nrows);
153 		break;
154 	    default:
155 #ifdef VT100_PRINTUNKNOWN
156 		printf("ed(%d) unknown\n", arg);
157 #endif
158 		break;
159 	}
160 	CHECK_DW;
161 }
162 
163 /*
164  * erase in line
165  */
166 void
167 wsemul_vt100_el(edp, arg)
168 	struct wsemul_vt100_emuldata *edp;
169 	int arg;
170 {
171 	switch (arg) {
172 	    case 0: /* cursor to end */
173 		ERASECOLS(edp->ccol, COLS_LEFT + 1, edp->defattr);
174 		break;
175 	    case 1: /* beginning to cursor */
176 		ERASECOLS(0, edp->ccol + 1, edp->defattr);
177 		break;
178 	    case 2: /* complete line */
179 		(*edp->emulops->erasecols)(edp->emulcookie, edp->crow,
180 					   0, edp->ncols,
181 					   edp->defattr);
182 		break;
183 	    default:
184 #ifdef VT100_PRINTUNKNOWN
185 		printf("el(%d) unknown\n", arg);
186 #endif
187 		break;
188 	}
189 }
190 
191 /*
192  * handle commands after CSI (ESC[)
193  */
194 void
195 wsemul_vt100_handle_csi(edp, c)
196 	struct wsemul_vt100_emuldata *edp;
197 	u_char c;
198 {
199 	int n, help, flags, fgcol, bgcol;
200 	long attr;
201 
202 #define A3(a, b, c) (((a) << 16) | ((b) << 8) | (c))
203 	switch (A3(edp->modif1, edp->modif2, c)) {
204 	    case A3('>', '\0', 'c'): /* DA secondary */
205 		wsdisplay_emulinput(edp->cbcookie, WSEMUL_VT_ID2,
206 				    sizeof(WSEMUL_VT_ID2));
207 		break;
208 
209 	    case A3('\0', '\0', 'J'): /* ED selective erase in display */
210 	    case A3('?', '\0', 'J'): /* DECSED selective erase in display */
211 		wsemul_vt100_ed(edp, ARG(0));
212 		break;
213 	    case A3('\0', '\0', 'K'): /* EL selective erase in line */
214 	    case A3('?', '\0', 'K'): /* DECSEL selective erase in line */
215 		wsemul_vt100_el(edp, ARG(0));
216 		break;
217 	    case A3('\0', '\0', 'h'): /* SM */
218 		for (n = 0; n < edp->nargs; n++)
219 			vt100_ansimode(edp, ARG(n), VTMODE_SET);
220 		break;
221 	    case A3('?', '\0', 'h'): /* DECSM */
222 		for (n = 0; n < edp->nargs; n++)
223 			vt100_decmode(edp, ARG(n), VTMODE_SET);
224 		break;
225 	    case A3('\0', '\0', 'l'): /* RM */
226 		for (n = 0; n < edp->nargs; n++)
227 			vt100_ansimode(edp, ARG(n), VTMODE_RESET);
228 		break;;
229 	    case A3('?', '\0', 'l'): /* DECRM */
230 		for (n = 0; n < edp->nargs; n++)
231 			vt100_decmode(edp, ARG(n), VTMODE_RESET);
232 		break;;
233 	    case A3('\0', '$', 'p'): /* DECRQM request mode ANSI */
234 		vt100_ansimode(edp, ARG(0), VTMODE_REPORT);
235 		break;
236 	    case A3('?', '$', 'p'): /* DECRQM request mode DEC */
237 		vt100_decmode(edp, ARG(0), VTMODE_REPORT);
238 		break;
239 	    case A3('\0', '\0', 'i'): /* MC printer controller mode */
240 	    case A3('?', '\0', 'i'): /* MC printer controller mode */
241 		switch (ARG(0)) {
242 		    case 0: /* print screen */
243 		    case 1: /* print cursor line */
244 		    case 4: /* off */
245 		    case 5: /* on */
246 #ifdef VT100_PRINTNOTIMPL
247 			printf("CSI%di ignored\n", ARG(0));
248 #endif
249 			break;
250 		    default:
251 #ifdef VT100_PRINTUNKNOWN
252 			printf("CSI%di unknown\n", ARG(0));
253 #endif
254 			break;
255 		}
256 		break;
257 
258 #define A2(a, b) (((a) << 8) | (b))
259 	    case A2('!', 'p'): /* DECSTR soft reset VT300 only */
260 		wsemul_vt100_reset(edp);
261 		break;
262 
263 	    case A2('"', 'p'): /* DECSCL */
264 		switch (ARG(0)) {
265 		    case 61: /* VT100 mode (no further arguments!) */
266 			break;
267 		    case 62:
268 		    case 63: /* VT300 mode */
269 			break;
270 		    default:
271 #ifdef VT100_PRINTUNKNOWN
272 			printf("CSI%d\"p unknown\n", ARG(0));
273 #endif
274 			break;
275 		}
276 		switch (ARG(1)) {
277 		    case 0:
278 		    case 2: /* 8-bit controls */
279 #ifdef VT100_PRINTNOTIMPL
280 			printf("CSI%d;%d\"p ignored\n", ARG(0), ARG(1));
281 #endif
282 			break;
283 		    case 1: /* 7-bit controls */
284 			break;
285 		    default:
286 #ifdef VT100_PRINTUNKNOWN
287 			printf("CSI%d;%d\"p unknown\n", ARG(0), ARG(1));
288 #endif
289 			break;
290 		}
291 		break;
292 	    case A2('"', 'q'): /* DECSCA select character attribute VT300 */
293 		switch (ARG(0)) {
294 		    case 0:
295 		    case 1: /* erasable */
296 			break;
297 		    case 2: /* not erasable */
298 #ifdef VT100_PRINTNOTIMPL
299 			printf("CSI2\"q ignored\n");
300 #endif
301 			break;
302 		    default:
303 #ifdef VT100_PRINTUNKNOWN
304 			printf("CSI%d\"q unknown\n", ARG(0));
305 #endif
306 			break;
307 		}
308 		break;
309 
310 	    case A2('$', 'u'): /* DECRQTSR request terminal status report */
311 		switch (ARG(0)) {
312 		    case 0: /* ignored */
313 			break;
314 		    case 1: /* terminal state report */
315 #ifdef VT100_PRINTNOTIMPL
316 			printf("CSI1$u ignored\n");
317 #endif
318 			break;
319 		    default:
320 #ifdef VT100_PRINTUNKNOWN
321 			printf("CSI%d$u unknown\n", ARG(0));
322 #endif
323 			break;
324 		}
325 		break;
326 	    case A2('$', 'w'): /* DECRQPSR request presentation status report
327 				(VT300 only) */
328 		switch (ARG(0)) {
329 		    case 0: /* error */
330 			break;
331 		    case 1: /* cursor information report */
332 #ifdef VT100_PRINTNOTIMPL
333 			printf("CSI1$w ignored\n");
334 #endif
335 			break;
336 		    case 2: /* tab stop report */
337 			{
338 			int i, n, ps = 0;
339 			char buf[20];
340 			KASSERT(edp->tabs != 0);
341 			wsdisplay_emulinput(edp->cbcookie, "\033P2$u", 5);
342 			for (i = 0; i < edp->ncols; i++)
343 				if (edp->tabs[i]) {
344 					n = sprintf(buf, "%s%d",
345 						    (ps ? "/" : ""), i + 1);
346 					wsdisplay_emulinput(edp->cbcookie,
347 							    buf, n);
348 					ps = 1;
349 				}
350 			}
351 			wsdisplay_emulinput(edp->cbcookie, "\033\\", 2);
352 			break;
353 		    default:
354 #ifdef VT100_PRINTUNKNOWN
355 			printf("CSI%d$w unknown\n", ARG(0));
356 #endif
357 			break;
358 		}
359 		break;
360 	    case A2('$', '}'): /* DECSASD select active status display */
361 		switch (ARG(0)) {
362 		    case 0: /* main display */
363 		    case 1: /* status line */
364 #ifdef VT100_PRINTNOTIMPL
365 			printf("CSI%d$} ignored\n", ARG(0));
366 #endif
367 			break;
368 		    default:
369 #ifdef VT100_PRINTUNKNOWN
370 			printf("CSI%d$} unknown\n", ARG(0));
371 #endif
372 			break;
373 		}
374 		break;
375 	    case A2('$', '~'): /* DECSSDD select status line type */
376 		switch (ARG(0)) {
377 		    case 0: /* none */
378 		    case 1: /* indicator */
379 		    case 2: /* host-writable */
380 #ifdef VT100_PRINTNOTIMPL
381 			printf("CSI%d$~ ignored\n", ARG(0));
382 #endif
383 			break;
384 		    default:
385 #ifdef VT100_PRINTUNKNOWN
386 			printf("CSI%d$~ unknown\n", ARG(0));
387 #endif
388 			break;
389 		}
390 		break;
391 
392 	    case A2('&', 'u'): /* DECRQUPSS request user preferred
393 				  supplemental set */
394 		wsdisplay_emulinput(edp->emulcookie, "\033P0!u%5\033\\", 9);
395 		break;
396 
397 	    case '@': /* ICH insert character VT300 only */
398 		n = min(DEF1_ARG(0), COLS_LEFT + 1);
399 		help = NCOLS - (edp->ccol + n);
400 		if (help > 0)
401 			COPYCOLS(edp->ccol, edp->ccol + n, help);
402 		ERASECOLS(edp->ccol, n, edp->defattr);
403 		break;
404 	    case 'A': /* CUU */
405 		edp->crow -= min(DEF1_ARG(0), ROWS_ABOVE);
406 		CHECK_DW;
407 		break;
408 	    case 'B': /* CUD */
409 		edp->crow += min(DEF1_ARG(0), ROWS_BELOW);
410 		CHECK_DW;
411 		break;
412 	    case 'C': /* CUF */
413 		edp->ccol += min(DEF1_ARG(0), COLS_LEFT);
414 		break;
415 	    case 'D': /* CUB */
416 		edp->ccol -= min(DEF1_ARG(0), edp->ccol);
417 		edp->flags &= ~VTFL_LASTCHAR;
418 		break;
419 	    case 'H': /* CUP */
420 	    case 'f': /* HVP */
421 		if (edp->flags & VTFL_DECOM)
422 			edp->crow = edp->scrreg_startrow +
423 			    min(DEF1_ARG(0), edp->scrreg_nrows) - 1;
424 		else
425 			edp->crow = min(DEF1_ARG(0), edp->nrows) - 1;
426 		CHECK_DW;
427 		edp->ccol = min(DEF1_ARG(1), NCOLS) - 1;
428 		edp->flags &= ~VTFL_LASTCHAR;
429 		break;
430 	    case 'L': /* IL insert line */
431 	    case 'M': /* DL delete line */
432 		n = min(DEF1_ARG(0), ROWS_BELOW + 1);
433 		{
434 		int savscrstartrow, savscrnrows;
435 		savscrstartrow = edp->scrreg_startrow;
436 		savscrnrows = edp->scrreg_nrows;
437 		edp->scrreg_nrows -= ROWS_ABOVE;
438 		edp->scrreg_startrow = edp->crow;
439 		if (c == 'L')
440 			wsemul_vt100_scrolldown(edp, n);
441 		else
442 			wsemul_vt100_scrollup(edp, n);
443 		edp->scrreg_startrow = savscrstartrow;
444 		edp->scrreg_nrows = savscrnrows;
445 		}
446 		break;
447 	    case 'P': /* DCH delete character */
448 		n = min(DEF1_ARG(0), COLS_LEFT + 1);
449 		help = NCOLS - (edp->ccol + n);
450 		if (help > 0)
451 			COPYCOLS(edp->ccol + n, edp->ccol, help);
452 		ERASECOLS(NCOLS - n, n, edp->defattr);
453 		break;
454 	    case 'X': /* ECH erase character */
455 		n = min(DEF1_ARG(0), COLS_LEFT + 1);
456 		ERASECOLS(edp->ccol, n, edp->defattr);
457 		break;
458 	    case 'c': /* DA primary */
459 		if (ARG(0) == 0)
460 			wsdisplay_emulinput(edp->cbcookie, WSEMUL_VT_ID1,
461 					    sizeof(WSEMUL_VT_ID1));
462 		break;
463 	    case 'g': /* TBC */
464 		KASSERT(edp->tabs != 0);
465 		switch (ARG(0)) {
466 		    case 0:
467 			edp->tabs[edp->ccol] = 0;
468 			break;
469 		    case 3:
470 			memset(edp->tabs, 0, edp->ncols);
471 			break;
472 		    default:
473 #ifdef VT100_PRINTUNKNOWN
474 			printf("CSI%dg unknown\n", ARG(0));
475 #endif
476 			break;
477 		}
478 		break;
479 	    case 'm': /* SGR select graphic rendition */
480 		flags = edp->attrflags;
481 		fgcol = edp->fgcol;
482 		bgcol = edp->bgcol;
483 		for (n = 0; n < edp->nargs; n++) {
484 			switch (ARG(n)) {
485 			    case 0: /* reset */
486 				attr = edp->defattr;
487 				flags = 0;
488 				fgcol = WSCOL_WHITE;
489 				bgcol = WSCOL_BLACK;
490 				if (n == edp->nargs - 1) {
491 					edp->curattr = attr;
492 					edp->attrflags = flags;
493 					edp->fgcol = fgcol;
494 					edp->bgcol = bgcol;
495 					return;
496 				}
497 				break;
498 			    case 1: /* bold */
499 				flags |= WSATTR_HILIT;
500 				break;
501 			    case 4: /* underline */
502 				flags |= WSATTR_UNDERLINE;
503 				break;
504 			    case 5: /* blink */
505 				flags |= WSATTR_BLINK;
506 				break;
507 			    case 7: /* reverse */
508 				flags |= WSATTR_REVERSE;
509 				break;
510 			    case 22: /* ~bold VT300 only */
511 				flags &= ~WSATTR_HILIT;
512 				break;
513 			    case 24: /* ~underline VT300 only */
514 				flags &= ~WSATTR_UNDERLINE;
515 				break;
516 			    case 25: /* ~blink VT300 only */
517 				flags &= ~WSATTR_BLINK;
518 				break;
519 			    case 27: /* ~reverse VT300 only */
520 				flags &= ~WSATTR_REVERSE;
521 				break;
522 			    case 30: case 31: case 32: case 33:
523 			    case 34: case 35: case 36: case 37:
524 				/* fg color */
525 				flags |= WSATTR_WSCOLORS;
526 				fgcol = ARG(n) - 30;
527 				break;
528 			    case 40: case 41: case 42: case 43:
529 			    case 44: case 45: case 46: case 47:
530 				/* bg color */
531 				flags |= WSATTR_WSCOLORS;
532 				bgcol = ARG(n) - 40;
533 				break;
534 			    default:
535 #ifdef VT100_PRINTUNKNOWN
536 				printf("CSI%dm unknown\n", ARG(n));
537 #endif
538 			}
539 		}
540 		if (vt100_selectattribute(edp, flags, fgcol, bgcol, &attr)) {
541 #ifdef VT100_DEBUG
542 			printf("error allocating attr %d/%d/%x\n",
543 			       fgcol, bgcol, flags);
544 #endif
545 		} else {
546 			edp->curattr = attr;
547 			edp->attrflags = flags;
548 			edp->fgcol = fgcol;
549 			edp->bgcol = bgcol;
550 		}
551 		break;
552 	    case 'n': /* reports */
553 		switch (ARG(0)) {
554 		    case 5: /* DSR operating status */
555 			/* 0 = OK, 3 = malfunction */
556 			wsdisplay_emulinput(edp->cbcookie, "\033[0n", 4);
557 			break;
558 		    case 6: { /* DSR cursor position report */
559 			char buf[20];
560 			int row;
561 			if (edp->flags & VTFL_DECOM)
562 				row = ROWS_ABOVE;
563 			else
564 				row = edp->crow;
565 			n = sprintf(buf, "\033[%d;%dR",
566 				    row + 1, edp->ccol + 1);
567 			wsdisplay_emulinput(edp->cbcookie, buf, n);
568 			}
569 			break;
570 		    case 15: /* DSR printer status */
571 			/* 13 = no printer, 10 = ready, 11 = not ready */
572 			wsdisplay_emulinput(edp->cbcookie, "\033[?13n", 6);
573 			break;
574 		    case 25: /* UDK status - VT300 only */
575 			/* 20 = locked, 21 = unlocked */
576 			wsdisplay_emulinput(edp->cbcookie, "\033[?21n", 6);
577 			break;
578 		    case 26: /* keyboard dialect */
579 			/* 1 = north american , 7 = german */
580 			wsdisplay_emulinput(edp->cbcookie, "\033[?27;1n", 8);
581 			break;
582 		    default:
583 #ifdef VT100_PRINTUNKNOWN
584 			printf("CSI%dn unknown\n", ARG(0));
585 #endif
586 			break;
587 		}
588 		break;
589 	    case 'r': /* DECSTBM set top/bottom margins */
590 		help = min(DEF1_ARG(0), edp->nrows) - 1;
591 		n = min(DEFx_ARG(1, edp->nrows), edp->nrows) - help;
592 		if (n < 2) {
593 			/* minimal scrolling region has 2 lines */
594 			return;
595 		} else {
596 			edp->scrreg_startrow = help;
597 			edp->scrreg_nrows = n;
598 		}
599 		edp->crow = ((edp->flags & VTFL_DECOM) ?
600 			     edp->scrreg_startrow : 0);
601 		edp->ccol = 0;
602 		break;
603 	    case 'y':
604 		switch (ARG(0)) {
605 		    case 4: /* DECTST invoke confidence test */
606 			/* ignore */
607 			break;
608 		    default:
609 #ifdef VT100_PRINTUNKNOWN
610 			printf("CSI%dy unknown\n", ARG(0));
611 #endif
612 			break;
613 		}
614 		break;
615 	    default:
616 #ifdef VT100_PRINTUNKNOWN
617 		printf("CSI%c (%d, %d) unknown\n", c, ARG(0), ARG(1));
618 #endif
619 	}
620 }
621 
622 /*
623  * get an attribute from the graphics driver,
624  * try to find replacements if the desired appearance
625  * is not supported
626  */
627 static int
628 vt100_selectattribute(edp, flags, fgcol, bgcol, attr)
629 	struct wsemul_vt100_emuldata *edp;
630 	int flags, fgcol, bgcol;
631 	long *attr;
632 {
633 	if ((flags & WSATTR_HILIT) &&
634 	    !(edp->scrcapabilities & WSSCREEN_HILIT)) {
635 		flags &= ~WSATTR_HILIT;
636 		if (edp->scrcapabilities & WSSCREEN_WSCOLORS) {
637 			fgcol = WSCOL_RED;
638 			flags |= WSATTR_WSCOLORS;
639 		} else {
640 #ifdef VT100_DEBUG
641 			printf("bold ignored (impossible)\n");
642 #endif
643 		}
644 	}
645 	if ((flags & WSATTR_UNDERLINE) &&
646 	    !(edp->scrcapabilities & WSSCREEN_UNDERLINE)) {
647 		flags &= ~WSATTR_UNDERLINE;
648 		if (edp->scrcapabilities & WSSCREEN_WSCOLORS) {
649 			bgcol = WSCOL_BROWN;
650 			flags &= ~WSATTR_UNDERLINE;
651 			flags |= WSATTR_WSCOLORS;
652 		} else {
653 #ifdef VT100_DEBUG
654 			printf("underline ignored (impossible)\n");
655 #endif
656 		}
657 	}
658 	if ((flags & WSATTR_BLINK) &&
659 	    !(edp->scrcapabilities & WSSCREEN_BLINK)) {
660 		flags &= ~WSATTR_BLINK;
661 #ifdef VT100_DEBUG
662 		printf("blink ignored (impossible)\n");
663 #endif
664 	}
665 	if ((flags & WSATTR_REVERSE) &&
666 	    !(edp->scrcapabilities & WSSCREEN_REVERSE)) {
667 		flags &= ~WSATTR_REVERSE;
668 		if (edp->scrcapabilities & WSSCREEN_WSCOLORS) {
669 			int help;
670 			help = bgcol;
671 			bgcol = fgcol;
672 			fgcol = help;
673 			flags |= WSATTR_WSCOLORS;
674 		} else {
675 #ifdef VT100_DEBUG
676 			printf("reverse ignored (impossible)\n");
677 #endif
678 		}
679 	}
680 	if ((flags & WSATTR_WSCOLORS) &&
681 	    !(edp->scrcapabilities & WSSCREEN_WSCOLORS)) {
682 		flags &= ~WSATTR_WSCOLORS;
683 #ifdef VT100_DEBUG
684 		printf("colors ignored (impossible)\n");
685 #endif
686 	}
687 	return ((*edp->emulops->alloc_attr)(edp->emulcookie,
688 					    fgcol, bgcol, flags,
689 					    attr));
690 }
691 
692 /*
693  * handle device control sequences if the main state machine
694  * told so by setting edp->dcstype to a nonzero value
695  */
696 void
697 wsemul_vt100_handle_dcs(edp)
698 	struct wsemul_vt100_emuldata *edp;
699 {
700 	int i, pos;
701 
702 	switch (edp->dcstype) {
703 	    case 0: /* not handled */
704 		return;
705 	    case DCSTYPE_TABRESTORE:
706 		KASSERT(edp->tabs != 0);
707 		memset(edp->tabs, 0, edp->ncols);
708 		pos = 0;
709 		for (i = 0; i < edp->dcspos; i++) {
710 			char c = edp->dcsarg[i];
711 			switch (c) {
712 			    case '0': case '1': case '2': case '3': case '4':
713 			    case '5': case '6': case '7': case '8': case '9':
714 				pos = pos * 10 + (edp->dcsarg[i] - '0');
715 				break;
716 			    case '/':
717 				if (pos > 0)
718 					edp->tabs[pos - 1] = 1;
719 				pos = 0;
720 				break;
721 			    default:
722 #ifdef VT100_PRINTUNKNOWN
723 				printf("unknown char %c in DCS\n", c);
724 #endif
725 			}
726 		}
727 		if (pos > 0)
728 			edp->tabs[pos - 1] = 1;
729 		break;
730 	    default:
731 		panic("wsemul_vt100_handle_dcs: bad type %d", edp->dcstype);
732 	}
733 	edp->dcstype = 0;
734 }
735 
736 static int
737 vt100_ansimode(edp, nr, op)
738 	struct wsemul_vt100_emuldata *edp;
739 	int nr, op;
740 {
741 	int res = 0; /* default: unknown */
742 
743 	switch (nr) {
744 	    case 2: /* KAM keyboard locked/unlocked */
745 		break;
746 	    case 3: /* CRM control representation */
747 		break;
748 	    case 4: /* IRM insert/replace characters */
749 		if (op == VTMODE_SET)
750 			edp->flags |= VTFL_INSERTMODE;
751 		else if (op == VTMODE_RESET)
752 			edp->flags &= ~VTFL_INSERTMODE;
753 		res = ((edp->flags & VTFL_INSERTMODE) ? 1 : 2);
754 		break;
755 	    case 10: /* HEM horizontal editing (permanently reset) */
756 		res = 4;
757 		break;
758 	    case 12: /* SRM local echo off/on */
759 		res = 4; /* permanently reset ??? */
760 		break;
761 	    case 20: /* LNM newline = newline/linefeed */
762 		break;
763 	    default:
764 #ifdef VT100_PRINTUNKNOWN
765 		printf("ANSI mode %d unknown\n", nr);
766 #endif
767 	}
768 	return (res);
769 }
770 
771 static int
772 vt100_decmode(edp, nr, op)
773 	struct wsemul_vt100_emuldata *edp;
774 	int nr, op;
775 {
776 	int res = 0; /* default: unknown */
777 
778 	switch (nr) {
779 	    case 1: /* DECCKM application/nomal cursor keys */
780 		if (op == VTMODE_SET)
781 			edp->flags |= VTFL_APPLCURSOR;
782 		else if (op == VTMODE_RESET)
783 			edp->flags &= ~VTFL_APPLCURSOR;
784 		res = ((edp->flags & VTFL_APPLCURSOR) ? 1 : 2);
785 		break;
786 	    case 2: /* DECANM ANSI vt100/vt52 */
787 		res = 3; /* permanently set ??? */
788 		break;
789 	    case 3: /* DECCOLM 132/80 cols */
790 	    case 4: /* DECSCLM smooth/jump scroll */
791 	    case 5: /* DECSCNM light/dark background */
792 		res = 4; /* all permanently reset ??? */
793 		break;
794 	    case 6: /* DECOM move within/outside margins */
795 		if (op == VTMODE_SET)
796 			edp->flags |= VTFL_DECOM;
797 		else if (op == VTMODE_RESET)
798 			edp->flags &= ~VTFL_DECOM;
799 		res = ((edp->flags & VTFL_DECOM) ? 1 : 2);
800 		break;
801 	    case 7: /* DECAWM autowrap */
802 		if (op == VTMODE_SET)
803 			edp->flags |= VTFL_DECAWM;
804 		else if (op == VTMODE_RESET)
805 			edp->flags &= ~VTFL_DECAWM;
806 		res = ((edp->flags & VTFL_DECAWM) ? 1 : 2);
807 		break;
808 	    case 8: /* DECARM keyboard autorepeat */
809 		break;
810 	    case 18: /* DECPFF print form feed */
811 		break;
812 	    case 19: /* DECPEX printer extent: screen/scrolling region */
813 		break;
814 	    case 25: /* DECTCEM text cursor on/off */
815 		if (op == VTMODE_SET || op == VTMODE_RESET) {
816 			edp->flags = (edp->flags & ~VTFL_CURSORON) |
817 			    ((op == VTMODE_SET) ? VTFL_CURSORON : 0);
818 			(*edp->emulops->cursor)(edp->emulcookie,
819 						(op == VTMODE_SET),
820 						edp->crow, edp->ccol);
821 		}
822 		res = ((edp->flags & VTFL_CURSORON) ? 1 : 2);
823 		break;
824 	    case 42: /* DECNRCM use 7-bit NRC /
825 		      7/8 bit from DEC multilingual or ISO-latin-1*/
826 		if (op == VTMODE_SET)
827 			edp->flags |= VTFL_NATCHARSET;
828 		else if (op == VTMODE_RESET)
829 			edp->flags &= ~VTFL_NATCHARSET;
830 		res = ((edp->flags & VTFL_NATCHARSET) ? 1 : 2);
831 		break;
832 	    case 66: /* DECNKM numeric keypad */
833 		break;
834 	    case 68: /* DECKBUM keyboard usage data processing/typewriter */
835 		break;
836 	    default:
837 #ifdef VT100_PRINTUNKNOWN
838 		printf("DEC mode %d unknown\n", nr);
839 #endif
840 		break;
841 	}
842 	return (res);
843 }
844