teken_subr.h revision 197522
157434Smarkm/*- 257434Smarkm * Copyright (c) 2008-2009 Ed Schouten <ed@FreeBSD.org> 3255460Sdes * All rights reserved. 4255460Sdes * 557434Smarkm * Redistribution and use in source and binary forms, with or without 6197679Sdes * modification, are permitted provided that the following conditions 7158519Sdes * are met: 857434Smarkm * 1. Redistributions of source code must retain the above copyright 9255460Sdes * notice, this list of conditions and the following disclaimer. 10255460Sdes * 2. Redistributions in binary form must reproduce the above copyright 11197679Sdes * notice, this list of conditions and the following disclaimer in the 12255460Sdes * documentation and/or other materials provided with the distribution. 13197679Sdes * 14255460Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15255460Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16255386Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1774818Sru * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18255460Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19255460Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20255460Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21255460Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22255460Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23255460Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24255460Sdes * SUCH DAMAGE. 25255460Sdes * 26255460Sdes * $FreeBSD: head/sys/teken/teken_subr.h 197522 2009-09-26 15:26:32Z ed $ 27255460Sdes */ 2857434Smarkm 2957434Smarkmstatic void teken_subr_cursor_up(teken_t *, unsigned int); 3074818Srustatic void teken_subr_erase_line(teken_t *, unsigned int); 31158529Sdesstatic void teken_subr_regular_character(teken_t *, teken_char_t); 32158529Sdesstatic void teken_subr_reset_to_initial_state(teken_t *); 33static void teken_subr_save_cursor(teken_t *); 34 35static inline int 36teken_tab_isset(teken_t *t, unsigned int col) 37{ 38 unsigned int b, o; 39 40 if (col >= T_NUMCOL) 41 return ((col % 8) == 0); 42 43 b = col / (sizeof(unsigned int) * 8); 44 o = col % (sizeof(unsigned int) * 8); 45 46 return (t->t_tabstops[b] & (1 << o)); 47} 48 49static inline void 50teken_tab_clear(teken_t *t, unsigned int col) 51{ 52 unsigned int b, o; 53 54 if (col >= T_NUMCOL) 55 return; 56 57 b = col / (sizeof(unsigned int) * 8); 58 o = col % (sizeof(unsigned int) * 8); 59 60 t->t_tabstops[b] &= ~(1 << o); 61} 62 63static inline void 64teken_tab_set(teken_t *t, unsigned int col) 65{ 66 unsigned int b, o; 67 68 if (col >= T_NUMCOL) 69 return; 70 71 b = col / (sizeof(unsigned int) * 8); 72 o = col % (sizeof(unsigned int) * 8); 73 74 t->t_tabstops[b] |= 1 << o; 75} 76 77static void 78teken_tab_default(teken_t *t) 79{ 80 unsigned int i; 81 82 memset(&t->t_tabstops, 0, T_NUMCOL / 8); 83 84 for (i = 8; i < T_NUMCOL; i += 8) 85 teken_tab_set(t, i); 86} 87 88static void 89teken_subr_do_scroll(teken_t *t, int amount) 90{ 91 teken_rect_t tr; 92 teken_pos_t tp; 93 94 teken_assert(t->t_cursor.tp_row <= t->t_winsize.tp_row); 95 teken_assert(t->t_scrollreg.ts_end <= t->t_winsize.tp_row); 96 teken_assert(amount != 0); 97 98 /* Copy existing data 1 line up. */ 99 if (amount > 0) { 100 /* Scroll down. */ 101 102 /* Copy existing data up. */ 103 if (t->t_scrollreg.ts_begin + amount < t->t_scrollreg.ts_end) { 104 tr.tr_begin.tp_row = t->t_scrollreg.ts_begin + amount; 105 tr.tr_begin.tp_col = 0; 106 tr.tr_end.tp_row = t->t_scrollreg.ts_end; 107 tr.tr_end.tp_col = t->t_winsize.tp_col; 108 tp.tp_row = t->t_scrollreg.ts_begin; 109 tp.tp_col = 0; 110 teken_funcs_copy(t, &tr, &tp); 111 112 tr.tr_begin.tp_row = t->t_scrollreg.ts_end - amount; 113 } else { 114 tr.tr_begin.tp_row = t->t_scrollreg.ts_begin; 115 } 116 117 /* Clear the last lines. */ 118 tr.tr_begin.tp_col = 0; 119 tr.tr_end.tp_row = t->t_scrollreg.ts_end; 120 tr.tr_end.tp_col = t->t_winsize.tp_col; 121 teken_funcs_fill(t, &tr, BLANK, &t->t_curattr); 122 } else { 123 /* Scroll up. */ 124 amount = -amount; 125 126 /* Copy existing data down. */ 127 if (t->t_scrollreg.ts_begin + amount < t->t_scrollreg.ts_end) { 128 tr.tr_begin.tp_row = t->t_scrollreg.ts_begin; 129 tr.tr_begin.tp_col = 0; 130 tr.tr_end.tp_row = t->t_scrollreg.ts_end - amount; 131 tr.tr_end.tp_col = t->t_winsize.tp_col; 132 tp.tp_row = t->t_scrollreg.ts_begin + amount; 133 tp.tp_col = 0; 134 teken_funcs_copy(t, &tr, &tp); 135 136 tr.tr_end.tp_row = t->t_scrollreg.ts_begin + amount; 137 } else { 138 tr.tr_end.tp_row = t->t_scrollreg.ts_end; 139 } 140 141 /* Clear the first lines. */ 142 tr.tr_begin.tp_row = t->t_scrollreg.ts_begin; 143 tr.tr_begin.tp_col = 0; 144 tr.tr_end.tp_col = t->t_winsize.tp_col; 145 teken_funcs_fill(t, &tr, BLANK, &t->t_curattr); 146 } 147} 148 149static ssize_t 150teken_subr_do_cpr(teken_t *t, unsigned int cmd, char response[16]) 151{ 152 153 switch (cmd) { 154 case 5: /* Operating status. */ 155 strcpy(response, "0n"); 156 return (2); 157 case 6: { /* Cursor position. */ 158 int len; 159 160 len = snprintf(response, 16, "%u;%uR", 161 (t->t_cursor.tp_row - t->t_originreg.ts_begin) + 1, 162 t->t_cursor.tp_col + 1); 163 164 if (len >= 16) 165 return (-1); 166 return (len); 167 } 168 case 15: /* Printer status. */ 169 strcpy(response, "13n"); 170 return (3); 171 case 25: /* UDK status. */ 172 strcpy(response, "20n"); 173 return (3); 174 case 26: /* Keyboard status. */ 175 strcpy(response, "27;1n"); 176 return (5); 177 default: 178 teken_printf("Unknown DSR\n"); 179 return (-1); 180 } 181} 182 183static void 184teken_subr_alignment_test(teken_t *t) 185{ 186 teken_rect_t tr; 187 188 t->t_cursor.tp_row = t->t_cursor.tp_col = 0; 189 t->t_scrollreg.ts_begin = 0; 190 t->t_scrollreg.ts_end = t->t_winsize.tp_row; 191 t->t_originreg = t->t_scrollreg; 192 t->t_stateflags &= ~(TS_WRAPPED|TS_ORIGIN); 193 teken_funcs_cursor(t); 194 195 tr.tr_begin.tp_row = 0; 196 tr.tr_begin.tp_col = 0; 197 tr.tr_end = t->t_winsize; 198 teken_funcs_fill(t, &tr, 'E', &t->t_defattr); 199} 200 201static void 202teken_subr_backspace(teken_t *t) 203{ 204 205 if (t->t_stateflags & TS_CONS25) { 206 if (t->t_cursor.tp_col == 0) { 207 if (t->t_cursor.tp_row == t->t_originreg.ts_begin) 208 return; 209 t->t_cursor.tp_row--; 210 t->t_cursor.tp_col = t->t_winsize.tp_col - 1; 211 } else { 212 t->t_cursor.tp_col--; 213 } 214 } else { 215 if (t->t_cursor.tp_col == 0) 216 return; 217 218 t->t_cursor.tp_col--; 219 t->t_stateflags &= ~TS_WRAPPED; 220 } 221 222 teken_funcs_cursor(t); 223} 224 225static void 226teken_subr_bell(teken_t *t) 227{ 228 229 teken_funcs_bell(t); 230} 231 232static void 233teken_subr_carriage_return(teken_t *t) 234{ 235 236 t->t_cursor.tp_col = 0; 237 t->t_stateflags &= ~TS_WRAPPED; 238 teken_funcs_cursor(t); 239} 240 241static void 242teken_subr_cursor_backward(teken_t *t, unsigned int ncols) 243{ 244 245 if (ncols > t->t_cursor.tp_col) 246 t->t_cursor.tp_col = 0; 247 else 248 t->t_cursor.tp_col -= ncols; 249 t->t_stateflags &= ~TS_WRAPPED; 250 teken_funcs_cursor(t); 251} 252 253static void 254teken_subr_cursor_backward_tabulation(teken_t *t, unsigned int ntabs) 255{ 256 257 do { 258 /* Stop when we've reached the beginning of the line. */ 259 if (t->t_cursor.tp_col == 0) 260 break; 261 262 t->t_cursor.tp_col--; 263 264 /* Tab marker set. */ 265 if (teken_tab_isset(t, t->t_cursor.tp_col)) 266 ntabs--; 267 } while (ntabs > 0); 268 269 teken_funcs_cursor(t); 270} 271 272static void 273teken_subr_cursor_down(teken_t *t, unsigned int nrows) 274{ 275 276 if (t->t_cursor.tp_row + nrows >= t->t_scrollreg.ts_end) 277 t->t_cursor.tp_row = t->t_scrollreg.ts_end - 1; 278 else 279 t->t_cursor.tp_row += nrows; 280 t->t_stateflags &= ~TS_WRAPPED; 281 teken_funcs_cursor(t); 282} 283 284static void 285teken_subr_cursor_forward(teken_t *t, unsigned int ncols) 286{ 287 288 if (t->t_cursor.tp_col + ncols >= t->t_winsize.tp_col) 289 t->t_cursor.tp_col = t->t_winsize.tp_col - 1; 290 else 291 t->t_cursor.tp_col += ncols; 292 t->t_stateflags &= ~TS_WRAPPED; 293 teken_funcs_cursor(t); 294} 295 296static void 297teken_subr_cursor_forward_tabulation(teken_t *t, unsigned int ntabs) 298{ 299 300 do { 301 /* Stop when we've reached the end of the line. */ 302 if (t->t_cursor.tp_col == t->t_winsize.tp_col - 1) 303 break; 304 305 t->t_cursor.tp_col++; 306 307 /* Tab marker set. */ 308 if (teken_tab_isset(t, t->t_cursor.tp_col)) 309 ntabs--; 310 } while (ntabs > 0); 311 312 teken_funcs_cursor(t); 313} 314 315static void 316teken_subr_cursor_next_line(teken_t *t, unsigned int ncols) 317{ 318 319 t->t_cursor.tp_col = 0; 320 teken_subr_cursor_down(t, ncols); 321} 322 323static void 324teken_subr_cursor_position(teken_t *t, unsigned int row, unsigned int col) 325{ 326 327 t->t_cursor.tp_row = t->t_originreg.ts_begin + row - 1; 328 if (row >= t->t_originreg.ts_end) 329 t->t_cursor.tp_row = t->t_originreg.ts_end - 1; 330 331 t->t_cursor.tp_col = col - 1; 332 if (t->t_cursor.tp_col >= t->t_winsize.tp_col) 333 t->t_cursor.tp_col = t->t_winsize.tp_col - 1; 334 335 t->t_stateflags &= ~TS_WRAPPED; 336 teken_funcs_cursor(t); 337} 338 339static void 340teken_subr_cursor_position_report(teken_t *t, unsigned int cmd) 341{ 342 char response[18] = "\x1B["; 343 ssize_t len; 344 345 len = teken_subr_do_cpr(t, cmd, response + 2); 346 if (len < 0) 347 return; 348 349 teken_funcs_respond(t, response, len + 2); 350} 351 352static void 353teken_subr_cursor_previous_line(teken_t *t, unsigned int ncols) 354{ 355 356 t->t_cursor.tp_col = 0; 357 teken_subr_cursor_up(t, ncols); 358} 359 360static void 361teken_subr_cursor_up(teken_t *t, unsigned int nrows) 362{ 363 364 if (t->t_scrollreg.ts_begin + nrows >= t->t_cursor.tp_row) 365 t->t_cursor.tp_row = t->t_scrollreg.ts_begin; 366 else 367 t->t_cursor.tp_row -= nrows; 368 t->t_stateflags &= ~TS_WRAPPED; 369 teken_funcs_cursor(t); 370} 371 372static void 373teken_subr_delete_character(teken_t *t, unsigned int ncols) 374{ 375 teken_rect_t tr; 376 377 tr.tr_begin.tp_row = t->t_cursor.tp_row; 378 tr.tr_end.tp_row = t->t_cursor.tp_row + 1; 379 tr.tr_end.tp_col = t->t_winsize.tp_col; 380 381 if (t->t_cursor.tp_col + ncols >= t->t_winsize.tp_col) { 382 tr.tr_begin.tp_col = t->t_cursor.tp_col; 383 } else { 384 /* Copy characters to the left. */ 385 tr.tr_begin.tp_col = t->t_cursor.tp_col + ncols; 386 teken_funcs_copy(t, &tr, &t->t_cursor); 387 388 tr.tr_begin.tp_col = t->t_winsize.tp_col - ncols; 389 } 390 391 /* Blank trailing columns. */ 392 teken_funcs_fill(t, &tr, BLANK, &t->t_curattr); 393} 394 395static void 396teken_subr_delete_line(teken_t *t, unsigned int nrows) 397{ 398 teken_rect_t tr; 399 400 /* Ignore if outside scrolling region. */ 401 if (t->t_cursor.tp_row < t->t_scrollreg.ts_begin || 402 t->t_cursor.tp_row >= t->t_scrollreg.ts_end) 403 return; 404 405 tr.tr_begin.tp_col = 0; 406 tr.tr_end.tp_row = t->t_scrollreg.ts_end; 407 tr.tr_end.tp_col = t->t_winsize.tp_col; 408 409 if (t->t_cursor.tp_row + nrows >= t->t_scrollreg.ts_end) { 410 tr.tr_begin.tp_row = t->t_cursor.tp_row; 411 } else { 412 teken_pos_t tp; 413 414 /* Copy rows up. */ 415 tr.tr_begin.tp_row = t->t_cursor.tp_row + nrows; 416 tp.tp_row = t->t_cursor.tp_row; 417 tp.tp_col = 0; 418 teken_funcs_copy(t, &tr, &tp); 419 420 tr.tr_begin.tp_row = t->t_scrollreg.ts_end - nrows; 421 } 422 423 /* Blank trailing rows. */ 424 teken_funcs_fill(t, &tr, BLANK, &t->t_curattr); 425} 426 427static void 428teken_subr_device_control_string(teken_t *t __unused) 429{ 430 431 teken_printf("device control string???\n"); 432} 433 434static void 435teken_subr_device_status_report(teken_t *t, unsigned int cmd) 436{ 437 char response[19] = "\x1B[?"; 438 ssize_t len; 439 440 len = teken_subr_do_cpr(t, cmd, response + 3); 441 if (len < 0) 442 return; 443 444 teken_funcs_respond(t, response, len + 3); 445} 446 447static void 448teken_subr_double_height_double_width_line_top(teken_t *t __unused) 449{ 450 451 teken_printf("double height double width top\n"); 452} 453 454static void 455teken_subr_double_height_double_width_line_bottom(teken_t *t __unused) 456{ 457 458 teken_printf("double height double width bottom\n"); 459} 460 461static void 462teken_subr_erase_character(teken_t *t, unsigned int ncols) 463{ 464 teken_rect_t tr; 465 466 tr.tr_begin = t->t_cursor; 467 tr.tr_end.tp_row = t->t_cursor.tp_row + 1; 468 469 if (t->t_cursor.tp_col + ncols >= t->t_winsize.tp_col) 470 tr.tr_end.tp_col = t->t_winsize.tp_col; 471 else 472 tr.tr_end.tp_col = t->t_cursor.tp_col + ncols; 473 474 teken_funcs_fill(t, &tr, BLANK, &t->t_curattr); 475} 476 477static void 478teken_subr_erase_display(teken_t *t, unsigned int mode) 479{ 480 teken_rect_t r; 481 482 r.tr_begin.tp_col = 0; 483 r.tr_end.tp_col = t->t_winsize.tp_col; 484 485 switch (mode) { 486 case 1: /* Erase from the top to the cursor. */ 487 teken_subr_erase_line(t, 1); 488 489 /* Erase lines above. */ 490 if (t->t_cursor.tp_row == 0) 491 return; 492 r.tr_begin.tp_row = 0; 493 r.tr_end.tp_row = t->t_cursor.tp_row; 494 break; 495 case 2: /* Erase entire display. */ 496 r.tr_begin.tp_row = 0; 497 r.tr_end.tp_row = t->t_winsize.tp_row; 498 break; 499 default: /* Erase from cursor to the bottom. */ 500 teken_subr_erase_line(t, 0); 501 502 /* Erase lines below. */ 503 if (t->t_cursor.tp_row == t->t_winsize.tp_row - 1) 504 return; 505 r.tr_begin.tp_row = t->t_cursor.tp_row + 1; 506 r.tr_end.tp_row = t->t_winsize.tp_row; 507 break; 508 } 509 510 teken_funcs_fill(t, &r, BLANK, &t->t_curattr); 511} 512 513static void 514teken_subr_erase_line(teken_t *t, unsigned int mode) 515{ 516 teken_rect_t r; 517 518 r.tr_begin.tp_row = t->t_cursor.tp_row; 519 r.tr_end.tp_row = t->t_cursor.tp_row + 1; 520 521 switch (mode) { 522 case 1: /* Erase from the beginning of the line to the cursor. */ 523 r.tr_begin.tp_col = 0; 524 r.tr_end.tp_col = t->t_cursor.tp_col + 1; 525 break; 526 case 2: /* Erase entire line. */ 527 r.tr_begin.tp_col = 0; 528 r.tr_end.tp_col = t->t_winsize.tp_col; 529 break; 530 default: /* Erase from cursor to the end of the line. */ 531 r.tr_begin.tp_col = t->t_cursor.tp_col; 532 r.tr_end.tp_col = t->t_winsize.tp_col; 533 break; 534 } 535 536 teken_funcs_fill(t, &r, BLANK, &t->t_curattr); 537} 538 539static void 540teken_subr_g0_scs_special_graphics(teken_t *t __unused) 541{ 542 543 t->t_scs[0] = teken_scs_special_graphics; 544} 545 546static void 547teken_subr_g0_scs_uk_national(teken_t *t __unused) 548{ 549 550 t->t_scs[0] = teken_scs_uk_national; 551} 552 553static void 554teken_subr_g0_scs_us_ascii(teken_t *t __unused) 555{ 556 557 t->t_scs[0] = teken_scs_us_ascii; 558} 559 560static void 561teken_subr_g1_scs_special_graphics(teken_t *t __unused) 562{ 563 564 t->t_scs[1] = teken_scs_special_graphics; 565} 566 567static void 568teken_subr_g1_scs_uk_national(teken_t *t __unused) 569{ 570 571 t->t_scs[1] = teken_scs_uk_national; 572} 573 574static void 575teken_subr_g1_scs_us_ascii(teken_t *t __unused) 576{ 577 578 t->t_scs[1] = teken_scs_us_ascii; 579} 580 581static void 582teken_subr_horizontal_position_absolute(teken_t *t, unsigned int col) 583{ 584 585 t->t_cursor.tp_col = col - 1; 586 if (t->t_cursor.tp_col >= t->t_winsize.tp_col) 587 t->t_cursor.tp_col = t->t_winsize.tp_col - 1; 588 589 t->t_stateflags &= ~TS_WRAPPED; 590 teken_funcs_cursor(t); 591} 592 593static void 594teken_subr_horizontal_tab(teken_t *t) 595{ 596 597 if (t->t_stateflags & TS_CONS25) { 598 teken_subr_cursor_forward_tabulation(t, 1); 599 } else { 600 teken_rect_t tr; 601 602 tr.tr_begin = t->t_cursor; 603 teken_subr_cursor_forward_tabulation(t, 1); 604 tr.tr_end.tp_row = tr.tr_begin.tp_row + 1; 605 tr.tr_end.tp_col = t->t_cursor.tp_col; 606 607 /* Blank region that we skipped. */ 608 if (tr.tr_end.tp_col > tr.tr_begin.tp_col) 609 teken_funcs_fill(t, &tr, BLANK, &t->t_curattr); 610 } 611} 612 613static void 614teken_subr_horizontal_tab_set(teken_t *t) 615{ 616 617 teken_tab_set(t, t->t_cursor.tp_col); 618} 619 620static void 621teken_subr_index(teken_t *t) 622{ 623 624 if (t->t_cursor.tp_row < t->t_scrollreg.ts_end - 1) { 625 t->t_cursor.tp_row++; 626 t->t_stateflags &= ~TS_WRAPPED; 627 teken_funcs_cursor(t); 628 } else { 629 teken_subr_do_scroll(t, 1); 630 } 631} 632 633static void 634teken_subr_insert_character(teken_t *t, unsigned int ncols) 635{ 636 teken_rect_t tr; 637 638 tr.tr_begin = t->t_cursor; 639 tr.tr_end.tp_row = t->t_cursor.tp_row + 1; 640 641 if (t->t_cursor.tp_col + ncols >= t->t_winsize.tp_col) { 642 tr.tr_end.tp_col = t->t_winsize.tp_col; 643 } else { 644 teken_pos_t tp; 645 646 /* Copy characters to the right. */ 647 tr.tr_end.tp_col = t->t_winsize.tp_col - ncols; 648 tp.tp_row = t->t_cursor.tp_row; 649 tp.tp_col = t->t_cursor.tp_col + ncols; 650 teken_funcs_copy(t, &tr, &tp); 651 652 tr.tr_end.tp_col = t->t_cursor.tp_col + ncols; 653 } 654 655 /* Blank current location. */ 656 teken_funcs_fill(t, &tr, BLANK, &t->t_curattr); 657} 658 659static void 660teken_subr_insert_line(teken_t *t, unsigned int nrows) 661{ 662 teken_rect_t tr; 663 664 /* Ignore if outside scrolling region. */ 665 if (t->t_cursor.tp_row < t->t_scrollreg.ts_begin || 666 t->t_cursor.tp_row >= t->t_scrollreg.ts_end) 667 return; 668 669 tr.tr_begin.tp_row = t->t_cursor.tp_row; 670 tr.tr_begin.tp_col = 0; 671 tr.tr_end.tp_col = t->t_winsize.tp_col; 672 673 if (t->t_cursor.tp_row + nrows >= t->t_scrollreg.ts_end) { 674 tr.tr_end.tp_row = t->t_scrollreg.ts_end; 675 } else { 676 teken_pos_t tp; 677 678 /* Copy lines down. */ 679 tr.tr_end.tp_row = t->t_scrollreg.ts_end - nrows; 680 tp.tp_row = t->t_cursor.tp_row + nrows; 681 tp.tp_col = 0; 682 teken_funcs_copy(t, &tr, &tp); 683 684 tr.tr_end.tp_row = t->t_cursor.tp_row + nrows; 685 } 686 687 /* Blank current location. */ 688 teken_funcs_fill(t, &tr, BLANK, &t->t_curattr); 689} 690 691static void 692teken_subr_keypad_application_mode(teken_t *t) 693{ 694 695 teken_funcs_param(t, TP_KEYPADAPP, 1); 696} 697 698static void 699teken_subr_keypad_numeric_mode(teken_t *t) 700{ 701 702 teken_funcs_param(t, TP_KEYPADAPP, 0); 703} 704 705static void 706teken_subr_newline(teken_t *t) 707{ 708 709 t->t_cursor.tp_row++; 710 711 if (t->t_cursor.tp_row >= t->t_scrollreg.ts_end) { 712 teken_subr_do_scroll(t, 1); 713 t->t_cursor.tp_row = t->t_scrollreg.ts_end - 1; 714 } 715 716 t->t_stateflags &= ~TS_WRAPPED; 717 teken_funcs_cursor(t); 718} 719 720static void 721teken_subr_newpage(teken_t *t) 722{ 723 724 if (t->t_stateflags & TS_CONS25) { 725 teken_rect_t tr; 726 727 tr.tr_begin.tp_row = tr.tr_begin.tp_col = 0; 728 tr.tr_end = t->t_winsize; 729 teken_funcs_fill(t, &tr, BLANK, &t->t_curattr); 730 731 t->t_cursor.tp_row = t->t_cursor.tp_col = 0; 732 teken_funcs_cursor(t); 733 } else { 734 teken_subr_newline(t); 735 } 736} 737 738static void 739teken_subr_next_line(teken_t *t) 740{ 741 742 t->t_cursor.tp_col = 0; 743 teken_subr_newline(t); 744} 745 746static void 747teken_subr_pan_down(teken_t *t, unsigned int nrows) 748{ 749 750 teken_subr_do_scroll(t, (int)nrows); 751} 752 753static void 754teken_subr_pan_up(teken_t *t, unsigned int nrows) 755{ 756 757 teken_subr_do_scroll(t, -(int)nrows); 758} 759 760static void 761teken_subr_primary_device_attributes(teken_t *t, unsigned int request) 762{ 763 764 if (request == 0) { 765 const char response[] = "\x1B[?1;2c"; 766 767 teken_funcs_respond(t, response, sizeof response - 1); 768 } else { 769 teken_printf("Unknown DA1\n"); 770 } 771} 772 773static void 774teken_subr_do_putchar(teken_t *t, const teken_pos_t *tp, teken_char_t c, 775 int width) 776{ 777 778 if (t->t_stateflags & TS_INSERT && 779 tp->tp_col < t->t_winsize.tp_col - width) { 780 teken_rect_t ctr; 781 teken_pos_t ctp; 782 783 /* Insert mode. Move existing characters to the right. */ 784 ctr.tr_begin = *tp; 785 ctr.tr_end.tp_row = tp->tp_row + 1; 786 ctr.tr_end.tp_col = t->t_winsize.tp_col - width; 787 ctp.tp_row = tp->tp_row; 788 ctp.tp_col = tp->tp_col + width; 789 teken_funcs_copy(t, &ctr, &ctp); 790 } 791 792 if (width == 2 && tp->tp_col + 1 < t->t_winsize.tp_col) { 793 teken_pos_t tp2; 794 795 /* 796 * Store a space behind double width characters before 797 * actually printing them. This prevents artifacts when 798 * the consumer doesn't render it using double width 799 * glyphs. 800 */ 801 tp2.tp_row = tp->tp_row; 802 tp2.tp_col = tp->tp_col + 1; 803 teken_funcs_putchar(t, &tp2, BLANK, &t->t_curattr); 804 } 805 806 teken_funcs_putchar(t, tp, c, &t->t_curattr); 807} 808 809static void 810teken_subr_regular_character(teken_t *t, teken_char_t c) 811{ 812 int width; 813 814 if (t->t_stateflags & TS_8BIT) { 815 if (!(t->t_stateflags & TS_CONS25) && (c <= 0x1b || c == 0x7f)) 816 return; 817 c = teken_scs_process(t, c); 818 width = 1; 819 } else { 820 c = teken_scs_process(t, c); 821 width = teken_wcwidth(c); 822 /* XXX: Don't process zero-width characters yet. */ 823 if (width <= 0) 824 return; 825 } 826 827 if (t->t_stateflags & TS_CONS25) { 828 teken_subr_do_putchar(t, &t->t_cursor, c, width); 829 t->t_cursor.tp_col += width; 830 831 if (t->t_cursor.tp_col >= t->t_winsize.tp_col) { 832 if (t->t_cursor.tp_row == t->t_scrollreg.ts_end - 1) { 833 /* Perform scrolling. */ 834 teken_subr_do_scroll(t, 1); 835 } else { 836 /* No scrolling needed. */ 837 if (t->t_cursor.tp_row < 838 t->t_winsize.tp_row - 1) 839 t->t_cursor.tp_row++; 840 } 841 t->t_cursor.tp_col = 0; 842 } 843 } else if (t->t_cursor.tp_col == t->t_winsize.tp_col - 1 && 844 (t->t_stateflags & (TS_WRAPPED|TS_AUTOWRAP)) == 845 (TS_WRAPPED|TS_AUTOWRAP)) { 846 teken_pos_t tp; 847 848 /* Perform line wrapping. */ 849 850 if (t->t_cursor.tp_row == t->t_scrollreg.ts_end - 1) { 851 /* Perform scrolling. */ 852 teken_subr_do_scroll(t, 1); 853 tp.tp_row = t->t_scrollreg.ts_end - 1; 854 } else { 855 /* No scrolling needed. */ 856 tp.tp_row = t->t_cursor.tp_row + 1; 857 if (tp.tp_row == t->t_winsize.tp_row) { 858 /* 859 * Corner case: regular character 860 * outside scrolling region, but at the 861 * bottom of the screen. 862 */ 863 teken_subr_do_putchar(t, &t->t_cursor, 864 c, width); 865 return; 866 } 867 } 868 869 tp.tp_col = 0; 870 teken_subr_do_putchar(t, &tp, c, width); 871 872 t->t_cursor.tp_row = tp.tp_row; 873 t->t_cursor.tp_col = width; 874 t->t_stateflags &= ~TS_WRAPPED; 875 } else { 876 /* No line wrapping needed. */ 877 teken_subr_do_putchar(t, &t->t_cursor, c, width); 878 t->t_cursor.tp_col += width; 879 880 if (t->t_cursor.tp_col >= t->t_winsize.tp_col) { 881 t->t_stateflags |= TS_WRAPPED; 882 t->t_cursor.tp_col = t->t_winsize.tp_col - 1; 883 } else { 884 t->t_stateflags &= ~TS_WRAPPED; 885 } 886 } 887 888 teken_funcs_cursor(t); 889} 890 891static void 892teken_subr_reset_dec_mode(teken_t *t, unsigned int cmd) 893{ 894 895 switch (cmd) { 896 case 1: /* Cursor keys mode. */ 897 teken_funcs_param(t, TP_CURSORKEYS, 0); 898 break; 899 case 2: /* DECANM: ANSI/VT52 mode. */ 900 teken_printf("DECRST VT52\n"); 901 break; 902 case 3: /* 132 column mode. */ 903 teken_funcs_param(t, TP_132COLS, 0); 904 teken_subr_reset_to_initial_state(t); 905 break; 906 case 5: /* Inverse video. */ 907 teken_printf("DECRST inverse video\n"); 908 break; 909 case 6: /* Origin mode. */ 910 t->t_stateflags &= ~TS_ORIGIN; 911 t->t_originreg.ts_begin = 0; 912 t->t_originreg.ts_end = t->t_winsize.tp_row; 913 t->t_cursor.tp_row = t->t_cursor.tp_col = 0; 914 t->t_stateflags &= ~TS_WRAPPED; 915 teken_funcs_cursor(t); 916 break; 917 case 7: /* Autowrap mode. */ 918 t->t_stateflags &= ~TS_AUTOWRAP; 919 break; 920 case 8: /* Autorepeat mode. */ 921 teken_funcs_param(t, TP_AUTOREPEAT, 0); 922 break; 923 case 25: /* Hide cursor. */ 924 teken_funcs_param(t, TP_SHOWCURSOR, 0); 925 break; 926 case 40: /* Disallow 132 columns. */ 927 teken_printf("DECRST allow 132\n"); 928 break; 929 case 45: /* Disable reverse wraparound. */ 930 teken_printf("DECRST reverse wraparound\n"); 931 break; 932 case 47: /* Switch to alternate buffer. */ 933 teken_printf("Switch to alternate buffer\n"); 934 break; 935 default: 936 teken_printf("Unknown DECRST: %u\n", cmd); 937 } 938} 939 940static void 941teken_subr_reset_mode(teken_t *t, unsigned int cmd) 942{ 943 944 switch (cmd) { 945 case 4: 946 t->t_stateflags &= ~TS_INSERT; 947 break; 948 default: 949 teken_printf("Unknown reset mode: %u\n", cmd); 950 } 951} 952 953static void 954teken_subr_do_reset(teken_t *t) 955{ 956 957 t->t_curattr = t->t_defattr; 958 t->t_cursor.tp_row = t->t_cursor.tp_col = 0; 959 t->t_scrollreg.ts_begin = 0; 960 t->t_scrollreg.ts_end = t->t_winsize.tp_row; 961 t->t_originreg = t->t_scrollreg; 962 t->t_stateflags &= TS_8BIT|TS_CONS25; 963 t->t_stateflags |= TS_AUTOWRAP; 964 965 t->t_scs[0] = teken_scs_us_ascii; 966 t->t_scs[1] = teken_scs_us_ascii; 967 t->t_curscs = 0; 968 969 teken_subr_save_cursor(t); 970 teken_tab_default(t); 971} 972 973static void 974teken_subr_reset_to_initial_state(teken_t *t) 975{ 976 977 teken_subr_do_reset(t); 978 teken_subr_erase_display(t, 2); 979 teken_funcs_param(t, TP_SHOWCURSOR, 1); 980 teken_funcs_cursor(t); 981} 982 983static void 984teken_subr_restore_cursor(teken_t *t) 985{ 986 987 t->t_cursor = t->t_saved_cursor; 988 t->t_curattr = t->t_saved_curattr; 989 t->t_scs[t->t_curscs] = t->t_saved_curscs; 990 t->t_stateflags &= ~TS_WRAPPED; 991 992 /* Get out of origin mode when the cursor is moved outside. */ 993 if (t->t_cursor.tp_row < t->t_originreg.ts_begin || 994 t->t_cursor.tp_row >= t->t_originreg.ts_end) { 995 t->t_stateflags &= ~TS_ORIGIN; 996 t->t_originreg.ts_begin = 0; 997 t->t_originreg.ts_end = t->t_winsize.tp_row; 998 } 999 1000 teken_funcs_cursor(t); 1001} 1002 1003static void 1004teken_subr_reverse_index(teken_t *t) 1005{ 1006 1007 if (t->t_cursor.tp_row > t->t_scrollreg.ts_begin) { 1008 t->t_cursor.tp_row--; 1009 t->t_stateflags &= ~TS_WRAPPED; 1010 teken_funcs_cursor(t); 1011 } else { 1012 teken_subr_do_scroll(t, -1); 1013 } 1014} 1015 1016static void 1017teken_subr_save_cursor(teken_t *t) 1018{ 1019 1020 t->t_saved_cursor = t->t_cursor; 1021 t->t_saved_curattr = t->t_curattr; 1022 t->t_saved_curscs = t->t_scs[t->t_curscs]; 1023} 1024 1025static void 1026teken_subr_secondary_device_attributes(teken_t *t, unsigned int request) 1027{ 1028 1029 if (request == 0) { 1030 const char response[] = "\x1B[>0;10;0c"; 1031 teken_funcs_respond(t, response, sizeof response - 1); 1032 } else { 1033 teken_printf("Unknown DA2\n"); 1034 } 1035} 1036 1037static void 1038teken_subr_set_dec_mode(teken_t *t, unsigned int cmd) 1039{ 1040 1041 switch (cmd) { 1042 case 1: /* Cursor keys mode. */ 1043 teken_funcs_param(t, TP_CURSORKEYS, 1); 1044 break; 1045 case 2: /* DECANM: ANSI/VT52 mode. */ 1046 teken_printf("DECSET VT52\n"); 1047 break; 1048 case 3: /* 132 column mode. */ 1049 teken_funcs_param(t, TP_132COLS, 1); 1050 teken_subr_reset_to_initial_state(t); 1051 break; 1052 case 5: /* Inverse video. */ 1053 teken_printf("DECSET inverse video\n"); 1054 break; 1055 case 6: /* Origin mode. */ 1056 t->t_stateflags |= TS_ORIGIN; 1057 t->t_originreg = t->t_scrollreg; 1058 t->t_cursor.tp_row = t->t_scrollreg.ts_begin; 1059 t->t_cursor.tp_col = 0; 1060 t->t_stateflags &= ~TS_WRAPPED; 1061 teken_funcs_cursor(t); 1062 break; 1063 case 7: /* Autowrap mode. */ 1064 t->t_stateflags |= TS_AUTOWRAP; 1065 break; 1066 case 8: /* Autorepeat mode. */ 1067 teken_funcs_param(t, TP_AUTOREPEAT, 1); 1068 break; 1069 case 25: /* Display cursor. */ 1070 teken_funcs_param(t, TP_SHOWCURSOR, 1); 1071 break; 1072 case 40: /* Allow 132 columns. */ 1073 teken_printf("DECSET allow 132\n"); 1074 break; 1075 case 45: /* Enable reverse wraparound. */ 1076 teken_printf("DECSET reverse wraparound\n"); 1077 break; 1078 case 47: /* Switch to alternate buffer. */ 1079 teken_printf("Switch away from alternate buffer\n"); 1080 break; 1081 default: 1082 teken_printf("Unknown DECSET: %u\n", cmd); 1083 } 1084} 1085 1086static void 1087teken_subr_set_mode(teken_t *t, unsigned int cmd) 1088{ 1089 1090 switch (cmd) { 1091 case 4: 1092 teken_printf("Insert mode\n"); 1093 t->t_stateflags |= TS_INSERT; 1094 break; 1095 default: 1096 teken_printf("Unknown set mode: %u\n", cmd); 1097 } 1098} 1099 1100static void 1101teken_subr_set_graphic_rendition(teken_t *t, unsigned int ncmds, 1102 unsigned int cmds[]) 1103{ 1104 unsigned int i, n; 1105 1106 /* No attributes means reset. */ 1107 if (ncmds == 0) { 1108 t->t_curattr = t->t_defattr; 1109 return; 1110 } 1111 1112 for (i = 0; i < ncmds; i++) { 1113 n = cmds[i]; 1114 1115 switch (n) { 1116 case 0: /* Reset. */ 1117 t->t_curattr = t->t_defattr; 1118 break; 1119 case 1: /* Bold. */ 1120 t->t_curattr.ta_format |= TF_BOLD; 1121 break; 1122 case 4: /* Underline. */ 1123 t->t_curattr.ta_format |= TF_UNDERLINE; 1124 break; 1125 case 5: /* Blink. */ 1126 t->t_curattr.ta_format |= TF_BLINK; 1127 break; 1128 case 7: /* Reverse. */ 1129 t->t_curattr.ta_format |= TF_REVERSE; 1130 break; 1131 case 22: /* Remove bold. */ 1132 t->t_curattr.ta_format &= ~TF_BOLD; 1133 break; 1134 case 24: /* Remove underline. */ 1135 t->t_curattr.ta_format &= ~TF_UNDERLINE; 1136 break; 1137 case 25: /* Remove blink. */ 1138 t->t_curattr.ta_format &= ~TF_BLINK; 1139 break; 1140 case 27: /* Remove reverse. */ 1141 t->t_curattr.ta_format &= ~TF_REVERSE; 1142 break; 1143 case 30: /* Set foreground color: black */ 1144 case 31: /* Set foreground color: red */ 1145 case 32: /* Set foreground color: green */ 1146 case 33: /* Set foreground color: brown */ 1147 case 34: /* Set foreground color: blue */ 1148 case 35: /* Set foreground color: magenta */ 1149 case 36: /* Set foreground color: cyan */ 1150 case 37: /* Set foreground color: white */ 1151 t->t_curattr.ta_fgcolor = n - 30; 1152 break; 1153 case 38: /* Set foreground color: 256 color mode */ 1154 if (i + 2 >= ncmds || cmds[i + 1] != 5) 1155 continue; 1156 t->t_curattr.ta_fgcolor = cmds[i + 2]; 1157 i += 2; 1158 break; 1159 case 39: /* Set default foreground color. */ 1160 t->t_curattr.ta_fgcolor = t->t_defattr.ta_fgcolor; 1161 break; 1162 case 40: /* Set background color: black */ 1163 case 41: /* Set background color: red */ 1164 case 42: /* Set background color: green */ 1165 case 43: /* Set background color: brown */ 1166 case 44: /* Set background color: blue */ 1167 case 45: /* Set background color: magenta */ 1168 case 46: /* Set background color: cyan */ 1169 case 47: /* Set background color: white */ 1170 t->t_curattr.ta_bgcolor = n - 40; 1171 break; 1172 case 48: /* Set background color: 256 color mode */ 1173 if (i + 2 >= ncmds || cmds[i + 1] != 5) 1174 continue; 1175 t->t_curattr.ta_bgcolor = cmds[i + 2]; 1176 i += 2; 1177 break; 1178 case 49: /* Set default background color. */ 1179 t->t_curattr.ta_bgcolor = t->t_defattr.ta_bgcolor; 1180 break; 1181 case 90: /* Set bright foreground color: black */ 1182 case 91: /* Set bright foreground color: red */ 1183 case 92: /* Set bright foreground color: green */ 1184 case 93: /* Set bright foreground color: brown */ 1185 case 94: /* Set bright foreground color: blue */ 1186 case 95: /* Set bright foreground color: magenta */ 1187 case 96: /* Set bright foreground color: cyan */ 1188 case 97: /* Set bright foreground color: white */ 1189 t->t_curattr.ta_fgcolor = n - 90 + 8; 1190 break; 1191 case 100: /* Set bright background color: black */ 1192 case 101: /* Set bright background color: red */ 1193 case 102: /* Set bright background color: green */ 1194 case 103: /* Set bright background color: brown */ 1195 case 104: /* Set bright background color: blue */ 1196 case 105: /* Set bright background color: magenta */ 1197 case 106: /* Set bright background color: cyan */ 1198 case 107: /* Set bright background color: white */ 1199 t->t_curattr.ta_bgcolor = n - 100 + 8; 1200 break; 1201 default: 1202 teken_printf("unsupported attribute %u\n", n); 1203 } 1204 } 1205} 1206 1207static void 1208teken_subr_set_top_and_bottom_margins(teken_t *t, unsigned int top, 1209 unsigned int bottom) 1210{ 1211 1212 /* Adjust top row number. */ 1213 if (top > 0) 1214 top--; 1215 /* Adjust bottom row number. */ 1216 if (bottom == 0 || bottom > t->t_winsize.tp_row) 1217 bottom = t->t_winsize.tp_row; 1218 1219 /* Invalid arguments. */ 1220 if (top >= bottom - 1) { 1221 top = 0; 1222 bottom = t->t_winsize.tp_row; 1223 } 1224 1225 t->t_scrollreg.ts_begin = top; 1226 t->t_scrollreg.ts_end = bottom; 1227 if (t->t_stateflags & TS_ORIGIN) { 1228 /* XXX: home cursor? */ 1229 t->t_originreg = t->t_scrollreg; 1230 t->t_cursor.tp_row = t->t_originreg.ts_begin; 1231 t->t_cursor.tp_col = 0; 1232 t->t_stateflags &= ~TS_WRAPPED; 1233 teken_funcs_cursor(t); 1234 } 1235} 1236 1237static void 1238teken_subr_single_height_double_width_line(teken_t *t __unused) 1239{ 1240 1241 teken_printf("single height double width???\n"); 1242} 1243 1244static void 1245teken_subr_single_height_single_width_line(teken_t *t __unused) 1246{ 1247 1248 teken_printf("single height single width???\n"); 1249} 1250 1251static void 1252teken_subr_string_terminator(teken_t *t __unused) 1253{ 1254 1255 teken_printf("string terminator???\n"); 1256} 1257 1258static void 1259teken_subr_tab_clear(teken_t *t, unsigned int cmd) 1260{ 1261 1262 switch (cmd) { 1263 case 0: 1264 teken_tab_clear(t, t->t_cursor.tp_col); 1265 break; 1266 case 3: 1267 memset(&t->t_tabstops, 0, T_NUMCOL / 8); 1268 break; 1269 } 1270} 1271 1272static void 1273teken_subr_vertical_position_absolute(teken_t *t, unsigned int row) 1274{ 1275 1276 t->t_cursor.tp_row = t->t_originreg.ts_begin + row - 1; 1277 if (row >= t->t_originreg.ts_end) 1278 t->t_cursor.tp_row = t->t_originreg.ts_end - 1; 1279 1280 1281 t->t_stateflags &= ~TS_WRAPPED; 1282 teken_funcs_cursor(t); 1283} 1284