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