wsemul_sun.c revision 1.2 1 /* $NetBSD: wsemul_sun.c,v 1.2 1998/03/27 18:22:36 drochner Exp $ */
2
3 /*
4 * Copyright (c) 1996, 1997 Christopher G. Demetriou. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by Christopher G. Demetriou
17 * for the NetBSD Project.
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 static const char _copyright[] __attribute__ ((unused)) =
34 "Copyright (c) 1996, 1997 Christopher G. Demetriou. All rights reserved.";
35 static const char _rcsid[] __attribute__ ((unused)) =
36 "$NetBSD: wsemul_sun.c,v 1.2 1998/03/27 18:22:36 drochner Exp $";
37
38 /* XXX DESCRIPTION/SOURCE OF INFORMATION */
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/time.h>
43 #include <sys/malloc.h>
44 #include <sys/fcntl.h>
45
46 #include <dev/wscons/wsconsio.h>
47 #include <dev/wscons/wsdisplayvar.h>
48 #include <dev/wscons/wsemulvar.h>
49 #include <dev/wscons/ascii.h>
50
51 void *wsemul_sun_cnattach __P((const struct wsscreen_descr *, void *,
52 int, int));
53 void *wsemul_sun_attach __P((int console, const struct wsscreen_descr *,
54 void *, int, int, void *));
55 void wsemul_sun_output __P((void *cookie, const u_char *data, u_int count));
56 void wsemul_sun_detach __P((void *cookie, u_int *crowp, u_int *ccolp));
57
58 const struct wsemul_ops wsemul_sun_ops = {
59 "sun",
60 wsemul_sun_cnattach,
61 wsemul_sun_attach,
62 wsemul_sun_output,
63 wsemul_sun_detach,
64 };
65
66 #define SUN_EMUL_STATE_NORMAL 0 /* normal processing */
67 #define SUN_EMUL_STATE_HAVEESC 1 /* seen start of ctl seq */
68 #define SUN_EMUL_STATE_CONTROL 2 /* processing ctl seq */
69
70 #define SUN_EMUL_NARGS 2 /* max # of args to a command */
71
72 struct wsemul_sun_emuldata {
73 const struct wsdisplay_emulops *emulops;
74 void *emulcookie;
75 void *cbcookie;
76 u_int nrows, ncols, crow, ccol;
77
78 u_int state; /* processing state */
79 u_int args[SUN_EMUL_NARGS]; /* command args, if CONTROL */
80 u_int scrolldist; /* distance to scroll */
81 };
82
83 static u_int wsemul_sun_output_normal __P((struct wsemul_sun_emuldata *,
84 u_char));
85 static u_int wsemul_sun_output_haveesc __P((struct wsemul_sun_emuldata *,
86 u_char));
87 static u_int wsemul_sun_output_control __P((struct wsemul_sun_emuldata *,
88 u_char));
89 static void wsemul_sun_control __P((struct wsemul_sun_emuldata *, u_char));
90
91 struct wsemul_sun_emuldata wsemul_sun_console_emuldata;
92
93 /* some useful utility macros */
94 #define ARG(n) (edp->args[(n)])
95 #define NORMALIZE_ARG(n) (ARG(n) ? ARG(n) : 1)
96 #define COLS_LEFT (edp->ncols - edp->ccol - 1)
97 #define ROWS_LEFT (edp->nrows - edp->crow - 1)
98
99 void *
100 wsemul_sun_cnattach(type, cookie, ccol, crow)
101 const struct wsscreen_descr *type;
102 void *cookie;
103 int ccol, crow;
104 {
105 struct wsemul_sun_emuldata *edp;
106
107 edp = &wsemul_sun_console_emuldata;
108
109 edp->emulops = type->textops;
110 edp->emulcookie = cookie;
111 edp->nrows = type->nrows;
112 edp->ncols = type->ncols;
113 edp->crow = crow;
114 edp->ccol = ccol;
115 edp->cbcookie = NULL;
116
117 edp->state = SUN_EMUL_STATE_NORMAL;
118 edp->scrolldist = 1;
119
120 return (edp);
121 }
122
123 void *
124 wsemul_sun_attach(console, type, cookie, ccol, crow, cbcookie)
125 int console;
126 const struct wsscreen_descr *type;
127 void *cookie;
128 int ccol, crow;
129 void *cbcookie;
130 {
131 struct wsemul_sun_emuldata *edp;
132
133 if (console)
134 edp = &wsemul_sun_console_emuldata;
135 else {
136 edp = malloc(sizeof *edp, M_DEVBUF, M_WAITOK);
137
138 edp->emulops = type->textops;
139 edp->emulcookie = cookie;
140 edp->nrows = type->nrows;
141 edp->ncols = type->ncols;
142 edp->crow = crow;
143 edp->ccol = ccol;
144
145 edp->state = SUN_EMUL_STATE_NORMAL;
146 edp->scrolldist = 1;
147 }
148
149 edp->cbcookie = cbcookie;
150
151 return (edp);
152 }
153
154 static inline u_int
155 wsemul_sun_output_normal(edp, c)
156 struct wsemul_sun_emuldata *edp;
157 u_char c;
158 {
159 u_int newstate = SUN_EMUL_STATE_NORMAL;
160 u_int n;
161
162 switch (c) {
163 case ASCII_BEL: /* "Bell (BEL)" */
164 wsdisplay_emulbell(edp->cbcookie);
165 break;
166
167 case ASCII_BS: /* "Backspace (BS)" */
168 if (edp->ccol > 0)
169 edp->ccol--;
170 break;
171
172 case ASCII_CR: /* "Return (CR)" */
173 edp->ccol = 0;
174 break;
175
176 case ASCII_HT: /* "Tab (TAB)" */
177 n = min(8 - (edp->ccol & 7), COLS_LEFT);
178 (*edp->emulops->erasecols)(edp->emulcookie, edp->crow,
179 edp->ccol, n);
180 edp->ccol += n;
181 break;
182
183 case ASCII_NP: /* "Form Feed (FF)" */
184 (*edp->emulops->eraserows)(edp->emulcookie, 0, edp->nrows);
185 edp->ccol = 0;
186 edp->crow = 0;
187 break;
188
189 case ASCII_VT: /* "Reverse Line Feed" */
190 if (edp->crow > 0)
191 edp->crow--;
192 break;
193
194 case ASCII_ESC: /* "Escape (ESC)" */
195 if (edp->state == SUN_EMUL_STATE_NORMAL) {
196 newstate = SUN_EMUL_STATE_HAVEESC;
197 break;
198 }
199 /* special case: fall through, we're printing one out */
200 /* FALLTHRU */
201
202 default: /* normal character */
203 (*edp->emulops->putstr)(edp->emulcookie, edp->crow, edp->ccol,
204 &c, 1);
205 edp->ccol++;
206
207 /* if cur col is still on cur line, done. */
208 if (edp->ccol < edp->ncols)
209 break;
210
211 /* wrap the column around. */
212 edp->ccol = 0;
213
214 /* FALLTHRU */
215
216 case ASCII_LF: /* "Line Feed (LF)" */
217 /* if the cur line isn't the last, incr and leave. */
218 if (edp->crow < edp->nrows - 1) {
219 edp->crow++;
220 break;
221 }
222
223 /*
224 * if we're in wrap-around mode, go to the first
225 * line and clear it.
226 */
227 if (edp->scrolldist == 0) {
228 edp->crow = 0;
229 (*edp->emulops->eraserows)(edp->emulcookie, 0, 1);
230 break;
231 }
232
233 /* scroll by the scrolling distance. */
234 (*edp->emulops->copyrows)(edp->emulcookie, edp->scrolldist, 0,
235 edp->nrows - edp->scrolldist);
236 (*edp->emulops->eraserows)(edp->emulcookie,
237 edp->nrows - edp->scrolldist, edp->scrolldist);
238 edp->crow -= edp->scrolldist - 1;
239 break;
240 }
241
242 return (newstate);
243 }
244
245 static inline u_int
246 wsemul_sun_output_haveesc(edp, c)
247 struct wsemul_sun_emuldata *edp;
248 u_char c;
249 {
250 u_int newstate;
251
252 switch (c) {
253 case '[': /* continuation of multi-char sequence */
254 bzero(edp->args, sizeof (edp->args));
255 newstate = SUN_EMUL_STATE_CONTROL;
256 break;
257
258 default:
259 /* spit out the escape char (???), then the new character */
260 wsemul_sun_output_normal(edp, ASCII_ESC); /* ??? */
261 newstate = wsemul_sun_output_normal(edp, c);
262 break;
263 }
264
265 return (newstate);
266 }
267
268 static inline void
269 wsemul_sun_control(edp, c)
270 struct wsemul_sun_emuldata *edp;
271 u_char c;
272 {
273 u_int n, src, dst;
274
275 switch (c) {
276 case '@': /* "Insert Character (ICH)" */
277 n = min(NORMALIZE_ARG(0), COLS_LEFT + 1);
278 src = edp->ccol;
279 dst = edp->ccol + n;
280 if (dst < edp->ncols) {
281 (*edp->emulops->copycols)(edp->emulcookie, edp->crow,
282 src, dst, edp->ncols - dst);
283 }
284 (*edp->emulops->erasecols)(edp->emulcookie, edp->crow,
285 src, dst - src);
286 break;
287
288 case 'E': /* "Cursor Next Line (CNL)" */
289 edp->ccol = 0;
290 /* FALLTHRU */
291 case 'A': /* "Cursor Up (CUU)" */
292 edp->crow -= min(NORMALIZE_ARG(0), edp->crow);
293 break;
294
295 case 'B': /* "Cursor Down (CUD)" */
296 edp->crow += min(NORMALIZE_ARG(0), ROWS_LEFT);
297 break;
298
299 case 'C': /* "Cursor Forward (CUF)" */
300 edp->ccol += min(NORMALIZE_ARG(0), COLS_LEFT);
301 break;
302
303 case 'D': /* "Cursor Backward (CUB)" */
304 edp->ccol -= min(NORMALIZE_ARG(0), edp->ccol);
305 break;
306
307 case 'f': /* "Horizontal And Vertical Position (HVP)" */
308 case 'H': /* "Cursor Position (CUP)" */
309 edp->crow = min(NORMALIZE_ARG(1), edp->nrows) - 1;
310 edp->ccol = min(NORMALIZE_ARG(0), edp->ncols) - 1;
311 break;
312
313 case 'J': /* "Erase in Display (ED)" */
314 if (ROWS_LEFT > 0) {
315 (*edp->emulops->eraserows)(edp->emulcookie,
316 edp->crow + 1, ROWS_LEFT);
317 }
318 /* FALLTHRU */
319 case 'K': /* "Erase in Line (EL)" */
320 (*edp->emulops->erasecols)(edp->emulcookie, edp->crow,
321 edp->ccol, COLS_LEFT + 1);
322 break;
323
324 case 'L': /* "Insert Line (IL)" */
325 n = min(NORMALIZE_ARG(0), ROWS_LEFT + 1);
326 src = edp->crow;
327 dst = edp->crow + n;
328 if (dst < edp->nrows) {
329 (*edp->emulops->copyrows)(edp->emulcookie,
330 src, dst, edp->nrows - dst);
331 }
332 (*edp->emulops->eraserows)(edp->emulcookie,
333 src, dst - src);
334 break;
335
336 case 'M': /* "Delete Line (DL)" */
337 n = min(NORMALIZE_ARG(0), ROWS_LEFT + 1);
338 src = edp->crow + n;
339 dst = edp->crow;
340 if (src < edp->nrows) {
341 (*edp->emulops->copyrows)(edp->emulcookie,
342 src, dst, edp->nrows - src);
343 }
344 (*edp->emulops->eraserows)(edp->emulcookie,
345 dst + edp->nrows - src, src - dst);
346 break;
347
348 case 'P': /* "Delete Character (DCH)" */
349 n = min(NORMALIZE_ARG(0), COLS_LEFT + 1);
350 src = edp->ccol + n;
351 dst = edp->ccol;
352 if (src < edp->ncols) {
353 (*edp->emulops->copycols)(edp->emulcookie, edp->crow,
354 src, dst, edp->ncols - src);
355 }
356 (*edp->emulops->erasecols)(edp->emulcookie, edp->crow,
357 dst + edp->ncols - src, src - dst);
358 break;
359
360 case 'm': /* "Select Graphic Rendition (SGR)" */
361 /* XXX rendition currently ignored */
362 break;
363
364 case 'p': /* "Black On White (SUNBOW)" */
365 /* XXX rendition currently ignored */
366 break;
367
368 case 'q': /* "White On Black (SUNWOB)" */
369 /* XXX rendition currently ignored */
370 break;
371
372 case 'r': /* "Set Scrolling (SUNSCRL)" */
373 edp->scrolldist = min(ARG(0), edp->nrows);
374 break;
375
376 case 's': /* "Reset Terminal Emulator (SUNRESET)" */
377 edp->scrolldist = 1;
378 /* XXX rendition aspects of this currently ignored */
379 break;
380 }
381 }
382
383 static inline u_int
384 wsemul_sun_output_control(edp, c)
385 struct wsemul_sun_emuldata *edp;
386 u_char c;
387 {
388 u_int newstate = SUN_EMUL_STATE_CONTROL;
389 u_int i;
390
391 switch (c) {
392 case '0': case '1': case '2': case '3': case '4': /* argument digit */
393 case '5': case '6': case '7': case '8': case '9':
394 edp->args[0] = (edp->args[0] * 10) + (c - '0');
395 break;
396
397 case ';': /* argument terminator */
398 for (i = 1; i < SUN_EMUL_NARGS; i++)
399 edp->args[i] = edp->args[i - 1];
400 edp->args[0] = 0;
401 break;
402
403 default: /* end of escape sequence */
404 wsemul_sun_control(edp, c);
405 newstate = SUN_EMUL_STATE_NORMAL;
406 break;
407 }
408 return (newstate);
409 }
410
411 void
412 wsemul_sun_output(cookie, data, count)
413 void *cookie;
414 const u_char *data;
415 u_int count;
416 {
417 struct wsemul_sun_emuldata *edp = cookie;
418 u_int newstate;
419
420 /* XXX */
421 (*edp->emulops->cursor)(edp->emulcookie, 0, edp->crow, edp->ccol);
422 for (; count > 0; data++, count--) {
423 switch (edp->state) {
424 case SUN_EMUL_STATE_NORMAL:
425 /* XXX SCAN INPUT FOR NEWLINES, DO PRESCROLLING */
426 newstate = wsemul_sun_output_normal(edp, *data);
427 break;
428 case SUN_EMUL_STATE_HAVEESC:
429 newstate = wsemul_sun_output_haveesc(edp, *data);
430 break;
431 case SUN_EMUL_STATE_CONTROL:
432 newstate = wsemul_sun_output_control(edp, *data);
433 break;
434 default:
435 #ifdef DIAGNOSTIC
436 panic("wsemul_sun: invalid state %d\n", edp->state);
437 #endif
438 /* try to recover, if things get screwed up... */
439 newstate = wsemul_sun_output_normal(edp, *data);
440 break;
441 }
442 edp->state = newstate;
443 }
444 /* XXX */
445 (*edp->emulops->cursor)(edp->emulcookie, 1, edp->crow, edp->ccol);
446 }
447
448 void
449 wsemul_sun_detach(cookie, crowp, ccolp)
450 void *cookie;
451 u_int *crowp, *ccolp;
452 {
453 struct wsemul_sun_emuldata *edp = cookie;
454
455 *crowp = edp->crow;
456 *ccolp = edp->ccol;
457 if (edp != &wsemul_sun_console_emuldata)
458 free(edp, M_DEVBUF);
459 }
460