1 /* $OpenBSD: wsemul_sun.c,v 1.32 2015/08/28 00:03:53 deraadt Exp $ */ 2 /* $NetBSD: wsemul_sun.c,v 1.11 2000/01/05 11:19:36 drochner Exp $ */ 3 4 /* 5 * Copyright (c) 2007, 2013 Miodrag Vallat. 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice, this permission notice, and the disclaimer below 10 * appear in all copies. 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 */ 20 /* 21 * Copyright (c) 1996, 1997 Christopher G. Demetriou. All rights reserved. 22 * 23 * Redistribution and use in source and binary forms, with or without 24 * modification, are permitted provided that the following conditions 25 * are met: 26 * 1. Redistributions of source code must retain the above copyright 27 * notice, this list of conditions and the following disclaimer. 28 * 2. Redistributions in binary form must reproduce the above copyright 29 * notice, this list of conditions and the following disclaimer in the 30 * documentation and/or other materials provided with the distribution. 31 * 3. All advertising materials mentioning features or use of this software 32 * must display the following acknowledgement: 33 * This product includes software developed by Christopher G. Demetriou 34 * for the NetBSD Project. 35 * 4. The name of the author may not be used to endorse or promote products 36 * derived from this software without specific prior written permission 37 * 38 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 39 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 40 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 41 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 42 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 43 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 44 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 45 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 46 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 47 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 48 */ 49 50 /* 51 * This file implements a sun terminal personality for wscons. 52 * 53 * Derived from old rcons code. 54 * Color support from NetBSD's rcons color code, and wsemul_vt100. 55 */ 56 57 #include <sys/param.h> 58 #include <sys/systm.h> 59 #include <sys/time.h> 60 #include <sys/malloc.h> 61 #include <sys/fcntl.h> 62 63 #include <dev/wscons/wscons_features.h> 64 #include <dev/wscons/wsconsio.h> 65 #include <dev/wscons/wsdisplayvar.h> 66 #include <dev/wscons/wsemulvar.h> 67 #include <dev/wscons/wsksymdef.h> 68 #include <dev/wscons/ascii.h> 69 70 void *wsemul_sun_cnattach(const struct wsscreen_descr *, void *, 71 int, int, long); 72 void *wsemul_sun_attach(int, const struct wsscreen_descr *, 73 void *, int, int, void *, long); 74 u_int wsemul_sun_output(void *, const u_char *, u_int, int); 75 int wsemul_sun_translate(void *, kbd_t, keysym_t, const u_char **); 76 void wsemul_sun_detach(void *, u_int *, u_int *); 77 void wsemul_sun_resetop(void *, enum wsemul_resetops); 78 79 const struct wsemul_ops wsemul_sun_ops = { 80 "sun", 81 wsemul_sun_cnattach, 82 wsemul_sun_attach, 83 wsemul_sun_output, 84 wsemul_sun_translate, 85 wsemul_sun_detach, 86 wsemul_sun_resetop 87 }; 88 89 #define SUN_EMUL_STATE_NORMAL 0 /* normal processing */ 90 #define SUN_EMUL_STATE_HAVEESC 1 /* seen start of ctl seq */ 91 #define SUN_EMUL_STATE_CONTROL 2 /* processing ESC [ ctl seq */ 92 #define SUN_EMUL_STATE_PERCENT 3 /* processing ESC % ctl seq */ 93 94 #define SUN_EMUL_FLAGS_UTF8 0x01 /* UTF-8 character set */ 95 96 #define SUN_EMUL_NARGS 2 /* max # of args to a command */ 97 98 struct wsemul_sun_emuldata { 99 const struct wsdisplay_emulops *emulops; 100 struct wsemul_abortstate abortstate; 101 void *emulcookie; 102 void *cbcookie; 103 int scrcapabilities; 104 u_int nrows, ncols, crow, ccol; 105 long defattr; /* default attribute (rendition) */ 106 107 u_int state; /* processing state */ 108 u_int flags; 109 u_int args[SUN_EMUL_NARGS]; /* command args, if CONTROL */ 110 int nargs; /* number of args */ 111 112 u_int scrolldist; /* distance to scroll */ 113 long curattr, bkgdattr; /* currently used attribute */ 114 long kernattr; /* attribute for kernel output */ 115 int attrflags, fgcol, bgcol; /* properties of curattr */ 116 117 struct wsemul_inputstate instate; /* userland input state */ 118 struct wsemul_inputstate kstate; /* kernel input state */ 119 120 #ifdef HAVE_UTF8_SUPPORT 121 u_char translatebuf[6]; 122 #else 123 u_char translatebuf[1]; 124 #endif 125 126 #ifdef DIAGNOSTIC 127 int console; 128 #endif 129 }; 130 131 void wsemul_sun_init(struct wsemul_sun_emuldata *, 132 const struct wsscreen_descr *, void *, int, int, long); 133 int wsemul_sun_jump_scroll(struct wsemul_sun_emuldata *, const u_char *, 134 u_int, int); 135 void wsemul_sun_reset(struct wsemul_sun_emuldata *); 136 int wsemul_sun_output_lowchars(struct wsemul_sun_emuldata *, 137 struct wsemul_inputstate *, int); 138 int wsemul_sun_output_normal(struct wsemul_sun_emuldata *, 139 struct wsemul_inputstate *, int); 140 int wsemul_sun_output_haveesc(struct wsemul_sun_emuldata *, 141 struct wsemul_inputstate *); 142 int wsemul_sun_output_control(struct wsemul_sun_emuldata *, 143 struct wsemul_inputstate *); 144 int wsemul_sun_output_percent(struct wsemul_sun_emuldata *, 145 struct wsemul_inputstate *); 146 int wsemul_sun_control(struct wsemul_sun_emuldata *, 147 struct wsemul_inputstate *); 148 int wsemul_sun_selectattribute(struct wsemul_sun_emuldata *, int, int, int, 149 long *, long *); 150 int wsemul_sun_scrollup(struct wsemul_sun_emuldata *, u_int); 151 152 struct wsemul_sun_emuldata wsemul_sun_console_emuldata; 153 154 /* some useful utility macros */ 155 #define ARG(n,c) \ 156 ((n) >= edp->nargs ? 0 : edp->args[(n) + MAX(0, edp->nargs - (c))]) 157 #define NORMALIZE(arg) ((arg) != 0 ? (arg) : 1) 158 #define COLS_LEFT (edp->ncols - 1 - edp->ccol) 159 #define ROWS_LEFT (edp->nrows - 1 - edp->crow) 160 161 void 162 wsemul_sun_init(struct wsemul_sun_emuldata *edp, 163 const struct wsscreen_descr *type, void *cookie, int ccol, int crow, 164 long defattr) 165 { 166 edp->emulops = type->textops; 167 edp->emulcookie = cookie; 168 edp->scrcapabilities = type->capabilities; 169 edp->nrows = type->nrows; 170 edp->ncols = type->ncols; 171 edp->crow = crow; 172 edp->ccol = ccol; 173 edp->defattr = defattr; 174 wsemul_reset_abortstate(&edp->abortstate); 175 } 176 177 void 178 wsemul_sun_reset(struct wsemul_sun_emuldata *edp) 179 { 180 edp->flags = 0; 181 edp->state = SUN_EMUL_STATE_NORMAL; 182 edp->bkgdattr = edp->curattr = edp->defattr; 183 edp->attrflags = 0; 184 edp->fgcol = WSCOL_BLACK; 185 edp->bgcol = WSCOL_WHITE; 186 edp->scrolldist = 1; 187 edp->instate.inchar = 0; 188 edp->instate.mbleft = 0; 189 edp->kstate.inchar = 0; 190 edp->kstate.mbleft = 0; 191 } 192 193 void * 194 wsemul_sun_cnattach(const struct wsscreen_descr *type, void *cookie, int ccol, 195 int crow, long defattr) 196 { 197 struct wsemul_sun_emuldata *edp; 198 int res; 199 200 edp = &wsemul_sun_console_emuldata; 201 wsemul_sun_init(edp, type, cookie, ccol, crow, defattr); 202 203 #ifndef WS_KERNEL_FG 204 #define WS_KERNEL_FG WSCOL_BLACK 205 #endif 206 #ifndef WS_KERNEL_BG 207 #define WS_KERNEL_BG WSCOL_WHITE 208 #endif 209 #ifndef WS_KERNEL_COLATTR 210 #define WS_KERNEL_COLATTR 0 211 #endif 212 #ifndef WS_KERNEL_MONOATTR 213 #define WS_KERNEL_MONOATTR 0 214 #endif 215 if (type->capabilities & WSSCREEN_WSCOLORS) 216 res = (*edp->emulops->alloc_attr)(cookie, 217 WS_KERNEL_FG, WS_KERNEL_BG, 218 WS_KERNEL_COLATTR | WSATTR_WSCOLORS, 219 &edp->kernattr); 220 else 221 res = (*edp->emulops->alloc_attr)(cookie, 0, 0, 222 WS_KERNEL_MONOATTR, 223 &edp->kernattr); 224 if (res) 225 edp->kernattr = defattr; 226 227 edp->cbcookie = NULL; 228 229 #ifdef DIAGNOSTIC 230 edp->console = 1; 231 #endif 232 233 wsemul_sun_reset(edp); 234 return (edp); 235 } 236 237 void * 238 wsemul_sun_attach(int console, const struct wsscreen_descr *type, void *cookie, 239 int ccol, int crow, void *cbcookie, long defattr) 240 { 241 struct wsemul_sun_emuldata *edp; 242 243 if (console) { 244 edp = &wsemul_sun_console_emuldata; 245 #ifdef DIAGNOSTIC 246 KASSERT(edp->console == 1); 247 #endif 248 } else { 249 edp = malloc(sizeof *edp, M_DEVBUF, M_NOWAIT); 250 if (edp == NULL) 251 return (NULL); 252 wsemul_sun_init(edp, type, cookie, ccol, crow, defattr); 253 254 #ifdef DIAGNOSTIC 255 edp->console = 0; 256 #endif 257 } 258 259 edp->cbcookie = cbcookie; 260 261 wsemul_sun_reset(edp); 262 return (edp); 263 } 264 265 int 266 wsemul_sun_output_lowchars(struct wsemul_sun_emuldata *edp, 267 struct wsemul_inputstate *instate, int kernel) 268 { 269 u_int n; 270 int rc = 0; 271 272 switch (instate->inchar) { 273 case ASCII_NUL: 274 default: 275 /* ignore */ 276 break; 277 278 case ASCII_BEL: /* "Bell (BEL)" */ 279 wsdisplay_emulbell(edp->cbcookie); 280 break; 281 282 case ASCII_BS: /* "Backspace (BS)" */ 283 if (edp->ccol > 0) 284 edp->ccol--; 285 break; 286 287 case ASCII_CR: /* "Return (CR)" */ 288 edp->ccol = 0; 289 break; 290 291 case ASCII_HT: /* "Tab (TAB)" */ 292 n = min(8 - (edp->ccol & 7), COLS_LEFT); 293 if (n != 0) { 294 WSEMULOP(rc, edp, &edp->abortstate, erasecols, 295 (edp->emulcookie, edp->crow, edp->ccol, n, 296 kernel ? edp->kernattr : edp->bkgdattr)); 297 if (rc != 0) 298 break; 299 edp->ccol += n; 300 } 301 break; 302 303 case ASCII_FF: /* "Form Feed (FF)" */ 304 WSEMULOP(rc, edp, &edp->abortstate, eraserows, 305 (edp->emulcookie, 0, edp->nrows, edp->bkgdattr)); 306 if (rc != 0) 307 break; 308 edp->ccol = edp->crow = 0; 309 break; 310 311 case ASCII_VT: /* "Reverse Line Feed" */ 312 if (edp->crow > 0) 313 edp->crow--; 314 break; 315 316 case ASCII_ESC: /* "Escape (ESC)" */ 317 if (kernel) { 318 printf("wsemul_sun_output_lowchars: ESC in kernel " 319 "output ignored\n"); 320 break; /* ignore the ESC */ 321 } 322 323 edp->state = SUN_EMUL_STATE_HAVEESC; 324 break; 325 326 case ASCII_LF: /* "Line Feed (LF)" */ 327 /* if the cur line isn't the last, incr and leave. */ 328 if (ROWS_LEFT > 0) 329 edp->crow++; 330 else { 331 rc = wsemul_sun_scrollup(edp, edp->scrolldist); 332 if (rc != 0) 333 break; 334 } 335 break; 336 } 337 338 return rc; 339 } 340 341 int 342 wsemul_sun_output_normal(struct wsemul_sun_emuldata *edp, 343 struct wsemul_inputstate *instate, int kernel) 344 { 345 int rc; 346 u_int outchar; 347 348 (*edp->emulops->mapchar)(edp->emulcookie, instate->inchar, &outchar); 349 WSEMULOP(rc, edp, &edp->abortstate, putchar, 350 (edp->emulcookie, edp->crow, edp->ccol, 351 outchar, kernel ? edp->kernattr : edp->curattr)); 352 if (rc != 0) 353 return rc; 354 355 if (++edp->ccol >= edp->ncols) { 356 /* if the cur line isn't the last, incr and leave. */ 357 if (ROWS_LEFT > 0) 358 edp->crow++; 359 else { 360 rc = wsemul_sun_scrollup(edp, edp->scrolldist); 361 if (rc != 0) { 362 /* undo line wrap */ 363 edp->ccol--; 364 365 return rc; 366 } 367 } 368 edp->ccol = 0; 369 } 370 371 return 0; 372 } 373 374 int 375 wsemul_sun_output_haveesc(struct wsemul_sun_emuldata *edp, 376 struct wsemul_inputstate *instate) 377 { 378 switch (instate->inchar) { 379 case '[': /* continuation of multi-char sequence */ 380 edp->nargs = 0; 381 bzero(edp->args, sizeof (edp->args)); 382 edp->state = SUN_EMUL_STATE_CONTROL; 383 break; 384 #ifdef HAVE_UTF8_SUPPORT 385 case '%': 386 edp->state = SUN_EMUL_STATE_PERCENT; 387 break; 388 #endif 389 default: 390 #ifdef DEBUG 391 printf("ESC %x unknown\n", instate->inchar); 392 #endif 393 edp->state = SUN_EMUL_STATE_NORMAL; /* XXX is this wise? */ 394 break; 395 } 396 return 0; 397 } 398 399 int 400 wsemul_sun_control(struct wsemul_sun_emuldata *edp, 401 struct wsemul_inputstate *instate) 402 { 403 u_int n, src, dst; 404 int flags, fgcol, bgcol; 405 long attr, bkgdattr; 406 int rc = 0; 407 408 switch (instate->inchar) { 409 case '@': /* "Insert Character (ICH)" */ 410 n = min(NORMALIZE(ARG(0,1)), COLS_LEFT + 1); 411 src = edp->ccol; 412 dst = edp->ccol + n; 413 if (dst < edp->ncols) { 414 WSEMULOP(rc, edp, &edp->abortstate, copycols, 415 (edp->emulcookie, edp->crow, src, dst, 416 edp->ncols - dst)); 417 if (rc != 0) 418 break; 419 } 420 WSEMULOP(rc, edp, &edp->abortstate, erasecols, 421 (edp->emulcookie, edp->crow, src, n, edp->bkgdattr)); 422 break; 423 424 case 'A': /* "Cursor Up (CUU)" */ 425 edp->crow -= min(NORMALIZE(ARG(0,1)), edp->crow); 426 break; 427 428 case 'E': /* "Cursor Next Line (CNL)" */ 429 edp->ccol = 0; 430 /* FALLTHROUGH */ 431 case 'B': /* "Cursor Down (CUD)" */ 432 edp->crow += min(NORMALIZE(ARG(0,1)), ROWS_LEFT); 433 break; 434 435 case 'C': /* "Cursor Forward (CUF)" */ 436 edp->ccol += min(NORMALIZE(ARG(0,1)), COLS_LEFT); 437 break; 438 439 case 'D': /* "Cursor Backward (CUB)" */ 440 edp->ccol -= min(NORMALIZE(ARG(0,1)), edp->ccol); 441 break; 442 443 case 'f': /* "Horizontal And Vertical Position (HVP)" */ 444 case 'H': /* "Cursor Position (CUP)" */ 445 edp->crow = min(NORMALIZE(ARG(0,2)), edp->nrows) - 1; 446 edp->ccol = min(NORMALIZE(ARG(1,2)), edp->ncols) - 1; 447 break; 448 449 case 'J': /* "Erase in Display (ED)" */ 450 if (ROWS_LEFT > 0) { 451 WSEMULOP(rc, edp, &edp->abortstate, eraserows, 452 (edp->emulcookie, edp->crow + 1, ROWS_LEFT, 453 edp->bkgdattr)); 454 if (rc != 0) 455 break; 456 } 457 /* FALLTHROUGH */ 458 case 'K': /* "Erase in Line (EL)" */ 459 WSEMULOP(rc, edp, &edp->abortstate, erasecols, 460 (edp->emulcookie, edp->crow, edp->ccol, COLS_LEFT + 1, 461 edp->bkgdattr)); 462 break; 463 464 case 'L': /* "Insert Line (IL)" */ 465 n = min(NORMALIZE(ARG(0,1)), ROWS_LEFT + 1); 466 src = edp->crow; 467 dst = edp->crow + n; 468 if (dst < edp->nrows) { 469 WSEMULOP(rc, edp, &edp->abortstate, copyrows, 470 (edp->emulcookie, src, dst, edp->nrows - dst)); 471 if (rc != 0) 472 break; 473 } 474 WSEMULOP(rc, edp, &edp->abortstate, eraserows, 475 (edp->emulcookie, src, n, edp->bkgdattr)); 476 break; 477 478 case 'M': /* "Delete Line (DL)" */ 479 n = min(NORMALIZE(ARG(0,1)), ROWS_LEFT + 1); 480 src = edp->crow + n; 481 dst = edp->crow; 482 if (src < edp->nrows) { 483 WSEMULOP(rc, edp, &edp->abortstate, copyrows, 484 (edp->emulcookie, src, dst, edp->nrows - src)); 485 if (rc != 0) 486 break; 487 } 488 WSEMULOP(rc, edp, &edp->abortstate, eraserows, 489 (edp->emulcookie, dst + edp->nrows - src, n, 490 edp->bkgdattr)); 491 break; 492 493 case 'P': /* "Delete Character (DCH)" */ 494 n = min(NORMALIZE(ARG(0,1)), COLS_LEFT + 1); 495 src = edp->ccol + n; 496 dst = edp->ccol; 497 if (src < edp->ncols) { 498 WSEMULOP(rc, edp, &edp->abortstate, copycols, 499 (edp->emulcookie, edp->crow, src, dst, 500 edp->ncols - src)); 501 if (rc != 0) 502 break; 503 } 504 WSEMULOP(rc, edp, &edp->abortstate, erasecols, 505 (edp->emulcookie, edp->crow, edp->ncols - n, n, 506 edp->bkgdattr)); 507 break; 508 509 case 'm': /* "Select Graphic Rendition (SGR)" */ 510 flags = edp->attrflags; 511 fgcol = edp->fgcol; 512 bgcol = edp->bgcol; 513 514 for (n = 0; n < edp->nargs; n++) { 515 switch (ARG(n,edp->nargs)) { 516 /* Clear all attributes || End underline */ 517 case 0: 518 if (n == edp->nargs - 1) { 519 edp->bkgdattr = 520 edp->curattr = edp->defattr; 521 edp->attrflags = 0; 522 edp->fgcol = WSCOL_BLACK; 523 edp->bgcol = WSCOL_WHITE; 524 return 0; 525 } 526 flags = 0; 527 fgcol = WSCOL_BLACK; 528 bgcol = WSCOL_WHITE; 529 break; 530 /* Begin bold */ 531 case 1: 532 flags |= WSATTR_HILIT; 533 break; 534 /* Begin underline */ 535 case 4: 536 flags |= WSATTR_UNDERLINE; 537 break; 538 /* Begin reverse */ 539 case 7: 540 flags |= WSATTR_REVERSE; 541 break; 542 /* ANSI foreground color */ 543 case 30: case 31: case 32: case 33: 544 case 34: case 35: case 36: case 37: 545 fgcol = ARG(n,edp->nargs) - 30; 546 break; 547 /* ANSI background color */ 548 case 40: case 41: case 42: case 43: 549 case 44: case 45: case 46: case 47: 550 bgcol = ARG(n,edp->nargs) - 40; 551 break; 552 } 553 } 554 setattr: 555 if (wsemul_sun_selectattribute(edp, flags, fgcol, bgcol, &attr, 556 &bkgdattr)) { 557 #ifdef DEBUG 558 printf("error allocating attr %d/%d/%x\n", 559 fgcol, bgcol, flags); 560 #endif 561 } else { 562 edp->curattr = attr; 563 edp->bkgdattr = bkgdattr; 564 edp->attrflags = flags; 565 edp->fgcol = fgcol; 566 edp->bgcol = bgcol; 567 } 568 break; 569 570 case 'p': /* "Black On White (SUNBOW)" */ 571 flags = 0; 572 fgcol = WSCOL_BLACK; 573 bgcol = WSCOL_WHITE; 574 goto setattr; 575 576 case 'q': /* "White On Black (SUNWOB)" */ 577 flags = 0; 578 fgcol = WSCOL_WHITE; 579 bgcol = WSCOL_BLACK; 580 goto setattr; 581 582 case 'r': /* "Set Scrolling (SUNSCRL)" */ 583 edp->scrolldist = min(ARG(0,1), edp->nrows); 584 break; 585 586 case 's': /* "Reset Terminal Emulator (SUNRESET)" */ 587 wsemul_sun_reset(edp); 588 break; 589 } 590 591 return rc; 592 } 593 594 int 595 wsemul_sun_output_control(struct wsemul_sun_emuldata *edp, 596 struct wsemul_inputstate *instate) 597 { 598 int oargs; 599 int rc; 600 601 switch (instate->inchar) { 602 case '0': case '1': case '2': case '3': case '4': /* argument digit */ 603 case '5': case '6': case '7': case '8': case '9': 604 /* 605 * If we receive more arguments than we are expecting, 606 * discard the earliest arguments. 607 */ 608 if (edp->nargs > SUN_EMUL_NARGS - 1) { 609 bcopy(edp->args + 1, edp->args, 610 (SUN_EMUL_NARGS - 1) * sizeof(edp->args[0])); 611 edp->args[edp->nargs = SUN_EMUL_NARGS - 1] = 0; 612 } 613 edp->args[edp->nargs] = (edp->args[edp->nargs] * 10) + 614 (instate->inchar - '0'); 615 break; 616 617 case ';': /* argument terminator */ 618 edp->nargs++; 619 break; 620 621 default: /* end of escape sequence */ 622 oargs = edp->nargs++; 623 if (edp->nargs > SUN_EMUL_NARGS) 624 edp->nargs = SUN_EMUL_NARGS; 625 rc = wsemul_sun_control(edp, instate); 626 if (rc != 0) { 627 /* undo nargs progress */ 628 edp->nargs = oargs; 629 630 return rc; 631 } 632 edp->state = SUN_EMUL_STATE_NORMAL; 633 break; 634 } 635 636 return 0; 637 } 638 639 #ifdef HAVE_UTF8_SUPPORT 640 int 641 wsemul_sun_output_percent(struct wsemul_sun_emuldata *edp, 642 struct wsemul_inputstate *instate) 643 { 644 switch (instate->inchar) { 645 case 'G': 646 edp->flags |= SUN_EMUL_FLAGS_UTF8; 647 edp->kstate.mbleft = edp->instate.mbleft = 0; 648 break; 649 case '@': 650 edp->flags &= ~SUN_EMUL_FLAGS_UTF8; 651 break; 652 } 653 edp->state = SUN_EMUL_STATE_NORMAL; 654 return 0; 655 } 656 #endif 657 658 u_int 659 wsemul_sun_output(void *cookie, const u_char *data, u_int count, int kernel) 660 { 661 struct wsemul_sun_emuldata *edp = cookie; 662 struct wsemul_inputstate *instate; 663 u_int processed = 0; 664 #ifdef HAVE_JUMP_SCROLL 665 int lines; 666 #endif 667 int rc = 0; 668 669 #ifdef DIAGNOSTIC 670 if (kernel && !edp->console) 671 panic("wsemul_sun_output: kernel output, not console"); 672 #endif 673 674 instate = kernel ? &edp->kstate : &edp->instate; 675 676 switch (edp->abortstate.state) { 677 case ABORT_FAILED_CURSOR: 678 /* 679 * If we could not display the cursor back, we pretended not 680 * having been able to display the last character. But this 681 * is a lie, so compensate here. 682 */ 683 data++, count--; 684 processed++; 685 wsemul_reset_abortstate(&edp->abortstate); 686 break; 687 case ABORT_OK: 688 /* remove cursor image */ 689 rc = (*edp->emulops->cursor) 690 (edp->emulcookie, 0, edp->crow, edp->ccol); 691 if (rc != 0) 692 return 0; 693 break; 694 default: 695 break; 696 } 697 698 for (;;) { 699 #ifdef HAVE_JUMP_SCROLL 700 switch (edp->abortstate.state) { 701 case ABORT_FAILED_JUMP_SCROLL: 702 /* 703 * If we failed a previous jump scroll attempt, we 704 * need to try to resume it with the same distance. 705 * We can not recompute it since there might be more 706 * bytes in the tty ring, causing a different result. 707 */ 708 lines = edp->abortstate.lines; 709 break; 710 case ABORT_OK: 711 /* 712 * If scrolling is not disabled and we are the bottom of 713 * the screen, count newlines until an escape sequence 714 * appears. 715 */ 716 if ((edp->state == SUN_EMUL_STATE_NORMAL || kernel) && 717 ROWS_LEFT == 0 && edp->scrolldist != 0) 718 lines = wsemul_sun_jump_scroll(edp, data, 719 count, kernel); 720 else 721 lines = 0; 722 break; 723 default: 724 /* 725 * If we are recovering a non-scrolling failure, 726 * do not try to scroll yet. 727 */ 728 lines = 0; 729 break; 730 } 731 732 if (lines > 1) { 733 wsemul_resume_abort(&edp->abortstate); 734 rc = wsemul_sun_scrollup(edp, lines); 735 if (rc != 0) { 736 wsemul_abort_jump_scroll(&edp->abortstate, 737 lines); 738 return processed; 739 } 740 wsemul_reset_abortstate(&edp->abortstate); 741 edp->crow--; 742 } 743 #endif 744 745 wsemul_resume_abort(&edp->abortstate); 746 747 if (wsemul_getchar(&data, &count, instate, 748 #ifdef HAVE_UTF8_SUPPORT 749 (edp->state == SUN_EMUL_STATE_NORMAL && !kernel) ? 750 edp->flags & SUN_EMUL_FLAGS_UTF8 : 0 751 #else 752 0 753 #endif 754 ) != 0) 755 break; 756 757 if (instate->inchar < ' ') { 758 rc = wsemul_sun_output_lowchars(edp, instate, kernel); 759 if (rc != 0) 760 break; 761 processed++; 762 continue; 763 } 764 765 if (kernel) { 766 rc = wsemul_sun_output_normal(edp, instate, 1); 767 if (rc != 0) 768 break; 769 processed++; 770 continue; 771 } 772 773 switch (edp->state) { 774 case SUN_EMUL_STATE_NORMAL: 775 rc = wsemul_sun_output_normal(edp, instate, 0); 776 break; 777 case SUN_EMUL_STATE_HAVEESC: 778 rc = wsemul_sun_output_haveesc(edp, instate); 779 break; 780 case SUN_EMUL_STATE_CONTROL: 781 rc = wsemul_sun_output_control(edp, instate); 782 break; 783 #ifdef HAVE_UTF8_SUPPORT 784 case SUN_EMUL_STATE_PERCENT: 785 rc = wsemul_sun_output_percent(edp, instate); 786 break; 787 #endif 788 default: 789 #ifdef DIAGNOSTIC 790 panic("wsemul_sun: invalid state %d", edp->state); 791 #else 792 /* try to recover, if things get screwed up... */ 793 edp->state = SUN_EMUL_STATE_NORMAL; 794 rc = wsemul_sun_output_normal(edp, instate, 0); 795 #endif 796 break; 797 } 798 if (rc != 0) 799 break; 800 processed++; 801 } 802 803 if (rc != 0) 804 wsemul_abort_other(&edp->abortstate); 805 else { 806 /* put cursor image back */ 807 rc = (*edp->emulops->cursor) 808 (edp->emulcookie, 1, edp->crow, edp->ccol); 809 if (rc != 0) { 810 /* 811 * Fail the last character output, remembering that 812 * only the cursor operation really needs to be done. 813 */ 814 wsemul_abort_cursor(&edp->abortstate); 815 processed--; 816 } 817 } 818 819 if (rc == 0) 820 wsemul_reset_abortstate(&edp->abortstate); 821 822 return processed; 823 } 824 825 #ifdef HAVE_JUMP_SCROLL 826 int 827 wsemul_sun_jump_scroll(struct wsemul_sun_emuldata *edp, const u_char *data, 828 u_int count, int kernel) 829 { 830 u_int pos, lines; 831 struct wsemul_inputstate tmpstate; 832 833 lines = 0; 834 pos = edp->ccol; 835 tmpstate = kernel ? edp->kstate : edp->instate; /* structure copy */ 836 837 while (wsemul_getchar(&data, &count, &tmpstate, 838 #ifdef HAVE_UTF8_SUPPORT 839 kernel ? 0 : edp->flags & SUN_EMUL_FLAGS_UTF8 840 #else 841 0 842 #endif 843 ) == 0) { 844 if (tmpstate.inchar == ASCII_FF || 845 tmpstate.inchar == ASCII_VT || 846 tmpstate.inchar == ASCII_ESC) 847 break; 848 849 switch (tmpstate.inchar) { 850 case ASCII_BS: 851 if (pos > 0) 852 pos--; 853 break; 854 case ASCII_CR: 855 pos = 0; 856 break; 857 case ASCII_HT: 858 pos = (pos + 7) & ~7; 859 if (pos >= edp->ncols) 860 pos = edp->ncols - 1; 861 break; 862 case ASCII_LF: 863 break; 864 default: 865 if (++pos >= edp->ncols) { 866 pos = 0; 867 tmpstate.inchar = ASCII_LF; 868 } 869 break; 870 } 871 if (tmpstate.inchar == ASCII_LF) { 872 if (++lines >= edp->nrows - 1) 873 break; 874 } 875 } 876 877 return lines; 878 } 879 #endif 880 881 /* 882 * Get an attribute from the graphics driver. 883 * Try to find replacements if the desired appearance is not supported. 884 */ 885 int 886 wsemul_sun_selectattribute(struct wsemul_sun_emuldata *edp, int flags, 887 int fgcol, int bgcol, long *attr, long *bkgdattr) 888 { 889 int error; 890 891 /* 892 * Rasops will force white on black as normal output colors, unless 893 * WSATTR_WSCOLORS is specified. Since Sun console is black on white, 894 * always use WSATTR_WSCOLORS and our colors, as we know better. 895 */ 896 if (!(edp->scrcapabilities & WSSCREEN_WSCOLORS)) { 897 flags &= ~WSATTR_WSCOLORS; 898 } else { 899 flags |= WSATTR_WSCOLORS; 900 } 901 902 error = (*edp->emulops->alloc_attr)(edp->emulcookie, fgcol, bgcol, 903 flags & WSATTR_WSCOLORS, bkgdattr); 904 if (error) 905 return (error); 906 907 if ((flags & WSATTR_HILIT) && 908 !(edp->scrcapabilities & WSSCREEN_HILIT)) { 909 flags &= ~WSATTR_HILIT; 910 if (edp->scrcapabilities & WSSCREEN_WSCOLORS) { 911 fgcol = WSCOL_RED; 912 flags |= WSATTR_WSCOLORS; 913 } 914 } 915 if ((flags & WSATTR_UNDERLINE) && 916 !(edp->scrcapabilities & WSSCREEN_UNDERLINE)) { 917 flags &= ~WSATTR_UNDERLINE; 918 if (edp->scrcapabilities & WSSCREEN_WSCOLORS) { 919 fgcol = WSCOL_CYAN; 920 flags &= ~WSATTR_UNDERLINE; 921 flags |= WSATTR_WSCOLORS; 922 } 923 } 924 if ((flags & WSATTR_BLINK) && 925 !(edp->scrcapabilities & WSSCREEN_BLINK)) { 926 flags &= ~WSATTR_BLINK; 927 } 928 if ((flags & WSATTR_REVERSE) && 929 !(edp->scrcapabilities & WSSCREEN_REVERSE)) { 930 flags &= ~WSATTR_REVERSE; 931 if (edp->scrcapabilities & WSSCREEN_WSCOLORS) { 932 int help; 933 help = bgcol; 934 bgcol = fgcol; 935 fgcol = help; 936 flags |= WSATTR_WSCOLORS; 937 } 938 } 939 error = (*edp->emulops->alloc_attr)(edp->emulcookie, fgcol, bgcol, 940 flags, attr); 941 if (error) 942 return (error); 943 944 return (0); 945 } 946 947 static const u_char *sun_fkeys[] = { 948 "\033[224z", /* F1 */ 949 "\033[225z", 950 "\033[226z", 951 "\033[227z", 952 "\033[228z", 953 "\033[229z", 954 "\033[230z", 955 "\033[231z", 956 "\033[232z", 957 "\033[233z", 958 "\033[234z", 959 "\033[235z", /* F12 */ 960 }; 961 962 static const u_char *sun_lkeys[] = { 963 "\033[207z", /* KS_Help */ 964 NULL, /* KS_Execute */ 965 "\033[200z", /* KS_Find */ 966 NULL, /* KS_Select */ 967 "\033[193z", /* KS_Again */ 968 "\033[194z", /* KS_Props */ 969 "\033[195z", /* KS_Undo */ 970 "\033[196z", /* KS_Front */ 971 "\033[197z", /* KS_Copy */ 972 "\033[198z", /* KS_Open */ 973 "\033[199z", /* KS_Paste */ 974 "\033[201z", /* KS_Cut */ 975 }; 976 977 int 978 wsemul_sun_translate(void *cookie, kbd_t layout, keysym_t in, 979 const u_char **out) 980 { 981 struct wsemul_sun_emuldata *edp = cookie; 982 983 if (KS_GROUP(in) == KS_GROUP_Ascii) { 984 *out = edp->translatebuf; 985 return (wsemul_utf8_translate(KS_VALUE(in), layout, 986 edp->translatebuf, edp->flags & SUN_EMUL_FLAGS_UTF8)); 987 } 988 989 if (KS_GROUP(in) == KS_GROUP_Keypad && (in & 0x80) == 0) { 990 edp->translatebuf[0] = in & 0xff; /* turn into ASCII */ 991 *out = edp->translatebuf; 992 return (1); 993 } 994 995 if (in >= KS_f1 && in <= KS_f12) { 996 *out = sun_fkeys[in - KS_f1]; 997 return (6); 998 } 999 if (in >= KS_F1 && in <= KS_F12) { 1000 *out = sun_fkeys[in - KS_F1]; 1001 return (6); 1002 } 1003 if (in >= KS_KP_F1 && in <= KS_KP_F4) { 1004 *out = sun_fkeys[in - KS_KP_F1]; 1005 return (6); 1006 } 1007 if (in >= KS_Help && in <= KS_Cut && sun_lkeys[in - KS_Help] != NULL) { 1008 *out = sun_lkeys[in - KS_Help]; 1009 return (6); 1010 } 1011 1012 switch (in) { 1013 case KS_Home: 1014 case KS_KP_Home: 1015 case KS_KP_Begin: 1016 *out = "\033[214z"; 1017 return (6); 1018 case KS_End: 1019 case KS_KP_End: 1020 *out = "\033[220z"; 1021 return (6); 1022 case KS_Insert: 1023 case KS_KP_Insert: 1024 *out = "\033[247z"; 1025 return (6); 1026 case KS_Prior: 1027 case KS_KP_Prior: 1028 *out = "\033[216z"; 1029 return (6); 1030 case KS_Next: 1031 case KS_KP_Next: 1032 *out = "\033[222z"; 1033 return (6); 1034 case KS_Up: 1035 case KS_KP_Up: 1036 *out = "\033[A"; 1037 return (3); 1038 case KS_Down: 1039 case KS_KP_Down: 1040 *out = "\033[B"; 1041 return (3); 1042 case KS_Left: 1043 case KS_KP_Left: 1044 *out = "\033[D"; 1045 return (3); 1046 case KS_Right: 1047 case KS_KP_Right: 1048 *out = "\033[C"; 1049 return (3); 1050 case KS_KP_Delete: 1051 *out = "\177"; 1052 return (1); 1053 } 1054 return (0); 1055 } 1056 1057 void 1058 wsemul_sun_detach(void *cookie, u_int *crowp, u_int *ccolp) 1059 { 1060 struct wsemul_sun_emuldata *edp = cookie; 1061 1062 *crowp = edp->crow; 1063 *ccolp = edp->ccol; 1064 if (edp != &wsemul_sun_console_emuldata) 1065 free(edp, M_DEVBUF, sizeof *edp); 1066 } 1067 1068 void 1069 wsemul_sun_resetop(void *cookie, enum wsemul_resetops op) 1070 { 1071 struct wsemul_sun_emuldata *edp = cookie; 1072 1073 switch (op) { 1074 case WSEMUL_RESET: 1075 wsemul_sun_reset(edp); 1076 break; 1077 case WSEMUL_CLEARSCREEN: 1078 (*edp->emulops->eraserows)(edp->emulcookie, 0, edp->nrows, 1079 edp->bkgdattr); 1080 edp->ccol = edp->crow = 0; 1081 (*edp->emulops->cursor)(edp->emulcookie, 1, 0, 0); 1082 break; 1083 case WSEMUL_CLEARCURSOR: 1084 (*edp->emulops->cursor)(edp->emulcookie, 0, edp->crow, 1085 edp->ccol); 1086 break; 1087 default: 1088 break; 1089 } 1090 } 1091 1092 int 1093 wsemul_sun_scrollup(struct wsemul_sun_emuldata *edp, u_int lines) 1094 { 1095 int rc; 1096 1097 /* 1098 * if we're in wrap-around mode, go to the first 1099 * line and clear it. 1100 */ 1101 if (lines == 0) { 1102 WSEMULOP(rc, edp, &edp->abortstate, eraserows, 1103 (edp->emulcookie, 0, 1, edp->bkgdattr)); 1104 if (rc != 0) 1105 return rc; 1106 1107 edp->crow = 0; 1108 return 0; 1109 } 1110 1111 /* 1112 * If the scrolling distance is equal to the screen height 1113 * (usually 34), clear the screen; otherwise, scroll by the 1114 * scrolling distance. 1115 */ 1116 if (lines < edp->nrows) { 1117 WSEMULOP(rc, edp, &edp->abortstate, copyrows, 1118 (edp->emulcookie, lines, 0, edp->nrows - lines)); 1119 if (rc != 0) 1120 return rc; 1121 } 1122 WSEMULOP(rc, edp, &edp->abortstate, eraserows, 1123 (edp->emulcookie, edp->nrows - lines, lines, edp->bkgdattr)); 1124 if (rc != 0) 1125 return rc; 1126 1127 edp->crow -= lines - 1; 1128 1129 return 0; 1130 } 1131