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