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