input.c revision 1.8
1/* $OpenBSD: input.c,v 1.8 2009/06/04 21:02:21 nicm Exp $ */ 2 3/* 4 * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19#include <sys/types.h> 20 21#include <stdint.h> 22#include <stdlib.h> 23#include <string.h> 24 25#include "tmux.h" 26 27#define INPUT_C0CONTROL(ch) (ch <= 0x1f) 28#define INPUT_INTERMEDIATE(ch) (ch == 0xa0 || (ch >= 0x20 && ch <= 0x2f)) 29#define INPUT_PARAMETER(ch) (ch >= 0x30 && ch <= 0x3f) 30#define INPUT_UPPERCASE(ch) (ch >= 0x40 && ch <= 0x5f) 31#define INPUT_LOWERCASE(ch) (ch >= 0x60 && ch <= 0x7e) 32#define INPUT_DELETE(ch) (ch == 0x7f) 33#define INPUT_C1CONTROL(ch) (ch >= 0x80 && ch <= 0x9f) 34#define INPUT_G1DISPLAYABLE(ch) (ch >= 0xa1 && ch <= 0xfe) 35#define INPUT_SPECIAL(ch) (ch == 0xff) 36 37int input_get_argument(struct input_ctx *, u_int, uint16_t *, uint16_t); 38int input_new_argument(struct input_ctx *); 39int input_add_argument(struct input_ctx *, u_char); 40 41void input_start_string(struct input_ctx *, int); 42void input_abort_string(struct input_ctx *); 43int input_add_string(struct input_ctx *, u_char); 44char *input_get_string(struct input_ctx *); 45 46void input_state(struct input_ctx *, void *); 47 48void input_state_first(u_char, struct input_ctx *); 49void input_state_escape(u_char, struct input_ctx *); 50void input_state_intermediate(u_char, struct input_ctx *); 51void input_state_sequence_first(u_char, struct input_ctx *); 52void input_state_sequence_next(u_char, struct input_ctx *); 53void input_state_sequence_intermediate(u_char, struct input_ctx *); 54void input_state_string_next(u_char, struct input_ctx *); 55void input_state_string_escape(u_char, struct input_ctx *); 56void input_state_utf8(u_char, struct input_ctx *); 57 58void input_handle_character(u_char, struct input_ctx *); 59void input_handle_c0_control(u_char, struct input_ctx *); 60void input_handle_c1_control(u_char, struct input_ctx *); 61void input_handle_private_two(u_char, struct input_ctx *); 62void input_handle_standard_two(u_char, struct input_ctx *); 63void input_handle_sequence(u_char, struct input_ctx *); 64 65void input_handle_sequence_cuu(struct input_ctx *); 66void input_handle_sequence_cud(struct input_ctx *); 67void input_handle_sequence_cuf(struct input_ctx *); 68void input_handle_sequence_cub(struct input_ctx *); 69void input_handle_sequence_dch(struct input_ctx *); 70void input_handle_sequence_cbt(struct input_ctx *); 71void input_handle_sequence_dl(struct input_ctx *); 72void input_handle_sequence_ich(struct input_ctx *); 73void input_handle_sequence_il(struct input_ctx *); 74void input_handle_sequence_vpa(struct input_ctx *); 75void input_handle_sequence_hpa(struct input_ctx *); 76void input_handle_sequence_cup(struct input_ctx *); 77void input_handle_sequence_cup(struct input_ctx *); 78void input_handle_sequence_tbc(struct input_ctx *); 79void input_handle_sequence_ed(struct input_ctx *); 80void input_handle_sequence_el(struct input_ctx *); 81void input_handle_sequence_sm(struct input_ctx *); 82void input_handle_sequence_rm(struct input_ctx *); 83void input_handle_sequence_decstbm(struct input_ctx *); 84void input_handle_sequence_sgr(struct input_ctx *); 85void input_handle_sequence_dsr(struct input_ctx *); 86 87int input_sequence_cmp(const void *, const void *); 88 89struct input_sequence_entry { 90 u_char ch; 91 void (*fn)(struct input_ctx *); 92}; 93const struct input_sequence_entry input_sequence_table[] = { 94 { '@', input_handle_sequence_ich }, 95 { 'A', input_handle_sequence_cuu }, 96 { 'B', input_handle_sequence_cud }, 97 { 'C', input_handle_sequence_cuf }, 98 { 'D', input_handle_sequence_cub }, 99 { 'G', input_handle_sequence_hpa }, 100 { 'H', input_handle_sequence_cup }, 101 { 'J', input_handle_sequence_ed }, 102 { 'K', input_handle_sequence_el }, 103 { 'L', input_handle_sequence_il }, 104 { 'M', input_handle_sequence_dl }, 105 { 'P', input_handle_sequence_dch }, 106 { 'Z', input_handle_sequence_cbt }, 107 { 'd', input_handle_sequence_vpa }, 108 { 'f', input_handle_sequence_cup }, 109 { 'g', input_handle_sequence_tbc }, 110 { 'h', input_handle_sequence_sm }, 111 { 'l', input_handle_sequence_rm }, 112 { 'm', input_handle_sequence_sgr }, 113 { 'n', input_handle_sequence_dsr }, 114 { 'r', input_handle_sequence_decstbm }, 115}; 116 117int 118input_sequence_cmp(const void *a, const void *b) 119{ 120 int ai = ((const struct input_sequence_entry *) a)->ch; 121 int bi = ((const struct input_sequence_entry *) b)->ch; 122 123 return (ai - bi); 124} 125 126int 127input_new_argument(struct input_ctx *ictx) 128{ 129 struct input_arg *arg; 130 131 ARRAY_EXPAND(&ictx->args, 1); 132 133 arg = &ARRAY_LAST(&ictx->args); 134 arg->used = 0; 135 136 return (0); 137} 138 139int 140input_add_argument(struct input_ctx *ictx, u_char ch) 141{ 142 struct input_arg *arg; 143 144 if (ARRAY_LENGTH(&ictx->args) == 0) 145 return (0); 146 147 arg = &ARRAY_LAST(&ictx->args); 148 if (arg->used > (sizeof arg->data) - 1) 149 return (-1); 150 arg->data[arg->used++] = ch; 151 152 return (0); 153} 154 155int 156input_get_argument(struct input_ctx *ictx, u_int i, uint16_t *n, uint16_t d) 157{ 158 struct input_arg *arg; 159 const char *errstr; 160 161 *n = d; 162 if (i >= ARRAY_LENGTH(&ictx->args)) 163 return (0); 164 165 arg = &ARRAY_ITEM(&ictx->args, i); 166 if (*arg->data == '\0') 167 return (0); 168 169 *n = strtonum(arg->data, 0, UINT16_MAX, &errstr); 170 if (errstr != NULL) 171 return (-1); 172 return (0); 173} 174 175void 176input_start_string(struct input_ctx *ictx, int type) 177{ 178 ictx->string_type = type; 179 ictx->string_len = 0; 180} 181 182void 183input_abort_string(struct input_ctx *ictx) 184{ 185 if (ictx->string_buf != NULL) 186 xfree(ictx->string_buf); 187 ictx->string_buf = NULL; 188} 189 190int 191input_add_string(struct input_ctx *ictx, u_char ch) 192{ 193 ictx->string_buf = xrealloc(ictx->string_buf, 1, ictx->string_len + 1); 194 ictx->string_buf[ictx->string_len++] = ch; 195 196 if (ictx->string_len >= MAXSTRINGLEN) { 197 input_abort_string(ictx); 198 return (1); 199 } 200 201 return (0); 202} 203 204char * 205input_get_string(struct input_ctx *ictx) 206{ 207 char *s; 208 209 if (ictx->string_buf == NULL || input_add_string(ictx, '\0') != 0) 210 return (xstrdup("")); 211 212 s = ictx->string_buf; 213 ictx->string_buf = NULL; 214 return (s); 215} 216 217void 218input_state(struct input_ctx *ictx, void *state) 219{ 220 ictx->state = state; 221} 222 223void 224input_init(struct window_pane *wp) 225{ 226 struct input_ctx *ictx = &wp->ictx; 227 228 ARRAY_INIT(&ictx->args); 229 230 ictx->string_len = 0; 231 ictx->string_buf = NULL; 232 233 memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell); 234 235 memcpy(&ictx->saved_cell, &grid_default_cell, sizeof ictx->saved_cell); 236 ictx->saved_cx = 0; 237 ictx->saved_cy = 0; 238 239 input_state(ictx, input_state_first); 240} 241 242void 243input_free(struct window_pane *wp) 244{ 245 if (wp->ictx.string_buf != NULL) 246 xfree(wp->ictx.string_buf); 247 248 ARRAY_FREE(&wp->ictx.args); 249} 250 251void 252input_parse(struct window_pane *wp) 253{ 254 struct input_ctx *ictx = &wp->ictx; 255 u_char ch; 256 257 if (BUFFER_USED(wp->in) == 0) 258 return; 259 260 ictx->buf = BUFFER_OUT(wp->in); 261 ictx->len = BUFFER_USED(wp->in); 262 ictx->off = 0; 263 264 ictx->wp = wp; 265 266 log_debug2("entry; buffer=%zu", ictx->len); 267 268 if (wp->mode == NULL) 269 screen_write_start(&ictx->ctx, wp, &wp->base); 270 else 271 screen_write_start(&ictx->ctx, NULL, &wp->base); 272 273 if (ictx->off != ictx->len) 274 wp->window->flags |= WINDOW_ACTIVITY; 275 while (ictx->off < ictx->len) { 276 ch = ictx->buf[ictx->off++]; 277 ictx->state(ch, ictx); 278 } 279 280 screen_write_stop(&ictx->ctx); 281 282 buffer_remove(wp->in, ictx->len); 283} 284 285void 286input_state_first(u_char ch, struct input_ctx *ictx) 287{ 288 ictx->intermediate = '\0'; 289 290 if (INPUT_C0CONTROL(ch)) { 291 if (ch == 0x1b) 292 input_state(ictx, input_state_escape); 293 else 294 input_handle_c0_control(ch, ictx); 295 return; 296 } 297 298#if 0 299 if (INPUT_C1CONTROL(ch)) { 300 ch -= 0x40; 301 if (ch == '[') 302 input_state(ictx, input_state_sequence_first); 303 else if (ch == ']') { 304 input_start_string(ictx, STRING_SYSTEM); 305 input_state(ictx, input_state_string_next); 306 } else if (ch == '_') { 307 input_start_string(ictx, STRING_APPLICATION); 308 input_state(ictx, input_state_string_next); 309 } else 310 input_handle_c1_control(ch, ictx); 311 return; 312 } 313#endif 314 315 if (INPUT_DELETE(ch)) 316 return; 317 318 input_handle_character(ch, ictx); 319} 320 321void 322input_state_escape(u_char ch, struct input_ctx *ictx) 323{ 324 /* Treat C1 control and G1 displayable as 7-bit equivalent. */ 325 if (INPUT_C1CONTROL(ch) || INPUT_G1DISPLAYABLE(ch)) 326 ch &= 0x7f; 327 328 if (INPUT_C0CONTROL(ch)) { 329 input_handle_c0_control(ch, ictx); 330 return; 331 } 332 333 if (INPUT_INTERMEDIATE(ch)) { 334 log_debug2(":: in1 %zu: %hhu (%c)", ictx->off, ch, ch); 335 ictx->intermediate = ch; 336 input_state(ictx, input_state_intermediate); 337 return; 338 } 339 340 if (INPUT_PARAMETER(ch)) { 341 input_state(ictx, input_state_first); 342 input_handle_private_two(ch, ictx); 343 return; 344 } 345 346 if (INPUT_UPPERCASE(ch)) { 347 if (ch == '[') 348 input_state(ictx, input_state_sequence_first); 349 else if (ch == ']') { 350 input_start_string(ictx, STRING_SYSTEM); 351 input_state(ictx, input_state_string_next); 352 } else if (ch == '_') { 353 input_start_string(ictx, STRING_APPLICATION); 354 input_state(ictx, input_state_string_next); 355 } else { 356 input_state(ictx, input_state_first); 357 input_handle_c1_control(ch, ictx); 358 } 359 return; 360 } 361 362 if (INPUT_LOWERCASE(ch)) { 363 input_state(ictx, input_state_first); 364 input_handle_standard_two(ch, ictx); 365 return; 366 } 367 368 input_state(ictx, input_state_first); 369} 370 371void 372input_state_intermediate(u_char ch, struct input_ctx *ictx) 373{ 374 if (INPUT_INTERMEDIATE(ch)) { 375 /* Multiple intermediates currently ignored. */ 376 log_debug2(":: in2 %zu: %hhu (%c)", ictx->off, ch, ch); 377 return; 378 } 379 380 if (INPUT_PARAMETER(ch)) { 381 input_state(ictx, input_state_first); 382 input_handle_private_two(ch, ictx); 383 return; 384 } 385 386 if (INPUT_UPPERCASE(ch) || INPUT_LOWERCASE(ch)) { 387 input_state(ictx, input_state_first); 388 input_handle_standard_two(ch, ictx); 389 return; 390 } 391 392 input_state(ictx, input_state_first); 393} 394 395void 396input_state_sequence_first(u_char ch, struct input_ctx *ictx) 397{ 398 ictx->private = '\0'; 399 ARRAY_CLEAR(&ictx->args); 400 401 /* Most C0 control are accepted within CSI. */ 402 if (INPUT_C0CONTROL(ch)) { 403 if (ch == 0x1b) { /* ESC */ 404 /* Abort sequence and begin with new. */ 405 input_state(ictx, input_state_escape); 406 return; 407 } else if (ch == 0x18 || ch == 0x1a) { /* CAN and SUB */ 408 /* Abort sequence. */ 409 input_state(ictx, input_state_first); 410 return; 411 } 412 413 /* Handle C0 immediately. */ 414 input_handle_c0_control(ch, ictx); 415 416 /* 417 * Just come back to this state, in case the next character 418 * is the start of a private sequence. 419 */ 420 return; 421 } 422 423 input_state(ictx, input_state_sequence_next); 424 425 /* Private sequence: always the first character. */ 426 if (ch >= 0x3c && ch <= 0x3f) { 427 ictx->private = ch; 428 return; 429 } 430 431 /* Pass character on directly. */ 432 input_state_sequence_next(ch, ictx); 433} 434 435void 436input_state_sequence_next(u_char ch, struct input_ctx *ictx) 437{ 438 if (INPUT_INTERMEDIATE(ch)) { 439 if (input_add_argument(ictx, '\0') != 0) 440 input_state(ictx, input_state_first); 441 else { 442 log_debug2(":: si1 %zu: %hhu (%c)", ictx->off, ch, ch); 443 input_state(ictx, input_state_sequence_intermediate); 444 } 445 return; 446 } 447 448 if (INPUT_PARAMETER(ch)) { 449 if (ARRAY_EMPTY(&ictx->args)) 450 input_new_argument(ictx); 451 452 if (ch == ';') { 453 if (input_add_argument(ictx, '\0') != 0) 454 input_state(ictx, input_state_first); 455 else 456 input_new_argument(ictx); 457 } else if (input_add_argument(ictx, ch) != 0) 458 input_state(ictx, input_state_first); 459 return; 460 } 461 462 if (INPUT_UPPERCASE(ch) || INPUT_LOWERCASE(ch)) { 463 if (input_add_argument(ictx, '\0') != 0) 464 input_state(ictx, input_state_first); 465 else { 466 input_state(ictx, input_state_first); 467 input_handle_sequence(ch, ictx); 468 } 469 return; 470 } 471 472 /* Most C0 control are accepted within CSI. */ 473 if (INPUT_C0CONTROL(ch)) { 474 if (ch == 0x1b) { /* ESC */ 475 /* Abort sequence and begin with new. */ 476 input_state(ictx, input_state_escape); 477 return; 478 } else if (ch == 0x18 || ch == 0x1a) { /* CAN and SUB */ 479 /* Abort sequence. */ 480 input_state(ictx, input_state_first); 481 return; 482 } 483 484 /* Handle C0 immediately. */ 485 input_handle_c0_control(ch, ictx); 486 487 return; 488 } 489 490 input_state(ictx, input_state_first); 491} 492 493void 494input_state_sequence_intermediate(u_char ch, struct input_ctx *ictx) 495{ 496 if (INPUT_INTERMEDIATE(ch)) { 497 log_debug2(":: si2 %zu: %hhu (%c)", ictx->off, ch, ch); 498 return; 499 } 500 501 if (INPUT_UPPERCASE(ch) || INPUT_LOWERCASE(ch)) { 502 input_state(ictx, input_state_first); 503 input_handle_sequence(ch, ictx); 504 return; 505 } 506 507 input_state(ictx, input_state_first); 508} 509 510void 511input_state_string_next(u_char ch, struct input_ctx *ictx) 512{ 513 if (ch == 0x1b) { 514 input_state(ictx, input_state_string_escape); 515 return; 516 } 517 if (ch == 0x07) { 518 input_state_string_escape(ch, ictx); 519 return; 520 } 521 522 if (ch >= 0x20) { 523 if (input_add_string(ictx, ch) != 0) 524 input_state(ictx, input_state_first); 525 return; 526 } 527} 528 529void 530input_state_string_escape(u_char ch, struct input_ctx *ictx) 531{ 532 char *s; 533 534 if (ch == '\007' || ch == '\\') { 535 input_state(ictx, input_state_first); 536 switch (ictx->string_type) { 537 case STRING_SYSTEM: 538 if (ch != '\007') 539 return; 540 s = input_get_string(ictx); 541 if ((s[0] != '0' && s[0] != '2') || s[1] != ';') { 542 xfree(s); 543 return; 544 } 545 screen_set_title(ictx->ctx.s, s + 2); 546 server_status_window(ictx->wp->window); 547 xfree(s); 548 break; 549 case STRING_APPLICATION: 550 if (ch != '\\') 551 return; 552 s = input_get_string(ictx); 553 screen_set_title(ictx->ctx.s, s); 554 server_status_window(ictx->wp->window); 555 xfree(s); 556 break; 557 case STRING_NAME: 558 if (ch != '\\') 559 return; 560 xfree(ictx->wp->window->name); 561 ictx->wp->window->name = input_get_string(ictx); 562 server_status_window(ictx->wp->window); 563 break; 564 } 565 return; 566 } 567 568 input_state(ictx, input_state_string_next); 569 input_state_string_next(ch, ictx); 570} 571 572void 573input_state_utf8(u_char ch, struct input_ctx *ictx) 574{ 575 log_debug2("-- un %zu: %hhu (%c)", ictx->off, ch, ch); 576 577 ictx->utf8_buf[ictx->utf8_off++] = ch; 578 if (--ictx->utf8_len != 0) 579 return; 580 input_state(ictx, input_state_first); 581 582 ictx->cell.flags |= GRID_FLAG_UTF8; 583 screen_write_cell(&ictx->ctx, &ictx->cell, ictx->utf8_buf); 584 ictx->cell.flags &= ~GRID_FLAG_UTF8; 585} 586 587void 588input_handle_character(u_char ch, struct input_ctx *ictx) 589{ 590 struct window_pane *wp = ictx->wp; 591 592 if (ch > 0x7f && options_get_number(&wp->window->options, "utf8")) { 593 /* 594 * UTF-8 sequence. 595 * 596 * 11000010-11011111 C2-DF start of 2-byte sequence 597 * 11100000-11101111 E0-EF start of 3-byte sequence 598 * 11110000-11110100 F0-F4 start of 4-byte sequence 599 */ 600 memset(ictx->utf8_buf, 0xff, sizeof ictx->utf8_buf); 601 ictx->utf8_buf[0] = ch; 602 ictx->utf8_off = 1; 603 604 if (ch >= 0xc2 && ch <= 0xdf) { 605 log_debug2("-- u2 %zu: %hhu (%c)", ictx->off, ch, ch); 606 input_state(ictx, input_state_utf8); 607 ictx->utf8_len = 1; 608 return; 609 } 610 if (ch >= 0xe0 && ch <= 0xef) { 611 log_debug2("-- u3 %zu: %hhu (%c)", ictx->off, ch, ch); 612 input_state(ictx, input_state_utf8); 613 ictx->utf8_len = 2; 614 return; 615 } 616 if (ch >= 0xf0 && ch <= 0xf4) { 617 log_debug2("-- u4 %zu: %hhu (%c)", ictx->off, ch, ch); 618 input_state(ictx, input_state_utf8); 619 ictx->utf8_len = 3; 620 return; 621 } 622 } 623 log_debug2("-- ch %zu: %hhu (%c)", ictx->off, ch, ch); 624 625 ictx->cell.data = ch; 626 screen_write_cell(&ictx->ctx, &ictx->cell, ictx->utf8_buf); 627} 628 629void 630input_handle_c0_control(u_char ch, struct input_ctx *ictx) 631{ 632 struct screen *s = ictx->ctx.s; 633 634 log_debug2("-- c0 %zu: %hhu", ictx->off, ch); 635 636 switch (ch) { 637 case '\0': /* NUL */ 638 break; 639 case '\n': /* LF */ 640 screen_write_linefeed(&ictx->ctx); 641 break; 642 case '\r': /* CR */ 643 screen_write_carriagereturn(&ictx->ctx); 644 break; 645 case '\007': /* BELL */ 646 ictx->wp->window->flags |= WINDOW_BELL; 647 break; 648 case '\010': /* BS */ 649 screen_write_cursorleft(&ictx->ctx, 1); 650 break; 651 case '\011': /* TAB */ 652 /* Don't tab beyond the end of the line. */ 653 if (s->cx >= screen_size_x(s) - 1) 654 break; 655 656 /* Find the next tab point, or use the last column if none. */ 657 do { 658 s->cx++; 659 if (bit_test(s->tabs, s->cx)) 660 break; 661 } while (s->cx < screen_size_x(s) - 1); 662 break; 663 case '\013': /* VT */ 664 screen_write_linefeed(&ictx->ctx); 665 break; 666 case '\016': /* SO */ 667 ictx->cell.attr |= GRID_ATTR_CHARSET; 668 break; 669 case '\017': /* SI */ 670 ictx->cell.attr &= ~GRID_ATTR_CHARSET; 671 break; 672 default: 673 log_debug("unknown c0: %hhu", ch); 674 break; 675 } 676} 677 678void 679input_handle_c1_control(u_char ch, struct input_ctx *ictx) 680{ 681 struct screen *s = ictx->ctx.s; 682 683 log_debug2("-- c1 %zu: %hhu (%c)", ictx->off, ch, ch); 684 685 switch (ch) { 686 case 'D': /* IND */ 687 screen_write_linefeed(&ictx->ctx); 688 break; 689 case 'E': /* NEL */ 690 screen_write_carriagereturn(&ictx->ctx); 691 screen_write_linefeed(&ictx->ctx); 692 break; 693 case 'H': /* HTS */ 694 if (s->cx < screen_size_x(s)) 695 bit_set(s->tabs, s->cx); 696 break; 697 case 'M': /* RI */ 698 screen_write_reverseindex(&ictx->ctx); 699 break; 700 default: 701 log_debug("unknown c1: %hhu", ch); 702 break; 703 } 704} 705 706void 707input_handle_private_two(u_char ch, struct input_ctx *ictx) 708{ 709 struct screen *s = ictx->ctx.s; 710 711 log_debug2( 712 "-- p2 %zu: %hhu (%c) %hhu", ictx->off, ch, ch, ictx->intermediate); 713 714 switch (ch) { 715 case '0': /* SCS */ 716 /* 717 * Not really supported, but fake it up enough for those that 718 * use it to switch character sets (by redefining G0 to 719 * graphics set, rather than switching to G1). 720 */ 721 switch (ictx->intermediate) { 722 case '(': /* G0 */ 723 ictx->cell.attr |= GRID_ATTR_CHARSET; 724 break; 725 } 726 break; 727 case '=': /* DECKPAM */ 728 if (ictx->intermediate != '\0') 729 break; 730 screen_write_kkeypadmode(&ictx->ctx, 1); 731 log_debug("kkeypad on (application mode)"); 732 break; 733 case '>': /* DECKPNM */ 734 if (ictx->intermediate != '\0') 735 break; 736 screen_write_kkeypadmode(&ictx->ctx, 0); 737 log_debug("kkeypad off (number mode)"); 738 break; 739 case '7': /* DECSC */ 740 if (ictx->intermediate != '\0') 741 break; 742 memcpy(&ictx->saved_cell, &ictx->cell, sizeof ictx->saved_cell); 743 ictx->saved_cx = s->cx; 744 ictx->saved_cy = s->cy; 745 break; 746 case '8': 747 switch (ictx->intermediate) { 748 case '\0': /* DECRC */ 749 memcpy( 750 &ictx->cell, &ictx->saved_cell, sizeof ictx->cell); 751 screen_write_cursormove( 752 &ictx->ctx, ictx->saved_cx, ictx->saved_cy); 753 break; 754 case '#': /* DECALN */ 755 screen_write_alignmenttest(&ictx->ctx); 756 break; 757 } 758 break; 759 default: 760 log_debug("unknown p2: %hhu", ch); 761 break; 762 } 763} 764 765void 766input_handle_standard_two(u_char ch, struct input_ctx *ictx) 767{ 768 log_debug2( 769 "-- s2 %zu: %hhu (%c) %hhu", ictx->off, ch, ch, ictx->intermediate); 770 771 switch (ch) { 772 case 'B': /* SCS */ 773 /* 774 * Not really supported, but fake it up enough for those that 775 * use it to switch character sets (by redefining G0 to 776 * graphics set, rather than switching to G1). 777 */ 778 switch (ictx->intermediate) { 779 case '(': /* G0 */ 780 ictx->cell.attr &= ~GRID_ATTR_CHARSET; 781 break; 782 } 783 break; 784 case 'c': /* RIS */ 785 memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell); 786 787 memcpy(&ictx->saved_cell, &ictx->cell, sizeof ictx->saved_cell); 788 ictx->saved_cx = 0; 789 ictx->saved_cy = 0; 790 791 screen_reset_tabs(ictx->ctx.s); 792 793 screen_write_scrollregion( 794 &ictx->ctx, 0, screen_size_y(ictx->ctx.s) - 1); 795 796 screen_write_insertmode(&ictx->ctx, 0); 797 screen_write_kcursormode(&ictx->ctx, 0); 798 screen_write_kkeypadmode(&ictx->ctx, 0); 799 screen_write_mousemode(&ictx->ctx, 0); 800 801 screen_write_clearscreen(&ictx->ctx); 802 screen_write_cursormove(&ictx->ctx, 0, 0); 803 break; 804 case 'k': 805 input_start_string(ictx, STRING_NAME); 806 input_state(ictx, input_state_string_next); 807 break; 808 default: 809 log_debug("unknown s2: %hhu", ch); 810 break; 811 } 812} 813 814void 815input_handle_sequence(u_char ch, struct input_ctx *ictx) 816{ 817 struct input_sequence_entry *entry, find; 818 struct screen *s = ictx->ctx.s; 819 u_int i; 820 struct input_arg *iarg; 821 822 log_debug2("-- sq %zu: %hhu (%c): %u [sx=%u, sy=%u, cx=%u, cy=%u, " 823 "ru=%u, rl=%u]", ictx->off, ch, ch, ARRAY_LENGTH(&ictx->args), 824 screen_size_x(s), screen_size_y(s), s->cx, s->cy, s->rupper, 825 s->rlower); 826 for (i = 0; i < ARRAY_LENGTH(&ictx->args); i++) { 827 iarg = &ARRAY_ITEM(&ictx->args, i); 828 if (*iarg->data != '\0') 829 log_debug2(" ++ %u: %s", i, iarg->data); 830 } 831 832 find.ch = ch; 833 entry = bsearch(&find, 834 input_sequence_table, nitems(input_sequence_table), 835 sizeof input_sequence_table[0], input_sequence_cmp); 836 if (entry != NULL) 837 entry->fn(ictx); 838 else 839 log_debug("unknown sq: %c (%hhu %hhu)", ch, ch, ictx->private); 840} 841 842void 843input_handle_sequence_cuu(struct input_ctx *ictx) 844{ 845 uint16_t n; 846 847 if (ictx->private != '\0') 848 return; 849 850 if (ARRAY_LENGTH(&ictx->args) > 1) 851 return; 852 if (input_get_argument(ictx, 0, &n, 1) != 0) 853 return; 854 if (n == 0) 855 n = 1; 856 857 screen_write_cursorup(&ictx->ctx, n); 858} 859 860void 861input_handle_sequence_cud(struct input_ctx *ictx) 862{ 863 uint16_t n; 864 865 if (ictx->private != '\0') 866 return; 867 868 if (ARRAY_LENGTH(&ictx->args) > 1) 869 return; 870 if (input_get_argument(ictx, 0, &n, 1) != 0) 871 return; 872 if (n == 0) 873 n = 1; 874 875 screen_write_cursordown(&ictx->ctx, n); 876} 877 878void 879input_handle_sequence_cuf(struct input_ctx *ictx) 880{ 881 uint16_t n; 882 883 if (ictx->private != '\0') 884 return; 885 886 if (ARRAY_LENGTH(&ictx->args) > 1) 887 return; 888 if (input_get_argument(ictx, 0, &n, 1) != 0) 889 return; 890 if (n == 0) 891 n = 1; 892 893 screen_write_cursorright(&ictx->ctx, n); 894} 895 896void 897input_handle_sequence_cub(struct input_ctx *ictx) 898{ 899 uint16_t n; 900 901 if (ictx->private != '\0') 902 return; 903 904 if (ARRAY_LENGTH(&ictx->args) > 1) 905 return; 906 if (input_get_argument(ictx, 0, &n, 1) != 0) 907 return; 908 if (n == 0) 909 n = 1; 910 911 screen_write_cursorleft(&ictx->ctx, n); 912} 913 914void 915input_handle_sequence_dch(struct input_ctx *ictx) 916{ 917 uint16_t n; 918 919 if (ictx->private != '\0') 920 return; 921 922 if (ARRAY_LENGTH(&ictx->args) > 1) 923 return; 924 if (input_get_argument(ictx, 0, &n, 1) != 0) 925 return; 926 if (n == 0) 927 n = 1; 928 929 screen_write_deletecharacter(&ictx->ctx, n); 930} 931 932void 933input_handle_sequence_cbt(struct input_ctx *ictx) 934{ 935 struct screen *s = ictx->ctx.s; 936 uint16_t n; 937 938 if (ictx->private != '\0') 939 return; 940 941 if (ARRAY_LENGTH(&ictx->args) > 1) 942 return; 943 if (input_get_argument(ictx, 0, &n, 1) != 0) 944 return; 945 if (n == 0) 946 n = 1; 947 948 /* Find the previous tab point, n times. */ 949 while (s->cx > 0 && n-- > 0) { 950 do 951 s->cx--; 952 while (s->cx > 0 && !bit_test(s->tabs, s->cx)); 953 } 954} 955 956void 957input_handle_sequence_dl(struct input_ctx *ictx) 958{ 959 uint16_t n; 960 961 if (ictx->private != '\0') 962 return; 963 964 if (ARRAY_LENGTH(&ictx->args) > 1) 965 return; 966 if (input_get_argument(ictx, 0, &n, 1) != 0) 967 return; 968 if (n == 0) 969 n = 1; 970 971 screen_write_deleteline(&ictx->ctx, n); 972} 973 974void 975input_handle_sequence_ich(struct input_ctx *ictx) 976{ 977 uint16_t n; 978 979 if (ictx->private != '\0') 980 return; 981 982 if (ARRAY_LENGTH(&ictx->args) > 1) 983 return; 984 if (input_get_argument(ictx, 0, &n, 1) != 0) 985 return; 986 if (n == 0) 987 n = 1; 988 989 screen_write_insertcharacter(&ictx->ctx, n); 990} 991 992void 993input_handle_sequence_il(struct input_ctx *ictx) 994{ 995 uint16_t n; 996 997 if (ictx->private != '\0') 998 return; 999 1000 if (ARRAY_LENGTH(&ictx->args) > 1) 1001 return; 1002 if (input_get_argument(ictx, 0, &n, 1) != 0) 1003 return; 1004 if (n == 0) 1005 n = 1; 1006 1007 screen_write_insertline(&ictx->ctx, n); 1008} 1009 1010void 1011input_handle_sequence_vpa(struct input_ctx *ictx) 1012{ 1013 struct screen *s = ictx->ctx.s; 1014 uint16_t n; 1015 1016 if (ictx->private != '\0') 1017 return; 1018 1019 if (ARRAY_LENGTH(&ictx->args) > 1) 1020 return; 1021 if (input_get_argument(ictx, 0, &n, 1) != 0) 1022 return; 1023 if (n == 0) 1024 n = 1; 1025 1026 screen_write_cursormove(&ictx->ctx, s->cx, n - 1); 1027} 1028 1029void 1030input_handle_sequence_hpa(struct input_ctx *ictx) 1031{ 1032 struct screen *s = ictx->ctx.s; 1033 uint16_t n; 1034 1035 if (ictx->private != '\0') 1036 return; 1037 1038 if (ARRAY_LENGTH(&ictx->args) > 1) 1039 return; 1040 if (input_get_argument(ictx, 0, &n, 1) != 0) 1041 return; 1042 if (n == 0) 1043 n = 1; 1044 1045 screen_write_cursormove(&ictx->ctx, n - 1, s->cy); 1046} 1047 1048void 1049input_handle_sequence_cup(struct input_ctx *ictx) 1050{ 1051 uint16_t n, m; 1052 1053 if (ictx->private != '\0') 1054 return; 1055 1056 if (ARRAY_LENGTH(&ictx->args) > 2) 1057 return; 1058 if (input_get_argument(ictx, 0, &n, 1) != 0) 1059 return; 1060 if (input_get_argument(ictx, 1, &m, 1) != 0) 1061 return; 1062 if (n == 0) 1063 n = 1; 1064 if (m == 0) 1065 m = 1; 1066 1067 screen_write_cursormove(&ictx->ctx, m - 1, n - 1); 1068} 1069 1070void 1071input_handle_sequence_tbc(struct input_ctx *ictx) 1072{ 1073 struct screen *s = ictx->ctx.s; 1074 uint16_t n; 1075 1076 if (ictx->private != '\0') 1077 return; 1078 1079 if (ARRAY_LENGTH(&ictx->args) > 1) 1080 return; 1081 if (input_get_argument(ictx, 0, &n, 1) != 0) 1082 return; 1083 1084 switch (n) { 1085 case 0: 1086 if (s->cx < screen_size_x(s)) 1087 bit_clear(s->tabs, s->cx); 1088 break; 1089 case 3: 1090 bit_nclear(s->tabs, 0, screen_size_x(s) - 1); 1091 break; 1092 } 1093} 1094 1095void 1096input_handle_sequence_ed(struct input_ctx *ictx) 1097{ 1098 uint16_t n; 1099 1100 if (ictx->private != '\0') 1101 return; 1102 1103 if (ARRAY_LENGTH(&ictx->args) > 1) 1104 return; 1105 if (input_get_argument(ictx, 0, &n, 0) != 0) 1106 return; 1107 if (n > 2) 1108 return; 1109 1110 switch (n) { 1111 case 0: 1112 screen_write_clearendofscreen(&ictx->ctx); 1113 break; 1114 case 1: 1115 screen_write_clearstartofscreen(&ictx->ctx); 1116 break; 1117 case 2: 1118 screen_write_clearscreen(&ictx->ctx); 1119 break; 1120 } 1121} 1122 1123void 1124input_handle_sequence_el(struct input_ctx *ictx) 1125{ 1126 uint16_t n; 1127 1128 if (ictx->private != '\0') 1129 return; 1130 1131 if (ARRAY_LENGTH(&ictx->args) > 1) 1132 return; 1133 if (input_get_argument(ictx, 0, &n, 0) != 0) 1134 return; 1135 if (n > 2) 1136 return; 1137 1138 switch (n) { 1139 case 0: 1140 screen_write_clearendofline(&ictx->ctx); 1141 break; 1142 case 1: 1143 screen_write_clearstartofline(&ictx->ctx); 1144 break; 1145 case 2: 1146 screen_write_clearline(&ictx->ctx); 1147 break; 1148 } 1149} 1150 1151void 1152input_handle_sequence_sm(struct input_ctx *ictx) 1153{ 1154 uint16_t n; 1155 1156 if (ARRAY_LENGTH(&ictx->args) > 1) 1157 return; 1158 if (input_get_argument(ictx, 0, &n, 0) != 0) 1159 return; 1160 1161 if (ictx->private == '?') { 1162 switch (n) { 1163 case 1: /* GATM */ 1164 screen_write_kcursormode(&ictx->ctx, 1); 1165 log_debug("kcursor on"); 1166 break; 1167 case 25: /* TCEM */ 1168 screen_write_cursormode(&ictx->ctx, 1); 1169 log_debug("cursor on"); 1170 break; 1171 case 1000: 1172 screen_write_mousemode(&ictx->ctx, 1); 1173 log_debug("mouse on"); 1174 break; 1175 default: 1176 log_debug("unknown SM [%hhu]: %u", ictx->private, n); 1177 break; 1178 } 1179 } else { 1180 switch (n) { 1181 case 4: /* IRM */ 1182 screen_write_insertmode(&ictx->ctx, 1); 1183 log_debug("insert on"); 1184 break; 1185 case 34: 1186 /* Cursor high visibility not supported. */ 1187 break; 1188 default: 1189 log_debug("unknown SM [%hhu]: %u", ictx->private, n); 1190 break; 1191 } 1192 } 1193} 1194 1195void 1196input_handle_sequence_rm(struct input_ctx *ictx) 1197{ 1198 uint16_t n; 1199 1200 if (ARRAY_LENGTH(&ictx->args) > 1) 1201 return; 1202 if (input_get_argument(ictx, 0, &n, 0) != 0) 1203 return; 1204 1205 if (ictx->private == '?') { 1206 switch (n) { 1207 case 1: /* GATM */ 1208 screen_write_kcursormode(&ictx->ctx, 0); 1209 log_debug("kcursor off"); 1210 break; 1211 case 25: /* TCEM */ 1212 screen_write_cursormode(&ictx->ctx, 0); 1213 log_debug("cursor off"); 1214 break; 1215 case 1000: 1216 screen_write_mousemode(&ictx->ctx, 0); 1217 log_debug("mouse off"); 1218 break; 1219 default: 1220 log_debug("unknown RM [%hhu]: %u", ictx->private, n); 1221 break; 1222 } 1223 } else if (ictx->private == '\0') { 1224 switch (n) { 1225 case 4: /* IRM */ 1226 screen_write_insertmode(&ictx->ctx, 0); 1227 log_debug("insert off"); 1228 break; 1229 case 34: 1230 /* Cursor high visibility not supported. */ 1231 break; 1232 default: 1233 log_debug("unknown RM [%hhu]: %u", ictx->private, n); 1234 break; 1235 } 1236 } 1237} 1238 1239void 1240input_handle_sequence_dsr(struct input_ctx *ictx) 1241{ 1242 struct screen *s = ictx->ctx.s; 1243 uint16_t n; 1244 char reply[32]; 1245 1246 if (ARRAY_LENGTH(&ictx->args) > 1) 1247 return; 1248 if (input_get_argument(ictx, 0, &n, 0) != 0) 1249 return; 1250 1251 if (ictx->private == '\0') { 1252 switch (n) { 1253 case 6: /* cursor position */ 1254 xsnprintf(reply, sizeof reply, 1255 "\033[%u;%uR", s->cy + 1, s->cx + 1); 1256 log_debug("cursor request, reply: %s", reply); 1257 buffer_write(ictx->wp->out, reply, strlen(reply)); 1258 break; 1259 } 1260 } 1261 1262} 1263 1264void 1265input_handle_sequence_decstbm(struct input_ctx *ictx) 1266{ 1267 struct screen *s = ictx->ctx.s; 1268 uint16_t n, m; 1269 1270 if (ictx->private != '\0') 1271 return; 1272 1273 if (ARRAY_LENGTH(&ictx->args) > 2) 1274 return; 1275 if (input_get_argument(ictx, 0, &n, 0) != 0) 1276 return; 1277 if (input_get_argument(ictx, 1, &m, 0) != 0) 1278 return; 1279 if (n == 0) 1280 n = 1; 1281 if (m == 0) 1282 m = screen_size_y(s); 1283 1284 screen_write_scrollregion(&ictx->ctx, n - 1, m - 1); 1285} 1286 1287void 1288input_handle_sequence_sgr(struct input_ctx *ictx) 1289{ 1290 struct grid_cell *gc = &ictx->cell; 1291 u_int i; 1292 uint16_t m, o; 1293 u_char attr; 1294 1295 if (ARRAY_LENGTH(&ictx->args) == 0) { 1296 attr = gc->attr; 1297 memcpy(gc, &grid_default_cell, sizeof *gc); 1298 gc->attr |= (attr & GRID_ATTR_CHARSET); 1299 return; 1300 } 1301 1302 for (i = 0; i < ARRAY_LENGTH(&ictx->args); i++) { 1303 if (input_get_argument(ictx, i, &m, 0) != 0) 1304 return; 1305 1306 if (m == 38 || m == 48) { 1307 i++; 1308 if (input_get_argument(ictx, i, &o, 0) != 0) 1309 return; 1310 if (o != 5) 1311 continue; 1312 1313 i++; 1314 if (input_get_argument(ictx, i, &o, 0) != 0) 1315 return; 1316 if (m == 38) { 1317 gc->flags |= GRID_FLAG_FG256; 1318 gc->fg = o; 1319 } else if (m == 48) { 1320 gc->flags |= GRID_FLAG_BG256; 1321 gc->bg = o; 1322 } 1323 continue; 1324 } 1325 1326 switch (m) { 1327 case 0: 1328 case 10: 1329 attr = gc->attr; 1330 memcpy(gc, &grid_default_cell, sizeof *gc); 1331 gc->attr |= (attr & GRID_ATTR_CHARSET); 1332 break; 1333 case 1: 1334 gc->attr |= GRID_ATTR_BRIGHT; 1335 break; 1336 case 2: 1337 gc->attr |= GRID_ATTR_DIM; 1338 break; 1339 case 3: 1340 gc->attr |= GRID_ATTR_ITALICS; 1341 break; 1342 case 4: 1343 gc->attr |= GRID_ATTR_UNDERSCORE; 1344 break; 1345 case 5: 1346 gc->attr |= GRID_ATTR_BLINK; 1347 break; 1348 case 7: 1349 gc->attr |= GRID_ATTR_REVERSE; 1350 break; 1351 case 8: 1352 gc->attr |= GRID_ATTR_HIDDEN; 1353 break; 1354 case 22: 1355 gc->attr &= ~(GRID_ATTR_BRIGHT|GRID_ATTR_DIM); 1356 break; 1357 case 23: 1358 gc->attr &= ~GRID_ATTR_ITALICS; 1359 break; 1360 case 24: 1361 gc->attr &= ~GRID_ATTR_UNDERSCORE; 1362 break; 1363 case 25: 1364 gc->attr &= ~GRID_ATTR_BLINK; 1365 break; 1366 case 27: 1367 gc->attr &= ~GRID_ATTR_REVERSE; 1368 break; 1369 case 30: 1370 case 31: 1371 case 32: 1372 case 33: 1373 case 34: 1374 case 35: 1375 case 36: 1376 case 37: 1377 gc->flags &= ~GRID_FLAG_FG256; 1378 gc->fg = m - 30; 1379 break; 1380 case 39: 1381 gc->flags &= ~GRID_FLAG_FG256; 1382 gc->fg = 8; 1383 break; 1384 case 40: 1385 case 41: 1386 case 42: 1387 case 43: 1388 case 44: 1389 case 45: 1390 case 46: 1391 case 47: 1392 gc->flags &= ~GRID_FLAG_BG256; 1393 gc->bg = m - 40; 1394 break; 1395 case 49: 1396 gc->flags &= ~GRID_FLAG_BG256; 1397 gc->bg = 8; 1398 break; 1399 } 1400 } 1401} 1402