wsemul_vt100.c revision 1.12 1 /* $NetBSD: wsemul_vt100.c,v 1.12 1999/11/03 15:55:29 mycroft 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 case WSEMUL_CLEARSCREEN:
273 wsemul_vt100_ed(edp, 2);
274 edp->ccol = edp->crow = 0;
275 (*edp->emulops->cursor)(edp->emulcookie,
276 edp->flags & VTFL_CURSORON, 0, 0);
277 break;
278 default:
279 break;
280 }
281 }
282
283 void
284 wsemul_vt100_reset(edp)
285 struct wsemul_vt100_emuldata *edp;
286 {
287 int i;
288
289 edp->state = VT100_EMUL_STATE_NORMAL;
290 edp->flags = VTFL_DECAWM | VTFL_CURSORON;
291 edp->curattr = edp->defattr;
292 edp->attrflags = 0;
293 edp->fgcol = WSCOL_WHITE;
294 edp->bgcol = WSCOL_BLACK;
295 edp->scrreg_startrow = 0;
296 edp->scrreg_nrows = edp->nrows;
297 if (edp->tabs) {
298 memset(edp->tabs, 0, edp->ncols);
299 for (i = 8; i < edp->ncols; i += 8)
300 edp->tabs[i] = 1;
301 }
302 edp->dcspos = 0;
303 edp->dcstype = 0;
304 edp->chartab_G[0] = 0;
305 edp->chartab_G[1] = edp->nrctab; /* ??? */
306 edp->chartab_G[2] = edp->isolatin1tab;
307 edp->chartab_G[3] = edp->isolatin1tab;
308 edp->chartab0 = 0;
309 edp->chartab1 = 2;
310 edp->sschartab = 0;
311 }
312
313 /*
314 * now all the state machine bits
315 */
316
317 static void
318 wsemul_vt100_output_normal(edp, c, kernel)
319 struct wsemul_vt100_emuldata *edp;
320 u_char c;
321 int kernel;
322 {
323 u_int *ct, dc;
324
325 if ((edp->flags & (VTFL_LASTCHAR | VTFL_DECAWM)) ==
326 (VTFL_LASTCHAR | VTFL_DECAWM)) {
327 if (ROWS_BELOW > 0) {
328 edp->crow++;
329 CHECK_DW;
330 } else
331 wsemul_vt100_scrollup(edp, 1);
332 edp->ccol = 0;
333 edp->flags &= ~VTFL_LASTCHAR;
334 }
335
336 if (c & 0x80) {
337 c &= 0x7f;
338 ct = edp->chartab_G[edp->chartab1];
339 } else {
340 if (edp->sschartab) {
341 ct = edp->chartab_G[edp->sschartab];
342 edp->sschartab = 0;
343 } else
344 ct = edp->chartab_G[edp->chartab0];
345 }
346 dc = (ct ? ct[c] : c);
347
348 if ((edp->flags & VTFL_INSERTMODE) && COLS_LEFT)
349 COPYCOLS(edp->ccol, edp->ccol + 1, COLS_LEFT);
350
351 (*edp->emulops->putchar)(edp->emulcookie, edp->crow,
352 edp->ccol << edp->dw, dc,
353 kernel ? edp->kernattr : edp->curattr);
354
355 if (COLS_LEFT)
356 edp->ccol++;
357 else
358 edp->flags |= VTFL_LASTCHAR;
359 }
360
361 static void
362 wsemul_vt100_output_c0c1(edp, c, kernel)
363 struct wsemul_vt100_emuldata *edp;
364 u_char c;
365 int kernel;
366 {
367 u_int n;
368
369 switch (c) {
370 case ASCII_NUL:
371 default:
372 /* ignore */
373 break;
374 case ASCII_BEL:
375 wsdisplay_emulbell(edp->cbcookie);
376 break;
377 case ASCII_BS:
378 if (edp->ccol > 0) {
379 edp->ccol--;
380 edp->flags &= ~VTFL_LASTCHAR;
381 }
382 break;
383 case ASCII_CR:
384 edp->ccol = 0;
385 edp->flags &= ~VTFL_LASTCHAR;
386 break;
387 case ASCII_HT:
388 if (edp->tabs) {
389 if (!COLS_LEFT)
390 break;
391 for (n = edp->ccol + 1; n < NCOLS - 1; n++)
392 if (edp->tabs[n])
393 break;
394 } else {
395 n = edp->ccol + min(8 - (edp->ccol & 7), COLS_LEFT);
396 }
397 edp->ccol = n;
398 break;
399 case ASCII_SO: /* LS1 */
400 edp->chartab0 = 1;
401 break;
402 case ASCII_SI: /* LS0 */
403 edp->chartab0 = 0;
404 break;
405 case ASCII_ESC:
406 #ifdef DIAGNOSTIC
407 if (kernel)
408 panic("ESC in kernel output");
409 #endif
410 if (edp->state == VT100_EMUL_STATE_STRING) {
411 /* might be a string end */
412 edp->state = VT100_EMUL_STATE_STRING_ESC;
413 } else {
414 /* XXX cancel current escape sequence */
415 edp->state = VT100_EMUL_STATE_ESC;
416 }
417 break;
418 #if 0
419 case CSI: /* 8-bit */
420 /* XXX cancel current escape sequence */
421 edp->nargs = 0;
422 memset(edp->args, 0, sizeof (edp->args));
423 edp->modif1 = edp->modif2 = '\0';
424 edp->state = VT100_EMUL_STATE_CSI;
425 break;
426 case DCS: /* 8-bit */
427 /* XXX cancel current escape sequence */
428 edp->nargs = 0;
429 memset(edp->args, 0, sizeof (edp->args));
430 edp->state = VT100_EMUL_STATE_DCS;
431 break;
432 case ST: /* string end 8-bit */
433 /* XXX only in VT100_EMUL_STATE_STRING */
434 wsemul_vt100_handle_dcs(edp);
435 return (VT100_EMUL_STATE_NORMAL);
436 #endif
437 case ASCII_LF:
438 case ASCII_VT:
439 case ASCII_FF:
440 if (ROWS_BELOW > 0) {
441 edp->crow++;
442 CHECK_DW;
443 } else
444 wsemul_vt100_scrollup(edp, 1);
445 break;
446 }
447 }
448
449 static u_int
450 wsemul_vt100_output_esc(edp, c)
451 struct wsemul_vt100_emuldata *edp;
452 u_char c;
453 {
454 u_int newstate = VT100_EMUL_STATE_NORMAL;
455 int i;
456
457 switch (c) {
458 case '[': /* CSI */
459 edp->nargs = 0;
460 memset(edp->args, 0, sizeof (edp->args));
461 edp->modif1 = edp->modif2 = '\0';
462 newstate = VT100_EMUL_STATE_CSI;
463 break;
464 case '7': /* DECSC */
465 edp->savedcursor_row = edp->crow;
466 edp->savedcursor_col = edp->ccol;
467 edp->savedattr = edp->curattr;
468 edp->savedattrflags = edp->attrflags;
469 edp->savedfgcol = edp->fgcol;
470 edp->savedbgcol = edp->bgcol;
471 for (i = 0; i < 4; i++)
472 edp->savedchartab_G[i] = edp->chartab_G[i];
473 edp->savedchartab0 = edp->chartab0;
474 edp->savedchartab1 = edp->chartab1;
475 break;
476 case '8': /* DECRC */
477 edp->crow = edp->savedcursor_row;
478 edp->ccol = edp->savedcursor_col;
479 edp->curattr = edp->savedattr;
480 edp->attrflags = edp->savedattrflags;
481 edp->fgcol = edp->savedfgcol;
482 edp->bgcol = edp->savedbgcol;
483 for (i = 0; i < 4; i++)
484 edp->chartab_G[i] = edp->savedchartab_G[i];
485 edp->chartab0 = edp->savedchartab0;
486 edp->chartab1 = edp->savedchartab1;
487 break;
488 case '=': /* DECKPAM application mode */
489 edp->flags |= VTFL_APPLKEYPAD;
490 break;
491 case '>': /* DECKPNM numeric mode */
492 edp->flags &= ~VTFL_APPLKEYPAD;
493 break;
494 case 'E': /* NEL */
495 edp->ccol = 0;
496 /* FALLTHRU */
497 case 'D': /* IND */
498 if (ROWS_BELOW > 0) {
499 edp->crow++;
500 CHECK_DW;
501 break;
502 }
503 wsemul_vt100_scrollup(edp, 1);
504 break;
505 case 'H': /* HTS */
506 KASSERT(edp->tabs != 0);
507 edp->tabs[edp->ccol] = 1;
508 break;
509 case '~': /* LS1R */
510 edp->chartab1 = 1;
511 break;
512 case 'n': /* LS2 */
513 edp->chartab0 = 2;
514 break;
515 case '}': /* LS2R */
516 edp->chartab1 = 2;
517 break;
518 case 'o': /* LS3 */
519 edp->chartab0 = 3;
520 break;
521 case '|': /* LS3R */
522 edp->chartab1 = 3;
523 break;
524 case 'N': /* SS2 */
525 edp->sschartab = 2;
526 break;
527 case 'O': /* SS3 */
528 edp->sschartab = 3;
529 break;
530 case 'M': /* RI */
531 if (ROWS_ABOVE > 0) {
532 edp->crow--;
533 CHECK_DW;
534 break;
535 }
536 wsemul_vt100_scrolldown(edp, 1);
537 break;
538 case 'P': /* DCS */
539 edp->nargs = 0;
540 memset(edp->args, 0, sizeof (edp->args));
541 newstate = VT100_EMUL_STATE_DCS;
542 break;
543 case 'c': /* RIS */
544 wsemul_vt100_reset(edp);
545 wsemul_vt100_ed(edp, 2);
546 edp->ccol = edp->crow = 0;
547 break;
548 case '(': case ')': case '*': case '+': /* SCS */
549 edp->designating = c - '(';
550 newstate = VT100_EMUL_STATE_SCS94;
551 break;
552 case '-': case '.': case '/': /* SCS */
553 edp->designating = c - '-' + 1;
554 newstate = VT100_EMUL_STATE_SCS96;
555 break;
556 case '#':
557 newstate = VT100_EMUL_STATE_ESC_HASH;
558 break;
559 case ' ': /* 7/8 bit */
560 newstate = VT100_EMUL_STATE_ESC_SPC;
561 break;
562 case ']': /* OSC operating system command */
563 case '^': /* PM privacy message */
564 case '_': /* APC application program command */
565 /* ignored */
566 newstate = VT100_EMUL_STATE_STRING;
567 break;
568 case '<': /* exit VT52 mode - ignored */
569 break;
570 default:
571 #ifdef VT100_PRINTUNKNOWN
572 printf("ESC%c unknown\n", c);
573 #endif
574 break;
575 }
576
577 return (newstate);
578 }
579
580 static u_int
581 wsemul_vt100_output_scs94(edp, c)
582 struct wsemul_vt100_emuldata *edp;
583 u_char c;
584 {
585 u_int newstate = VT100_EMUL_STATE_NORMAL;
586
587 switch (c) {
588 case '%': /* probably DEC supplemental graphic */
589 newstate = VT100_EMUL_STATE_SCS94_PERCENT;
590 break;
591 case 'A': /* british / national */
592 edp->chartab_G[edp->designating] = edp->nrctab;
593 break;
594 case 'B': /* ASCII */
595 edp->chartab_G[edp->designating] = 0;
596 break;
597 case '<': /* user preferred supplemental */
598 /* XXX not really "user" preferred */
599 edp->chartab_G[edp->designating] = edp->isolatin1tab;
600 break;
601 case '0': /* DEC special graphic */
602 edp->chartab_G[edp->designating] = edp->decgraphtab;
603 break;
604 case '>': /* DEC tech */
605 edp->chartab_G[edp->designating] = edp->dectechtab;
606 break;
607 default:
608 #ifdef VT100_PRINTUNKNOWN
609 printf("ESC%c%c unknown\n", edp->designating + '(', c);
610 #endif
611 break;
612 }
613 return (newstate);
614 }
615
616 static u_int
617 wsemul_vt100_output_scs94_percent(edp, c)
618 struct wsemul_vt100_emuldata *edp;
619 u_char c;
620 {
621 switch (c) {
622 case '5': /* DEC supplemental graphic */
623 /* XXX there are differences */
624 edp->chartab_G[edp->designating] = edp->isolatin1tab;
625 break;
626 default:
627 #ifdef VT100_PRINTUNKNOWN
628 printf("ESC%c%%%c unknown\n", edp->designating + '(', c);
629 #endif
630 break;
631 }
632 return (VT100_EMUL_STATE_NORMAL);
633 }
634
635 static u_int
636 wsemul_vt100_output_scs96(edp, c)
637 struct wsemul_vt100_emuldata *edp;
638 u_char c;
639 {
640 u_int newstate = VT100_EMUL_STATE_NORMAL;
641 int nrc;
642
643 switch (c) {
644 case '%': /* probably portugese */
645 newstate = VT100_EMUL_STATE_SCS96_PERCENT;
646 break;
647 case 'A': /* ISO-latin-1 supplemental */
648 edp->chartab_G[edp->designating] = edp->isolatin1tab;
649 break;
650 case '4': /* dutch */
651 nrc = 1;
652 goto setnrc;
653 case '5': case 'C': /* finnish */
654 nrc = 2;
655 goto setnrc;
656 case 'R': /* french */
657 nrc = 3;
658 goto setnrc;
659 case 'Q': /* french canadian */
660 nrc = 4;
661 goto setnrc;
662 case 'K': /* german */
663 nrc = 5;
664 goto setnrc;
665 case 'Y': /* italian */
666 nrc = 6;
667 goto setnrc;
668 case 'E': case '6': /* norwegian / danish */
669 nrc = 7;
670 goto setnrc;
671 case 'Z': /* spanish */
672 nrc = 9;
673 goto setnrc;
674 case '7': case 'H': /* swedish */
675 nrc = 10;
676 goto setnrc;
677 case '=': /* swiss */
678 nrc = 11;
679 setnrc:
680 vt100_setnrc(edp, nrc); /* what table ??? */
681 break;
682 default:
683 #ifdef VT100_PRINTUNKNOWN
684 printf("ESC%c%c unknown\n", edp->designating + '-' - 1, c);
685 #endif
686 break;
687 }
688 return (newstate);
689 }
690
691 static u_int
692 wsemul_vt100_output_scs96_percent(edp, c)
693 struct wsemul_vt100_emuldata *edp;
694 u_char c;
695 {
696 switch (c) {
697 case '6': /* portugese */
698 vt100_setnrc(edp, 8);
699 break;
700 default:
701 #ifdef VT100_PRINTUNKNOWN
702 printf("ESC%c%%%c unknown\n", edp->designating + '-', c);
703 #endif
704 break;
705 }
706 return (VT100_EMUL_STATE_NORMAL);
707 }
708
709 static u_int
710 wsemul_vt100_output_esc_spc(edp, c)
711 struct wsemul_vt100_emuldata *edp;
712 u_char c;
713 {
714 switch (c) {
715 case 'F': /* 7-bit controls */
716 case 'G': /* 8-bit controls */
717 #ifdef VT100_PRINTNOTIMPL
718 printf("ESC<SPC>%c ignored\n", c);
719 #endif
720 break;
721 default:
722 #ifdef VT100_PRINTUNKNOWN
723 printf("ESC<SPC>%c unknown\n", c);
724 #endif
725 break;
726 }
727 return (VT100_EMUL_STATE_NORMAL);
728 }
729
730 static u_int
731 wsemul_vt100_output_string(edp, c)
732 struct wsemul_vt100_emuldata *edp;
733 u_char c;
734 {
735 if (edp->dcstype && edp->dcspos < DCS_MAXLEN)
736 edp->dcsarg[edp->dcspos++] = c;
737 return (VT100_EMUL_STATE_STRING);
738 }
739
740 static u_int
741 wsemul_vt100_output_string_esc(edp, c)
742 struct wsemul_vt100_emuldata *edp;
743 u_char c;
744 {
745 if (c == '\\') { /* ST complete */
746 wsemul_vt100_handle_dcs(edp);
747 return (VT100_EMUL_STATE_NORMAL);
748 } else
749 return (VT100_EMUL_STATE_STRING);
750 }
751
752 static u_int
753 wsemul_vt100_output_dcs(edp, c)
754 struct wsemul_vt100_emuldata *edp;
755 u_char c;
756 {
757 u_int newstate = VT100_EMUL_STATE_DCS;
758
759 switch (c) {
760 case '0': case '1': case '2': case '3': case '4':
761 case '5': case '6': case '7': case '8': case '9':
762 /* argument digit */
763 if (edp->nargs > VT100_EMUL_NARGS - 1)
764 break;
765 edp->args[edp->nargs] = (edp->args[edp->nargs] * 10) +
766 (c - '0');
767 break;
768 case ';': /* argument terminator */
769 edp->nargs++;
770 break;
771 default:
772 edp->nargs++;
773 if (edp->nargs > VT100_EMUL_NARGS) {
774 #ifdef VT100_DEBUG
775 printf("vt100: too many arguments\n");
776 #endif
777 edp->nargs = VT100_EMUL_NARGS;
778 }
779 newstate = VT100_EMUL_STATE_STRING;
780 switch (c) {
781 case '$':
782 newstate = VT100_EMUL_STATE_DCS_DOLLAR;
783 break;
784 case '{': /* DECDLD soft charset */
785 case '!': /* DECRQUPSS user preferred supplemental set */
786 /* 'u' must follow - need another state */
787 case '|': /* DECUDK program F6..F20 */
788 #ifdef VT100_PRINTNOTIMPL
789 printf("DCS%c ignored\n", c);
790 #endif
791 break;
792 default:
793 #ifdef VT100_PRINTUNKNOWN
794 printf("DCS%c (%d, %d) unknown\n", c, ARG(0), ARG(1));
795 #endif
796 break;
797 }
798 }
799
800 return (newstate);
801 }
802
803 static u_int
804 wsemul_vt100_output_dcs_dollar(edp, c)
805 struct wsemul_vt100_emuldata *edp;
806 u_char c;
807 {
808 switch (c) {
809 case 'p': /* DECRSTS terminal state restore */
810 case 'q': /* DECRQSS control function request */
811 #ifdef VT100_PRINTNOTIMPL
812 printf("DCS$%c ignored\n", c);
813 #endif
814 break;
815 case 't': /* DECRSPS restore presentation state */
816 switch (ARG(0)) {
817 case 0: /* error */
818 break;
819 case 1: /* cursor information restore */
820 #ifdef VT100_PRINTNOTIMPL
821 printf("DCS1$t ignored\n");
822 #endif
823 break;
824 case 2: /* tab stop restore */
825 edp->dcspos = 0;
826 edp->dcstype = DCSTYPE_TABRESTORE;
827 break;
828 default:
829 #ifdef VT100_PRINTUNKNOWN
830 printf("DCS%d$t unknown\n", ARG(0));
831 #endif
832 break;
833 }
834 break;
835 default:
836 #ifdef VT100_PRINTUNKNOWN
837 printf("DCS$%c (%d, %d) unknown\n", c, ARG(0), ARG(1));
838 #endif
839 break;
840 }
841 return (VT100_EMUL_STATE_STRING);
842 }
843
844 static u_int
845 wsemul_vt100_output_esc_hash(edp, c)
846 struct wsemul_vt100_emuldata *edp;
847 u_char c;
848 {
849 int i;
850
851 switch (c) {
852 case '5': /* DECSWL single width, single height */
853 if (edp->dw) {
854 for (i = 0; i < edp->ncols / 2; i++)
855 (*edp->emulops->copycols)(edp->emulcookie,
856 edp->crow,
857 2 * i, i, 1);
858 (*edp->emulops->erasecols)(edp->emulcookie, edp->crow,
859 i, edp->ncols - i,
860 edp->defattr);
861 edp->dblwid[edp->crow] = 0;
862 edp->dw = 0;
863 }
864 break;
865 case '6': /* DECDWL double width, single height */
866 case '3': /* DECDHL double width, double height, top half */
867 case '4': /* DECDHL double width, double height, bottom half */
868 if (!edp->dw) {
869 for (i = edp->ncols / 2 - 1; i >= 0; i--)
870 (*edp->emulops->copycols)(edp->emulcookie,
871 edp->crow,
872 i, 2 * i, 1);
873 for (i = 0; i < edp->ncols / 2; i++)
874 (*edp->emulops->erasecols)(edp->emulcookie,
875 edp->crow,
876 2 * i + 1, 1,
877 edp->defattr);
878 edp->dblwid[edp->crow] = 1;
879 edp->dw = 1;
880 if (edp->ccol > (edp->ncols >> 1) - 1)
881 edp->ccol = (edp->ncols >> 1) - 1;
882 }
883 break;
884 case '8': { /* DECALN */
885 int i, j;
886 for (i = 0; i < edp->nrows; i++)
887 for (j = 0; j < edp->ncols; j++)
888 (*edp->emulops->putchar)(edp->emulcookie, i, j,
889 'E', edp->curattr);
890 }
891 edp->ccol = 0;
892 edp->crow = 0;
893 break;
894 default:
895 #ifdef VT100_PRINTUNKNOWN
896 printf("ESC#%c unknown\n", c);
897 #endif
898 break;
899 }
900 return (VT100_EMUL_STATE_NORMAL);
901 }
902
903 static u_int
904 wsemul_vt100_output_csi(edp, c)
905 struct wsemul_vt100_emuldata *edp;
906 u_char c;
907 {
908 u_int newstate = VT100_EMUL_STATE_CSI;
909
910 switch (c) {
911 case '0': case '1': case '2': case '3': case '4':
912 case '5': case '6': case '7': case '8': case '9':
913 /* argument digit */
914 if (edp->nargs > VT100_EMUL_NARGS - 1)
915 break;
916 edp->args[edp->nargs] = (edp->args[edp->nargs] * 10) +
917 (c - '0');
918 break;
919 case ';': /* argument terminator */
920 edp->nargs++;
921 break;
922 case '?': /* DEC specific */
923 case '>': /* DA query */
924 edp->modif1 = c;
925 break;
926 case '!':
927 case '"':
928 case '$':
929 case '&':
930 edp->modif2 = c;
931 break;
932 default: /* end of escape sequence */
933 edp->nargs++;
934 if (edp->nargs > VT100_EMUL_NARGS) {
935 #ifdef VT100_DEBUG
936 printf("vt100: too many arguments\n");
937 #endif
938 edp->nargs = VT100_EMUL_NARGS;
939 }
940 wsemul_vt100_handle_csi(edp, c);
941 newstate = VT100_EMUL_STATE_NORMAL;
942 break;
943 }
944 return (newstate);
945 }
946
947 void
948 wsemul_vt100_output(cookie, data, count, kernel)
949 void *cookie;
950 const u_char *data;
951 u_int count;
952 int kernel;
953 {
954 struct wsemul_vt100_emuldata *edp = cookie;
955
956 #ifdef DIAGNOSTIC
957 if (kernel && !edp->console)
958 panic("wsemul_vt100_output: kernel output, not console");
959 #endif
960
961 if (edp->flags & VTFL_CURSORON)
962 (*edp->emulops->cursor)(edp->emulcookie, 0,
963 edp->crow, edp->ccol << edp->dw);
964 for (; count > 0; data++, count--) {
965 if ((*data & 0x7f) < 0x20) {
966 wsemul_vt100_output_c0c1(edp, *data, kernel);
967 continue;
968 }
969 if (edp->state == VT100_EMUL_STATE_NORMAL || kernel) {
970 wsemul_vt100_output_normal(edp, *data, kernel);
971 continue;
972 }
973 #ifdef DIAGNOSTIC
974 if (edp->state > sizeof(vt100_output) / sizeof(vt100_output[0]))
975 panic("wsemul_vt100: invalid state %d\n", edp->state);
976 #endif
977 edp->state = vt100_output[edp->state - 1](edp, *data);
978 }
979 if (edp->flags & VTFL_CURSORON)
980 (*edp->emulops->cursor)(edp->emulcookie, 1,
981 edp->crow, edp->ccol << edp->dw);
982 }
983