wsemul_vt100.c revision 1.36.6.2 1 /* $NetBSD: wsemul_vt100.c,v 1.36.6.2 2017/08/28 17:52:31 skrll 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 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 */
28
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: wsemul_vt100.c,v 1.36.6.2 2017/08/28 17:52:31 skrll Exp $");
31
32 #ifdef _KERNEL_OPT
33 #include "opt_wsmsgattrs.h"
34 #endif
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/time.h>
39 #include <sys/malloc.h>
40 #include <sys/fcntl.h>
41
42 #include <dev/wscons/wsconsio.h>
43 #include <dev/wscons/wsdisplayvar.h>
44 #include <dev/wscons/wsemulvar.h>
45 #include <dev/wscons/wsemul_vt100var.h>
46 #include <dev/wscons/ascii.h>
47
48 void *wsemul_vt100_cnattach(const struct wsscreen_descr *, void *,
49 int, int, long);
50 void *wsemul_vt100_attach(int console, const struct wsscreen_descr *,
51 void *, int, int, void *, long);
52 void wsemul_vt100_output(void *cookie, const u_char *data, u_int count, int);
53 void wsemul_vt100_detach(void *cookie, u_int *crowp, u_int *ccolp);
54 void wsemul_vt100_resetop(void *, enum wsemul_resetops);
55 #ifdef WSDISPLAY_CUSTOM_OUTPUT
56 static void wsemul_vt100_getmsgattrs(void *, struct wsdisplay_msgattrs *);
57 static void wsemul_vt100_setmsgattrs(void *, const struct wsscreen_descr *,
58 const struct wsdisplay_msgattrs *);
59 #endif /* WSDISPLAY_CUSTOM_OUTPUT */
60 static void wsemul_vt100_resize(void *, const struct wsscreen_descr *);
61
62 const struct wsemul_ops wsemul_vt100_ops = {
63 "vt100",
64 wsemul_vt100_cnattach,
65 wsemul_vt100_attach,
66 wsemul_vt100_output,
67 wsemul_vt100_translate,
68 wsemul_vt100_detach,
69 wsemul_vt100_resetop,
70 #ifdef WSDISPLAY_CUSTOM_OUTPUT
71 wsemul_vt100_getmsgattrs,
72 wsemul_vt100_setmsgattrs,
73 #else
74 NULL,
75 NULL,
76 #endif
77 .resize = wsemul_vt100_resize
78 };
79
80 struct wsemul_vt100_emuldata wsemul_vt100_console_emuldata;
81
82 static void wsemul_vt100_init(struct wsemul_vt100_emuldata *,
83 const struct wsscreen_descr *,
84 void *, int, int, long);
85
86 static void wsemul_vt100_output_normal(struct wsemul_vt100_emuldata *,
87 u_char, int);
88 static void wsemul_vt100_output_c0c1(struct wsemul_vt100_emuldata *,
89 u_char, int);
90 static void wsemul_vt100_nextline(struct wsemul_vt100_emuldata *);
91 typedef u_int vt100_handler(struct wsemul_vt100_emuldata *, u_char);
92
93 static vt100_handler
94 wsemul_vt100_output_esc,
95 wsemul_vt100_output_csi,
96 wsemul_vt100_output_scs94,
97 wsemul_vt100_output_scs94_percent,
98 wsemul_vt100_output_scs96,
99 wsemul_vt100_output_scs96_percent,
100 wsemul_vt100_output_esc_hash,
101 wsemul_vt100_output_esc_spc,
102 wsemul_vt100_output_string,
103 wsemul_vt100_output_string_esc,
104 wsemul_vt100_output_dcs,
105 wsemul_vt100_output_dcs_dollar;
106
107 #define VT100_EMUL_STATE_NORMAL 0 /* normal processing */
108 #define VT100_EMUL_STATE_ESC 1 /* got ESC */
109 #define VT100_EMUL_STATE_CSI 2 /* got CSI (ESC[) */
110 #define VT100_EMUL_STATE_SCS94 3 /* got ESC{()*+} */
111 #define VT100_EMUL_STATE_SCS94_PERCENT 4 /* got ESC{()*+}% */
112 #define VT100_EMUL_STATE_SCS96 5 /* got ESC{-./} */
113 #define VT100_EMUL_STATE_SCS96_PERCENT 6 /* got ESC{-./}% */
114 #define VT100_EMUL_STATE_ESC_HASH 7 /* got ESC# */
115 #define VT100_EMUL_STATE_ESC_SPC 8 /* got ESC<SPC> */
116 #define VT100_EMUL_STATE_STRING 9 /* waiting for ST (ESC\) */
117 #define VT100_EMUL_STATE_STRING_ESC 10 /* waiting for ST, got ESC */
118 #define VT100_EMUL_STATE_DCS 11 /* got DCS (ESC P) */
119 #define VT100_EMUL_STATE_DCS_DOLLAR 12 /* got DCS<p>$ */
120
121 vt100_handler *vt100_output[] = {
122 wsemul_vt100_output_esc,
123 wsemul_vt100_output_csi,
124 wsemul_vt100_output_scs94,
125 wsemul_vt100_output_scs94_percent,
126 wsemul_vt100_output_scs96,
127 wsemul_vt100_output_scs96_percent,
128 wsemul_vt100_output_esc_hash,
129 wsemul_vt100_output_esc_spc,
130 wsemul_vt100_output_string,
131 wsemul_vt100_output_string_esc,
132 wsemul_vt100_output_dcs,
133 wsemul_vt100_output_dcs_dollar,
134 };
135
136 static void
137 wsemul_vt100_init(struct wsemul_vt100_emuldata *edp,
138 const struct wsscreen_descr *type, void *cookie, int ccol, int crow,
139 long defattr)
140 {
141 struct vt100base_data *vd = &edp->bd;
142 int error;
143
144 vd->emulops = type->textops;
145 vd->emulcookie = cookie;
146 vd->scrcapabilities = type->capabilities;
147 vd->nrows = type->nrows;
148 vd->ncols = type->ncols;
149 vd->crow = crow;
150 vd->ccol = ccol;
151
152 /* The underlying driver has already allocated a default and simple
153 * attribute for us, which is stored in defattr. We try to set the
154 * values specified by the kernel options below, but in case of
155 * failure we fallback to the value given by the driver. */
156
157 if (type->capabilities & WSSCREEN_WSCOLORS) {
158 vd->msgattrs.default_attrs = WS_DEFAULT_COLATTR |
159 WSATTR_WSCOLORS;
160 vd->msgattrs.default_bg = WS_DEFAULT_BG;
161 vd->msgattrs.default_fg = WS_DEFAULT_FG;
162
163 vd->msgattrs.kernel_attrs = WS_KERNEL_COLATTR |
164 WSATTR_WSCOLORS;
165 vd->msgattrs.kernel_bg = WS_KERNEL_BG;
166 vd->msgattrs.kernel_fg = WS_KERNEL_FG;
167 } else {
168 vd->msgattrs.default_attrs = WS_DEFAULT_MONOATTR;
169 vd->msgattrs.default_bg = vd->msgattrs.default_fg = 0;
170
171 vd->msgattrs.kernel_attrs = WS_KERNEL_MONOATTR;
172 vd->msgattrs.kernel_bg = vd->msgattrs.kernel_fg = 0;
173 }
174
175 error = (*vd->emulops->allocattr)(cookie,
176 vd->msgattrs.default_fg,
177 vd->msgattrs.default_bg,
178 vd->msgattrs.default_attrs,
179 &vd->defattr);
180 if (error) {
181 vd->defattr = defattr;
182 /* XXX This assumes the driver has allocated white on black
183 * XXX as the default attribute, which is not always true.
184 * XXX Maybe we need an emulop that, given an attribute,
185 * XXX (defattr) returns its flags and colors? */
186 vd->msgattrs.default_attrs = 0;
187 vd->msgattrs.default_bg = WSCOL_BLACK;
188 vd->msgattrs.default_fg = WSCOL_WHITE;
189 } else {
190 if (vd->emulops->replaceattr != NULL)
191 (*vd->emulops->replaceattr)(cookie, defattr,
192 vd->defattr);
193 }
194
195 #if defined(WS_KERNEL_CUSTOMIZED)
196 /* Set up kernel colors, in case they were customized by the user;
197 * otherwise default to the colors specified for the console.
198 * In case of failure, we use console colors too; we can assume
199 * they are good as they have been previously allocated and
200 * verified. */
201 error = (*vd->emulops->allocattr)(cookie,
202 vd->msgattrs.kernel_fg,
203 vd->msgattrs.kernel_bg,
204 vd->msgattrs.kernel_attrs,
205 &edp->kernattr);
206 if (error)
207 #endif
208 edp->kernattr = vd->defattr;
209 }
210
211 void *
212 wsemul_vt100_cnattach(const struct wsscreen_descr *type, void *cookie,
213 int ccol, int crow, long defattr)
214 {
215 struct wsemul_vt100_emuldata *edp;
216 struct vt100base_data *vd;
217
218 edp = &wsemul_vt100_console_emuldata;
219 vd = &edp->bd;
220 wsemul_vt100_init(edp, type, cookie, ccol, crow, defattr);
221 #ifdef DIAGNOSTIC
222 edp->console = 1;
223 #endif
224 vd->cbcookie = NULL;
225
226 vd->tabs = 0;
227 vd->dblwid = 0;
228 vd->dw = 0;
229 vd->dcsarg = 0;
230 edp->isolatin1tab = edp->decgraphtab = edp->dectechtab = 0;
231 edp->nrctab = 0;
232 wsemul_vt100_reset(edp);
233 return (edp);
234 }
235
236 void *
237 wsemul_vt100_attach(int console, const struct wsscreen_descr *type,
238 void *cookie, int ccol, int crow, void *cbcookie, long defattr)
239 {
240 struct wsemul_vt100_emuldata *edp;
241 struct vt100base_data *vd;
242
243 if (console) {
244 edp = &wsemul_vt100_console_emuldata;
245 #ifdef DIAGNOSTIC
246 KASSERT(edp->console == 1);
247 #endif
248 } else {
249 edp = malloc(sizeof *edp, M_DEVBUF, M_WAITOK);
250 wsemul_vt100_init(edp, type, cookie, ccol, crow, defattr);
251 #ifdef DIAGNOSTIC
252 edp->console = 0;
253 #endif
254 }
255 vd = &edp->bd;
256 vd->cbcookie = cbcookie;
257
258 vd->tabs = malloc(1024, M_DEVBUF, M_NOWAIT);
259 vd->dblwid = malloc(1024, M_DEVBUF, M_NOWAIT|M_ZERO);
260 vd->dw = 0;
261 vd->dcsarg = malloc(DCS_MAXLEN, M_DEVBUF, M_NOWAIT);
262 edp->isolatin1tab = malloc(128 * sizeof(int), M_DEVBUF, M_NOWAIT);
263 edp->decgraphtab = malloc(128 * sizeof(int), M_DEVBUF, M_NOWAIT);
264 edp->dectechtab = malloc(128 * sizeof(int), M_DEVBUF, M_NOWAIT);
265 edp->nrctab = malloc(128 * sizeof(int), M_DEVBUF, M_NOWAIT);
266 vt100_initchartables(edp);
267 wsemul_vt100_reset(edp);
268 return (edp);
269 }
270
271 void
272 wsemul_vt100_detach(void *cookie, u_int *crowp, u_int *ccolp)
273 {
274 struct wsemul_vt100_emuldata *edp = cookie;
275 struct vt100base_data *vd = &edp->bd;
276
277 *crowp = vd->crow;
278 *ccolp = vd->ccol;
279 #define f(ptr) if (ptr) {free(ptr, M_DEVBUF); ptr = 0;}
280 f(vd->tabs)
281 f(vd->dblwid)
282 f(vd->dcsarg)
283 f(edp->isolatin1tab)
284 f(edp->decgraphtab)
285 f(edp->dectechtab)
286 f(edp->nrctab)
287 #undef f
288 if (edp != &wsemul_vt100_console_emuldata)
289 free(edp, M_DEVBUF);
290 }
291
292 static void
293 wsemul_vt100_resize(void * cookie, const struct wsscreen_descr *type)
294 {
295 struct wsemul_vt100_emuldata *edp = cookie;
296
297 edp->bd.nrows = type->nrows;
298 edp->bd.ncols = type->ncols;
299 wsemul_vt100_reset(edp);
300 wsemul_vt100_resetop(cookie, WSEMUL_CLEARSCREEN);
301 }
302
303 void
304 wsemul_vt100_resetop(void *cookie, enum wsemul_resetops op)
305 {
306 struct wsemul_vt100_emuldata *edp = cookie;
307 struct vt100base_data *vd = &edp->bd;
308
309 switch (op) {
310 case WSEMUL_RESET:
311 wsemul_vt100_reset(edp);
312 break;
313 case WSEMUL_SYNCFONT:
314 vt100_initchartables(edp);
315 break;
316 case WSEMUL_CLEARSCREEN:
317 wsemul_vt100_ed(vd, 2);
318 vd->ccol = vd->crow = 0;
319 (*vd->emulops->cursor)(vd->emulcookie,
320 vd->flags & VTFL_CURSORON, 0, 0);
321 break;
322 default:
323 break;
324 }
325 }
326
327 void
328 wsemul_vt100_reset(struct wsemul_vt100_emuldata *edp)
329 {
330 struct vt100base_data *vd = &edp->bd;
331 int i;
332
333 edp->state = VT100_EMUL_STATE_NORMAL;
334 vd->flags = VTFL_DECAWM | VTFL_CURSORON;
335 vd->bkgdattr = vd->curattr = vd->defattr;
336 vd->attrflags = vd->msgattrs.default_attrs;
337 vd->fgcol = vd->msgattrs.default_fg;
338 vd->bgcol = vd->msgattrs.default_bg;
339 vd->scrreg_startrow = 0;
340 vd->scrreg_nrows = vd->nrows;
341 if (vd->tabs) {
342 memset(vd->tabs, 0, vd->ncols);
343 for (i = 8; i < vd->ncols; i += 8)
344 vd->tabs[i] = 1;
345 }
346 vd->dcspos = 0;
347 vd->dcstype = 0;
348 edp->chartab_G[0] = 0;
349 edp->chartab_G[1] = edp->nrctab; /* ??? */
350 edp->chartab_G[2] = edp->isolatin1tab;
351 edp->chartab_G[3] = edp->isolatin1tab;
352 edp->chartab0 = 0;
353 edp->chartab1 = 2;
354 edp->sschartab = 0;
355 }
356
357 /*
358 * now all the state machine bits
359 */
360
361 /*
362 * Move the cursor to the next line if possible. If the cursor is at
363 * the bottom of the scroll area, then scroll it up. If the cursor is
364 * at the bottom of the screen then don't move it down.
365 */
366 static void
367 wsemul_vt100_nextline(struct wsemul_vt100_emuldata *edp)
368 {
369 struct vt100base_data *vd = &edp->bd;
370
371 if (ROWS_BELOW(vd) == 0) {
372 /* Bottom of the scroll region. */
373 wsemul_vt100_scrollup(vd, 1);
374 } else {
375 if ((vd->crow+1) < vd->nrows)
376 /* Cursor not at the bottom of the screen. */
377 vd->crow++;
378 CHECK_DW(vd);
379 }
380 }
381
382 static void
383 wsemul_vt100_output_normal(struct wsemul_vt100_emuldata *edp, u_char c,
384 int kernel)
385 {
386 struct vt100base_data *vd = &edp->bd;
387 u_int *ct, dc;
388
389 if ((vd->flags & (VTFL_LASTCHAR | VTFL_DECAWM)) ==
390 (VTFL_LASTCHAR | VTFL_DECAWM)) {
391 wsemul_vt100_nextline(edp);
392 vd->ccol = 0;
393 vd->flags &= ~VTFL_LASTCHAR;
394 }
395
396 if (c & 0x80) {
397 c &= 0x7f;
398 ct = edp->chartab_G[edp->chartab1];
399 } else {
400 if (edp->sschartab) {
401 ct = edp->chartab_G[edp->sschartab];
402 edp->sschartab = 0;
403 } else
404 ct = edp->chartab_G[edp->chartab0];
405 }
406 dc = (ct ? ct[c] : c);
407
408 if ((vd->flags & VTFL_INSERTMODE) && COLS_LEFT(vd))
409 COPYCOLS(vd, vd->ccol, vd->ccol + 1, COLS_LEFT(vd));
410
411 (*vd->emulops->putchar)(vd->emulcookie, vd->crow,
412 vd->ccol << vd->dw, dc,
413 kernel ? edp->kernattr : vd->curattr);
414
415 if (COLS_LEFT(vd))
416 vd->ccol++;
417 else
418 vd->flags |= VTFL_LASTCHAR;
419 }
420
421 static void
422 wsemul_vt100_output_c0c1(struct wsemul_vt100_emuldata *edp, u_char c,
423 int kernel)
424 {
425 struct vt100base_data *vd = &edp->bd;
426 u_int n;
427
428 switch (c) {
429 case ASCII_NUL:
430 default:
431 /* ignore */
432 break;
433 case ASCII_BEL:
434 wsdisplay_emulbell(vd->cbcookie);
435 break;
436 case ASCII_BS:
437 if (vd->ccol > 0) {
438 vd->ccol--;
439 vd->flags &= ~VTFL_LASTCHAR;
440 }
441 break;
442 case ASCII_CR:
443 vd->ccol = 0;
444 vd->flags &= ~VTFL_LASTCHAR;
445 break;
446 case ASCII_HT:
447 if (vd->tabs) {
448 if (!COLS_LEFT(vd))
449 break;
450 for (n = vd->ccol + 1; n < NCOLS(vd) - 1; n++)
451 if (vd->tabs[n])
452 break;
453 } else {
454 n = vd->ccol + min(8 - (vd->ccol & 7), COLS_LEFT(vd));
455 }
456 vd->ccol = n;
457 break;
458 case ASCII_SO: /* LS1 */
459 edp->chartab0 = 1;
460 break;
461 case ASCII_SI: /* LS0 */
462 edp->chartab0 = 0;
463 break;
464 case ASCII_ESC:
465 if (kernel) {
466 printf("wsemul_vt100_output_c0c1: ESC in kernel output ignored\n");
467 break; /* ignore the ESC */
468 }
469
470 if (edp->state == VT100_EMUL_STATE_STRING) {
471 /* might be a string end */
472 edp->state = VT100_EMUL_STATE_STRING_ESC;
473 } else {
474 /* XXX cancel current escape sequence */
475 edp->state = VT100_EMUL_STATE_ESC;
476 }
477 break;
478 #if 0
479 case CSI: /* 8-bit */
480 /* XXX cancel current escape sequence */
481 edp->nargs = 0;
482 memset(edp->args, 0, sizeof (edp->args));
483 edp->modif1 = edp->modif2 = '\0';
484 edp->state = VT100_EMUL_STATE_CSI;
485 break;
486 case DCS: /* 8-bit */
487 /* XXX cancel current escape sequence */
488 edp->nargs = 0;
489 memset(edp->args, 0, sizeof (edp->args));
490 edp->state = VT100_EMUL_STATE_DCS;
491 break;
492 case ST: /* string end 8-bit */
493 /* XXX only in VT100_EMUL_STATE_STRING */
494 wsemul_vt100_handle_dcs(edp);
495 return (VT100_EMUL_STATE_NORMAL);
496 #endif
497 case ASCII_LF:
498 case ASCII_VT:
499 case ASCII_FF:
500 wsemul_vt100_nextline(edp);
501 break;
502 }
503 }
504
505 static u_int
506 wsemul_vt100_output_esc(struct wsemul_vt100_emuldata *edp, u_char c)
507 {
508 struct vt100base_data *vd = &edp->bd;
509 u_int newstate = VT100_EMUL_STATE_NORMAL;
510 int i;
511
512 switch (c) {
513 case '[': /* CSI */
514 vd->nargs = 0;
515 memset(vd->args, 0, sizeof (vd->args));
516 vd->modif1 = vd->modif2 = '\0';
517 newstate = VT100_EMUL_STATE_CSI;
518 break;
519 case '7': /* DECSC */
520 vd->flags |= VTFL_SAVEDCURS;
521 edp->savedcursor_row = vd->crow;
522 edp->savedcursor_col = vd->ccol;
523 edp->savedattr = vd->curattr;
524 edp->savedbkgdattr = vd->bkgdattr;
525 edp->savedattrflags = vd->attrflags;
526 edp->savedfgcol = vd->fgcol;
527 edp->savedbgcol = vd->bgcol;
528 for (i = 0; i < 4; i++)
529 edp->savedchartab_G[i] = edp->chartab_G[i];
530 edp->savedchartab0 = edp->chartab0;
531 edp->savedchartab1 = edp->chartab1;
532 break;
533 case '8': /* DECRC */
534 if ((vd->flags & VTFL_SAVEDCURS) == 0)
535 break;
536 vd->crow = edp->savedcursor_row;
537 vd->ccol = edp->savedcursor_col;
538 vd->curattr = edp->savedattr;
539 vd->bkgdattr = edp->savedbkgdattr;
540 vd->attrflags = edp->savedattrflags;
541 vd->fgcol = edp->savedfgcol;
542 vd->bgcol = edp->savedbgcol;
543 for (i = 0; i < 4; i++)
544 edp->chartab_G[i] = edp->savedchartab_G[i];
545 edp->chartab0 = edp->savedchartab0;
546 edp->chartab1 = edp->savedchartab1;
547 break;
548 case '=': /* DECKPAM application mode */
549 vd->flags |= VTFL_APPLKEYPAD;
550 break;
551 case '>': /* DECKPNM numeric mode */
552 vd->flags &= ~VTFL_APPLKEYPAD;
553 break;
554 case 'E': /* NEL */
555 vd->ccol = 0;
556 /* FALLTHRU */
557 case 'D': /* IND */
558 wsemul_vt100_nextline(edp);
559 break;
560 case 'H': /* HTS */
561 KASSERT(vd->tabs != 0);
562 vd->tabs[vd->ccol] = 1;
563 break;
564 case '~': /* LS1R */
565 edp->chartab1 = 1;
566 break;
567 case 'n': /* LS2 */
568 edp->chartab0 = 2;
569 break;
570 case '}': /* LS2R */
571 edp->chartab1 = 2;
572 break;
573 case 'o': /* LS3 */
574 edp->chartab0 = 3;
575 break;
576 case '|': /* LS3R */
577 edp->chartab1 = 3;
578 break;
579 case 'N': /* SS2 */
580 edp->sschartab = 2;
581 break;
582 case 'O': /* SS3 */
583 edp->sschartab = 3;
584 break;
585 case 'M': /* RI */
586 if (ROWS_ABOVE(vd) > 0) {
587 vd->crow--;
588 CHECK_DW(vd);
589 break;
590 }
591 wsemul_vt100_scrolldown(vd, 1);
592 break;
593 case 'P': /* DCS */
594 vd->nargs = 0;
595 memset(vd->args, 0, sizeof (vd->args));
596 newstate = VT100_EMUL_STATE_DCS;
597 break;
598 case 'c': /* RIS */
599 wsemul_vt100_reset(edp);
600 wsemul_vt100_ed(vd, 2);
601 vd->ccol = vd->crow = 0;
602 break;
603 case '(': case ')': case '*': case '+': /* SCS */
604 edp->designating = c - '(';
605 newstate = VT100_EMUL_STATE_SCS94;
606 break;
607 case '-': case '.': case '/': /* SCS */
608 edp->designating = c - '-' + 1;
609 newstate = VT100_EMUL_STATE_SCS96;
610 break;
611 case '#':
612 newstate = VT100_EMUL_STATE_ESC_HASH;
613 break;
614 case ' ': /* 7/8 bit */
615 newstate = VT100_EMUL_STATE_ESC_SPC;
616 break;
617 case ']': /* OSC operating system command */
618 case '^': /* PM privacy message */
619 case '_': /* APC application program command */
620 /* ignored */
621 newstate = VT100_EMUL_STATE_STRING;
622 break;
623 case '<': /* exit VT52 mode - ignored */
624 break;
625 default:
626 #ifdef VT100_PRINTUNKNOWN
627 printf("ESC%c unknown\n", c);
628 #endif
629 break;
630 }
631
632 return (newstate);
633 }
634
635 static u_int
636 wsemul_vt100_output_scs94(struct wsemul_vt100_emuldata *edp, u_char c)
637 {
638 u_int newstate = VT100_EMUL_STATE_NORMAL;
639
640 switch (c) {
641 case '%': /* probably DEC supplemental graphic */
642 newstate = VT100_EMUL_STATE_SCS94_PERCENT;
643 break;
644 case 'A': /* british / national */
645 edp->chartab_G[edp->designating] = edp->nrctab;
646 break;
647 case 'B': /* ASCII */
648 edp->chartab_G[edp->designating] = 0;
649 break;
650 case '<': /* user preferred supplemental */
651 /* XXX not really "user" preferred */
652 edp->chartab_G[edp->designating] = edp->isolatin1tab;
653 break;
654 case '0': /* DEC special graphic */
655 edp->chartab_G[edp->designating] = edp->decgraphtab;
656 break;
657 case '>': /* DEC tech */
658 edp->chartab_G[edp->designating] = edp->dectechtab;
659 break;
660 default:
661 #ifdef VT100_PRINTUNKNOWN
662 printf("ESC%c%c unknown\n", edp->designating + '(', c);
663 #endif
664 break;
665 }
666 return (newstate);
667 }
668
669 static u_int
670 wsemul_vt100_output_scs94_percent(struct wsemul_vt100_emuldata *edp, u_char c)
671 {
672 switch (c) {
673 case '5': /* DEC supplemental graphic */
674 /* XXX there are differences */
675 edp->chartab_G[edp->designating] = edp->isolatin1tab;
676 break;
677 default:
678 #ifdef VT100_PRINTUNKNOWN
679 printf("ESC%c%%%c unknown\n", edp->designating + '(', c);
680 #endif
681 break;
682 }
683 return (VT100_EMUL_STATE_NORMAL);
684 }
685
686 static u_int
687 wsemul_vt100_output_scs96(struct wsemul_vt100_emuldata *edp, u_char c)
688 {
689 u_int newstate = VT100_EMUL_STATE_NORMAL;
690 int nrc;
691
692 switch (c) {
693 case '%': /* probably portuguese */
694 newstate = VT100_EMUL_STATE_SCS96_PERCENT;
695 break;
696 case 'A': /* ISO-latin-1 supplemental */
697 edp->chartab_G[edp->designating] = edp->isolatin1tab;
698 break;
699 case '4': /* dutch */
700 nrc = 1;
701 goto setnrc;
702 case '5': case 'C': /* finnish */
703 nrc = 2;
704 goto setnrc;
705 case 'R': /* french */
706 nrc = 3;
707 goto setnrc;
708 case 'Q': /* french canadian */
709 nrc = 4;
710 goto setnrc;
711 case 'K': /* german */
712 nrc = 5;
713 goto setnrc;
714 case 'Y': /* italian */
715 nrc = 6;
716 goto setnrc;
717 case 'E': case '6': /* norwegian / danish */
718 nrc = 7;
719 goto setnrc;
720 case 'Z': /* spanish */
721 nrc = 9;
722 goto setnrc;
723 case '7': case 'H': /* swedish */
724 nrc = 10;
725 goto setnrc;
726 case '=': /* swiss */
727 nrc = 11;
728 setnrc:
729 vt100_setnrc(edp, nrc); /* what table ??? */
730 break;
731 default:
732 #ifdef VT100_PRINTUNKNOWN
733 printf("ESC%c%c unknown\n", edp->designating + '-' - 1, c);
734 #endif
735 break;
736 }
737 return (newstate);
738 }
739
740 static u_int
741 wsemul_vt100_output_scs96_percent(struct wsemul_vt100_emuldata *edp, u_char c)
742 {
743 switch (c) {
744 case '6': /* portuguese */
745 vt100_setnrc(edp, 8);
746 break;
747 default:
748 #ifdef VT100_PRINTUNKNOWN
749 printf("ESC%c%%%c unknown\n", edp->designating + '-', c);
750 #endif
751 break;
752 }
753 return (VT100_EMUL_STATE_NORMAL);
754 }
755
756 static u_int
757 wsemul_vt100_output_esc_spc(struct wsemul_vt100_emuldata *edp,
758 u_char c)
759 {
760 switch (c) {
761 case 'F': /* 7-bit controls */
762 case 'G': /* 8-bit controls */
763 #ifdef VT100_PRINTNOTIMPL
764 printf("ESC<SPC>%c ignored\n", c);
765 #endif
766 break;
767 default:
768 #ifdef VT100_PRINTUNKNOWN
769 printf("ESC<SPC>%c unknown\n", c);
770 #endif
771 break;
772 }
773 return (VT100_EMUL_STATE_NORMAL);
774 }
775
776 static u_int
777 wsemul_vt100_output_string(struct wsemul_vt100_emuldata *edp, u_char c)
778 {
779 struct vt100base_data *vd = &edp->bd;
780
781 if (vd->dcstype && vd->dcspos < DCS_MAXLEN)
782 vd->dcsarg[vd->dcspos++] = c;
783 return (VT100_EMUL_STATE_STRING);
784 }
785
786 static u_int
787 wsemul_vt100_output_string_esc(struct wsemul_vt100_emuldata *edp, u_char c)
788 {
789 struct vt100base_data *vd = &edp->bd;
790
791 if (c == '\\') { /* ST complete */
792 wsemul_vt100_handle_dcs(vd);
793 return (VT100_EMUL_STATE_NORMAL);
794 } else
795 return (VT100_EMUL_STATE_STRING);
796 }
797
798 static u_int
799 wsemul_vt100_output_dcs(struct wsemul_vt100_emuldata *edp, u_char c)
800 {
801 struct vt100base_data *vd = &edp->bd;
802 u_int newstate = VT100_EMUL_STATE_DCS;
803
804 switch (c) {
805 case '0': case '1': case '2': case '3': case '4':
806 case '5': case '6': case '7': case '8': case '9':
807 /* argument digit */
808 if (vd->nargs > VT100_EMUL_NARGS - 1)
809 break;
810 vd->args[vd->nargs] = (vd->args[vd->nargs] * 10) +
811 (c - '0');
812 break;
813 case ';': /* argument terminator */
814 vd->nargs++;
815 break;
816 default:
817 vd->nargs++;
818 if (vd->nargs > VT100_EMUL_NARGS) {
819 #ifdef VT100_DEBUG
820 printf("vt100: too many arguments\n");
821 #endif
822 vd->nargs = VT100_EMUL_NARGS;
823 }
824 newstate = VT100_EMUL_STATE_STRING;
825 switch (c) {
826 case '$':
827 newstate = VT100_EMUL_STATE_DCS_DOLLAR;
828 break;
829 case '{': /* DECDLD soft charset */
830 case '!': /* DECRQUPSS user preferred supplemental set */
831 /* 'u' must follow - need another state */
832 case '|': /* DECUDK program F6..F20 */
833 #ifdef VT100_PRINTNOTIMPL
834 printf("DCS%c ignored\n", c);
835 #endif
836 break;
837 default:
838 #ifdef VT100_PRINTUNKNOWN
839 printf("DCS%c (%d, %d) unknown\n", c, ARG(vd, 0), ARG(vd, 1));
840 #endif
841 break;
842 }
843 }
844
845 return (newstate);
846 }
847
848 static u_int
849 wsemul_vt100_output_dcs_dollar(struct wsemul_vt100_emuldata *edp, u_char c)
850 {
851 struct vt100base_data *vd = &edp->bd;
852
853 switch (c) {
854 case 'p': /* DECRSTS terminal state restore */
855 case 'q': /* DECRQSS control function request */
856 #ifdef VT100_PRINTNOTIMPL
857 printf("DCS$%c ignored\n", c);
858 #endif
859 break;
860 case 't': /* DECRSPS restore presentation state */
861 switch (ARG(vd, 0)) {
862 case 0: /* error */
863 break;
864 case 1: /* cursor information restore */
865 #ifdef VT100_PRINTNOTIMPL
866 printf("DCS1$t ignored\n");
867 #endif
868 break;
869 case 2: /* tab stop restore */
870 vd->dcspos = 0;
871 vd->dcstype = DCSTYPE_TABRESTORE;
872 break;
873 default:
874 #ifdef VT100_PRINTUNKNOWN
875 printf("DCS%d$t unknown\n", ARG(vd, 0));
876 #endif
877 break;
878 }
879 break;
880 default:
881 #ifdef VT100_PRINTUNKNOWN
882 printf("DCS$%c (%d, %d) unknown\n", c, ARG(vd, 0), ARG(vd, 1));
883 #endif
884 break;
885 }
886 return (VT100_EMUL_STATE_STRING);
887 }
888
889 static u_int
890 wsemul_vt100_output_esc_hash(struct wsemul_vt100_emuldata *edp, u_char c)
891 {
892 struct vt100base_data *vd = &edp->bd;
893 int i, j;
894
895 switch (c) {
896 case '5': /* DECSWL single width, single height */
897 if (vd->dw) {
898 for (i = 0; i < vd->ncols / 2; i++)
899 (*vd->emulops->copycols)(vd->emulcookie,
900 vd->crow,
901 2 * i, i, 1);
902 (*vd->emulops->erasecols)(vd->emulcookie, vd->crow,
903 i, vd->ncols - i,
904 vd->bkgdattr);
905 vd->dblwid[vd->crow] = 0;
906 vd->dw = 0;
907 }
908 break;
909 case '6': /* DECDWL double width, single height */
910 case '3': /* DECDHL double width, double height, top half */
911 case '4': /* DECDHL double width, double height, bottom half */
912 if (!vd->dw) {
913 for (i = vd->ncols / 2 - 1; i >= 0; i--)
914 (*vd->emulops->copycols)(vd->emulcookie,
915 vd->crow,
916 i, 2 * i, 1);
917 for (i = 0; i < vd->ncols / 2; i++)
918 (*vd->emulops->erasecols)(vd->emulcookie,
919 vd->crow,
920 2 * i + 1, 1,
921 vd->bkgdattr);
922 vd->dblwid[vd->crow] = 1;
923 vd->dw = 1;
924 if (vd->ccol > (vd->ncols >> 1) - 1)
925 vd->ccol = (vd->ncols >> 1) - 1;
926 }
927 break;
928 case '8': /* DECALN */
929 for (i = 0; i < vd->nrows; i++)
930 for (j = 0; j < vd->ncols; j++)
931 (*vd->emulops->putchar)(vd->emulcookie, i, j,
932 'E', vd->curattr);
933 vd->ccol = 0;
934 vd->crow = 0;
935 break;
936 default:
937 #ifdef VT100_PRINTUNKNOWN
938 printf("ESC#%c unknown\n", c);
939 #endif
940 break;
941 }
942 return (VT100_EMUL_STATE_NORMAL);
943 }
944
945 static u_int
946 wsemul_vt100_output_csi(struct wsemul_vt100_emuldata *edp, u_char c)
947 {
948 struct vt100base_data *vd = &edp->bd;
949 u_int newstate = VT100_EMUL_STATE_CSI;
950
951 switch (c) {
952 case '0': case '1': case '2': case '3': case '4':
953 case '5': case '6': case '7': case '8': case '9':
954 /* argument digit */
955 if (vd->nargs > VT100_EMUL_NARGS - 1)
956 break;
957 vd->args[vd->nargs] = (vd->args[vd->nargs] * 10) +
958 (c - '0');
959 break;
960 case ';': /* argument terminator */
961 vd->nargs++;
962 break;
963 case '?': /* DEC specific */
964 case '>': /* DA query */
965 vd->modif1 = c;
966 break;
967 case '!':
968 case '"':
969 case '$':
970 case '&':
971 vd->modif2 = c;
972 break;
973 default: /* end of escape sequence */
974 vd->nargs++;
975 if (vd->nargs > VT100_EMUL_NARGS) {
976 #ifdef VT100_DEBUG
977 printf("vt100: too many arguments\n");
978 #endif
979 vd->nargs = VT100_EMUL_NARGS;
980 }
981 wsemul_vt100_handle_csi(vd, c);
982 newstate = VT100_EMUL_STATE_NORMAL;
983 break;
984 }
985 return (newstate);
986 }
987
988 void
989 wsemul_vt100_output(void *cookie, const u_char *data, u_int count, int kernel)
990 {
991 struct wsemul_vt100_emuldata *edp = cookie;
992 struct vt100base_data *vd = &edp->bd;
993
994 #ifdef DIAGNOSTIC
995 if (kernel && !edp->console)
996 panic("wsemul_vt100_output: kernel output, not console");
997 #endif
998
999 if (vd->flags & VTFL_CURSORON)
1000 (*vd->emulops->cursor)(vd->emulcookie, 0,
1001 vd->crow, vd->ccol << vd->dw);
1002 for (; count > 0; data++, count--) {
1003 if ((*data & 0x7f) < 0x20) {
1004 wsemul_vt100_output_c0c1(edp, *data, kernel);
1005 continue;
1006 }
1007 if (edp->state == VT100_EMUL_STATE_NORMAL || kernel) {
1008 wsemul_vt100_output_normal(edp, *data, kernel);
1009 continue;
1010 }
1011 #ifdef DIAGNOSTIC
1012 if (edp->state > sizeof(vt100_output) / sizeof(vt100_output[0]))
1013 panic("wsemul_vt100: invalid state %d", edp->state);
1014 #endif
1015 edp->state = vt100_output[edp->state - 1](edp, *data);
1016 }
1017 if (vd->flags & VTFL_CURSORON)
1018 (*vd->emulops->cursor)(vd->emulcookie, 1,
1019 vd->crow, vd->ccol << vd->dw);
1020 }
1021
1022 #ifdef WSDISPLAY_CUSTOM_OUTPUT
1023 static void
1024 wsemul_vt100_getmsgattrs(void *cookie, struct wsdisplay_msgattrs *ma)
1025 {
1026 struct wsemul_vt100_emuldata *edp = cookie;
1027 struct vt100base_data *vd = &edp->bd;
1028
1029 *ma = vd->msgattrs;
1030 }
1031
1032 static void
1033 wsemul_vt100_setmsgattrs(void *cookie, const struct wsscreen_descr *type,
1034 const struct wsdisplay_msgattrs *ma)
1035 {
1036 int error;
1037 long tmp;
1038 struct wsemul_vt100_emuldata *edp = cookie;
1039 struct vt100base_data *vd = &edp->bd;
1040
1041 vd->msgattrs = *ma;
1042 if (type->capabilities & WSSCREEN_WSCOLORS) {
1043 vd->msgattrs.default_attrs |= WSATTR_WSCOLORS;
1044 vd->msgattrs.kernel_attrs |= WSATTR_WSCOLORS;
1045 } else {
1046 vd->msgattrs.default_bg = vd->msgattrs.kernel_bg = 0;
1047 vd->msgattrs.default_fg = vd->msgattrs.kernel_fg = 0;
1048 }
1049
1050 error = (*vd->emulops->allocattr)(vd->emulcookie,
1051 vd->msgattrs.default_fg,
1052 vd->msgattrs.default_bg,
1053 vd->msgattrs.default_attrs,
1054 &tmp);
1055 #ifndef VT100_DEBUG
1056 __USE(error);
1057 #else
1058 if (error)
1059 printf("vt100: failed to allocate attribute for default "
1060 "messages\n");
1061 else
1062 #endif
1063 {
1064 if (vd->curattr == vd->defattr) {
1065 vd->bkgdattr = vd->curattr = tmp;
1066 vd->attrflags = vd->msgattrs.default_attrs;
1067 vd->bgcol = vd->msgattrs.default_bg;
1068 vd->fgcol = vd->msgattrs.default_fg;
1069 } else {
1070 edp->savedbkgdattr = edp->savedattr = tmp;
1071 edp->savedattrflags = vd->msgattrs.default_attrs;
1072 edp->savedbgcol = vd->msgattrs.default_bg;
1073 edp->savedfgcol = vd->msgattrs.default_fg;
1074 }
1075 if (vd->emulops->replaceattr != NULL)
1076 (*vd->emulops->replaceattr)(vd->emulcookie,
1077 vd->defattr, tmp);
1078 vd->defattr = tmp;
1079 }
1080
1081 error = (*vd->emulops->allocattr)(vd->emulcookie,
1082 vd->msgattrs.kernel_fg,
1083 vd->msgattrs.kernel_bg,
1084 vd->msgattrs.kernel_attrs,
1085 &tmp);
1086 #ifdef VT100_DEBUG
1087 if (error)
1088 printf("vt100: failed to allocate attribute for kernel "
1089 "messages\n");
1090 else
1091 #endif
1092 {
1093 if (vd->emulops->replaceattr != NULL)
1094 (*vd->emulops->replaceattr)(vd->emulcookie,
1095 edp->kernattr, tmp);
1096 edp->kernattr = tmp;
1097 }
1098 }
1099 #endif /* WSDISPLAY_CUSTOM_OUTPUT */
1100