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