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