1 /* $OpenBSD: wsemul_vt100.c,v 1.48 2024/11/05 08:12:08 miod Exp $ */
2 /* $NetBSD: wsemul_vt100.c,v 1.13 2000/04/28 21:56:16 mycroft Exp $ */
3
4 /*
5 * Copyright (c) 2007, 2013 Miodrag Vallat.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice, this permission notice, and the disclaimer below
10 * appear in all copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 */
20 /*
21 * Copyright (c) 1998
22 * Matthias Drochner. All rights reserved.
23 *
24 * Redistribution and use in source and binary forms, with or without
25 * modification, are permitted provided that the following conditions
26 * are met:
27 * 1. Redistributions of source code must retain the above copyright
28 * notice, this list of conditions and the following disclaimer.
29 * 2. Redistributions in binary form must reproduce the above copyright
30 * notice, this list of conditions and the following disclaimer in the
31 * documentation and/or other materials provided with the distribution.
32 *
33 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
34 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
36 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
37 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
38 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
39 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
40 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
41 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
42 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43 *
44 */
45
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/time.h>
49 #include <sys/malloc.h>
50 #include <sys/fcntl.h>
51
52 #include <dev/wscons/wscons_features.h>
53 #include <dev/wscons/wsconsio.h>
54 #include <dev/wscons/wsdisplayvar.h>
55 #include <dev/wscons/wsemulvar.h>
56 #include <dev/wscons/wsemul_vt100var.h>
57 #include <dev/wscons/ascii.h>
58
59 void *wsemul_vt100_cnattach(const struct wsscreen_descr *, void *,
60 int, int, uint32_t);
61 void *wsemul_vt100_attach(int, const struct wsscreen_descr *,
62 void *, int, int, void *, uint32_t);
63 u_int wsemul_vt100_output(void *, const u_char *, u_int, int);
64 void wsemul_vt100_detach(void *, u_int *, u_int *);
65 void wsemul_vt100_resetop(void *, enum wsemul_resetops);
66
67 const struct wsemul_ops wsemul_vt100_ops = {
68 "vt100",
69 wsemul_vt100_cnattach,
70 wsemul_vt100_attach,
71 wsemul_vt100_output,
72 wsemul_vt100_translate,
73 wsemul_vt100_detach,
74 wsemul_vt100_resetop
75 };
76
77 struct wsemul_vt100_emuldata wsemul_vt100_console_emuldata;
78
79 void wsemul_vt100_init(struct wsemul_vt100_emuldata *,
80 const struct wsscreen_descr *, void *, int, int, uint32_t);
81 int wsemul_vt100_jump_scroll(struct wsemul_vt100_emuldata *,
82 const u_char *, u_int, int);
83 int wsemul_vt100_output_c0c1(struct wsemul_vt100_emuldata *,
84 struct wsemul_inputstate *, int);
85 int wsemul_vt100_nextline(struct wsemul_vt100_emuldata *);
86
87 typedef int vt100_handler(struct wsemul_vt100_emuldata *, struct
88 wsemul_inputstate *, int);
89 vt100_handler
90 wsemul_vt100_output_esc,
91 wsemul_vt100_output_csi,
92 wsemul_vt100_output_scs94,
93 wsemul_vt100_output_scs94_percent,
94 wsemul_vt100_output_scs96,
95 wsemul_vt100_output_scs96_percent,
96 wsemul_vt100_output_esc_hash,
97 wsemul_vt100_output_esc_spc,
98 wsemul_vt100_output_string,
99 wsemul_vt100_output_string_esc,
100 wsemul_vt100_output_dcs,
101 wsemul_vt100_output_dcs_dollar,
102 wsemul_vt100_output_esc_percent;
103
104 #define VT100_EMUL_STATE_NORMAL 0 /* normal processing */
105 #define VT100_EMUL_STATE_ESC 1 /* got ESC */
106 #define VT100_EMUL_STATE_CSI 2 /* got CSI (ESC[) */
107 #define VT100_EMUL_STATE_SCS94 3 /* got ESC{()*+} */
108 #define VT100_EMUL_STATE_SCS94_PERCENT 4 /* got ESC{()*+}% */
109 #define VT100_EMUL_STATE_SCS96 5 /* got ESC{-./} */
110 #define VT100_EMUL_STATE_SCS96_PERCENT 6 /* got ESC{-./}% */
111 #define VT100_EMUL_STATE_ESC_HASH 7 /* got ESC# */
112 #define VT100_EMUL_STATE_ESC_SPC 8 /* got ESC<SPC> */
113 #define VT100_EMUL_STATE_STRING 9 /* waiting for ST (ESC\) */
114 #define VT100_EMUL_STATE_STRING_ESC 10 /* waiting for ST, got ESC */
115 #define VT100_EMUL_STATE_DCS 11 /* got DCS (ESC P) */
116 #define VT100_EMUL_STATE_DCS_DOLLAR 12 /* got DCS<p>$ */
117 #define VT100_EMUL_STATE_ESC_PERCENT 13 /* got ESC% */
118
119 vt100_handler *vt100_output[] = {
120 wsemul_vt100_output_esc,
121 wsemul_vt100_output_csi,
122 wsemul_vt100_output_scs94,
123 wsemul_vt100_output_scs94_percent,
124 wsemul_vt100_output_scs96,
125 wsemul_vt100_output_scs96_percent,
126 wsemul_vt100_output_esc_hash,
127 wsemul_vt100_output_esc_spc,
128 wsemul_vt100_output_string,
129 wsemul_vt100_output_string_esc,
130 wsemul_vt100_output_dcs,
131 wsemul_vt100_output_dcs_dollar,
132 wsemul_vt100_output_esc_percent,
133 };
134
135 void
wsemul_vt100_init(struct wsemul_vt100_emuldata * edp,const struct wsscreen_descr * type,void * cookie,int ccol,int crow,uint32_t defattr)136 wsemul_vt100_init(struct wsemul_vt100_emuldata *edp,
137 const struct wsscreen_descr *type, void *cookie, int ccol, int crow,
138 uint32_t defattr)
139 {
140 edp->emulops = type->textops;
141 edp->emulcookie = cookie;
142 edp->scrcapabilities = type->capabilities;
143 edp->nrows = type->nrows;
144 edp->ncols = type->ncols;
145 edp->crow = crow;
146 edp->ccol = ccol;
147 edp->defattr = defattr;
148 wsemul_reset_abortstate(&edp->abortstate);
149 }
150
151 void *
wsemul_vt100_cnattach(const struct wsscreen_descr * type,void * cookie,int ccol,int crow,uint32_t defattr)152 wsemul_vt100_cnattach(const struct wsscreen_descr *type, void *cookie, int ccol,
153 int crow, uint32_t defattr)
154 {
155 struct wsemul_vt100_emuldata *edp;
156 int res;
157
158 edp = &wsemul_vt100_console_emuldata;
159 wsemul_vt100_init(edp, type, cookie, ccol, crow, defattr);
160 #ifdef DIAGNOSTIC
161 edp->console = 1;
162 #endif
163 edp->cbcookie = NULL;
164
165 #ifndef WS_KERNEL_FG
166 #define WS_KERNEL_FG WSCOL_WHITE
167 #endif
168 #ifndef WS_KERNEL_BG
169 #define WS_KERNEL_BG WSCOL_BLUE
170 #endif
171 #ifndef WS_KERNEL_COLATTR
172 #define WS_KERNEL_COLATTR 0
173 #endif
174 #ifndef WS_KERNEL_MONOATTR
175 #define WS_KERNEL_MONOATTR 0
176 #endif
177 if (type->capabilities & WSSCREEN_WSCOLORS)
178 res = (*edp->emulops->pack_attr)(cookie,
179 WS_KERNEL_FG, WS_KERNEL_BG,
180 WS_KERNEL_COLATTR | WSATTR_WSCOLORS, &edp->kernattr);
181 else
182 res = (*edp->emulops->pack_attr)(cookie, 0, 0,
183 WS_KERNEL_MONOATTR, &edp->kernattr);
184 if (res)
185 edp->kernattr = defattr;
186
187 edp->tabs = NULL;
188 #ifdef HAVE_DOUBLE_WIDTH_HEIGHT
189 edp->dblwid = NULL;
190 edp->dw = 0;
191 #endif
192 edp->dcsarg = NULL;
193 edp->isolatin1tab = edp->decgraphtab = edp->dectechtab = NULL;
194 edp->nrctab = NULL;
195 wsemul_vt100_reset(edp);
196 return (edp);
197 }
198
199 void *
wsemul_vt100_attach(int console,const struct wsscreen_descr * type,void * cookie,int ccol,int crow,void * cbcookie,uint32_t defattr)200 wsemul_vt100_attach(int console, const struct wsscreen_descr *type,
201 void *cookie, int ccol, int crow, void *cbcookie, uint32_t defattr)
202 {
203 struct wsemul_vt100_emuldata *edp;
204
205 if (console) {
206 edp = &wsemul_vt100_console_emuldata;
207 KASSERT(edp->console == 1);
208 } else {
209 edp = malloc(sizeof *edp, M_DEVBUF, M_NOWAIT);
210 if (edp == NULL)
211 return (NULL);
212 wsemul_vt100_init(edp, type, cookie, ccol, crow, defattr);
213 #ifdef DIAGNOSTIC
214 edp->console = 0;
215 #endif
216 }
217 edp->cbcookie = cbcookie;
218
219 edp->tabs = malloc(edp->ncols, M_DEVBUF, M_NOWAIT);
220 #ifdef HAVE_DOUBLE_WIDTH_HEIGHT
221 edp->dblwid = malloc(edp->nrows, M_DEVBUF, M_NOWAIT | M_ZERO);
222 edp->dw = 0;
223 #endif
224 edp->dcsarg = malloc(DCS_MAXLEN, M_DEVBUF, M_NOWAIT);
225 edp->isolatin1tab = malloc(128 * sizeof(u_int), M_DEVBUF, M_NOWAIT);
226 edp->decgraphtab = malloc(128 * sizeof(u_int), M_DEVBUF, M_NOWAIT);
227 edp->dectechtab = malloc(128 * sizeof(u_int), M_DEVBUF, M_NOWAIT);
228 edp->nrctab = malloc(128 * sizeof(u_int), M_DEVBUF, M_NOWAIT);
229 vt100_initchartables(edp);
230 wsemul_vt100_reset(edp);
231 return (edp);
232 }
233
234 void
wsemul_vt100_detach(void * cookie,u_int * crowp,u_int * ccolp)235 wsemul_vt100_detach(void *cookie, u_int *crowp, u_int *ccolp)
236 {
237 struct wsemul_vt100_emuldata *edp = cookie;
238
239 *crowp = edp->crow;
240 *ccolp = edp->ccol;
241 #define f(ptr) do { free(ptr, M_DEVBUF, 0); ptr = NULL; } while (0)
242 f(edp->tabs);
243 #ifdef HAVE_DOUBLE_WIDTH_HEIGHT
244 f(edp->dblwid);
245 #endif
246 f(edp->dcsarg);
247 f(edp->isolatin1tab);
248 f(edp->decgraphtab);
249 f(edp->dectechtab);
250 f(edp->nrctab);
251 #undef f
252 if (edp != &wsemul_vt100_console_emuldata)
253 free(edp, M_DEVBUF, sizeof *edp);
254 }
255
256 void
wsemul_vt100_resetop(void * cookie,enum wsemul_resetops op)257 wsemul_vt100_resetop(void *cookie, enum wsemul_resetops op)
258 {
259 struct wsemul_vt100_emuldata *edp = cookie;
260
261 switch (op) {
262 case WSEMUL_RESET:
263 wsemul_vt100_reset(edp);
264 break;
265 case WSEMUL_SYNCFONT:
266 vt100_initchartables(edp);
267 break;
268 case WSEMUL_CLEARSCREEN:
269 (void)wsemul_vt100_ed(edp, 2);
270 edp->ccol = edp->crow = 0;
271 (*edp->emulops->cursor)(edp->emulcookie,
272 edp->flags & VTFL_CURSORON, 0, 0);
273 break;
274 case WSEMUL_CLEARCURSOR:
275 (*edp->emulops->cursor)(edp->emulcookie, 0, edp->crow,
276 edp->ccol);
277 break;
278 default:
279 break;
280 }
281 }
282
283 void
wsemul_vt100_reset(struct wsemul_vt100_emuldata * edp)284 wsemul_vt100_reset(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] = NULL;
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 edp->instate.inchar = 0;
311 edp->instate.lbound = 0;
312 edp->instate.mbleft = 0;
313 edp->instate.last_output = 0;
314 edp->kstate.inchar = 0;
315 edp->kstate.lbound = 0;
316 edp->kstate.mbleft = 0;
317 edp->kstate.last_output = 0;
318 }
319
320 /*
321 * Move the cursor to the next line if possible. If the cursor is at
322 * the bottom of the scroll area, then scroll it up. If the cursor is
323 * at the bottom of the screen then don't move it down.
324 */
325 int
wsemul_vt100_nextline(struct wsemul_vt100_emuldata * edp)326 wsemul_vt100_nextline(struct wsemul_vt100_emuldata *edp)
327 {
328 int rc;
329
330 if (ROWS_BELOW == 0) {
331 /* Bottom of the scroll region. */
332 rc = wsemul_vt100_scrollup(edp, 1);
333 } else {
334 if ((edp->crow+1) < edp->nrows)
335 /* Cursor not at the bottom of the screen. */
336 edp->crow++;
337 CHECK_DW;
338 rc = 0;
339 }
340
341 return rc;
342 }
343
344 /*
345 * now all the state machine bits
346 */
347
348 int
wsemul_vt100_output_normal(struct wsemul_vt100_emuldata * edp,struct wsemul_inputstate * instate,int kernel,int count)349 wsemul_vt100_output_normal(struct wsemul_vt100_emuldata *edp,
350 struct wsemul_inputstate *instate, int kernel, int count)
351 {
352 u_int *ct, dc;
353 u_char c;
354 int oldsschartab = edp->sschartab;
355 int m;
356 int rc = 0;
357
358 #ifdef HAVE_UTF8_SUPPORT
359 if (edp->flags & VTFL_UTF8) {
360 (*edp->emulops->mapchar)(edp->emulcookie, instate->inchar, &dc);
361 } else
362 #endif
363 {
364 c = instate->inchar & 0xff;
365 if (c & 0x80) {
366 c &= 0x7f;
367 ct = edp->chartab_G[edp->chartab1];
368 } else {
369 if (edp->sschartab) {
370 ct = edp->chartab_G[edp->sschartab];
371 edp->sschartab = 0;
372 } else
373 ct = edp->chartab_G[edp->chartab0];
374 }
375 dc = ct ? ct[c] : c;
376 }
377
378 for (m = 0; m < count; m++) {
379 if ((edp->flags & (VTFL_LASTCHAR | VTFL_DECAWM)) ==
380 (VTFL_LASTCHAR | VTFL_DECAWM)) {
381 rc = wsemul_vt100_nextline(edp);
382 if (rc != 0)
383 return rc;
384 edp->ccol = 0;
385 edp->flags &= ~VTFL_LASTCHAR;
386 }
387
388 if ((edp->flags & VTFL_INSERTMODE) && COLS_LEFT) {
389 WSEMULOP(rc, edp, &edp->abortstate, copycols,
390 COPYCOLS(edp->ccol, edp->ccol + 1, COLS_LEFT));
391 if (rc != 0)
392 break;
393 }
394
395 #ifdef HAVE_DOUBLE_WIDTH_HEIGHT
396 WSEMULOP(rc, edp, &edp->abortstate, putchar,
397 (edp->emulcookie, edp->crow, edp->ccol << edp->dw, dc,
398 kernel ? edp->kernattr : edp->curattr));
399 #else
400 WSEMULOP(rc, edp, &edp->abortstate, putchar,
401 (edp->emulcookie, edp->crow, edp->ccol, dc,
402 kernel ? edp->kernattr : edp->curattr));
403 #endif
404 if (rc != 0)
405 break;
406
407 if (COLS_LEFT)
408 edp->ccol++;
409 else
410 edp->flags |= VTFL_LASTCHAR;
411 }
412
413 if (rc != 0) {
414 /* undo potential sschartab update */
415 edp->sschartab = oldsschartab;
416
417 return rc;
418 }
419
420 return 0;
421 }
422
423 int
wsemul_vt100_output_c0c1(struct wsemul_vt100_emuldata * edp,struct wsemul_inputstate * instate,int kernel)424 wsemul_vt100_output_c0c1(struct wsemul_vt100_emuldata *edp,
425 struct wsemul_inputstate *instate, int kernel)
426 {
427 u_int n;
428 int rc = 0;
429
430 switch (instate->inchar) {
431 case ASCII_NUL:
432 default:
433 /* ignore */
434 break;
435 case ASCII_BEL:
436 if (edp->state == VT100_EMUL_STATE_STRING) {
437 /* acts as an equivalent to the ``ESC \'' string end */
438 wsemul_vt100_handle_dcs(edp);
439 edp->state = VT100_EMUL_STATE_NORMAL;
440 } else {
441 wsdisplay_emulbell(edp->cbcookie);
442 }
443 break;
444 case ASCII_BS:
445 if (edp->ccol > 0) {
446 edp->ccol--;
447 edp->flags &= ~VTFL_LASTCHAR;
448 }
449 break;
450 case ASCII_CR:
451 edp->ccol = 0;
452 break;
453 case ASCII_HT:
454 if (edp->tabs) {
455 if (!COLS_LEFT)
456 break;
457 for (n = edp->ccol + 1; n < NCOLS - 1; n++)
458 if (edp->tabs[n])
459 break;
460 } else {
461 n = edp->ccol + min(8 - (edp->ccol & 7), COLS_LEFT);
462 }
463 edp->ccol = n;
464 break;
465 case ASCII_SO: /* LS1 */
466 edp->flags &= ~VTFL_UTF8;
467 edp->chartab0 = 1;
468 break;
469 case ASCII_SI: /* LS0 */
470 edp->flags &= ~VTFL_UTF8;
471 edp->chartab0 = 0;
472 break;
473 case ASCII_ESC:
474 if (kernel) {
475 printf("wsemul_vt100_output_c0c1: ESC in kernel "
476 "output ignored\n");
477 break; /* ignore the ESC */
478 }
479
480 if (edp->state == VT100_EMUL_STATE_STRING) {
481 /* might be a string end */
482 edp->state = VT100_EMUL_STATE_STRING_ESC;
483 } else {
484 /* XXX cancel current escape sequence */
485 edp->state = VT100_EMUL_STATE_ESC;
486 }
487 break;
488 case ASCII_CAN:
489 case ASCII_SUB:
490 /* cancel current escape sequence */
491 edp->state = VT100_EMUL_STATE_NORMAL;
492 break;
493 case ASCII_LF:
494 case ASCII_VT:
495 case ASCII_FF:
496 rc = wsemul_vt100_nextline(edp);
497 break;
498 }
499
500 if (COLS_LEFT != 0)
501 edp->flags &= ~VTFL_LASTCHAR;
502
503 return rc;
504 }
505
506 int
wsemul_vt100_output_esc(struct wsemul_vt100_emuldata * edp,struct wsemul_inputstate * instate,int kernel)507 wsemul_vt100_output_esc(struct wsemul_vt100_emuldata *edp,
508 struct wsemul_inputstate *instate, int kernel)
509 {
510 u_int newstate = VT100_EMUL_STATE_NORMAL;
511 int rc = 0;
512 int i;
513
514 switch (instate->inchar) {
515 case '[': /* CSI */
516 edp->nargs = 0;
517 memset(edp->args, 0, sizeof (edp->args));
518 edp->modif1 = edp->modif2 = '\0';
519 newstate = VT100_EMUL_STATE_CSI;
520 break;
521 case '7': /* DECSC */
522 edp->flags |= VTFL_SAVEDCURS;
523 edp->savedcursor_row = edp->crow;
524 edp->savedcursor_col = edp->ccol;
525 edp->savedattr = edp->curattr;
526 edp->savedbkgdattr = edp->bkgdattr;
527 edp->savedattrflags = edp->attrflags;
528 edp->savedfgcol = edp->fgcol;
529 edp->savedbgcol = edp->bgcol;
530 for (i = 0; i < 4; i++)
531 edp->savedchartab_G[i] = edp->chartab_G[i];
532 edp->savedchartab0 = edp->chartab0;
533 edp->savedchartab1 = edp->chartab1;
534 break;
535 case '8': /* DECRC */
536 if ((edp->flags & VTFL_SAVEDCURS) == 0)
537 break;
538 edp->crow = edp->savedcursor_row;
539 edp->ccol = edp->savedcursor_col;
540 edp->curattr = edp->savedattr;
541 edp->bkgdattr = edp->savedbkgdattr;
542 edp->attrflags = edp->savedattrflags;
543 edp->fgcol = edp->savedfgcol;
544 edp->bgcol = edp->savedbgcol;
545 for (i = 0; i < 4; i++)
546 edp->chartab_G[i] = edp->savedchartab_G[i];
547 edp->chartab0 = edp->savedchartab0;
548 edp->chartab1 = edp->savedchartab1;
549 break;
550 case '=': /* DECKPAM application mode */
551 edp->flags |= VTFL_APPLKEYPAD;
552 break;
553 case '>': /* DECKPNM numeric mode */
554 edp->flags &= ~VTFL_APPLKEYPAD;
555 break;
556 case 'E': /* NEL */
557 edp->ccol = 0;
558 /* FALLTHROUGH */
559 case 'D': /* IND */
560 rc = wsemul_vt100_nextline(edp);
561 break;
562 case 'H': /* HTS */
563 if (edp->tabs != NULL)
564 edp->tabs[edp->ccol] = 1;
565 break;
566 case '~': /* LS1R */
567 edp->flags &= ~VTFL_UTF8;
568 edp->chartab1 = 1;
569 break;
570 case 'n': /* LS2 */
571 edp->flags &= ~VTFL_UTF8;
572 edp->chartab0 = 2;
573 break;
574 case '}': /* LS2R */
575 edp->flags &= ~VTFL_UTF8;
576 edp->chartab1 = 2;
577 break;
578 case 'o': /* LS3 */
579 edp->flags &= ~VTFL_UTF8;
580 edp->chartab0 = 3;
581 break;
582 case '|': /* LS3R */
583 edp->flags &= ~VTFL_UTF8;
584 edp->chartab1 = 3;
585 break;
586 case 'N': /* SS2 */
587 edp->flags &= ~VTFL_UTF8;
588 edp->sschartab = 2;
589 break;
590 case 'O': /* SS3 */
591 edp->flags &= ~VTFL_UTF8;
592 edp->sschartab = 3;
593 break;
594 case 'M': /* RI */
595 i = ROWS_ABOVE;
596 if (i > 0) {
597 if (edp->crow > 0)
598 edp->crow--;
599 CHECK_DW;
600 } else if (i == 0) {
601 /* Top of scroll region. */
602 rc = wsemul_vt100_scrolldown(edp, 1);
603 }
604 break;
605 case 'P': /* DCS */
606 edp->nargs = 0;
607 memset(edp->args, 0, sizeof (edp->args));
608 newstate = VT100_EMUL_STATE_DCS;
609 break;
610 case 'c': /* RIS */
611 wsemul_vt100_reset(edp);
612 rc = wsemul_vt100_ed(edp, 2);
613 if (rc != 0)
614 break;
615 edp->ccol = edp->crow = 0;
616 break;
617 case '(': case ')': case '*': case '+': /* SCS */
618 edp->designating = instate->inchar - '(';
619 newstate = VT100_EMUL_STATE_SCS94;
620 break;
621 case '-': case '.': case '/': /* SCS */
622 edp->designating = instate->inchar - '-' + 1;
623 newstate = VT100_EMUL_STATE_SCS96;
624 break;
625 case '#':
626 newstate = VT100_EMUL_STATE_ESC_HASH;
627 break;
628 case ' ': /* 7/8 bit */
629 newstate = VT100_EMUL_STATE_ESC_SPC;
630 break;
631 case ']': /* OSC operating system command */
632 case '^': /* PM privacy message */
633 case '_': /* APC application program command */
634 /* ignored */
635 newstate = VT100_EMUL_STATE_STRING;
636 break;
637 case '<': /* exit VT52 mode - ignored */
638 break;
639 case '%': /* UTF-8 encoding sequences */
640 newstate = VT100_EMUL_STATE_ESC_PERCENT;
641 break;
642 default:
643 #ifdef VT100_PRINTUNKNOWN
644 printf("ESC %x unknown\n", instate->inchar);
645 #endif
646 break;
647 }
648
649 if (COLS_LEFT != 0)
650 edp->flags &= ~VTFL_LASTCHAR;
651
652 if (rc != 0)
653 return rc;
654
655 edp->state = newstate;
656 return 0;
657 }
658
659 int
wsemul_vt100_output_scs94(struct wsemul_vt100_emuldata * edp,struct wsemul_inputstate * instate,int kernel)660 wsemul_vt100_output_scs94(struct wsemul_vt100_emuldata *edp,
661 struct wsemul_inputstate *instate, int kernel)
662 {
663 u_int newstate = VT100_EMUL_STATE_NORMAL;
664
665 switch (instate->inchar) {
666 case '%': /* probably DEC supplemental graphic */
667 newstate = VT100_EMUL_STATE_SCS94_PERCENT;
668 break;
669 case 'A': /* british / national */
670 edp->flags &= ~VTFL_UTF8;
671 edp->chartab_G[edp->designating] = edp->nrctab;
672 break;
673 case 'B': /* ASCII */
674 edp->flags &= ~VTFL_UTF8;
675 edp->chartab_G[edp->designating] = 0;
676 break;
677 case '<': /* user preferred supplemental */
678 /* XXX not really "user" preferred */
679 edp->flags &= ~VTFL_UTF8;
680 edp->chartab_G[edp->designating] = edp->isolatin1tab;
681 break;
682 case '0': /* DEC special graphic */
683 edp->flags &= ~VTFL_UTF8;
684 edp->chartab_G[edp->designating] = edp->decgraphtab;
685 break;
686 case '>': /* DEC tech */
687 edp->flags &= ~VTFL_UTF8;
688 edp->chartab_G[edp->designating] = edp->dectechtab;
689 break;
690 default:
691 #ifdef VT100_PRINTUNKNOWN
692 printf("ESC%c %x unknown\n", edp->designating + '(',
693 instate->inchar);
694 #endif
695 break;
696 }
697
698 edp->state = newstate;
699 return 0;
700 }
701
702 int
wsemul_vt100_output_scs94_percent(struct wsemul_vt100_emuldata * edp,struct wsemul_inputstate * instate,int kernel)703 wsemul_vt100_output_scs94_percent(struct wsemul_vt100_emuldata *edp,
704 struct wsemul_inputstate *instate, int kernel)
705 {
706 switch (instate->inchar) {
707 case '5': /* DEC supplemental graphic */
708 /* XXX there are differences */
709 edp->flags &= ~VTFL_UTF8;
710 edp->chartab_G[edp->designating] = edp->isolatin1tab;
711 break;
712 default:
713 #ifdef VT100_PRINTUNKNOWN
714 printf("ESC%c%% %x unknown\n", edp->designating + '(',
715 instate->inchar);
716 #endif
717 break;
718 }
719
720 edp->state = VT100_EMUL_STATE_NORMAL;
721 return 0;
722 }
723
724 int
wsemul_vt100_output_scs96(struct wsemul_vt100_emuldata * edp,struct wsemul_inputstate * instate,int kernel)725 wsemul_vt100_output_scs96(struct wsemul_vt100_emuldata *edp,
726 struct wsemul_inputstate *instate, int kernel)
727 {
728 u_int newstate = VT100_EMUL_STATE_NORMAL;
729 int nrc;
730
731 switch (instate->inchar) {
732 case '%': /* probably portuguese */
733 newstate = VT100_EMUL_STATE_SCS96_PERCENT;
734 break;
735 case 'A': /* ISO-latin-1 supplemental */
736 edp->flags &= ~VTFL_UTF8;
737 edp->chartab_G[edp->designating] = edp->isolatin1tab;
738 break;
739 case '4': /* dutch */
740 nrc = 1;
741 goto setnrc;
742 case '5': case 'C': /* finnish */
743 nrc = 2;
744 goto setnrc;
745 case 'R': /* french */
746 nrc = 3;
747 goto setnrc;
748 case 'Q': /* french canadian */
749 nrc = 4;
750 goto setnrc;
751 case 'K': /* german */
752 nrc = 5;
753 goto setnrc;
754 case 'Y': /* italian */
755 nrc = 6;
756 goto setnrc;
757 case 'E': case '6': /* norwegian / danish */
758 nrc = 7;
759 goto setnrc;
760 case 'Z': /* spanish */
761 nrc = 9;
762 goto setnrc;
763 case '7': case 'H': /* swedish */
764 nrc = 10;
765 goto setnrc;
766 case '=': /* swiss */
767 nrc = 11;
768 setnrc:
769 if (vt100_setnrc(edp, nrc) == 0) /* what table ??? */
770 break;
771 /* else FALLTHROUGH */
772 default:
773 #ifdef VT100_PRINTUNKNOWN
774 printf("ESC%c %x unknown\n", edp->designating + '-' - 1,
775 instate->inchar);
776 #endif
777 break;
778 }
779
780 edp->state = newstate;
781 return 0;
782 }
783
784 int
wsemul_vt100_output_scs96_percent(struct wsemul_vt100_emuldata * edp,struct wsemul_inputstate * instate,int kernel)785 wsemul_vt100_output_scs96_percent(struct wsemul_vt100_emuldata *edp,
786 struct wsemul_inputstate *instate, int kernel)
787 {
788 switch (instate->inchar) {
789 case '6': /* portuguese */
790 if (vt100_setnrc(edp, 8) == 0)
791 break;
792 /* else FALLTHROUGH */
793 default:
794 #ifdef VT100_PRINTUNKNOWN
795 printf("ESC%c%% %x unknown\n", edp->designating + '-' - 1,
796 instate->inchar);
797 #endif
798 break;
799 }
800
801 edp->state = VT100_EMUL_STATE_NORMAL;
802 return 0;
803 }
804
805 int
wsemul_vt100_output_esc_spc(struct wsemul_vt100_emuldata * edp,struct wsemul_inputstate * instate,int kernel)806 wsemul_vt100_output_esc_spc(struct wsemul_vt100_emuldata *edp,
807 struct wsemul_inputstate *instate, int kernel)
808 {
809 switch (instate->inchar) {
810 case 'F': /* 7-bit controls */
811 case 'G': /* 8-bit controls */
812 #ifdef VT100_PRINTNOTIMPL
813 printf("ESC<SPC> %x ignored\n", instate->inchar);
814 #endif
815 break;
816 default:
817 #ifdef VT100_PRINTUNKNOWN
818 printf("ESC<SPC> %x unknown\n", instate->inchar);
819 #endif
820 break;
821 }
822
823 edp->state = VT100_EMUL_STATE_NORMAL;
824 return 0;
825 }
826
827 int
wsemul_vt100_output_string(struct wsemul_vt100_emuldata * edp,struct wsemul_inputstate * instate,int kernel)828 wsemul_vt100_output_string(struct wsemul_vt100_emuldata *edp,
829 struct wsemul_inputstate *instate, int kernel)
830 {
831 if (edp->dcsarg && edp->dcstype && edp->dcspos < DCS_MAXLEN) {
832 if (instate->inchar & ~0xff) {
833 #ifdef VT100_PRINTUNKNOWN
834 printf("unknown char %x in DCS\n", instate->inchar);
835 #endif
836 } else
837 edp->dcsarg[edp->dcspos++] = (char)instate->inchar;
838 }
839
840 edp->state = VT100_EMUL_STATE_STRING;
841 return 0;
842 }
843
844 int
wsemul_vt100_output_string_esc(struct wsemul_vt100_emuldata * edp,struct wsemul_inputstate * instate,int kernel)845 wsemul_vt100_output_string_esc(struct wsemul_vt100_emuldata *edp,
846 struct wsemul_inputstate *instate, int kernel)
847 {
848 if (instate->inchar == '\\') { /* ST complete */
849 wsemul_vt100_handle_dcs(edp);
850 edp->state = VT100_EMUL_STATE_NORMAL;
851 } else
852 edp->state = VT100_EMUL_STATE_STRING;
853
854 return 0;
855 }
856
857 int
wsemul_vt100_output_dcs(struct wsemul_vt100_emuldata * edp,struct wsemul_inputstate * instate,int kernel)858 wsemul_vt100_output_dcs(struct wsemul_vt100_emuldata *edp,
859 struct wsemul_inputstate *instate, int kernel)
860 {
861 u_int newstate = VT100_EMUL_STATE_DCS;
862
863 switch (instate->inchar) {
864 case '0': case '1': case '2': case '3': case '4':
865 case '5': case '6': case '7': case '8': case '9':
866 /* argument digit */
867 if (edp->nargs >= VT100_EMUL_NARGS)
868 break;
869 edp->args[edp->nargs] = (edp->args[edp->nargs] * 10) +
870 (instate->inchar - '0');
871 break;
872 case ';': /* argument terminator */
873 if (edp->nargs < VT100_EMUL_NARGS)
874 edp->nargs++;
875 break;
876 default:
877 if (edp->nargs < VT100_EMUL_NARGS)
878 edp->nargs++;
879 newstate = VT100_EMUL_STATE_STRING;
880 switch (instate->inchar) {
881 case '$':
882 newstate = VT100_EMUL_STATE_DCS_DOLLAR;
883 break;
884 case '{': /* DECDLD soft charset */ /* } */
885 case '!': /* DECRQUPSS user preferred supplemental set */
886 /* 'u' must follow - need another state */
887 case '|': /* DECUDK program F6..F20 */
888 #ifdef VT100_PRINTNOTIMPL
889 printf("DCS%c ignored\n", (char)instate->inchar);
890 #endif
891 break;
892 default:
893 #ifdef VT100_PRINTUNKNOWN
894 printf("DCS %x (%d, %d) unknown\n", instate->inchar,
895 ARG(0), ARG(1));
896 #endif
897 break;
898 }
899 }
900
901 edp->state = newstate;
902 return 0;
903 }
904
905 int
wsemul_vt100_output_dcs_dollar(struct wsemul_vt100_emuldata * edp,struct wsemul_inputstate * instate,int kernel)906 wsemul_vt100_output_dcs_dollar(struct wsemul_vt100_emuldata *edp,
907 struct wsemul_inputstate *instate, int kernel)
908 {
909 switch (instate->inchar) {
910 case 'p': /* DECRSTS terminal state restore */
911 case 'q': /* DECRQSS control function request */
912 #ifdef VT100_PRINTNOTIMPL
913 printf("DCS$%c ignored\n", (char)instate->inchar);
914 #endif
915 break;
916 case 't': /* DECRSPS restore presentation state */
917 switch (ARG(0)) {
918 case 0: /* error */
919 break;
920 case 1: /* cursor information restore */
921 #ifdef VT100_PRINTNOTIMPL
922 printf("DCS1$t ignored\n");
923 #endif
924 break;
925 case 2: /* tab stop restore */
926 edp->dcspos = 0;
927 edp->dcstype = DCSTYPE_TABRESTORE;
928 break;
929 default:
930 #ifdef VT100_PRINTUNKNOWN
931 printf("DCS%d$t unknown\n", ARG(0));
932 #endif
933 break;
934 }
935 break;
936 default:
937 #ifdef VT100_PRINTUNKNOWN
938 printf("DCS$ %x (%d, %d) unknown\n",
939 instate->inchar, ARG(0), ARG(1));
940 #endif
941 break;
942 }
943
944 edp->state = VT100_EMUL_STATE_STRING;
945 return 0;
946 }
947
948 int
wsemul_vt100_output_esc_percent(struct wsemul_vt100_emuldata * edp,struct wsemul_inputstate * instate,int kernel)949 wsemul_vt100_output_esc_percent(struct wsemul_vt100_emuldata *edp,
950 struct wsemul_inputstate *instate, int kernel)
951 {
952 switch (instate->inchar) {
953 #ifdef HAVE_UTF8_SUPPORT
954 case 'G':
955 edp->flags |= VTFL_UTF8;
956 edp->kstate.mbleft = edp->instate.mbleft = 0;
957 break;
958 case '@':
959 edp->flags &= ~VTFL_UTF8;
960 break;
961 #endif
962 default:
963 #ifdef VT100_PRINTUNKNOWN
964 printf("ESC% %x unknown\n", instate->inchar);
965 #endif
966 break;
967 }
968 edp->state = VT100_EMUL_STATE_NORMAL;
969 return 0;
970 }
971
972 int
wsemul_vt100_output_esc_hash(struct wsemul_vt100_emuldata * edp,struct wsemul_inputstate * instate,int kernel)973 wsemul_vt100_output_esc_hash(struct wsemul_vt100_emuldata *edp,
974 struct wsemul_inputstate *instate, int kernel)
975 {
976 int rc = 0;
977
978 switch (instate->inchar) {
979 case '5': /* DECSWL single width, single height */
980 #ifdef HAVE_DOUBLE_WIDTH_HEIGHT
981 if (edp->dblwid != NULL && edp->dw != 0) {
982 int i;
983 for (i = 0; i < edp->ncols / 2; i++) {
984 WSEMULOP(rc, edp, &edp->abortstate, copycols,
985 (edp->emulcookie, edp->crow, 2 * i, i, 1));
986 if (rc != 0)
987 return rc;
988 }
989 WSEMULOP(rc, edp, &edp->abortstate, erasecols,
990 (edp->emulcookie, edp->crow, i, edp->ncols - i,
991 edp->bkgdattr));
992 if (rc != 0)
993 return rc;
994 edp->dblwid[edp->crow] = 0;
995 edp->dw = 0;
996 }
997 #endif
998 break;
999 case '6': /* DECDWL double width, single height */
1000 case '3': /* DECDHL double width, double height, top half */
1001 case '4': /* DECDHL double width, double height, bottom half */
1002 #ifdef HAVE_DOUBLE_WIDTH_HEIGHT
1003 if (edp->dblwid != NULL && edp->dw == 0) {
1004 int i;
1005 for (i = edp->ncols / 2 - 1; i >= 0; i--) {
1006 WSEMULOP(rc, edp, &edp->abortstate, copycols,
1007 (edp->emulcookie, edp->crow, i, 2 * i, 1));
1008 if (rc != 0)
1009 return rc;
1010 }
1011 for (i = 0; i < edp->ncols / 2; i++) {
1012 WSEMULOP(rc, edp, &edp->abortstate, erasecols,
1013 (edp->emulcookie, edp->crow, 2 * i + 1, 1,
1014 edp->bkgdattr));
1015 if (rc != 0)
1016 return rc;
1017 }
1018 edp->dblwid[edp->crow] = 1;
1019 edp->dw = 1;
1020 if (edp->ccol > (edp->ncols >> 1) - 1)
1021 edp->ccol = (edp->ncols >> 1) - 1;
1022 }
1023 #endif
1024 break;
1025 case '8': { /* DECALN */
1026 int i, j;
1027 for (i = 0; i < edp->nrows; i++)
1028 for (j = 0; j < edp->ncols; j++) {
1029 WSEMULOP(rc, edp, &edp->abortstate, putchar,
1030 (edp->emulcookie, i, j, 'E', edp->curattr));
1031 if (rc != 0)
1032 return rc;
1033 }
1034 }
1035 edp->ccol = 0;
1036 edp->crow = 0;
1037 break;
1038 default:
1039 #ifdef VT100_PRINTUNKNOWN
1040 printf("ESC# %x unknown\n", instate->inchar);
1041 #endif
1042 break;
1043 }
1044
1045 if (COLS_LEFT != 0)
1046 edp->flags &= ~VTFL_LASTCHAR;
1047
1048 edp->state = VT100_EMUL_STATE_NORMAL;
1049 return 0;
1050 }
1051
1052 int
wsemul_vt100_output_csi(struct wsemul_vt100_emuldata * edp,struct wsemul_inputstate * instate,int kernel)1053 wsemul_vt100_output_csi(struct wsemul_vt100_emuldata *edp,
1054 struct wsemul_inputstate *instate, int kernel)
1055 {
1056 u_int newstate = VT100_EMUL_STATE_CSI;
1057 int oargs;
1058 int rc = 0;
1059
1060 switch (instate->inchar) {
1061 case '0': case '1': case '2': case '3': case '4':
1062 case '5': case '6': case '7': case '8': case '9':
1063 /* argument digit */
1064 if (edp->nargs > VT100_EMUL_NARGS - 1)
1065 break;
1066 edp->args[edp->nargs] = (edp->args[edp->nargs] * 10) +
1067 (instate->inchar - '0');
1068 break;
1069 case ';': /* argument terminator */
1070 if (edp->nargs < VT100_EMUL_NARGS)
1071 edp->nargs++;
1072 break;
1073 case '?': /* DEC specific */
1074 case '>': /* DA query */
1075 edp->modif1 = (char)instate->inchar;
1076 break;
1077 case '!':
1078 case '"':
1079 case '$':
1080 case '&':
1081 edp->modif2 = (char)instate->inchar;
1082 break;
1083 default: /* end of escape sequence */
1084 oargs = edp->nargs;
1085 if (edp->nargs < VT100_EMUL_NARGS)
1086 edp->nargs++;
1087 rc = wsemul_vt100_handle_csi(edp, instate, kernel);
1088 if (rc != 0) {
1089 /* undo nargs progress */
1090 edp->nargs = oargs;
1091 return rc;
1092 }
1093 newstate = VT100_EMUL_STATE_NORMAL;
1094 break;
1095 }
1096
1097 if (COLS_LEFT != 0)
1098 edp->flags &= ~VTFL_LASTCHAR;
1099
1100 edp->state = newstate;
1101 return 0;
1102 }
1103
1104 u_int
wsemul_vt100_output(void * cookie,const u_char * data,u_int count,int kernel)1105 wsemul_vt100_output(void *cookie, const u_char *data, u_int count, int kernel)
1106 {
1107 struct wsemul_vt100_emuldata *edp = cookie;
1108 struct wsemul_inputstate *instate;
1109 u_int prev_count, processed = 0;
1110 #ifdef HAVE_JUMP_SCROLL
1111 int lines;
1112 #endif
1113 int rc = 0;
1114
1115 #ifdef DIAGNOSTIC
1116 if (kernel && !edp->console)
1117 panic("wsemul_vt100_output: kernel output, not console");
1118 #endif
1119
1120 instate = kernel ? &edp->kstate : &edp->instate;
1121
1122 switch (edp->abortstate.state) {
1123 case ABORT_FAILED_CURSOR:
1124 /*
1125 * If we could not display the cursor back, we pretended not
1126 * having been able to process the last byte. But this
1127 * is a lie, so compensate here.
1128 */
1129 data++, count--;
1130 processed++;
1131 wsemul_reset_abortstate(&edp->abortstate);
1132 break;
1133 case ABORT_OK:
1134 /* remove cursor image if visible */
1135 if (edp->flags & VTFL_CURSORON) {
1136 rc = (*edp->emulops->cursor)
1137 (edp->emulcookie, 0, edp->crow,
1138 #ifdef HAVE_DOUBLE_WIDTH_HEIGHT
1139 edp->ccol << edp->dw);
1140 #else
1141 edp->ccol);
1142 #endif
1143 if (rc != 0)
1144 return 0;
1145 }
1146 break;
1147 default:
1148 break;
1149 }
1150
1151 for (;;) {
1152 #ifdef HAVE_JUMP_SCROLL
1153 switch (edp->abortstate.state) {
1154 case ABORT_FAILED_JUMP_SCROLL:
1155 /*
1156 * If we failed a previous jump scroll attempt, we
1157 * need to try to resume it with the same distance.
1158 * We can not recompute it since there might be more
1159 * bytes in the tty ring, causing a different result.
1160 */
1161 lines = edp->abortstate.lines;
1162 break;
1163 case ABORT_OK:
1164 /*
1165 * If we are at the bottom of the scrolling area, count
1166 * newlines until an escape sequence appears.
1167 */
1168 if ((edp->state == VT100_EMUL_STATE_NORMAL || kernel) &&
1169 ROWS_BELOW == 0)
1170 lines = wsemul_vt100_jump_scroll(edp, data,
1171 count, kernel);
1172 else
1173 lines = 0;
1174 break;
1175 default:
1176 /*
1177 * If we are recovering a non-scrolling failure,
1178 * do not try to scroll yet.
1179 */
1180 lines = 0;
1181 break;
1182 }
1183
1184 if (lines > 1) {
1185 wsemul_resume_abort(&edp->abortstate);
1186 rc = wsemul_vt100_scrollup(edp, lines);
1187 if (rc != 0) {
1188 wsemul_abort_jump_scroll(&edp->abortstate,
1189 lines);
1190 return processed;
1191 }
1192 wsemul_reset_abortstate(&edp->abortstate);
1193 edp->crow -= lines;
1194 }
1195 #endif
1196
1197 wsemul_resume_abort(&edp->abortstate);
1198
1199 prev_count = count;
1200 if (wsemul_getchar(&data, &count, instate,
1201 #ifdef HAVE_UTF8_SUPPORT
1202 (edp->state == VT100_EMUL_STATE_NORMAL && !kernel) ?
1203 edp->flags & VTFL_UTF8 : 0
1204 #else
1205 0
1206 #endif
1207 ) != 0)
1208 break;
1209
1210 if (!(instate->inchar & ~0xff) &&
1211 (instate->inchar & 0x7f) < 0x20) {
1212 rc = wsemul_vt100_output_c0c1(edp, instate, kernel);
1213 if (rc != 0)
1214 break;
1215 processed += prev_count - count;
1216 continue;
1217 }
1218
1219 if (edp->state == VT100_EMUL_STATE_NORMAL || kernel) {
1220 rc =
1221 wsemul_vt100_output_normal(edp, instate, kernel, 1);
1222 if (rc != 0)
1223 break;
1224 instate->last_output = instate->inchar;
1225 processed += prev_count - count;
1226 continue;
1227 }
1228 #ifdef DIAGNOSTIC
1229 if (edp->state > nitems(vt100_output))
1230 panic("wsemul_vt100: invalid state %d", edp->state);
1231 #endif
1232 rc = vt100_output[edp->state - 1](edp, instate, kernel);
1233 if (rc != 0)
1234 break;
1235 processed += prev_count - count;
1236 }
1237
1238 if (rc != 0)
1239 wsemul_abort_other(&edp->abortstate);
1240 else {
1241 /* put cursor image back if visible */
1242 if (edp->flags & VTFL_CURSORON) {
1243 rc = (*edp->emulops->cursor)
1244 (edp->emulcookie, 1, edp->crow,
1245 #ifdef HAVE_DOUBLE_WIDTH_HEIGHT
1246 edp->ccol << edp->dw);
1247 #else
1248 edp->ccol);
1249 #endif
1250 if (rc != 0) {
1251 /*
1252 * Pretend the last byte hasn't been processed,
1253 * while remembering that only the cursor
1254 * operation really needs to be done.
1255 */
1256 wsemul_abort_cursor(&edp->abortstate);
1257 processed--;
1258 }
1259 }
1260 }
1261
1262 if (rc == 0)
1263 wsemul_reset_abortstate(&edp->abortstate);
1264
1265 return processed;
1266 }
1267
1268 #ifdef HAVE_JUMP_SCROLL
1269 int
wsemul_vt100_jump_scroll(struct wsemul_vt100_emuldata * edp,const u_char * data,u_int count,int kernel)1270 wsemul_vt100_jump_scroll(struct wsemul_vt100_emuldata *edp, const u_char *data,
1271 u_int count, int kernel)
1272 {
1273 struct wsemul_inputstate tmpstate;
1274 u_int pos, lines;
1275
1276 lines = 0;
1277 pos = edp->ccol;
1278 tmpstate = kernel ? edp->kstate : edp->instate; /* structure copy */
1279
1280 while (wsemul_getchar(&data, &count, &tmpstate,
1281 #ifdef HAVE_UTF8_SUPPORT
1282 kernel ? 0 : edp->flags & VTFL_UTF8
1283 #else
1284 0
1285 #endif
1286 ) == 0) {
1287 /*
1288 * Only char causing a transition from
1289 * VT100_EMUL_STATE_NORMAL to another state, for now.
1290 * Revisit this if this changes...
1291 */
1292 if (tmpstate.inchar == ASCII_ESC)
1293 break;
1294
1295 if (ISSET(edp->flags, VTFL_DECAWM))
1296 switch (tmpstate.inchar) {
1297 case ASCII_BS:
1298 if (pos > 0)
1299 pos--;
1300 break;
1301 case ASCII_CR:
1302 pos = 0;
1303 break;
1304 case ASCII_HT:
1305 if (edp->tabs) {
1306 pos++;
1307 while (pos < NCOLS - 1 &&
1308 edp->tabs[pos] == 0)
1309 pos++;
1310 } else {
1311 pos = (pos + 7) & ~7;
1312 if (pos >= NCOLS)
1313 pos = NCOLS - 1;
1314 }
1315 break;
1316 default:
1317 if (!(tmpstate.inchar & ~0xff) &&
1318 (tmpstate.inchar & 0x7f) < 0x20)
1319 break;
1320 if (pos++ >= NCOLS) {
1321 pos = 0;
1322 tmpstate.inchar = ASCII_LF;
1323 }
1324 break;
1325 }
1326
1327 if (tmpstate.inchar == ASCII_LF ||
1328 tmpstate.inchar == ASCII_VT ||
1329 tmpstate.inchar == ASCII_FF) {
1330 if (++lines >= edp->scrreg_nrows - 1)
1331 break;
1332 }
1333 }
1334
1335 return lines;
1336 }
1337 #endif
1338