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