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