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