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