wsemul_vt100_subr.c revision 1.33
1/* $NetBSD: wsemul_vt100_subr.c,v 1.33 2023/08/03 02:25:09 uwe 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_subr.c,v 1.33 2023/08/03 02:25:09 uwe Exp $"); 31 32#include <sys/param.h> 33#include <sys/systm.h> 34 35#include <dev/wscons/wsconsio.h> 36#include <dev/wscons/wsksymvar.h> 37#include <dev/wscons/wsdisplayvar.h> 38#include <dev/wscons/wsemulvar.h> 39#include <dev/wscons/vt100_base.h> 40 41#ifdef _KERNEL_OPT 42#include "opt_wsemul.h" 43#endif 44 45static int vt100_selectattribute(struct vt100base_data *, 46 int, int, int, long *, long *); 47static int vt100_ansimode(struct vt100base_data *, int, int); 48static int vt100_decmode(struct vt100base_data *, int, int); 49#define VTMODE_SET 33 50#define VTMODE_RESET 44 51#define VTMODE_REPORT 55 52 53/* 54 * scroll up within scrolling region 55 */ 56void 57wsemul_vt100_scrollup(struct vt100base_data *vd, int n) 58{ 59 int help; 60 61 if (n > vd->scrreg_nrows) 62 n = vd->scrreg_nrows; 63 64 help = vd->scrreg_nrows - n; 65 if (help > 0) { 66 (*vd->emulops->copyrows)(vd->emulcookie, 67 vd->scrreg_startrow + n, 68 vd->scrreg_startrow, 69 help); 70 if (vd->dblwid) 71 memmove(&vd->dblwid[vd->scrreg_startrow], 72 &vd->dblwid[vd->scrreg_startrow + n], 73 help); 74 } 75 (*vd->emulops->eraserows)(vd->emulcookie, 76 vd->scrreg_startrow + help, n, 77 vd->bkgdattr); 78 if (vd->dblwid) 79 memset(&vd->dblwid[vd->scrreg_startrow + help], 0, n); 80 CHECK_DW(vd); 81} 82 83/* 84 * scroll down within scrolling region 85 */ 86void 87wsemul_vt100_scrolldown(struct vt100base_data *vd, int n) 88{ 89 int help; 90 91 if (n > vd->scrreg_nrows) 92 n = vd->scrreg_nrows; 93 94 help = vd->scrreg_nrows - n; 95 if (help > 0) { 96 (*vd->emulops->copyrows)(vd->emulcookie, 97 vd->scrreg_startrow, 98 vd->scrreg_startrow + n, 99 help); 100 if (vd->dblwid) 101 memmove(&vd->dblwid[vd->scrreg_startrow + n], 102 &vd->dblwid[vd->scrreg_startrow], 103 help); 104 } 105 (*vd->emulops->eraserows)(vd->emulcookie, 106 vd->scrreg_startrow, n, 107 vd->bkgdattr); 108 if (vd->dblwid) 109 memset(&vd->dblwid[vd->scrreg_startrow], 0, n); 110 CHECK_DW(vd); 111} 112 113/* 114 * erase in display 115 */ 116void 117wsemul_vt100_ed(struct vt100base_data *vd, int arg) 118{ 119 int n; 120 121 switch (arg) { 122 case 0: /* cursor to end */ 123 ERASECOLS(vd, vd->ccol, COLS_LEFT(vd) + 1, vd->bkgdattr); 124 n = vd->nrows - vd->crow - 1; 125 if (n > 0) { 126 (*vd->emulops->eraserows)(vd->emulcookie, 127 vd->crow + 1, n, 128 vd->bkgdattr); 129 if (vd->dblwid) 130 memset(&vd->dblwid[vd->crow + 1], 0, n); 131 } 132 break; 133 case 1: /* beginning to cursor */ 134 if (vd->crow > 0) { 135 (*vd->emulops->eraserows)(vd->emulcookie, 136 0, vd->crow, 137 vd->bkgdattr); 138 if (vd->dblwid) 139 memset(&vd->dblwid[0], 0, vd->crow); 140 } 141 ERASECOLS(vd, 0, vd->ccol + 1, vd->bkgdattr); 142 break; 143 case 2: /* complete display */ 144 (*vd->emulops->eraserows)(vd->emulcookie, 145 0, vd->nrows, 146 vd->bkgdattr); 147 if (vd->dblwid) 148 memset(&vd->dblwid[0], 0, vd->nrows); 149 break; 150 default: 151#ifdef VT100_PRINTUNKNOWN 152 printf("ed(%d) unknown\n", arg); 153#endif 154 break; 155 } 156 CHECK_DW(vd); 157} 158 159/* 160 * erase in line 161 */ 162void 163wsemul_vt100_el(struct vt100base_data *vd, int arg) 164{ 165 switch (arg) { 166 case 0: /* cursor to end */ 167 ERASECOLS(vd, vd->ccol, COLS_LEFT(vd) + 1, vd->bkgdattr); 168 break; 169 case 1: /* beginning to cursor */ 170 ERASECOLS(vd, 0, vd->ccol + 1, vd->bkgdattr); 171 break; 172 case 2: /* complete line */ 173 (*vd->emulops->erasecols)(vd->emulcookie, vd->crow, 174 0, vd->ncols, 175 vd->bkgdattr); 176 break; 177 default: 178#ifdef VT100_PRINTUNKNOWN 179 printf("el(%d) unknown\n", arg); 180#endif 181 break; 182 } 183} 184 185/* 186 * handle commands after CSI (ESC[) 187 */ 188void 189wsemul_vt100_handle_csi(struct vt100base_data *vd, u_char c) 190{ 191 int n, m, help, flags, fgcol, bgcol; 192 long attr, bkgdattr; 193 194#define A3(a, b, c) (((a) << 16) | ((b) << 8) | (c)) 195 switch (A3(vd->modif1, vd->modif2, c)) { 196 case A3('>', '\0', 'c'): /* DA secondary */ 197 wsdisplay_emulinput(vd->cbcookie, WSEMUL_VT_ID2, 198 sizeof(WSEMUL_VT_ID2) - 1); 199 break; 200 201 case A3('\0', '\0', 'J'): /* ED selective erase in display */ 202 case A3('?', '\0', 'J'): /* DECSED selective erase in display */ 203 wsemul_vt100_ed(vd, ARG(vd, 0)); 204 break; 205 case A3('\0', '\0', 'K'): /* EL selective erase in line */ 206 case A3('?', '\0', 'K'): /* DECSEL selective erase in line */ 207 wsemul_vt100_el(vd, ARG(vd, 0)); 208 break; 209 case A3('\0', '\0', 'h'): /* SM */ 210 for (n = 0; n < vd->nargs; n++) 211 vt100_ansimode(vd, ARG(vd, n), VTMODE_SET); 212 break; 213 case A3('?', '\0', 'h'): /* DECSM */ 214 for (n = 0; n < vd->nargs; n++) 215 vt100_decmode(vd, ARG(vd, n), VTMODE_SET); 216 break; 217 case A3('\0', '\0', 'l'): /* RM */ 218 for (n = 0; n < vd->nargs; n++) 219 vt100_ansimode(vd, ARG(vd, n), VTMODE_RESET); 220 break; 221 case A3('?', '\0', 'l'): /* DECRM */ 222 for (n = 0; n < vd->nargs; n++) 223 vt100_decmode(vd, ARG(vd, n), VTMODE_RESET); 224 break; 225 case A3('\0', '$', 'p'): /* DECRQM request mode ANSI */ 226 vt100_ansimode(vd, ARG(vd, 0), VTMODE_REPORT); 227 break; 228 case A3('?', '$', 'p'): /* DECRQM request mode DEC */ 229 vt100_decmode(vd, ARG(vd, 0), VTMODE_REPORT); 230 break; 231 case A3('\0', '\0', 'i'): /* MC printer controller mode */ 232 case A3('?', '\0', 'i'): /* MC printer controller mode */ 233 switch (ARG(vd, 0)) { 234 case 0: /* print screen */ 235 case 1: /* print cursor line */ 236 case 4: /* off */ 237 case 5: /* on */ 238#ifdef VT100_PRINTNOTIMPL 239 printf("CSI%di ignored\n", ARG(vd, 0)); 240#endif 241 break; 242 default: 243#ifdef VT100_PRINTUNKNOWN 244 printf("CSI%di unknown\n", ARG(vd, 0)); 245#endif 246 break; 247 } 248 break; 249 250#define A2(a, b) (((a) << 8) | (b)) 251#if 0 /* XXX: edp not available here */ 252 case A2('!', 'p'): /* DECSTR soft reset VT300 only */ 253 wsemul_vt100_reset(edp); 254 break; 255#endif 256 257 case A2('"', 'p'): /* DECSCL */ 258 switch (ARG(vd, 0)) { 259 case 61: /* VT100 mode (no further arguments!) */ 260 break; 261 case 62: 262 case 63: /* VT300 mode */ 263 break; 264 default: 265#ifdef VT100_PRINTUNKNOWN 266 printf("CSI%d\"p unknown\n", ARG(vd, 0)); 267#endif 268 break; 269 } 270 switch (ARG(vd, 1)) { 271 case 0: 272 case 2: /* 8-bit controls */ 273#ifdef VT100_PRINTNOTIMPL 274 printf("CSI%d;%d\"p ignored\n", ARG(vd, 0), ARG(vd, 1)); 275#endif 276 break; 277 case 1: /* 7-bit controls */ 278 break; 279 default: 280#ifdef VT100_PRINTUNKNOWN 281 printf("CSI%d;%d\"p unknown\n", ARG(vd, 0), ARG(vd, 1)); 282#endif 283 break; 284 } 285 break; 286 case A2('"', 'q'): /* DECSCA select character attribute VT300 */ 287 switch (ARG(vd, 0)) { 288 case 0: 289 case 1: /* erasable */ 290 break; 291 case 2: /* not erasable */ 292#ifdef VT100_PRINTNOTIMPL 293 printf("CSI2\"q ignored\n"); 294#endif 295 break; 296 default: 297#ifdef VT100_PRINTUNKNOWN 298 printf("CSI%d\"q unknown\n", ARG(vd, 0)); 299#endif 300 break; 301 } 302 break; 303 304 case A2('$', 'u'): /* DECRQTSR request terminal status report */ 305 switch (ARG(vd, 0)) { 306 case 0: /* ignored */ 307 break; 308 case 1: /* terminal state report */ 309#ifdef VT100_PRINTNOTIMPL 310 printf("CSI1$u ignored\n"); 311#endif 312 break; 313 default: 314#ifdef VT100_PRINTUNKNOWN 315 printf("CSI%d$u unknown\n", ARG(vd, 0)); 316#endif 317 break; 318 } 319 break; 320 case A2('$', 'w'): /* DECRQPSR request presentation status report 321 (VT300 only) */ 322 switch (ARG(vd, 0)) { 323 case 0: /* error */ 324 break; 325 case 1: /* cursor information report */ 326#ifdef VT100_PRINTNOTIMPL 327 printf("CSI1$w ignored\n"); 328#endif 329 break; 330 case 2: /* tab stop report */ 331 { 332 int i, j, ps = 0; 333 char buf[20]; 334 KASSERT(vd->tabs != NULL); 335 wsdisplay_emulinput(vd->cbcookie, "\033P2$u", 5); 336 for (i = 0; i < vd->ncols; i++) 337 if (vd->tabs[i]) { 338 j = snprintf(buf, sizeof(buf), "%s%d", 339 (ps ? "/" : ""), i + 1); 340 wsdisplay_emulinput(vd->cbcookie, 341 buf, j); 342 ps = 1; 343 } 344 } 345 wsdisplay_emulinput(vd->cbcookie, "\033\\", 2); 346 break; 347 default: 348#ifdef VT100_PRINTUNKNOWN 349 printf("CSI%d$w unknown\n", ARG(vd, 0)); 350#endif 351 break; 352 } 353 break; 354 case A2('$', '}'): /* DECSASD select active status display */ 355 switch (ARG(vd, 0)) { 356 case 0: /* main display */ 357 case 1: /* status line */ 358#ifdef VT100_PRINTNOTIMPL 359 printf("CSI%d$} ignored\n", ARG(vd, 0)); 360#endif 361 break; 362 default: 363#ifdef VT100_PRINTUNKNOWN 364 printf("CSI%d$} unknown\n", ARG(vd, 0)); 365#endif 366 break; 367 } 368 break; 369 case A2('$', '~'): /* DECSSDD select status line type */ 370 switch (ARG(vd, 0)) { 371 case 0: /* none */ 372 case 1: /* indicator */ 373 case 2: /* host-writable */ 374#ifdef VT100_PRINTNOTIMPL 375 printf("CSI%d$~ ignored\n", ARG(vd, 0)); 376#endif 377 break; 378 default: 379#ifdef VT100_PRINTUNKNOWN 380 printf("CSI%d$~ unknown\n", ARG(vd, 0)); 381#endif 382 break; 383 } 384 break; 385 386 case A2('&', 'u'): /* DECRQUPSS request user preferred 387 supplemental set */ 388 wsdisplay_emulinput(vd->cbcookie, "\033P0!u%5\033\\", 9); 389 break; 390 391 case '@': /* ICH insert character VT300 only */ 392 n = uimin(DEF1_ARG(vd, 0), COLS_LEFT(vd) + 1); 393 help = NCOLS(vd) - (vd->ccol + n); 394 if (help > 0) 395 COPYCOLS(vd, vd->ccol, vd->ccol + n, help); 396 ERASECOLS(vd, vd->ccol, n, vd->bkgdattr); 397 break; 398 case 'A': /* CUU */ 399 /* stop at the top scroll margin */ 400 m = vd->scrreg_startrow; 401 if (vd->crow < m)/* but if already above the margin */ 402 m = 0; /* then at the screen top */ 403 help = vd->crow - m; /* rows above */ 404 vd->crow -= uimin(DEF1_ARG(vd, 0), help); 405 CHECK_DW(vd); 406 break; 407 case 'B': /* CUD */ 408 /* stop at the bottom scroll margin */ 409 m = vd->scrreg_startrow + vd->scrreg_nrows - 1; 410 if (vd->crow > m) /* but if already below the margin */ 411 m = vd->nrows - 1; /* then at the screen bottom */ 412 help = m - vd->crow; /* rows below */ 413 vd->crow += uimin(DEF1_ARG(vd, 0), help); 414 CHECK_DW(vd); 415 break; 416 case 'C': /* CUF */ 417 vd->ccol += uimin(DEF1_ARG(vd, 0), COLS_LEFT(vd)); 418 break; 419 case 'D': /* CUB */ 420 vd->ccol -= uimin(DEF1_ARG(vd, 0), vd->ccol); 421 vd->flags &= ~VTFL_LASTCHAR; 422 break; 423 case 'G': /* CHA */ 424 vd->ccol = uimin(DEF1_ARG(vd, 0) - 1, vd->ncols -1); 425 break; 426 case 'H': /* CUP */ 427 case 'f': /* HVP */ 428 if (vd->flags & VTFL_DECOM) 429 vd->crow = vd->scrreg_startrow + 430 uimin(DEF1_ARG(vd, 0), vd->scrreg_nrows) - 1; 431 else 432 vd->crow = uimin(DEF1_ARG(vd, 0), vd->nrows) - 1; 433 CHECK_DW(vd); 434 vd->ccol = uimin(DEF1_ARG(vd, 1), NCOLS(vd)) - 1; 435 vd->flags &= ~VTFL_LASTCHAR; 436 break; 437 case 'L': /* IL insert line */ 438 case 'M': /* DL delete line */ 439 /* ignored when the cursor is outside the scrolling region */ 440 if (vd->crow < vd->scrreg_startrow 441 || vd->scrreg_startrow + vd->scrreg_nrows <= vd->crow) 442 break; 443 n = uimin(DEF1_ARG(vd, 0), ROWS_BELOW(vd) + 1); 444 { 445 int savscrstartrow, savscrnrows; 446 savscrstartrow = vd->scrreg_startrow; 447 savscrnrows = vd->scrreg_nrows; 448 vd->scrreg_nrows -= ROWS_ABOVE(vd); 449 vd->scrreg_startrow = vd->crow; 450 if (c == 'L') 451 wsemul_vt100_scrolldown(vd, n); 452 else 453 wsemul_vt100_scrollup(vd, n); 454 vd->scrreg_startrow = savscrstartrow; 455 vd->scrreg_nrows = savscrnrows; 456 } 457 vd->ccol = 0; 458 break; 459 case 'P': /* DCH delete character */ 460 n = uimin(DEF1_ARG(vd, 0), COLS_LEFT(vd) + 1); 461 help = NCOLS(vd) - (vd->ccol + n); 462 if (help > 0) 463 COPYCOLS(vd, vd->ccol + n, vd->ccol, help); 464 ERASECOLS(vd, NCOLS(vd) - n, n, vd->bkgdattr); 465 break; 466 case 'S': /* SU */ 467 wsemul_vt100_scrollup(vd, DEF1_ARG(vd, 0)); 468 break; 469 case 'T': /* SD */ 470 wsemul_vt100_scrolldown(vd, DEF1_ARG(vd, 0)); 471 break; 472 case 'X': /* ECH erase character */ 473 n = uimin(DEF1_ARG(vd, 0), COLS_LEFT(vd) + 1); 474 ERASECOLS(vd, vd->ccol, n, vd->bkgdattr); 475 break; 476 case 'Z': /* CBT */ 477 if (vd->ccol == 0) 478 break; 479 for (m = 0; m < DEF1_ARG(vd, 0); m++) { 480 if (vd->tabs) { 481 for (n = vd->ccol - 1; n > 0; n--) { 482 if (vd->tabs[n]) 483 break; 484 } 485 } else 486 n = (vd->ccol - 1) & ~7; 487 vd->ccol = n; 488 if (n == 0) 489 break; 490 } 491 break; 492 case 'c': /* DA primary */ 493 if (ARG(vd, 0) == 0) 494 wsdisplay_emulinput(vd->cbcookie, WSEMUL_VT_ID1, 495 sizeof(WSEMUL_VT_ID1) - 1); 496 break; 497 case 'd': /* VPA */ 498 vd->crow = uimin(DEF1_ARG(vd, 0) - 1, vd->nrows - 1); 499 break; 500 case 'g': /* TBC */ 501 KASSERT(vd->tabs != NULL); 502 switch (ARG(vd, 0)) { 503 case 0: 504 vd->tabs[vd->ccol] = 0; 505 break; 506 case 3: 507 memset(vd->tabs, 0, vd->ncols); 508 break; 509 default: 510#ifdef VT100_PRINTUNKNOWN 511 printf("CSI%dg unknown\n", ARG(vd, 0)); 512#endif 513 break; 514 } 515 break; 516 case 'm': /* SGR select graphic rendition */ 517 flags = vd->attrflags; 518 fgcol = vd->fgcol; 519 bgcol = vd->bgcol; 520 for (n = 0; n < vd->nargs; n++) { 521 switch (ARG(vd, n)) { 522 case 0: /* reset */ 523 if (n == vd->nargs - 1) { 524 vd->bkgdattr = vd->curattr = vd->defattr; 525 vd->attrflags = vd->msgattrs.default_attrs; 526 vd->fgcol = vd->msgattrs.default_fg; 527 vd->bgcol = vd->msgattrs.default_bg; 528 return; 529 } 530 flags = vd->msgattrs.default_attrs; 531 fgcol = vd->msgattrs.default_fg; 532 bgcol = vd->msgattrs.default_bg; 533 break; 534 case 1: /* bold */ 535 flags |= WSATTR_HILIT; 536 break; 537 case 4: /* underline */ 538 flags |= WSATTR_UNDERLINE; 539 break; 540 case 5: /* blink */ 541 flags |= WSATTR_BLINK; 542 break; 543 case 7: /* reverse */ 544 flags |= WSATTR_REVERSE; 545 break; 546 case 22: /* ~bold VT300 only */ 547 flags &= ~WSATTR_HILIT; 548 break; 549 case 24: /* ~underline VT300 only */ 550 flags &= ~WSATTR_UNDERLINE; 551 break; 552 case 25: /* ~blink VT300 only */ 553 flags &= ~WSATTR_BLINK; 554 break; 555 case 27: /* ~reverse VT300 only */ 556 flags &= ~WSATTR_REVERSE; 557 break; 558 case 30: case 31: case 32: case 33: 559 case 34: case 35: case 36: case 37: 560 /* fg color */ 561 flags |= WSATTR_WSCOLORS; 562 fgcol = ARG(vd, n) - 30; 563 break; 564 case 39: 565 fgcol = vd->msgattrs.default_fg; 566 break; 567 case 40: case 41: case 42: case 43: 568 case 44: case 45: case 46: case 47: 569 /* bg color */ 570 flags |= WSATTR_WSCOLORS; 571 bgcol = ARG(vd, n) - 40; 572 break; 573 case 49: 574 bgcol = vd->msgattrs.default_bg; 575 break; 576 default: 577#ifdef VT100_PRINTUNKNOWN 578 printf("CSI%dm unknown\n", ARG(vd, n)); 579#endif 580 break; 581 } 582 } 583 if (vt100_selectattribute(vd, flags, fgcol, bgcol, &attr, 584 &bkgdattr)) { 585#ifdef VT100_DEBUG 586 printf("error allocating attr %d/%d/%x\n", 587 fgcol, bgcol, flags); 588#endif 589 } else { 590 vd->curattr = attr; 591 vd->bkgdattr = bkgdattr; 592 vd->attrflags = flags; 593 vd->fgcol = fgcol; 594 vd->bgcol = bgcol; 595 } 596 break; 597 case 't': /* terminal size and such */ 598 switch (ARG(vd, 0)) { 599 case 18: { /* xterm size */ 600 char buf[20]; 601 602 n = snprintf(buf, sizeof(buf), "\033[8;%d;%dt", 603 vd->nrows, vd->ncols); 604 wsdisplay_emulinput(vd->cbcookie, buf, n); 605 } 606 break; 607 } 608 break; 609 case 'n': /* reports */ 610 switch (ARG(vd, 0)) { 611 case 5: /* DSR operating status */ 612 /* 0 = OK, 3 = malfunction */ 613 wsdisplay_emulinput(vd->cbcookie, "\033[0n", 4); 614 break; 615 case 6: { /* DSR cursor position report */ 616 char buf[20]; 617 int row; 618 if (vd->flags & VTFL_DECOM) 619 row = ROWS_ABOVE(vd); 620 else 621 row = vd->crow; 622 n = snprintf(buf, sizeof(buf), "\033[%d;%dR", 623 row + 1, vd->ccol + 1); 624 wsdisplay_emulinput(vd->cbcookie, buf, n); 625 } 626 break; 627 case 15: /* DSR printer status */ 628 /* 13 = no printer, 10 = ready, 11 = not ready */ 629 wsdisplay_emulinput(vd->cbcookie, "\033[?13n", 6); 630 break; 631 case 25: /* UDK status - VT300 only */ 632 /* 20 = locked, 21 = unlocked */ 633 wsdisplay_emulinput(vd->cbcookie, "\033[?21n", 6); 634 break; 635 case 26: /* keyboard dialect */ 636 /* 1 = north american , 7 = german */ 637 wsdisplay_emulinput(vd->cbcookie, "\033[?27;1n", 8); 638 break; 639 default: 640#ifdef VT100_PRINTUNKNOWN 641 printf("CSI%dn unknown\n", ARG(vd, 0)); 642#endif 643 break; 644 } 645 break; 646 case 'r': /* DECSTBM set top/bottom margins */ 647 help = uimin(DEF1_ARG(vd, 0), vd->nrows) - 1; 648 n = uimin(DEFx_ARG(vd, 1, vd->nrows), vd->nrows) - help; 649 if (n < 2) { 650 /* minimal scrolling region has 2 lines */ 651 return; 652 } else { 653 vd->scrreg_startrow = help; 654 vd->scrreg_nrows = n; 655 } 656 vd->crow = ((vd->flags & VTFL_DECOM) ? 657 vd->scrreg_startrow : 0); 658 vd->ccol = 0; 659 break; 660 case 'y': 661 switch (ARG(vd, 0)) { 662 case 4: /* DECTST invoke confidence test */ 663 /* ignore */ 664 break; 665 default: 666#ifdef VT100_PRINTUNKNOWN 667 printf("CSI%dy unknown\n", ARG(vd, 0)); 668#endif 669 break; 670 } 671 break; 672 default: 673#ifdef VT100_PRINTUNKNOWN 674 printf("CSI%c (%d, %d) unknown\n", c, ARG(vd, 0), ARG(vd, 1)); 675#endif 676 break; 677 } 678} 679 680/* 681 * get an attribute from the graphics driver, 682 * try to find replacements if the desired appearance 683 * is not supported 684 */ 685static int 686vt100_selectattribute(struct vt100base_data *vd, 687 int flags, int fgcol, int bgcol, long *attr, long *bkgdattr) 688{ 689 int error; 690 691 if (!(vd->scrcapabilities & WSSCREEN_WSCOLORS)) { 692 flags &= ~WSATTR_WSCOLORS; 693#ifdef VT100_DEBUG 694 printf("colors ignored (impossible)\n"); 695#endif 696 } else 697 flags |= WSATTR_WSCOLORS; 698 error = (*vd->emulops->allocattr)(vd->emulcookie, fgcol, bgcol, 699 flags & WSATTR_WSCOLORS, bkgdattr); 700 if (error) 701 return (error); 702 703 if ((flags & WSATTR_HILIT) && 704 !(vd->scrcapabilities & WSSCREEN_HILIT)) { 705 flags &= ~WSATTR_HILIT; 706 if (vd->scrcapabilities & WSSCREEN_WSCOLORS) { 707#if defined(WSEMUL_VT100_HILIT_FG) && WSEMUL_VT100_HILIT_FG != -1 708 fgcol = WSEMUL_VT100_HILIT_FG; 709#elif !defined(WSEMUL_VT100_HILIT_FG) 710 fgcol = WSCOL_RED; 711#endif 712#if defined(WSEMUL_VT100_HILIT_BG) && WSEMUL_VT100_HILIT_BG != -1 713 bgcol = WSEMUL_VT100_HILIT_BG; 714#endif 715 flags |= WSATTR_WSCOLORS; 716 } else { 717#ifdef VT100_DEBUG 718 printf("bold ignored (impossible)\n"); 719#endif 720 } 721 } 722 if ((flags & WSATTR_UNDERLINE) && 723 !(vd->scrcapabilities & WSSCREEN_UNDERLINE)) { 724 flags &= ~WSATTR_UNDERLINE; 725 if (vd->scrcapabilities & WSSCREEN_WSCOLORS) { 726#if defined(WSEMUL_VT100_UNDERLINE_FG) && WSEMUL_VT100_UNDERLINE_FG != -1 727 fgcol = WSEMUL_VT100_UNDERLINE_FG; 728#endif 729#if defined(WSEMUL_VT100_UNDERLINE_BG) && WSEMUL_VT100_UNDERLINE_BG != -1 730 bgcol = WSEMUL_VT100_UNDERLINE_BG; 731#elif !defined(WSEMUL_VT100_UNDERLINE_BG) 732 bgcol = WSCOL_BROWN; 733#endif 734 flags |= WSATTR_WSCOLORS; 735 } else { 736#ifdef VT100_DEBUG 737 printf("underline ignored (impossible)\n"); 738#endif 739 } 740 } 741 if ((flags & WSATTR_BLINK) && 742 !(vd->scrcapabilities & WSSCREEN_BLINK)) { 743 flags &= ~WSATTR_BLINK; 744#ifdef VT100_DEBUG 745 printf("blink ignored (impossible)\n"); 746#endif 747 } 748 if ((flags & WSATTR_REVERSE) && 749 !(vd->scrcapabilities & WSSCREEN_REVERSE)) { 750 flags &= ~WSATTR_REVERSE; 751 if (vd->scrcapabilities & WSSCREEN_WSCOLORS) { 752 int help; 753 help = bgcol; 754 bgcol = fgcol; 755 fgcol = help; 756 flags |= WSATTR_WSCOLORS; 757 } else { 758#ifdef VT100_DEBUG 759 printf("reverse ignored (impossible)\n"); 760#endif 761 } 762 } 763 error = (*vd->emulops->allocattr)(vd->emulcookie, fgcol, bgcol, 764 flags, attr); 765 if (error) 766 return (error); 767 768 return (0); 769} 770 771/* 772 * handle device control sequences if the main state machine 773 * told so by setting vd->dcstype to a nonzero value 774 */ 775void 776wsemul_vt100_handle_dcs(struct vt100base_data *vd) 777{ 778 int i, pos; 779 780 switch (vd->dcstype) { 781 case 0: /* not handled */ 782 return; 783 case DCSTYPE_TABRESTORE: 784 KASSERT(vd->tabs != NULL); 785 KASSERT(vd->ncols <= 1024); 786 memset(vd->tabs, 0, vd->ncols); 787 pos = 0; 788 for (i = 0; i < vd->dcspos; i++) { 789 char c = vd->dcsarg[i]; 790 switch (c) { 791 case '0': case '1': case '2': case '3': case '4': 792 case '5': case '6': case '7': case '8': case '9': { 793 const int c0 = c - '0'; 794 if (pos < 0 || 795 pos > INT_MAX/10 || 796 pos * 10 > vd->ncols - c0) { 797 pos = -1; 798 break; 799 } 800 pos = pos * 10 + c0; 801 break; 802 } 803 case '/': 804 if (pos > 0) { 805 KASSERT(pos <= vd->ncols); 806 vd->tabs[pos - 1] = 1; 807 } 808 pos = 0; 809 break; 810 default: 811#ifdef VT100_PRINTUNKNOWN 812 printf("unknown char %c in DCS\n", c); 813#endif 814 break; 815 } 816 } 817 if (pos > 0) { 818 KASSERT(pos <= vd->ncols); 819 vd->tabs[pos - 1] = 1; 820 } 821 break; 822 default: 823 panic("wsemul_vt100_handle_dcs: bad type %d", vd->dcstype); 824 } 825 vd->dcstype = 0; 826} 827 828static int 829vt100_ansimode(struct vt100base_data *vd, int nr, int op) 830{ 831 int res = 0; /* default: unknown */ 832 833 switch (nr) { 834 case 2: /* KAM keyboard locked/unlocked */ 835 break; 836 case 3: /* CRM control representation */ 837 break; 838 case 4: /* IRM insert/replace characters */ 839 if (op == VTMODE_SET) 840 vd->flags |= VTFL_INSERTMODE; 841 else if (op == VTMODE_RESET) 842 vd->flags &= ~VTFL_INSERTMODE; 843 res = ((vd->flags & VTFL_INSERTMODE) ? 1 : 2); 844 break; 845 case 10: /* HEM horizontal editing (permanently reset) */ 846 res = 4; 847 break; 848 case 12: /* SRM local echo off/on */ 849 res = 4; /* permanently reset ??? */ 850 break; 851 case 20: /* LNM newline = newline/linefeed */ 852 break; 853 default: 854#ifdef VT100_PRINTUNKNOWN 855 printf("ANSI mode %d unknown\n", nr); 856#endif 857 break; 858 } 859 return (res); 860} 861 862static int 863vt100_decmode(struct vt100base_data *vd, int nr, int op) 864{ 865 int res = 0; /* default: unknown */ 866 int flags; 867 868 flags = vd->flags; 869 switch (nr) { 870 case 1: /* DECCKM application/nomal cursor keys */ 871 if (op == VTMODE_SET) 872 flags |= VTFL_APPLCURSOR; 873 else if (op == VTMODE_RESET) 874 flags &= ~VTFL_APPLCURSOR; 875 res = ((flags & VTFL_APPLCURSOR) ? 1 : 2); 876 break; 877 case 2: /* DECANM ANSI vt100/vt52 */ 878 res = 3; /* permanently set ??? */ 879 break; 880 case 3: /* DECCOLM 132/80 cols */ 881 case 4: /* DECSCLM smooth/jump scroll */ 882 case 5: /* DECSCNM light/dark background */ 883 res = 4; /* all permanently reset ??? */ 884 break; 885 case 6: /* DECOM move within/outside margins */ 886 if (op == VTMODE_SET) 887 flags |= VTFL_DECOM; 888 else if (op == VTMODE_RESET) 889 flags &= ~VTFL_DECOM; 890 res = ((flags & VTFL_DECOM) ? 1 : 2); 891 break; 892 case 7: /* DECAWM autowrap */ 893 if (op == VTMODE_SET) 894 flags |= VTFL_DECAWM; 895 else if (op == VTMODE_RESET) 896 flags &= ~VTFL_DECAWM; 897 res = ((flags & VTFL_DECAWM) ? 1 : 2); 898 break; 899 case 8: /* DECARM keyboard autorepeat */ 900 break; 901 case 18: /* DECPFF print form feed */ 902 break; 903 case 19: /* DECPEX printer extent: screen/scrolling region */ 904 break; 905 case 25: /* DECTCEM text cursor on/off */ 906 if (op == VTMODE_SET) 907 flags |= VTFL_CURSORON; 908 else if (op == VTMODE_RESET) 909 flags &= ~VTFL_CURSORON; 910 if (flags != vd->flags) 911 (*vd->emulops->cursor)(vd->emulcookie, 912 flags & VTFL_CURSORON, 913 vd->crow, vd->ccol); 914 res = ((flags & VTFL_CURSORON) ? 1 : 2); 915 break; 916 case 42: /* DECNRCM use 7-bit NRC / 917 7/8 bit from DEC multilingual or ISO-latin-1*/ 918 if (op == VTMODE_SET) 919 flags |= VTFL_NATCHARSET; 920 else if (op == VTMODE_RESET) 921 flags &= ~VTFL_NATCHARSET; 922 res = ((flags & VTFL_NATCHARSET) ? 1 : 2); 923 break; 924 case 66: /* DECNKM numeric keypad */ 925 break; 926 case 68: /* DECKBUM keyboard usage data processing/typewriter */ 927 break; 928 default: 929#ifdef VT100_PRINTUNKNOWN 930 printf("DEC mode %d unknown\n", nr); 931#endif 932 break; 933 } 934 vd->flags = flags; 935 936 return (res); 937} 938