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