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