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