1 /* $OpenBSD: wsemul_vt100.c,v 1.48 2024/11/05 08:12:08 miod Exp $ */ 2 /* $NetBSD: wsemul_vt100.c,v 1.13 2000/04/28 21:56:16 mycroft 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) 1998 22 * Matthias Drochner. All rights reserved. 23 * 24 * Redistribution and use in source and binary forms, with or without 25 * modification, are permitted provided that the following conditions 26 * are met: 27 * 1. Redistributions of source code must retain the above copyright 28 * notice, this list of conditions and the following disclaimer. 29 * 2. Redistributions in binary form must reproduce the above copyright 30 * notice, this list of conditions and the following disclaimer in the 31 * documentation and/or other materials provided with the distribution. 32 * 33 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 34 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 35 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 36 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 37 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 38 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 39 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 40 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 41 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 42 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 43 * 44 */ 45 46 #include <sys/param.h> 47 #include <sys/systm.h> 48 #include <sys/time.h> 49 #include <sys/malloc.h> 50 #include <sys/fcntl.h> 51 52 #include <dev/wscons/wscons_features.h> 53 #include <dev/wscons/wsconsio.h> 54 #include <dev/wscons/wsdisplayvar.h> 55 #include <dev/wscons/wsemulvar.h> 56 #include <dev/wscons/wsemul_vt100var.h> 57 #include <dev/wscons/ascii.h> 58 59 void *wsemul_vt100_cnattach(const struct wsscreen_descr *, void *, 60 int, int, uint32_t); 61 void *wsemul_vt100_attach(int, const struct wsscreen_descr *, 62 void *, int, int, void *, uint32_t); 63 u_int wsemul_vt100_output(void *, const u_char *, u_int, int); 64 void wsemul_vt100_detach(void *, u_int *, u_int *); 65 void wsemul_vt100_resetop(void *, enum wsemul_resetops); 66 67 const struct wsemul_ops wsemul_vt100_ops = { 68 "vt100", 69 wsemul_vt100_cnattach, 70 wsemul_vt100_attach, 71 wsemul_vt100_output, 72 wsemul_vt100_translate, 73 wsemul_vt100_detach, 74 wsemul_vt100_resetop 75 }; 76 77 struct wsemul_vt100_emuldata wsemul_vt100_console_emuldata; 78 79 void wsemul_vt100_init(struct wsemul_vt100_emuldata *, 80 const struct wsscreen_descr *, void *, int, int, uint32_t); 81 int wsemul_vt100_jump_scroll(struct wsemul_vt100_emuldata *, 82 const u_char *, u_int, int); 83 int wsemul_vt100_output_c0c1(struct wsemul_vt100_emuldata *, 84 struct wsemul_inputstate *, int); 85 int wsemul_vt100_nextline(struct wsemul_vt100_emuldata *); 86 87 typedef int vt100_handler(struct wsemul_vt100_emuldata *, struct 88 wsemul_inputstate *, int); 89 vt100_handler 90 wsemul_vt100_output_esc, 91 wsemul_vt100_output_csi, 92 wsemul_vt100_output_scs94, 93 wsemul_vt100_output_scs94_percent, 94 wsemul_vt100_output_scs96, 95 wsemul_vt100_output_scs96_percent, 96 wsemul_vt100_output_esc_hash, 97 wsemul_vt100_output_esc_spc, 98 wsemul_vt100_output_string, 99 wsemul_vt100_output_string_esc, 100 wsemul_vt100_output_dcs, 101 wsemul_vt100_output_dcs_dollar, 102 wsemul_vt100_output_esc_percent; 103 104 #define VT100_EMUL_STATE_NORMAL 0 /* normal processing */ 105 #define VT100_EMUL_STATE_ESC 1 /* got ESC */ 106 #define VT100_EMUL_STATE_CSI 2 /* got CSI (ESC[) */ 107 #define VT100_EMUL_STATE_SCS94 3 /* got ESC{()*+} */ 108 #define VT100_EMUL_STATE_SCS94_PERCENT 4 /* got ESC{()*+}% */ 109 #define VT100_EMUL_STATE_SCS96 5 /* got ESC{-./} */ 110 #define VT100_EMUL_STATE_SCS96_PERCENT 6 /* got ESC{-./}% */ 111 #define VT100_EMUL_STATE_ESC_HASH 7 /* got ESC# */ 112 #define VT100_EMUL_STATE_ESC_SPC 8 /* got ESC<SPC> */ 113 #define VT100_EMUL_STATE_STRING 9 /* waiting for ST (ESC\) */ 114 #define VT100_EMUL_STATE_STRING_ESC 10 /* waiting for ST, got ESC */ 115 #define VT100_EMUL_STATE_DCS 11 /* got DCS (ESC P) */ 116 #define VT100_EMUL_STATE_DCS_DOLLAR 12 /* got DCS<p>$ */ 117 #define VT100_EMUL_STATE_ESC_PERCENT 13 /* got ESC% */ 118 119 vt100_handler *vt100_output[] = { 120 wsemul_vt100_output_esc, 121 wsemul_vt100_output_csi, 122 wsemul_vt100_output_scs94, 123 wsemul_vt100_output_scs94_percent, 124 wsemul_vt100_output_scs96, 125 wsemul_vt100_output_scs96_percent, 126 wsemul_vt100_output_esc_hash, 127 wsemul_vt100_output_esc_spc, 128 wsemul_vt100_output_string, 129 wsemul_vt100_output_string_esc, 130 wsemul_vt100_output_dcs, 131 wsemul_vt100_output_dcs_dollar, 132 wsemul_vt100_output_esc_percent, 133 }; 134 135 void 136 wsemul_vt100_init(struct wsemul_vt100_emuldata *edp, 137 const struct wsscreen_descr *type, void *cookie, int ccol, int crow, 138 uint32_t defattr) 139 { 140 edp->emulops = type->textops; 141 edp->emulcookie = cookie; 142 edp->scrcapabilities = type->capabilities; 143 edp->nrows = type->nrows; 144 edp->ncols = type->ncols; 145 edp->crow = crow; 146 edp->ccol = ccol; 147 edp->defattr = defattr; 148 wsemul_reset_abortstate(&edp->abortstate); 149 } 150 151 void * 152 wsemul_vt100_cnattach(const struct wsscreen_descr *type, void *cookie, int ccol, 153 int crow, uint32_t defattr) 154 { 155 struct wsemul_vt100_emuldata *edp; 156 int res; 157 158 edp = &wsemul_vt100_console_emuldata; 159 wsemul_vt100_init(edp, type, cookie, ccol, crow, defattr); 160 #ifdef DIAGNOSTIC 161 edp->console = 1; 162 #endif 163 edp->cbcookie = NULL; 164 165 #ifndef WS_KERNEL_FG 166 #define WS_KERNEL_FG WSCOL_WHITE 167 #endif 168 #ifndef WS_KERNEL_BG 169 #define WS_KERNEL_BG WSCOL_BLUE 170 #endif 171 #ifndef WS_KERNEL_COLATTR 172 #define WS_KERNEL_COLATTR 0 173 #endif 174 #ifndef WS_KERNEL_MONOATTR 175 #define WS_KERNEL_MONOATTR 0 176 #endif 177 if (type->capabilities & WSSCREEN_WSCOLORS) 178 res = (*edp->emulops->pack_attr)(cookie, 179 WS_KERNEL_FG, WS_KERNEL_BG, 180 WS_KERNEL_COLATTR | WSATTR_WSCOLORS, &edp->kernattr); 181 else 182 res = (*edp->emulops->pack_attr)(cookie, 0, 0, 183 WS_KERNEL_MONOATTR, &edp->kernattr); 184 if (res) 185 edp->kernattr = defattr; 186 187 edp->tabs = NULL; 188 #ifdef HAVE_DOUBLE_WIDTH_HEIGHT 189 edp->dblwid = NULL; 190 edp->dw = 0; 191 #endif 192 edp->dcsarg = NULL; 193 edp->isolatin1tab = edp->decgraphtab = edp->dectechtab = NULL; 194 edp->nrctab = NULL; 195 wsemul_vt100_reset(edp); 196 return (edp); 197 } 198 199 void * 200 wsemul_vt100_attach(int console, const struct wsscreen_descr *type, 201 void *cookie, int ccol, int crow, void *cbcookie, uint32_t defattr) 202 { 203 struct wsemul_vt100_emuldata *edp; 204 205 if (console) { 206 edp = &wsemul_vt100_console_emuldata; 207 KASSERT(edp->console == 1); 208 } else { 209 edp = malloc(sizeof *edp, M_DEVBUF, M_NOWAIT); 210 if (edp == NULL) 211 return (NULL); 212 wsemul_vt100_init(edp, type, cookie, ccol, crow, defattr); 213 #ifdef DIAGNOSTIC 214 edp->console = 0; 215 #endif 216 } 217 edp->cbcookie = cbcookie; 218 219 edp->tabs = malloc(edp->ncols, M_DEVBUF, M_NOWAIT); 220 #ifdef HAVE_DOUBLE_WIDTH_HEIGHT 221 edp->dblwid = malloc(edp->nrows, M_DEVBUF, M_NOWAIT | M_ZERO); 222 edp->dw = 0; 223 #endif 224 edp->dcsarg = malloc(DCS_MAXLEN, M_DEVBUF, M_NOWAIT); 225 edp->isolatin1tab = malloc(128 * sizeof(u_int), M_DEVBUF, M_NOWAIT); 226 edp->decgraphtab = malloc(128 * sizeof(u_int), M_DEVBUF, M_NOWAIT); 227 edp->dectechtab = malloc(128 * sizeof(u_int), M_DEVBUF, M_NOWAIT); 228 edp->nrctab = malloc(128 * sizeof(u_int), M_DEVBUF, M_NOWAIT); 229 vt100_initchartables(edp); 230 wsemul_vt100_reset(edp); 231 return (edp); 232 } 233 234 void 235 wsemul_vt100_detach(void *cookie, u_int *crowp, u_int *ccolp) 236 { 237 struct wsemul_vt100_emuldata *edp = cookie; 238 239 *crowp = edp->crow; 240 *ccolp = edp->ccol; 241 #define f(ptr) do { free(ptr, M_DEVBUF, 0); ptr = NULL; } while (0) 242 f(edp->tabs); 243 #ifdef HAVE_DOUBLE_WIDTH_HEIGHT 244 f(edp->dblwid); 245 #endif 246 f(edp->dcsarg); 247 f(edp->isolatin1tab); 248 f(edp->decgraphtab); 249 f(edp->dectechtab); 250 f(edp->nrctab); 251 #undef f 252 if (edp != &wsemul_vt100_console_emuldata) 253 free(edp, M_DEVBUF, sizeof *edp); 254 } 255 256 void 257 wsemul_vt100_resetop(void *cookie, enum wsemul_resetops op) 258 { 259 struct wsemul_vt100_emuldata *edp = cookie; 260 261 switch (op) { 262 case WSEMUL_RESET: 263 wsemul_vt100_reset(edp); 264 break; 265 case WSEMUL_SYNCFONT: 266 vt100_initchartables(edp); 267 break; 268 case WSEMUL_CLEARSCREEN: 269 (void)wsemul_vt100_ed(edp, 2); 270 edp->ccol = edp->crow = 0; 271 (*edp->emulops->cursor)(edp->emulcookie, 272 edp->flags & VTFL_CURSORON, 0, 0); 273 break; 274 case WSEMUL_CLEARCURSOR: 275 (*edp->emulops->cursor)(edp->emulcookie, 0, edp->crow, 276 edp->ccol); 277 break; 278 default: 279 break; 280 } 281 } 282 283 void 284 wsemul_vt100_reset(struct wsemul_vt100_emuldata *edp) 285 { 286 int i; 287 288 edp->state = VT100_EMUL_STATE_NORMAL; 289 edp->flags = VTFL_DECAWM | VTFL_CURSORON; 290 edp->bkgdattr = edp->curattr = edp->defattr; 291 edp->attrflags = 0; 292 edp->fgcol = WSCOL_WHITE; 293 edp->bgcol = WSCOL_BLACK; 294 edp->scrreg_startrow = 0; 295 edp->scrreg_nrows = edp->nrows; 296 if (edp->tabs) { 297 memset(edp->tabs, 0, edp->ncols); 298 for (i = 8; i < edp->ncols; i += 8) 299 edp->tabs[i] = 1; 300 } 301 edp->dcspos = 0; 302 edp->dcstype = 0; 303 edp->chartab_G[0] = NULL; 304 edp->chartab_G[1] = edp->nrctab; /* ??? */ 305 edp->chartab_G[2] = edp->isolatin1tab; 306 edp->chartab_G[3] = edp->isolatin1tab; 307 edp->chartab0 = 0; 308 edp->chartab1 = 2; 309 edp->sschartab = 0; 310 edp->instate.inchar = 0; 311 edp->instate.lbound = 0; 312 edp->instate.mbleft = 0; 313 edp->instate.last_output = 0; 314 edp->kstate.inchar = 0; 315 edp->kstate.lbound = 0; 316 edp->kstate.mbleft = 0; 317 edp->kstate.last_output = 0; 318 } 319 320 /* 321 * Move the cursor to the next line if possible. If the cursor is at 322 * the bottom of the scroll area, then scroll it up. If the cursor is 323 * at the bottom of the screen then don't move it down. 324 */ 325 int 326 wsemul_vt100_nextline(struct wsemul_vt100_emuldata *edp) 327 { 328 int rc; 329 330 if (ROWS_BELOW == 0) { 331 /* Bottom of the scroll region. */ 332 rc = wsemul_vt100_scrollup(edp, 1); 333 } else { 334 if ((edp->crow+1) < edp->nrows) 335 /* Cursor not at the bottom of the screen. */ 336 edp->crow++; 337 CHECK_DW; 338 rc = 0; 339 } 340 341 return rc; 342 } 343 344 /* 345 * now all the state machine bits 346 */ 347 348 int 349 wsemul_vt100_output_normal(struct wsemul_vt100_emuldata *edp, 350 struct wsemul_inputstate *instate, int kernel, int count) 351 { 352 u_int *ct, dc; 353 u_char c; 354 int oldsschartab = edp->sschartab; 355 int m; 356 int rc = 0; 357 358 #ifdef HAVE_UTF8_SUPPORT 359 if (edp->flags & VTFL_UTF8) { 360 (*edp->emulops->mapchar)(edp->emulcookie, instate->inchar, &dc); 361 } else 362 #endif 363 { 364 c = instate->inchar & 0xff; 365 if (c & 0x80) { 366 c &= 0x7f; 367 ct = edp->chartab_G[edp->chartab1]; 368 } else { 369 if (edp->sschartab) { 370 ct = edp->chartab_G[edp->sschartab]; 371 edp->sschartab = 0; 372 } else 373 ct = edp->chartab_G[edp->chartab0]; 374 } 375 dc = ct ? ct[c] : c; 376 } 377 378 for (m = 0; m < count; m++) { 379 if ((edp->flags & (VTFL_LASTCHAR | VTFL_DECAWM)) == 380 (VTFL_LASTCHAR | VTFL_DECAWM)) { 381 rc = wsemul_vt100_nextline(edp); 382 if (rc != 0) 383 return rc; 384 edp->ccol = 0; 385 edp->flags &= ~VTFL_LASTCHAR; 386 } 387 388 if ((edp->flags & VTFL_INSERTMODE) && COLS_LEFT) { 389 WSEMULOP(rc, edp, &edp->abortstate, copycols, 390 COPYCOLS(edp->ccol, edp->ccol + 1, COLS_LEFT)); 391 if (rc != 0) 392 break; 393 } 394 395 #ifdef HAVE_DOUBLE_WIDTH_HEIGHT 396 WSEMULOP(rc, edp, &edp->abortstate, putchar, 397 (edp->emulcookie, edp->crow, edp->ccol << edp->dw, dc, 398 kernel ? edp->kernattr : edp->curattr)); 399 #else 400 WSEMULOP(rc, edp, &edp->abortstate, putchar, 401 (edp->emulcookie, edp->crow, edp->ccol, dc, 402 kernel ? edp->kernattr : edp->curattr)); 403 #endif 404 if (rc != 0) 405 break; 406 407 if (COLS_LEFT) 408 edp->ccol++; 409 else 410 edp->flags |= VTFL_LASTCHAR; 411 } 412 413 if (rc != 0) { 414 /* undo potential sschartab update */ 415 edp->sschartab = oldsschartab; 416 417 return rc; 418 } 419 420 return 0; 421 } 422 423 int 424 wsemul_vt100_output_c0c1(struct wsemul_vt100_emuldata *edp, 425 struct wsemul_inputstate *instate, int kernel) 426 { 427 u_int n; 428 int rc = 0; 429 430 switch (instate->inchar) { 431 case ASCII_NUL: 432 default: 433 /* ignore */ 434 break; 435 case ASCII_BEL: 436 if (edp->state == VT100_EMUL_STATE_STRING) { 437 /* acts as an equivalent to the ``ESC \'' string end */ 438 wsemul_vt100_handle_dcs(edp); 439 edp->state = VT100_EMUL_STATE_NORMAL; 440 } else { 441 wsdisplay_emulbell(edp->cbcookie); 442 } 443 break; 444 case ASCII_BS: 445 if (edp->ccol > 0) { 446 edp->ccol--; 447 edp->flags &= ~VTFL_LASTCHAR; 448 } 449 break; 450 case ASCII_CR: 451 edp->ccol = 0; 452 break; 453 case ASCII_HT: 454 if (edp->tabs) { 455 if (!COLS_LEFT) 456 break; 457 for (n = edp->ccol + 1; n < NCOLS - 1; n++) 458 if (edp->tabs[n]) 459 break; 460 } else { 461 n = edp->ccol + min(8 - (edp->ccol & 7), COLS_LEFT); 462 } 463 edp->ccol = n; 464 break; 465 case ASCII_SO: /* LS1 */ 466 edp->flags &= ~VTFL_UTF8; 467 edp->chartab0 = 1; 468 break; 469 case ASCII_SI: /* LS0 */ 470 edp->flags &= ~VTFL_UTF8; 471 edp->chartab0 = 0; 472 break; 473 case ASCII_ESC: 474 if (kernel) { 475 printf("wsemul_vt100_output_c0c1: ESC in kernel " 476 "output ignored\n"); 477 break; /* ignore the ESC */ 478 } 479 480 if (edp->state == VT100_EMUL_STATE_STRING) { 481 /* might be a string end */ 482 edp->state = VT100_EMUL_STATE_STRING_ESC; 483 } else { 484 /* XXX cancel current escape sequence */ 485 edp->state = VT100_EMUL_STATE_ESC; 486 } 487 break; 488 case ASCII_CAN: 489 case ASCII_SUB: 490 /* cancel current escape sequence */ 491 edp->state = VT100_EMUL_STATE_NORMAL; 492 break; 493 case ASCII_LF: 494 case ASCII_VT: 495 case ASCII_FF: 496 rc = wsemul_vt100_nextline(edp); 497 break; 498 } 499 500 if (COLS_LEFT != 0) 501 edp->flags &= ~VTFL_LASTCHAR; 502 503 return rc; 504 } 505 506 int 507 wsemul_vt100_output_esc(struct wsemul_vt100_emuldata *edp, 508 struct wsemul_inputstate *instate, int kernel) 509 { 510 u_int newstate = VT100_EMUL_STATE_NORMAL; 511 int rc = 0; 512 int i; 513 514 switch (instate->inchar) { 515 case '[': /* CSI */ 516 edp->nargs = 0; 517 memset(edp->args, 0, sizeof (edp->args)); 518 edp->modif1 = edp->modif2 = '\0'; 519 newstate = VT100_EMUL_STATE_CSI; 520 break; 521 case '7': /* DECSC */ 522 edp->flags |= VTFL_SAVEDCURS; 523 edp->savedcursor_row = edp->crow; 524 edp->savedcursor_col = edp->ccol; 525 edp->savedattr = edp->curattr; 526 edp->savedbkgdattr = edp->bkgdattr; 527 edp->savedattrflags = edp->attrflags; 528 edp->savedfgcol = edp->fgcol; 529 edp->savedbgcol = edp->bgcol; 530 for (i = 0; i < 4; i++) 531 edp->savedchartab_G[i] = edp->chartab_G[i]; 532 edp->savedchartab0 = edp->chartab0; 533 edp->savedchartab1 = edp->chartab1; 534 break; 535 case '8': /* DECRC */ 536 if ((edp->flags & VTFL_SAVEDCURS) == 0) 537 break; 538 edp->crow = edp->savedcursor_row; 539 edp->ccol = edp->savedcursor_col; 540 edp->curattr = edp->savedattr; 541 edp->bkgdattr = edp->savedbkgdattr; 542 edp->attrflags = edp->savedattrflags; 543 edp->fgcol = edp->savedfgcol; 544 edp->bgcol = edp->savedbgcol; 545 for (i = 0; i < 4; i++) 546 edp->chartab_G[i] = edp->savedchartab_G[i]; 547 edp->chartab0 = edp->savedchartab0; 548 edp->chartab1 = edp->savedchartab1; 549 break; 550 case '=': /* DECKPAM application mode */ 551 edp->flags |= VTFL_APPLKEYPAD; 552 break; 553 case '>': /* DECKPNM numeric mode */ 554 edp->flags &= ~VTFL_APPLKEYPAD; 555 break; 556 case 'E': /* NEL */ 557 edp->ccol = 0; 558 /* FALLTHROUGH */ 559 case 'D': /* IND */ 560 rc = wsemul_vt100_nextline(edp); 561 break; 562 case 'H': /* HTS */ 563 if (edp->tabs != NULL) 564 edp->tabs[edp->ccol] = 1; 565 break; 566 case '~': /* LS1R */ 567 edp->flags &= ~VTFL_UTF8; 568 edp->chartab1 = 1; 569 break; 570 case 'n': /* LS2 */ 571 edp->flags &= ~VTFL_UTF8; 572 edp->chartab0 = 2; 573 break; 574 case '}': /* LS2R */ 575 edp->flags &= ~VTFL_UTF8; 576 edp->chartab1 = 2; 577 break; 578 case 'o': /* LS3 */ 579 edp->flags &= ~VTFL_UTF8; 580 edp->chartab0 = 3; 581 break; 582 case '|': /* LS3R */ 583 edp->flags &= ~VTFL_UTF8; 584 edp->chartab1 = 3; 585 break; 586 case 'N': /* SS2 */ 587 edp->flags &= ~VTFL_UTF8; 588 edp->sschartab = 2; 589 break; 590 case 'O': /* SS3 */ 591 edp->flags &= ~VTFL_UTF8; 592 edp->sschartab = 3; 593 break; 594 case 'M': /* RI */ 595 i = ROWS_ABOVE; 596 if (i > 0) { 597 if (edp->crow > 0) 598 edp->crow--; 599 CHECK_DW; 600 } else if (i == 0) { 601 /* Top of scroll region. */ 602 rc = wsemul_vt100_scrolldown(edp, 1); 603 } 604 break; 605 case 'P': /* DCS */ 606 edp->nargs = 0; 607 memset(edp->args, 0, sizeof (edp->args)); 608 newstate = VT100_EMUL_STATE_DCS; 609 break; 610 case 'c': /* RIS */ 611 wsemul_vt100_reset(edp); 612 rc = wsemul_vt100_ed(edp, 2); 613 if (rc != 0) 614 break; 615 edp->ccol = edp->crow = 0; 616 break; 617 case '(': case ')': case '*': case '+': /* SCS */ 618 edp->designating = instate->inchar - '('; 619 newstate = VT100_EMUL_STATE_SCS94; 620 break; 621 case '-': case '.': case '/': /* SCS */ 622 edp->designating = instate->inchar - '-' + 1; 623 newstate = VT100_EMUL_STATE_SCS96; 624 break; 625 case '#': 626 newstate = VT100_EMUL_STATE_ESC_HASH; 627 break; 628 case ' ': /* 7/8 bit */ 629 newstate = VT100_EMUL_STATE_ESC_SPC; 630 break; 631 case ']': /* OSC operating system command */ 632 case '^': /* PM privacy message */ 633 case '_': /* APC application program command */ 634 /* ignored */ 635 newstate = VT100_EMUL_STATE_STRING; 636 break; 637 case '<': /* exit VT52 mode - ignored */ 638 break; 639 case '%': /* UTF-8 encoding sequences */ 640 newstate = VT100_EMUL_STATE_ESC_PERCENT; 641 break; 642 default: 643 #ifdef VT100_PRINTUNKNOWN 644 printf("ESC %x unknown\n", instate->inchar); 645 #endif 646 break; 647 } 648 649 if (COLS_LEFT != 0) 650 edp->flags &= ~VTFL_LASTCHAR; 651 652 if (rc != 0) 653 return rc; 654 655 edp->state = newstate; 656 return 0; 657 } 658 659 int 660 wsemul_vt100_output_scs94(struct wsemul_vt100_emuldata *edp, 661 struct wsemul_inputstate *instate, int kernel) 662 { 663 u_int newstate = VT100_EMUL_STATE_NORMAL; 664 665 switch (instate->inchar) { 666 case '%': /* probably DEC supplemental graphic */ 667 newstate = VT100_EMUL_STATE_SCS94_PERCENT; 668 break; 669 case 'A': /* british / national */ 670 edp->flags &= ~VTFL_UTF8; 671 edp->chartab_G[edp->designating] = edp->nrctab; 672 break; 673 case 'B': /* ASCII */ 674 edp->flags &= ~VTFL_UTF8; 675 edp->chartab_G[edp->designating] = 0; 676 break; 677 case '<': /* user preferred supplemental */ 678 /* XXX not really "user" preferred */ 679 edp->flags &= ~VTFL_UTF8; 680 edp->chartab_G[edp->designating] = edp->isolatin1tab; 681 break; 682 case '0': /* DEC special graphic */ 683 edp->flags &= ~VTFL_UTF8; 684 edp->chartab_G[edp->designating] = edp->decgraphtab; 685 break; 686 case '>': /* DEC tech */ 687 edp->flags &= ~VTFL_UTF8; 688 edp->chartab_G[edp->designating] = edp->dectechtab; 689 break; 690 default: 691 #ifdef VT100_PRINTUNKNOWN 692 printf("ESC%c %x unknown\n", edp->designating + '(', 693 instate->inchar); 694 #endif 695 break; 696 } 697 698 edp->state = newstate; 699 return 0; 700 } 701 702 int 703 wsemul_vt100_output_scs94_percent(struct wsemul_vt100_emuldata *edp, 704 struct wsemul_inputstate *instate, int kernel) 705 { 706 switch (instate->inchar) { 707 case '5': /* DEC supplemental graphic */ 708 /* XXX there are differences */ 709 edp->flags &= ~VTFL_UTF8; 710 edp->chartab_G[edp->designating] = edp->isolatin1tab; 711 break; 712 default: 713 #ifdef VT100_PRINTUNKNOWN 714 printf("ESC%c%% %x unknown\n", edp->designating + '(', 715 instate->inchar); 716 #endif 717 break; 718 } 719 720 edp->state = VT100_EMUL_STATE_NORMAL; 721 return 0; 722 } 723 724 int 725 wsemul_vt100_output_scs96(struct wsemul_vt100_emuldata *edp, 726 struct wsemul_inputstate *instate, int kernel) 727 { 728 u_int newstate = VT100_EMUL_STATE_NORMAL; 729 int nrc; 730 731 switch (instate->inchar) { 732 case '%': /* probably portuguese */ 733 newstate = VT100_EMUL_STATE_SCS96_PERCENT; 734 break; 735 case 'A': /* ISO-latin-1 supplemental */ 736 edp->flags &= ~VTFL_UTF8; 737 edp->chartab_G[edp->designating] = edp->isolatin1tab; 738 break; 739 case '4': /* dutch */ 740 nrc = 1; 741 goto setnrc; 742 case '5': case 'C': /* finnish */ 743 nrc = 2; 744 goto setnrc; 745 case 'R': /* french */ 746 nrc = 3; 747 goto setnrc; 748 case 'Q': /* french canadian */ 749 nrc = 4; 750 goto setnrc; 751 case 'K': /* german */ 752 nrc = 5; 753 goto setnrc; 754 case 'Y': /* italian */ 755 nrc = 6; 756 goto setnrc; 757 case 'E': case '6': /* norwegian / danish */ 758 nrc = 7; 759 goto setnrc; 760 case 'Z': /* spanish */ 761 nrc = 9; 762 goto setnrc; 763 case '7': case 'H': /* swedish */ 764 nrc = 10; 765 goto setnrc; 766 case '=': /* swiss */ 767 nrc = 11; 768 setnrc: 769 if (vt100_setnrc(edp, nrc) == 0) /* what table ??? */ 770 break; 771 /* else FALLTHROUGH */ 772 default: 773 #ifdef VT100_PRINTUNKNOWN 774 printf("ESC%c %x unknown\n", edp->designating + '-' - 1, 775 instate->inchar); 776 #endif 777 break; 778 } 779 780 edp->state = newstate; 781 return 0; 782 } 783 784 int 785 wsemul_vt100_output_scs96_percent(struct wsemul_vt100_emuldata *edp, 786 struct wsemul_inputstate *instate, int kernel) 787 { 788 switch (instate->inchar) { 789 case '6': /* portuguese */ 790 if (vt100_setnrc(edp, 8) == 0) 791 break; 792 /* else FALLTHROUGH */ 793 default: 794 #ifdef VT100_PRINTUNKNOWN 795 printf("ESC%c%% %x unknown\n", edp->designating + '-' - 1, 796 instate->inchar); 797 #endif 798 break; 799 } 800 801 edp->state = VT100_EMUL_STATE_NORMAL; 802 return 0; 803 } 804 805 int 806 wsemul_vt100_output_esc_spc(struct wsemul_vt100_emuldata *edp, 807 struct wsemul_inputstate *instate, int kernel) 808 { 809 switch (instate->inchar) { 810 case 'F': /* 7-bit controls */ 811 case 'G': /* 8-bit controls */ 812 #ifdef VT100_PRINTNOTIMPL 813 printf("ESC<SPC> %x ignored\n", instate->inchar); 814 #endif 815 break; 816 default: 817 #ifdef VT100_PRINTUNKNOWN 818 printf("ESC<SPC> %x unknown\n", instate->inchar); 819 #endif 820 break; 821 } 822 823 edp->state = VT100_EMUL_STATE_NORMAL; 824 return 0; 825 } 826 827 int 828 wsemul_vt100_output_string(struct wsemul_vt100_emuldata *edp, 829 struct wsemul_inputstate *instate, int kernel) 830 { 831 if (edp->dcsarg && edp->dcstype && edp->dcspos < DCS_MAXLEN) { 832 if (instate->inchar & ~0xff) { 833 #ifdef VT100_PRINTUNKNOWN 834 printf("unknown char %x in DCS\n", instate->inchar); 835 #endif 836 } else 837 edp->dcsarg[edp->dcspos++] = (char)instate->inchar; 838 } 839 840 edp->state = VT100_EMUL_STATE_STRING; 841 return 0; 842 } 843 844 int 845 wsemul_vt100_output_string_esc(struct wsemul_vt100_emuldata *edp, 846 struct wsemul_inputstate *instate, int kernel) 847 { 848 if (instate->inchar == '\\') { /* ST complete */ 849 wsemul_vt100_handle_dcs(edp); 850 edp->state = VT100_EMUL_STATE_NORMAL; 851 } else 852 edp->state = VT100_EMUL_STATE_STRING; 853 854 return 0; 855 } 856 857 int 858 wsemul_vt100_output_dcs(struct wsemul_vt100_emuldata *edp, 859 struct wsemul_inputstate *instate, int kernel) 860 { 861 u_int newstate = VT100_EMUL_STATE_DCS; 862 863 switch (instate->inchar) { 864 case '0': case '1': case '2': case '3': case '4': 865 case '5': case '6': case '7': case '8': case '9': 866 /* argument digit */ 867 if (edp->nargs >= VT100_EMUL_NARGS) 868 break; 869 edp->args[edp->nargs] = (edp->args[edp->nargs] * 10) + 870 (instate->inchar - '0'); 871 break; 872 case ';': /* argument terminator */ 873 if (edp->nargs < VT100_EMUL_NARGS) 874 edp->nargs++; 875 break; 876 default: 877 if (edp->nargs < VT100_EMUL_NARGS) 878 edp->nargs++; 879 newstate = VT100_EMUL_STATE_STRING; 880 switch (instate->inchar) { 881 case '$': 882 newstate = VT100_EMUL_STATE_DCS_DOLLAR; 883 break; 884 case '{': /* DECDLD soft charset */ /* } */ 885 case '!': /* DECRQUPSS user preferred supplemental set */ 886 /* 'u' must follow - need another state */ 887 case '|': /* DECUDK program F6..F20 */ 888 #ifdef VT100_PRINTNOTIMPL 889 printf("DCS%c ignored\n", (char)instate->inchar); 890 #endif 891 break; 892 default: 893 #ifdef VT100_PRINTUNKNOWN 894 printf("DCS %x (%d, %d) unknown\n", instate->inchar, 895 ARG(0), ARG(1)); 896 #endif 897 break; 898 } 899 } 900 901 edp->state = newstate; 902 return 0; 903 } 904 905 int 906 wsemul_vt100_output_dcs_dollar(struct wsemul_vt100_emuldata *edp, 907 struct wsemul_inputstate *instate, int kernel) 908 { 909 switch (instate->inchar) { 910 case 'p': /* DECRSTS terminal state restore */ 911 case 'q': /* DECRQSS control function request */ 912 #ifdef VT100_PRINTNOTIMPL 913 printf("DCS$%c ignored\n", (char)instate->inchar); 914 #endif 915 break; 916 case 't': /* DECRSPS restore presentation state */ 917 switch (ARG(0)) { 918 case 0: /* error */ 919 break; 920 case 1: /* cursor information restore */ 921 #ifdef VT100_PRINTNOTIMPL 922 printf("DCS1$t ignored\n"); 923 #endif 924 break; 925 case 2: /* tab stop restore */ 926 edp->dcspos = 0; 927 edp->dcstype = DCSTYPE_TABRESTORE; 928 break; 929 default: 930 #ifdef VT100_PRINTUNKNOWN 931 printf("DCS%d$t unknown\n", ARG(0)); 932 #endif 933 break; 934 } 935 break; 936 default: 937 #ifdef VT100_PRINTUNKNOWN 938 printf("DCS$ %x (%d, %d) unknown\n", 939 instate->inchar, ARG(0), ARG(1)); 940 #endif 941 break; 942 } 943 944 edp->state = VT100_EMUL_STATE_STRING; 945 return 0; 946 } 947 948 int 949 wsemul_vt100_output_esc_percent(struct wsemul_vt100_emuldata *edp, 950 struct wsemul_inputstate *instate, int kernel) 951 { 952 switch (instate->inchar) { 953 #ifdef HAVE_UTF8_SUPPORT 954 case 'G': 955 edp->flags |= VTFL_UTF8; 956 edp->kstate.mbleft = edp->instate.mbleft = 0; 957 break; 958 case '@': 959 edp->flags &= ~VTFL_UTF8; 960 break; 961 #endif 962 default: 963 #ifdef VT100_PRINTUNKNOWN 964 printf("ESC% %x unknown\n", instate->inchar); 965 #endif 966 break; 967 } 968 edp->state = VT100_EMUL_STATE_NORMAL; 969 return 0; 970 } 971 972 int 973 wsemul_vt100_output_esc_hash(struct wsemul_vt100_emuldata *edp, 974 struct wsemul_inputstate *instate, int kernel) 975 { 976 int rc = 0; 977 978 switch (instate->inchar) { 979 case '5': /* DECSWL single width, single height */ 980 #ifdef HAVE_DOUBLE_WIDTH_HEIGHT 981 if (edp->dblwid != NULL && edp->dw != 0) { 982 int i; 983 for (i = 0; i < edp->ncols / 2; i++) { 984 WSEMULOP(rc, edp, &edp->abortstate, copycols, 985 (edp->emulcookie, edp->crow, 2 * i, i, 1)); 986 if (rc != 0) 987 return rc; 988 } 989 WSEMULOP(rc, edp, &edp->abortstate, erasecols, 990 (edp->emulcookie, edp->crow, i, edp->ncols - i, 991 edp->bkgdattr)); 992 if (rc != 0) 993 return rc; 994 edp->dblwid[edp->crow] = 0; 995 edp->dw = 0; 996 } 997 #endif 998 break; 999 case '6': /* DECDWL double width, single height */ 1000 case '3': /* DECDHL double width, double height, top half */ 1001 case '4': /* DECDHL double width, double height, bottom half */ 1002 #ifdef HAVE_DOUBLE_WIDTH_HEIGHT 1003 if (edp->dblwid != NULL && edp->dw == 0) { 1004 int i; 1005 for (i = edp->ncols / 2 - 1; i >= 0; i--) { 1006 WSEMULOP(rc, edp, &edp->abortstate, copycols, 1007 (edp->emulcookie, edp->crow, i, 2 * i, 1)); 1008 if (rc != 0) 1009 return rc; 1010 } 1011 for (i = 0; i < edp->ncols / 2; i++) { 1012 WSEMULOP(rc, edp, &edp->abortstate, erasecols, 1013 (edp->emulcookie, edp->crow, 2 * i + 1, 1, 1014 edp->bkgdattr)); 1015 if (rc != 0) 1016 return rc; 1017 } 1018 edp->dblwid[edp->crow] = 1; 1019 edp->dw = 1; 1020 if (edp->ccol > (edp->ncols >> 1) - 1) 1021 edp->ccol = (edp->ncols >> 1) - 1; 1022 } 1023 #endif 1024 break; 1025 case '8': { /* DECALN */ 1026 int i, j; 1027 for (i = 0; i < edp->nrows; i++) 1028 for (j = 0; j < edp->ncols; j++) { 1029 WSEMULOP(rc, edp, &edp->abortstate, putchar, 1030 (edp->emulcookie, i, j, 'E', edp->curattr)); 1031 if (rc != 0) 1032 return rc; 1033 } 1034 } 1035 edp->ccol = 0; 1036 edp->crow = 0; 1037 break; 1038 default: 1039 #ifdef VT100_PRINTUNKNOWN 1040 printf("ESC# %x unknown\n", instate->inchar); 1041 #endif 1042 break; 1043 } 1044 1045 if (COLS_LEFT != 0) 1046 edp->flags &= ~VTFL_LASTCHAR; 1047 1048 edp->state = VT100_EMUL_STATE_NORMAL; 1049 return 0; 1050 } 1051 1052 int 1053 wsemul_vt100_output_csi(struct wsemul_vt100_emuldata *edp, 1054 struct wsemul_inputstate *instate, int kernel) 1055 { 1056 u_int newstate = VT100_EMUL_STATE_CSI; 1057 int oargs; 1058 int rc = 0; 1059 1060 switch (instate->inchar) { 1061 case '0': case '1': case '2': case '3': case '4': 1062 case '5': case '6': case '7': case '8': case '9': 1063 /* argument digit */ 1064 if (edp->nargs > VT100_EMUL_NARGS - 1) 1065 break; 1066 edp->args[edp->nargs] = (edp->args[edp->nargs] * 10) + 1067 (instate->inchar - '0'); 1068 break; 1069 case ';': /* argument terminator */ 1070 if (edp->nargs < VT100_EMUL_NARGS) 1071 edp->nargs++; 1072 break; 1073 case '?': /* DEC specific */ 1074 case '>': /* DA query */ 1075 edp->modif1 = (char)instate->inchar; 1076 break; 1077 case '!': 1078 case '"': 1079 case '$': 1080 case '&': 1081 edp->modif2 = (char)instate->inchar; 1082 break; 1083 default: /* end of escape sequence */ 1084 oargs = edp->nargs; 1085 if (edp->nargs < VT100_EMUL_NARGS) 1086 edp->nargs++; 1087 rc = wsemul_vt100_handle_csi(edp, instate, kernel); 1088 if (rc != 0) { 1089 /* undo nargs progress */ 1090 edp->nargs = oargs; 1091 return rc; 1092 } 1093 newstate = VT100_EMUL_STATE_NORMAL; 1094 break; 1095 } 1096 1097 if (COLS_LEFT != 0) 1098 edp->flags &= ~VTFL_LASTCHAR; 1099 1100 edp->state = newstate; 1101 return 0; 1102 } 1103 1104 u_int 1105 wsemul_vt100_output(void *cookie, const u_char *data, u_int count, int kernel) 1106 { 1107 struct wsemul_vt100_emuldata *edp = cookie; 1108 struct wsemul_inputstate *instate; 1109 u_int prev_count, processed = 0; 1110 #ifdef HAVE_JUMP_SCROLL 1111 int lines; 1112 #endif 1113 int rc = 0; 1114 1115 #ifdef DIAGNOSTIC 1116 if (kernel && !edp->console) 1117 panic("wsemul_vt100_output: kernel output, not console"); 1118 #endif 1119 1120 instate = kernel ? &edp->kstate : &edp->instate; 1121 1122 switch (edp->abortstate.state) { 1123 case ABORT_FAILED_CURSOR: 1124 /* 1125 * If we could not display the cursor back, we pretended not 1126 * having been able to process the last byte. But this 1127 * is a lie, so compensate here. 1128 */ 1129 data++, count--; 1130 processed++; 1131 wsemul_reset_abortstate(&edp->abortstate); 1132 break; 1133 case ABORT_OK: 1134 /* remove cursor image if visible */ 1135 if (edp->flags & VTFL_CURSORON) { 1136 rc = (*edp->emulops->cursor) 1137 (edp->emulcookie, 0, edp->crow, 1138 #ifdef HAVE_DOUBLE_WIDTH_HEIGHT 1139 edp->ccol << edp->dw); 1140 #else 1141 edp->ccol); 1142 #endif 1143 if (rc != 0) 1144 return 0; 1145 } 1146 break; 1147 default: 1148 break; 1149 } 1150 1151 for (;;) { 1152 #ifdef HAVE_JUMP_SCROLL 1153 switch (edp->abortstate.state) { 1154 case ABORT_FAILED_JUMP_SCROLL: 1155 /* 1156 * If we failed a previous jump scroll attempt, we 1157 * need to try to resume it with the same distance. 1158 * We can not recompute it since there might be more 1159 * bytes in the tty ring, causing a different result. 1160 */ 1161 lines = edp->abortstate.lines; 1162 break; 1163 case ABORT_OK: 1164 /* 1165 * If we are at the bottom of the scrolling area, count 1166 * newlines until an escape sequence appears. 1167 */ 1168 if ((edp->state == VT100_EMUL_STATE_NORMAL || kernel) && 1169 ROWS_BELOW == 0) 1170 lines = wsemul_vt100_jump_scroll(edp, data, 1171 count, kernel); 1172 else 1173 lines = 0; 1174 break; 1175 default: 1176 /* 1177 * If we are recovering a non-scrolling failure, 1178 * do not try to scroll yet. 1179 */ 1180 lines = 0; 1181 break; 1182 } 1183 1184 if (lines > 1) { 1185 wsemul_resume_abort(&edp->abortstate); 1186 rc = wsemul_vt100_scrollup(edp, lines); 1187 if (rc != 0) { 1188 wsemul_abort_jump_scroll(&edp->abortstate, 1189 lines); 1190 return processed; 1191 } 1192 wsemul_reset_abortstate(&edp->abortstate); 1193 edp->crow -= lines; 1194 } 1195 #endif 1196 1197 wsemul_resume_abort(&edp->abortstate); 1198 1199 prev_count = count; 1200 if (wsemul_getchar(&data, &count, instate, 1201 #ifdef HAVE_UTF8_SUPPORT 1202 (edp->state == VT100_EMUL_STATE_NORMAL && !kernel) ? 1203 edp->flags & VTFL_UTF8 : 0 1204 #else 1205 0 1206 #endif 1207 ) != 0) 1208 break; 1209 1210 if (!(instate->inchar & ~0xff) && 1211 (instate->inchar & 0x7f) < 0x20) { 1212 rc = wsemul_vt100_output_c0c1(edp, instate, kernel); 1213 if (rc != 0) 1214 break; 1215 processed += prev_count - count; 1216 continue; 1217 } 1218 1219 if (edp->state == VT100_EMUL_STATE_NORMAL || kernel) { 1220 rc = 1221 wsemul_vt100_output_normal(edp, instate, kernel, 1); 1222 if (rc != 0) 1223 break; 1224 instate->last_output = instate->inchar; 1225 processed += prev_count - count; 1226 continue; 1227 } 1228 #ifdef DIAGNOSTIC 1229 if (edp->state > nitems(vt100_output)) 1230 panic("wsemul_vt100: invalid state %d", edp->state); 1231 #endif 1232 rc = vt100_output[edp->state - 1](edp, instate, kernel); 1233 if (rc != 0) 1234 break; 1235 processed += prev_count - count; 1236 } 1237 1238 if (rc != 0) 1239 wsemul_abort_other(&edp->abortstate); 1240 else { 1241 /* put cursor image back if visible */ 1242 if (edp->flags & VTFL_CURSORON) { 1243 rc = (*edp->emulops->cursor) 1244 (edp->emulcookie, 1, edp->crow, 1245 #ifdef HAVE_DOUBLE_WIDTH_HEIGHT 1246 edp->ccol << edp->dw); 1247 #else 1248 edp->ccol); 1249 #endif 1250 if (rc != 0) { 1251 /* 1252 * Pretend the last byte hasn't been processed, 1253 * while remembering that only the cursor 1254 * operation really needs to be done. 1255 */ 1256 wsemul_abort_cursor(&edp->abortstate); 1257 processed--; 1258 } 1259 } 1260 } 1261 1262 if (rc == 0) 1263 wsemul_reset_abortstate(&edp->abortstate); 1264 1265 return processed; 1266 } 1267 1268 #ifdef HAVE_JUMP_SCROLL 1269 int 1270 wsemul_vt100_jump_scroll(struct wsemul_vt100_emuldata *edp, const u_char *data, 1271 u_int count, int kernel) 1272 { 1273 struct wsemul_inputstate tmpstate; 1274 u_int pos, lines; 1275 1276 lines = 0; 1277 pos = edp->ccol; 1278 tmpstate = kernel ? edp->kstate : edp->instate; /* structure copy */ 1279 1280 while (wsemul_getchar(&data, &count, &tmpstate, 1281 #ifdef HAVE_UTF8_SUPPORT 1282 kernel ? 0 : edp->flags & VTFL_UTF8 1283 #else 1284 0 1285 #endif 1286 ) == 0) { 1287 /* 1288 * Only char causing a transition from 1289 * VT100_EMUL_STATE_NORMAL to another state, for now. 1290 * Revisit this if this changes... 1291 */ 1292 if (tmpstate.inchar == ASCII_ESC) 1293 break; 1294 1295 if (ISSET(edp->flags, VTFL_DECAWM)) 1296 switch (tmpstate.inchar) { 1297 case ASCII_BS: 1298 if (pos > 0) 1299 pos--; 1300 break; 1301 case ASCII_CR: 1302 pos = 0; 1303 break; 1304 case ASCII_HT: 1305 if (edp->tabs) { 1306 pos++; 1307 while (pos < NCOLS - 1 && 1308 edp->tabs[pos] == 0) 1309 pos++; 1310 } else { 1311 pos = (pos + 7) & ~7; 1312 if (pos >= NCOLS) 1313 pos = NCOLS - 1; 1314 } 1315 break; 1316 default: 1317 if (!(tmpstate.inchar & ~0xff) && 1318 (tmpstate.inchar & 0x7f) < 0x20) 1319 break; 1320 if (pos++ >= NCOLS) { 1321 pos = 0; 1322 tmpstate.inchar = ASCII_LF; 1323 } 1324 break; 1325 } 1326 1327 if (tmpstate.inchar == ASCII_LF || 1328 tmpstate.inchar == ASCII_VT || 1329 tmpstate.inchar == ASCII_FF) { 1330 if (++lines >= edp->scrreg_nrows - 1) 1331 break; 1332 } 1333 } 1334 1335 return lines; 1336 } 1337 #endif 1338