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