input.c revision 1.57
1/* $OpenBSD: input.c,v 1.57 2013/01/17 20:30:43 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 <stdlib.h> 22#include <string.h> 23 24#include "tmux.h" 25 26/* 27 * Based on the description by Paul Williams at: 28 * 29 * http://vt100.net/emu/dec_ansi_parser 30 * 31 * With the following changes: 32 * 33 * - 7-bit only. 34 * 35 * - Support for UTF-8. 36 * 37 * - OSC (but not APC) may be terminated by \007 as well as ST. 38 * 39 * - A state for APC similar to OSC. Some terminals appear to use this to set 40 * the title. 41 * 42 * - A state for the screen \033k...\033\\ sequence to rename a window. This is 43 * pretty stupid but not supporting it is more trouble than it is worth. 44 * 45 * - Special handling for ESC inside a DCS to allow arbitrary byte sequences to 46 * be passed to the underlying teminal(s). 47 */ 48 49/* Helper functions. */ 50struct input_transition; 51int input_split(struct input_ctx *); 52int input_get(struct input_ctx *, u_int, int, int); 53void input_reply(struct input_ctx *, const char *, ...); 54void input_set_state(struct window_pane *, const struct input_transition *); 55 56/* Transition entry/exit handlers. */ 57void input_clear(struct input_ctx *); 58void input_enter_osc(struct input_ctx *); 59void input_exit_osc(struct input_ctx *); 60void input_enter_apc(struct input_ctx *); 61void input_exit_apc(struct input_ctx *); 62void input_enter_rename(struct input_ctx *); 63void input_exit_rename(struct input_ctx *); 64 65/* Input state handlers. */ 66int input_print(struct input_ctx *); 67int input_intermediate(struct input_ctx *); 68int input_parameter(struct input_ctx *); 69int input_input(struct input_ctx *); 70int input_c0_dispatch(struct input_ctx *); 71int input_esc_dispatch(struct input_ctx *); 72int input_csi_dispatch(struct input_ctx *); 73void input_csi_dispatch_sgr(struct input_ctx *); 74int input_dcs_dispatch(struct input_ctx *); 75int input_utf8_open(struct input_ctx *); 76int input_utf8_add(struct input_ctx *); 77int input_utf8_close(struct input_ctx *); 78 79/* Command table comparison function. */ 80int input_table_compare(const void *, const void *); 81 82/* Command table entry. */ 83struct input_table_entry { 84 int ch; 85 const char *interm; 86 int type; 87}; 88 89/* Escape commands. */ 90enum input_esc_type { 91 INPUT_ESC_DECALN, 92 INPUT_ESC_DECKPAM, 93 INPUT_ESC_DECKPNM, 94 INPUT_ESC_DECRC, 95 INPUT_ESC_DECSC, 96 INPUT_ESC_HTS, 97 INPUT_ESC_IND, 98 INPUT_ESC_NEL, 99 INPUT_ESC_RI, 100 INPUT_ESC_RIS, 101 INPUT_ESC_SCSOFF_G0, 102 INPUT_ESC_SCSON_G0, 103}; 104 105/* Escape command table. */ 106const struct input_table_entry input_esc_table[] = { 107 { '0', "(", INPUT_ESC_SCSOFF_G0 }, 108 { '7', "", INPUT_ESC_DECSC }, 109 { '8', "", INPUT_ESC_DECRC }, 110 { '8', "#", INPUT_ESC_DECALN }, 111 { '=', "", INPUT_ESC_DECKPAM }, 112 { '>', "", INPUT_ESC_DECKPNM }, 113 { 'B', "(", INPUT_ESC_SCSON_G0 }, 114 { 'D', "", INPUT_ESC_IND }, 115 { 'E', "", INPUT_ESC_NEL }, 116 { 'H', "", INPUT_ESC_HTS }, 117 { 'M', "", INPUT_ESC_RI }, 118 { 'c', "", INPUT_ESC_RIS }, 119}; 120 121/* Control (CSI) commands. */ 122enum input_csi_type { 123 INPUT_CSI_CBT, 124 INPUT_CSI_CNL, 125 INPUT_CSI_CPL, 126 INPUT_CSI_CUB, 127 INPUT_CSI_CUD, 128 INPUT_CSI_CUF, 129 INPUT_CSI_CUP, 130 INPUT_CSI_CUU, 131 INPUT_CSI_DA, 132 INPUT_CSI_DA_TWO, 133 INPUT_CSI_DCH, 134 INPUT_CSI_DECSCUSR, 135 INPUT_CSI_DECSTBM, 136 INPUT_CSI_DL, 137 INPUT_CSI_DSR, 138 INPUT_CSI_ECH, 139 INPUT_CSI_ED, 140 INPUT_CSI_EL, 141 INPUT_CSI_HPA, 142 INPUT_CSI_ICH, 143 INPUT_CSI_IL, 144 INPUT_CSI_RCP, 145 INPUT_CSI_RM, 146 INPUT_CSI_RM_PRIVATE, 147 INPUT_CSI_SCP, 148 INPUT_CSI_SGR, 149 INPUT_CSI_SM, 150 INPUT_CSI_SM_PRIVATE, 151 INPUT_CSI_TBC, 152 INPUT_CSI_VPA, 153}; 154 155/* Control (CSI) command table. */ 156const struct input_table_entry input_csi_table[] = { 157 { '@', "", INPUT_CSI_ICH }, 158 { 'A', "", INPUT_CSI_CUU }, 159 { 'B', "", INPUT_CSI_CUD }, 160 { 'C', "", INPUT_CSI_CUF }, 161 { 'D', "", INPUT_CSI_CUB }, 162 { 'E', "", INPUT_CSI_CNL }, 163 { 'F', "", INPUT_CSI_CPL }, 164 { 'G', "", INPUT_CSI_HPA }, 165 { 'H', "", INPUT_CSI_CUP }, 166 { 'J', "", INPUT_CSI_ED }, 167 { 'K', "", INPUT_CSI_EL }, 168 { 'L', "", INPUT_CSI_IL }, 169 { 'M', "", INPUT_CSI_DL }, 170 { 'P', "", INPUT_CSI_DCH }, 171 { 'X', "", INPUT_CSI_ECH }, 172 { 'Z', "", INPUT_CSI_CBT }, 173 { 'c', "", INPUT_CSI_DA }, 174 { 'c', ">", INPUT_CSI_DA_TWO }, 175 { 'd', "", INPUT_CSI_VPA }, 176 { 'f', "", INPUT_CSI_CUP }, 177 { 'g', "", INPUT_CSI_TBC }, 178 { 'h', "", INPUT_CSI_SM }, 179 { 'h', "?", INPUT_CSI_SM_PRIVATE }, 180 { 'l', "", INPUT_CSI_RM }, 181 { 'l', "?", INPUT_CSI_RM_PRIVATE }, 182 { 'm', "", INPUT_CSI_SGR }, 183 { 'n', "", INPUT_CSI_DSR }, 184 { 'q', " ", INPUT_CSI_DECSCUSR }, 185 { 'r', "", INPUT_CSI_DECSTBM }, 186 { 's', "", INPUT_CSI_SCP }, 187 { 'u', "", INPUT_CSI_RCP }, 188}; 189 190/* Input transition. */ 191struct input_transition { 192 int first; 193 int last; 194 195 int (*handler)(struct input_ctx *); 196 const struct input_state *state; 197}; 198 199/* Input state. */ 200struct input_state { 201 const char *name; 202 void (*enter)(struct input_ctx *); 203 void (*exit)(struct input_ctx *); 204 const struct input_transition *transitions; 205}; 206 207/* State transitions available from all states. */ 208#define INPUT_STATE_ANYWHERE \ 209 { 0x18, 0x18, input_c0_dispatch, &input_state_ground }, \ 210 { 0x1a, 0x1a, input_c0_dispatch, &input_state_ground }, \ 211 { 0x1b, 0x1b, NULL, &input_state_esc_enter } 212 213/* Forward declarations of state tables. */ 214const struct input_transition input_state_ground_table[]; 215const struct input_transition input_state_esc_enter_table[]; 216const struct input_transition input_state_esc_intermediate_table[]; 217const struct input_transition input_state_csi_enter_table[]; 218const struct input_transition input_state_csi_parameter_table[]; 219const struct input_transition input_state_csi_intermediate_table[]; 220const struct input_transition input_state_csi_ignore_table[]; 221const struct input_transition input_state_dcs_enter_table[]; 222const struct input_transition input_state_dcs_parameter_table[]; 223const struct input_transition input_state_dcs_intermediate_table[]; 224const struct input_transition input_state_dcs_handler_table[]; 225const struct input_transition input_state_dcs_escape_table[]; 226const struct input_transition input_state_dcs_ignore_table[]; 227const struct input_transition input_state_osc_string_table[]; 228const struct input_transition input_state_apc_string_table[]; 229const struct input_transition input_state_rename_string_table[]; 230const struct input_transition input_state_consume_st_table[]; 231const struct input_transition input_state_utf8_three_table[]; 232const struct input_transition input_state_utf8_two_table[]; 233const struct input_transition input_state_utf8_one_table[]; 234 235/* ground state definition. */ 236const struct input_state input_state_ground = { 237 "ground", 238 NULL, NULL, 239 input_state_ground_table 240}; 241 242/* esc_enter state definition. */ 243const struct input_state input_state_esc_enter = { 244 "esc_enter", 245 input_clear, NULL, 246 input_state_esc_enter_table 247}; 248 249/* esc_intermediate state definition. */ 250const struct input_state input_state_esc_intermediate = { 251 "esc_intermediate", 252 NULL, NULL, 253 input_state_esc_intermediate_table 254}; 255 256/* csi_enter state definition. */ 257const struct input_state input_state_csi_enter = { 258 "csi_enter", 259 input_clear, NULL, 260 input_state_csi_enter_table 261}; 262 263/* csi_parameter state definition. */ 264const struct input_state input_state_csi_parameter = { 265 "csi_parameter", 266 NULL, NULL, 267 input_state_csi_parameter_table 268}; 269 270/* csi_intermediate state definition. */ 271const struct input_state input_state_csi_intermediate = { 272 "csi_intermediate", 273 NULL, NULL, 274 input_state_csi_intermediate_table 275}; 276 277/* csi_ignore state definition. */ 278const struct input_state input_state_csi_ignore = { 279 "csi_ignore", 280 NULL, NULL, 281 input_state_csi_ignore_table 282}; 283 284/* dcs_enter state definition. */ 285const struct input_state input_state_dcs_enter = { 286 "dcs_enter", 287 input_clear, NULL, 288 input_state_dcs_enter_table 289}; 290 291/* dcs_parameter state definition. */ 292const struct input_state input_state_dcs_parameter = { 293 "dcs_parameter", 294 NULL, NULL, 295 input_state_dcs_parameter_table 296}; 297 298/* dcs_intermediate state definition. */ 299const struct input_state input_state_dcs_intermediate = { 300 "dcs_intermediate", 301 NULL, NULL, 302 input_state_dcs_intermediate_table 303}; 304 305/* dcs_handler state definition. */ 306const struct input_state input_state_dcs_handler = { 307 "dcs_handler", 308 NULL, NULL, 309 input_state_dcs_handler_table 310}; 311 312/* dcs_escape state definition. */ 313const struct input_state input_state_dcs_escape = { 314 "dcs_escape", 315 NULL, NULL, 316 input_state_dcs_escape_table 317}; 318 319/* dcs_ignore state definition. */ 320const struct input_state input_state_dcs_ignore = { 321 "dcs_ignore", 322 NULL, NULL, 323 input_state_dcs_ignore_table 324}; 325 326/* osc_string state definition. */ 327const struct input_state input_state_osc_string = { 328 "osc_string", 329 input_enter_osc, input_exit_osc, 330 input_state_osc_string_table 331}; 332 333/* apc_string state definition. */ 334const struct input_state input_state_apc_string = { 335 "apc_string", 336 input_enter_apc, input_exit_apc, 337 input_state_apc_string_table 338}; 339 340/* rename_string state definition. */ 341const struct input_state input_state_rename_string = { 342 "rename_string", 343 input_enter_rename, input_exit_rename, 344 input_state_rename_string_table 345}; 346 347/* consume_st state definition. */ 348const struct input_state input_state_consume_st = { 349 "consume_st", 350 NULL, NULL, 351 input_state_consume_st_table 352}; 353 354/* utf8_three state definition. */ 355const struct input_state input_state_utf8_three = { 356 "utf8_three", 357 NULL, NULL, 358 input_state_utf8_three_table 359}; 360 361/* utf8_two state definition. */ 362const struct input_state input_state_utf8_two = { 363 "utf8_two", 364 NULL, NULL, 365 input_state_utf8_two_table 366}; 367 368/* utf8_one state definition. */ 369const struct input_state input_state_utf8_one = { 370 "utf8_one", 371 NULL, NULL, 372 input_state_utf8_one_table 373}; 374 375/* ground state table. */ 376const struct input_transition input_state_ground_table[] = { 377 INPUT_STATE_ANYWHERE, 378 379 { 0x00, 0x17, input_c0_dispatch, NULL }, 380 { 0x19, 0x19, input_c0_dispatch, NULL }, 381 { 0x1c, 0x1f, input_c0_dispatch, NULL }, 382 { 0x20, 0x7e, input_print, NULL }, 383 { 0x7f, 0x7f, NULL, NULL }, 384 { 0x80, 0xc1, input_print, NULL }, 385 { 0xc2, 0xdf, input_utf8_open, &input_state_utf8_one }, 386 { 0xe0, 0xef, input_utf8_open, &input_state_utf8_two }, 387 { 0xf0, 0xf4, input_utf8_open, &input_state_utf8_three }, 388 { 0xf5, 0xff, input_print, NULL }, 389 390 { -1, -1, NULL, NULL } 391}; 392 393/* esc_enter state table. */ 394const struct input_transition input_state_esc_enter_table[] = { 395 INPUT_STATE_ANYWHERE, 396 397 { 0x00, 0x17, input_c0_dispatch, NULL }, 398 { 0x19, 0x19, input_c0_dispatch, NULL }, 399 { 0x1c, 0x1f, input_c0_dispatch, NULL }, 400 { 0x20, 0x2f, input_intermediate, &input_state_esc_intermediate }, 401 { 0x30, 0x4f, input_esc_dispatch, &input_state_ground }, 402 { 0x50, 0x50, NULL, &input_state_dcs_enter }, 403 { 0x51, 0x57, input_esc_dispatch, &input_state_ground }, 404 { 0x58, 0x58, NULL, &input_state_consume_st }, 405 { 0x59, 0x59, input_esc_dispatch, &input_state_ground }, 406 { 0x5a, 0x5a, input_esc_dispatch, &input_state_ground }, 407 { 0x5b, 0x5b, NULL, &input_state_csi_enter }, 408 { 0x5c, 0x5c, input_esc_dispatch, &input_state_ground }, 409 { 0x5d, 0x5d, NULL, &input_state_osc_string }, 410 { 0x5e, 0x5e, NULL, &input_state_consume_st }, 411 { 0x5f, 0x5f, NULL, &input_state_apc_string }, 412 { 0x60, 0x6a, input_esc_dispatch, &input_state_ground }, 413 { 0x6b, 0x6b, NULL, &input_state_rename_string }, 414 { 0x6c, 0x7e, input_esc_dispatch, &input_state_ground }, 415 { 0x7f, 0xff, NULL, NULL }, 416 417 { -1, -1, NULL, NULL } 418}; 419 420/* esc_interm state table. */ 421const struct input_transition input_state_esc_intermediate_table[] = { 422 INPUT_STATE_ANYWHERE, 423 424 { 0x00, 0x17, input_c0_dispatch, NULL }, 425 { 0x19, 0x19, input_c0_dispatch, NULL }, 426 { 0x1c, 0x1f, input_c0_dispatch, NULL }, 427 { 0x20, 0x2f, input_intermediate, NULL }, 428 { 0x30, 0x7e, input_esc_dispatch, &input_state_ground }, 429 { 0x7f, 0xff, NULL, NULL }, 430 431 { -1, -1, NULL, NULL } 432}; 433 434/* csi_enter state table. */ 435const struct input_transition input_state_csi_enter_table[] = { 436 INPUT_STATE_ANYWHERE, 437 438 { 0x00, 0x17, input_c0_dispatch, NULL }, 439 { 0x19, 0x19, input_c0_dispatch, NULL }, 440 { 0x1c, 0x1f, input_c0_dispatch, NULL }, 441 { 0x20, 0x2f, input_intermediate, &input_state_csi_intermediate }, 442 { 0x30, 0x39, input_parameter, &input_state_csi_parameter }, 443 { 0x3a, 0x3a, NULL, &input_state_csi_ignore }, 444 { 0x3b, 0x3b, input_parameter, &input_state_csi_parameter }, 445 { 0x3c, 0x3f, input_intermediate, &input_state_csi_parameter }, 446 { 0x40, 0x7e, input_csi_dispatch, &input_state_ground }, 447 { 0x7f, 0xff, NULL, NULL }, 448 449 { -1, -1, NULL, NULL } 450}; 451 452/* csi_parameter state table. */ 453const struct input_transition input_state_csi_parameter_table[] = { 454 INPUT_STATE_ANYWHERE, 455 456 { 0x00, 0x17, input_c0_dispatch, NULL }, 457 { 0x19, 0x19, input_c0_dispatch, NULL }, 458 { 0x1c, 0x1f, input_c0_dispatch, NULL }, 459 { 0x20, 0x2f, input_intermediate, &input_state_csi_intermediate }, 460 { 0x30, 0x39, input_parameter, NULL }, 461 { 0x3a, 0x3a, NULL, &input_state_csi_ignore }, 462 { 0x3b, 0x3b, input_parameter, NULL }, 463 { 0x3c, 0x3f, NULL, &input_state_csi_ignore }, 464 { 0x40, 0x7e, input_csi_dispatch, &input_state_ground }, 465 { 0x7f, 0xff, NULL, NULL }, 466 467 { -1, -1, NULL, NULL } 468}; 469 470/* csi_intermediate state table. */ 471const struct input_transition input_state_csi_intermediate_table[] = { 472 INPUT_STATE_ANYWHERE, 473 474 { 0x00, 0x17, input_c0_dispatch, NULL }, 475 { 0x19, 0x19, input_c0_dispatch, NULL }, 476 { 0x1c, 0x1f, input_c0_dispatch, NULL }, 477 { 0x20, 0x2f, input_intermediate, NULL }, 478 { 0x30, 0x3f, NULL, &input_state_csi_ignore }, 479 { 0x40, 0x7e, input_csi_dispatch, &input_state_ground }, 480 { 0x7f, 0xff, NULL, NULL }, 481 482 { -1, -1, NULL, NULL } 483}; 484 485/* csi_ignore state table. */ 486const struct input_transition input_state_csi_ignore_table[] = { 487 INPUT_STATE_ANYWHERE, 488 489 { 0x00, 0x17, input_c0_dispatch, NULL }, 490 { 0x19, 0x19, input_c0_dispatch, NULL }, 491 { 0x1c, 0x1f, input_c0_dispatch, NULL }, 492 { 0x20, 0x3f, NULL, NULL }, 493 { 0x40, 0x7e, NULL, &input_state_ground }, 494 { 0x7f, 0xff, NULL, NULL }, 495 496 { -1, -1, NULL, NULL } 497}; 498 499/* dcs_enter state table. */ 500const struct input_transition input_state_dcs_enter_table[] = { 501 INPUT_STATE_ANYWHERE, 502 503 { 0x00, 0x17, NULL, NULL }, 504 { 0x19, 0x19, NULL, NULL }, 505 { 0x1c, 0x1f, NULL, NULL }, 506 { 0x20, 0x2f, input_intermediate, &input_state_dcs_intermediate }, 507 { 0x30, 0x39, input_parameter, &input_state_dcs_parameter }, 508 { 0x3a, 0x3a, NULL, &input_state_dcs_ignore }, 509 { 0x3b, 0x3b, input_parameter, &input_state_dcs_parameter }, 510 { 0x3c, 0x3f, input_intermediate, &input_state_dcs_parameter }, 511 { 0x40, 0x7e, input_input, &input_state_dcs_handler }, 512 { 0x7f, 0xff, NULL, NULL }, 513 514 { -1, -1, NULL, NULL } 515}; 516 517/* dcs_parameter state table. */ 518const struct input_transition input_state_dcs_parameter_table[] = { 519 INPUT_STATE_ANYWHERE, 520 521 { 0x00, 0x17, NULL, NULL }, 522 { 0x19, 0x19, NULL, NULL }, 523 { 0x1c, 0x1f, NULL, NULL }, 524 { 0x20, 0x2f, input_intermediate, &input_state_dcs_intermediate }, 525 { 0x30, 0x39, input_parameter, NULL }, 526 { 0x3a, 0x3a, NULL, &input_state_dcs_ignore }, 527 { 0x3b, 0x3b, input_parameter, NULL }, 528 { 0x3c, 0x3f, NULL, &input_state_dcs_ignore }, 529 { 0x40, 0x7e, input_input, &input_state_dcs_handler }, 530 { 0x7f, 0xff, NULL, NULL }, 531 532 { -1, -1, NULL, NULL } 533}; 534 535/* dcs_interm state table. */ 536const struct input_transition input_state_dcs_intermediate_table[] = { 537 INPUT_STATE_ANYWHERE, 538 539 { 0x00, 0x17, NULL, NULL }, 540 { 0x19, 0x19, NULL, NULL }, 541 { 0x1c, 0x1f, NULL, NULL }, 542 { 0x20, 0x2f, input_intermediate, NULL }, 543 { 0x30, 0x3f, NULL, &input_state_dcs_ignore }, 544 { 0x40, 0x7e, input_input, &input_state_dcs_handler }, 545 { 0x7f, 0xff, NULL, NULL }, 546 547 { -1, -1, NULL, NULL } 548}; 549 550/* dcs_handler state table. */ 551const struct input_transition input_state_dcs_handler_table[] = { 552 /* No INPUT_STATE_ANYWHERE */ 553 554 { 0x00, 0x1a, input_input, NULL }, 555 { 0x1b, 0x1b, NULL, &input_state_dcs_escape }, 556 { 0x1c, 0xff, input_input, NULL }, 557 558 { -1, -1, NULL, NULL } 559}; 560 561/* dcs_escape state table. */ 562const struct input_transition input_state_dcs_escape_table[] = { 563 /* No INPUT_STATE_ANYWHERE */ 564 565 { 0x00, 0x5b, input_input, &input_state_dcs_handler }, 566 { 0x5c, 0x5c, input_dcs_dispatch, &input_state_ground }, 567 { 0x5d, 0xff, input_input, &input_state_dcs_handler }, 568 569 { -1, -1, NULL, NULL } 570}; 571 572/* dcs_ignore state table. */ 573const struct input_transition input_state_dcs_ignore_table[] = { 574 INPUT_STATE_ANYWHERE, 575 576 { 0x00, 0x17, NULL, NULL }, 577 { 0x19, 0x19, NULL, NULL }, 578 { 0x1c, 0x1f, NULL, NULL }, 579 { 0x20, 0xff, NULL, NULL }, 580 581 { -1, -1, NULL, NULL } 582}; 583 584/* osc_string state table. */ 585const struct input_transition input_state_osc_string_table[] = { 586 INPUT_STATE_ANYWHERE, 587 588 { 0x00, 0x06, NULL, NULL }, 589 { 0x07, 0x07, NULL, &input_state_ground }, 590 { 0x08, 0x17, NULL, NULL }, 591 { 0x19, 0x19, NULL, NULL }, 592 { 0x1c, 0x1f, NULL, NULL }, 593 { 0x20, 0xff, input_input, NULL }, 594 595 { -1, -1, NULL, NULL } 596}; 597 598/* apc_string state table. */ 599const struct input_transition input_state_apc_string_table[] = { 600 INPUT_STATE_ANYWHERE, 601 602 { 0x00, 0x17, NULL, NULL }, 603 { 0x19, 0x19, NULL, NULL }, 604 { 0x1c, 0x1f, NULL, NULL }, 605 { 0x20, 0xff, input_input, NULL }, 606 607 { -1, -1, NULL, NULL } 608}; 609 610/* rename_string state table. */ 611const struct input_transition input_state_rename_string_table[] = { 612 INPUT_STATE_ANYWHERE, 613 614 { 0x00, 0x17, NULL, NULL }, 615 { 0x19, 0x19, NULL, NULL }, 616 { 0x1c, 0x1f, NULL, NULL }, 617 { 0x20, 0xff, input_input, NULL }, 618 619 { -1, -1, NULL, NULL } 620}; 621 622/* consume_st state table. */ 623const struct input_transition input_state_consume_st_table[] = { 624 INPUT_STATE_ANYWHERE, 625 626 { 0x00, 0x17, NULL, NULL }, 627 { 0x19, 0x19, NULL, NULL }, 628 { 0x1c, 0x1f, NULL, NULL }, 629 { 0x20, 0xff, NULL, NULL }, 630 631 { -1, -1, NULL, NULL } 632}; 633 634/* utf8_three state table. */ 635const struct input_transition input_state_utf8_three_table[] = { 636 /* No INPUT_STATE_ANYWHERE */ 637 638 { 0x00, 0x7f, NULL, &input_state_ground }, 639 { 0x80, 0xbf, input_utf8_add, &input_state_utf8_two }, 640 { 0xc0, 0xff, NULL, &input_state_ground }, 641 642 { -1, -1, NULL, NULL } 643}; 644 645/* utf8_two state table. */ 646const struct input_transition input_state_utf8_two_table[] = { 647 /* No INPUT_STATE_ANYWHERE */ 648 649 { 0x00, 0x7f, NULL, &input_state_ground }, 650 { 0x80, 0xbf, input_utf8_add, &input_state_utf8_one }, 651 { 0xc0, 0xff, NULL, &input_state_ground }, 652 653 { -1, -1, NULL, NULL } 654}; 655 656/* utf8_one state table. */ 657const struct input_transition input_state_utf8_one_table[] = { 658 /* No INPUT_STATE_ANYWHERE */ 659 660 { 0x00, 0x7f, NULL, &input_state_ground }, 661 { 0x80, 0xbf, input_utf8_close, &input_state_ground }, 662 { 0xc0, 0xff, NULL, &input_state_ground }, 663 664 { -1, -1, NULL, NULL } 665}; 666 667/* Input table compare. */ 668int 669input_table_compare(const void *key, const void *value) 670{ 671 const struct input_ctx *ictx = key; 672 const struct input_table_entry *entry = value; 673 674 if (ictx->ch != entry->ch) 675 return (ictx->ch - entry->ch); 676 return (strcmp(ictx->interm_buf, entry->interm)); 677} 678 679/* Initialise input parser. */ 680void 681input_init(struct window_pane *wp) 682{ 683 struct input_ctx *ictx = &wp->ictx; 684 685 memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell); 686 687 memcpy(&ictx->old_cell, &grid_default_cell, sizeof ictx->old_cell); 688 ictx->old_cx = 0; 689 ictx->old_cy = 0; 690 691 *ictx->interm_buf = '\0'; 692 ictx->interm_len = 0; 693 694 *ictx->param_buf = '\0'; 695 ictx->param_len = 0; 696 697 ictx->state = &input_state_ground; 698 ictx->flags = 0; 699 700 ictx->since_ground = evbuffer_new(); 701} 702 703/* Destroy input parser. */ 704void 705input_free(struct window_pane *wp) 706{ 707 if (wp != NULL) 708 evbuffer_free(wp->ictx.since_ground); 709} 710 711/* Change input state. */ 712void 713input_set_state(struct window_pane *wp, const struct input_transition *itr) 714{ 715 struct input_ctx *ictx = &wp->ictx; 716 struct evbuffer *ground_evb = ictx->since_ground; 717 718 if (ictx->state->exit != NULL) 719 ictx->state->exit(ictx); 720 721 if (itr->state == &input_state_ground) 722 evbuffer_drain(ground_evb, EVBUFFER_LENGTH(ground_evb)); 723 724 ictx->state = itr->state; 725 if (ictx->state->enter != NULL) 726 ictx->state->enter(ictx); 727} 728 729/* Parse input. */ 730void 731input_parse(struct window_pane *wp) 732{ 733 struct input_ctx *ictx = &wp->ictx; 734 const struct input_transition *itr; 735 struct evbuffer *evb = wp->event->input; 736 u_char *buf; 737 size_t len, off; 738 739 if (EVBUFFER_LENGTH(evb) == 0) 740 return; 741 742 wp->window->flags |= WINDOW_ACTIVITY; 743 wp->window->flags &= ~WINDOW_SILENCE; 744 745 /* 746 * Open the screen. Use NULL wp if there is a mode set as don't want to 747 * update the tty. 748 */ 749 if (wp->mode == NULL) 750 screen_write_start(&ictx->ctx, wp, &wp->base); 751 else 752 screen_write_start(&ictx->ctx, NULL, &wp->base); 753 ictx->wp = wp; 754 755 buf = EVBUFFER_DATA(evb); 756 len = EVBUFFER_LENGTH(evb); 757 notify_input(wp, evb); 758 off = 0; 759 760 /* Parse the input. */ 761 while (off < len) { 762 ictx->ch = buf[off++]; 763 log_debug("%s: '%c' %s", __func__, ictx->ch, ictx->state->name); 764 765 /* Find the transition. */ 766 itr = ictx->state->transitions; 767 while (itr->first != -1 && itr->last != -1) { 768 if (ictx->ch >= itr->first && ictx->ch <= itr->last) 769 break; 770 itr++; 771 } 772 if (itr->first == -1 || itr->last == -1) { 773 /* No transition? Eh? */ 774 fatalx("No transition from state!"); 775 } 776 777 /* 778 * Execute the handler, if any. Don't switch state if it 779 * returns non-zero. 780 */ 781 if (itr->handler != NULL && itr->handler(ictx) != 0) 782 continue; 783 784 /* And switch state, if necessary. */ 785 if (itr->state != NULL) 786 input_set_state(wp, itr); 787 788 /* If not in ground state, save input. */ 789 if (ictx->state != &input_state_ground) 790 evbuffer_add(ictx->since_ground, &ictx->ch, 1); 791 } 792 793 /* Close the screen. */ 794 screen_write_stop(&ictx->ctx); 795 796 evbuffer_drain(evb, len); 797} 798 799/* Split the parameter list (if any). */ 800int 801input_split(struct input_ctx *ictx) 802 803{ 804 const char *errstr; 805 char *ptr, *out; 806 int n; 807 808 ictx->param_list_len = 0; 809 if (ictx->param_len == 0) 810 return (0); 811 812 ptr = ictx->param_buf; 813 while ((out = strsep(&ptr, ";")) != NULL) { 814 if (*out == '\0') 815 n = -1; 816 else { 817 n = strtonum(out, 0, INT_MAX, &errstr); 818 if (errstr != NULL) 819 return (-1); 820 } 821 822 ictx->param_list[ictx->param_list_len++] = n; 823 if (ictx->param_list_len == nitems(ictx->param_list)) 824 return (-1); 825 } 826 827 return (0); 828} 829 830/* Get an argument or return default value. */ 831int 832input_get(struct input_ctx *ictx, u_int validx, int minval, int defval) 833{ 834 int retval; 835 836 if (validx >= ictx->param_list_len) 837 return (defval); 838 839 retval = ictx->param_list[validx]; 840 if (retval == -1) 841 return (defval); 842 if (retval < minval) 843 return (minval); 844 return (retval); 845} 846 847/* Reply to terminal query. */ 848void 849input_reply(struct input_ctx *ictx, const char *fmt, ...) 850{ 851 va_list ap; 852 char *reply; 853 854 va_start(ap, fmt); 855 vasprintf(&reply, fmt, ap); 856 va_end(ap); 857 858 bufferevent_write(ictx->wp->event, reply, strlen(reply)); 859 free(reply); 860} 861 862/* Clear saved state. */ 863void 864input_clear(struct input_ctx *ictx) 865{ 866 *ictx->interm_buf = '\0'; 867 ictx->interm_len = 0; 868 869 *ictx->param_buf = '\0'; 870 ictx->param_len = 0; 871 872 *ictx->input_buf = '\0'; 873 ictx->input_len = 0; 874 875 ictx->flags &= ~INPUT_DISCARD; 876} 877 878/* Output this character to the screen. */ 879int 880input_print(struct input_ctx *ictx) 881{ 882 ictx->cell.data = ictx->ch; 883 screen_write_cell(&ictx->ctx, &ictx->cell, NULL); 884 885 return (0); 886} 887 888/* Collect intermediate string. */ 889int 890input_intermediate(struct input_ctx *ictx) 891{ 892 if (ictx->interm_len == (sizeof ictx->interm_buf) - 1) 893 ictx->flags |= INPUT_DISCARD; 894 else { 895 ictx->interm_buf[ictx->interm_len++] = ictx->ch; 896 ictx->interm_buf[ictx->interm_len] = '\0'; 897 } 898 899 return (0); 900} 901 902/* Collect parameter string. */ 903int 904input_parameter(struct input_ctx *ictx) 905{ 906 if (ictx->param_len == (sizeof ictx->param_buf) - 1) 907 ictx->flags |= INPUT_DISCARD; 908 else { 909 ictx->param_buf[ictx->param_len++] = ictx->ch; 910 ictx->param_buf[ictx->param_len] = '\0'; 911 } 912 913 return (0); 914} 915 916/* Collect input string. */ 917int 918input_input(struct input_ctx *ictx) 919{ 920 if (ictx->input_len == (sizeof ictx->input_buf) - 1) 921 ictx->flags |= INPUT_DISCARD; 922 else { 923 ictx->input_buf[ictx->input_len++] = ictx->ch; 924 ictx->input_buf[ictx->input_len] = '\0'; 925 } 926 927 return (0); 928} 929 930/* Execute C0 control sequence. */ 931int 932input_c0_dispatch(struct input_ctx *ictx) 933{ 934 struct screen_write_ctx *sctx = &ictx->ctx; 935 struct window_pane *wp = ictx->wp; 936 struct screen *s = sctx->s; 937 u_int trigger; 938 939 log_debug("%s: '%c", __func__, ictx->ch); 940 941 switch (ictx->ch) { 942 case '\000': /* NUL */ 943 break; 944 case '\007': /* BEL */ 945 wp->window->flags |= WINDOW_BELL; 946 break; 947 case '\010': /* BS */ 948 screen_write_backspace(sctx); 949 goto count_c0; 950 case '\011': /* HT */ 951 /* Don't tab beyond the end of the line. */ 952 if (s->cx >= screen_size_x(s) - 1) 953 break; 954 955 /* Find the next tab point, or use the last column if none. */ 956 do { 957 s->cx++; 958 if (bit_test(s->tabs, s->cx)) 959 break; 960 } while (s->cx < screen_size_x(s) - 1); 961 break; 962 case '\012': /* LF */ 963 case '\013': /* VT */ 964 case '\014': /* FF */ 965 screen_write_linefeed(sctx, 0); 966 goto count_c0; 967 case '\015': /* CR */ 968 screen_write_carriagereturn(sctx); 969 goto count_c0; 970 case '\016': /* SO */ 971 ictx->cell.attr |= GRID_ATTR_CHARSET; 972 break; 973 case '\017': /* SI */ 974 ictx->cell.attr &= ~GRID_ATTR_CHARSET; 975 break; 976 default: 977 log_debug("%s: unknown '%c'", __func__, ictx->ch); 978 break; 979 } 980 981 return (0); 982 983count_c0: 984 trigger = options_get_number(&wp->window->options, "c0-change-trigger"); 985 if (++wp->changes == trigger) { 986 wp->flags |= PANE_DROP; 987 window_pane_timer_start(wp); 988 } 989 990 return (0); 991} 992 993/* Execute escape sequence. */ 994int 995input_esc_dispatch(struct input_ctx *ictx) 996{ 997 struct screen_write_ctx *sctx = &ictx->ctx; 998 struct screen *s = sctx->s; 999 struct input_table_entry *entry; 1000 1001 if (ictx->flags & INPUT_DISCARD) 1002 return (0); 1003 log_debug("%s: '%c', %s", __func__, ictx->ch, ictx->interm_buf); 1004 1005 entry = bsearch(ictx, input_esc_table, nitems(input_esc_table), 1006 sizeof input_esc_table[0], input_table_compare); 1007 if (entry == NULL) { 1008 log_debug("%s: unknown '%c'", __func__, ictx->ch); 1009 return (0); 1010 } 1011 1012 switch (entry->type) { 1013 case INPUT_ESC_RIS: 1014 memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell); 1015 memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell); 1016 ictx->old_cx = 0; 1017 ictx->old_cy = 0; 1018 1019 screen_write_reset(sctx); 1020 break; 1021 case INPUT_ESC_IND: 1022 screen_write_linefeed(sctx, 0); 1023 break; 1024 case INPUT_ESC_NEL: 1025 screen_write_carriagereturn(sctx); 1026 screen_write_linefeed(sctx, 0); 1027 break; 1028 case INPUT_ESC_HTS: 1029 if (s->cx < screen_size_x(s)) 1030 bit_set(s->tabs, s->cx); 1031 break; 1032 case INPUT_ESC_RI: 1033 screen_write_reverseindex(sctx); 1034 break; 1035 case INPUT_ESC_DECKPAM: 1036 screen_write_kkeypadmode(sctx, 1); 1037 break; 1038 case INPUT_ESC_DECKPNM: 1039 screen_write_kkeypadmode(sctx, 0); 1040 break; 1041 case INPUT_ESC_DECSC: 1042 memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell); 1043 ictx->old_cx = s->cx; 1044 ictx->old_cy = s->cy; 1045 break; 1046 case INPUT_ESC_DECRC: 1047 memcpy(&ictx->cell, &ictx->old_cell, sizeof ictx->cell); 1048 screen_write_cursormove(sctx, ictx->old_cx, ictx->old_cy); 1049 break; 1050 case INPUT_ESC_DECALN: 1051 screen_write_alignmenttest(sctx); 1052 break; 1053 case INPUT_ESC_SCSON_G0: 1054 /* 1055 * Not really supported, but fake it up enough for those that 1056 * use it to switch character sets (by redefining G0 to 1057 * graphics set, rather than switching to G1). 1058 */ 1059 ictx->cell.attr &= ~GRID_ATTR_CHARSET; 1060 break; 1061 case INPUT_ESC_SCSOFF_G0: 1062 ictx->cell.attr |= GRID_ATTR_CHARSET; 1063 break; 1064 } 1065 1066 return (0); 1067} 1068 1069/* Execute control sequence. */ 1070int 1071input_csi_dispatch(struct input_ctx *ictx) 1072{ 1073 struct screen_write_ctx *sctx = &ictx->ctx; 1074 struct window_pane *wp = ictx->wp; 1075 struct screen *s = sctx->s; 1076 struct input_table_entry *entry; 1077 int n, m; 1078 1079 if (ictx->flags & INPUT_DISCARD) 1080 return (0); 1081 if (input_split(ictx) != 0) 1082 return (0); 1083 log_debug("%s: '%c' \"%s\" \"%s\"", 1084 __func__, ictx->ch, ictx->interm_buf, ictx->param_buf); 1085 1086 entry = bsearch(ictx, input_csi_table, nitems(input_csi_table), 1087 sizeof input_csi_table[0], input_table_compare); 1088 if (entry == NULL) { 1089 log_debug("%s: unknown '%c'", __func__, ictx->ch); 1090 return (0); 1091 } 1092 1093 switch (entry->type) { 1094 case INPUT_CSI_CBT: 1095 /* Find the previous tab point, n times. */ 1096 n = input_get(ictx, 0, 1, 1); 1097 while (s->cx > 0 && n-- > 0) { 1098 do 1099 s->cx--; 1100 while (s->cx > 0 && !bit_test(s->tabs, s->cx)); 1101 } 1102 break; 1103 case INPUT_CSI_CUB: 1104 screen_write_cursorleft(sctx, input_get(ictx, 0, 1, 1)); 1105 break; 1106 case INPUT_CSI_CUD: 1107 screen_write_cursordown(sctx, input_get(ictx, 0, 1, 1)); 1108 break; 1109 case INPUT_CSI_CUF: 1110 screen_write_cursorright(sctx, input_get(ictx, 0, 1, 1)); 1111 break; 1112 case INPUT_CSI_CUP: 1113 n = input_get(ictx, 0, 1, 1); 1114 m = input_get(ictx, 1, 1, 1); 1115 screen_write_cursormove(sctx, m - 1, n - 1); 1116 break; 1117 case INPUT_CSI_CUU: 1118 screen_write_cursorup(sctx, input_get(ictx, 0, 1, 1)); 1119 break; 1120 case INPUT_CSI_CNL: 1121 screen_write_carriagereturn(sctx); 1122 screen_write_cursordown(sctx, input_get(ictx, 0, 1, 1)); 1123 break; 1124 case INPUT_CSI_CPL: 1125 screen_write_carriagereturn(sctx); 1126 screen_write_cursorup(sctx, input_get(ictx, 0, 1, 1)); 1127 break; 1128 case INPUT_CSI_DA: 1129 switch (input_get(ictx, 0, 0, 0)) { 1130 case 0: 1131 input_reply(ictx, "\033[?1;2c"); 1132 break; 1133 default: 1134 log_debug("%s: unknown '%c'", __func__, ictx->ch); 1135 break; 1136 } 1137 break; 1138 case INPUT_CSI_DA_TWO: 1139 switch (input_get(ictx, 0, 0, 0)) { 1140 case 0: 1141 input_reply(ictx, "\033[>0;95;0c"); 1142 break; 1143 default: 1144 log_debug("%s: unknown '%c'", __func__, ictx->ch); 1145 break; 1146 } 1147 break; 1148 case INPUT_CSI_ECH: 1149 screen_write_clearcharacter(sctx, input_get(ictx, 0, 1, 1)); 1150 break; 1151 case INPUT_CSI_DCH: 1152 screen_write_deletecharacter(sctx, input_get(ictx, 0, 1, 1)); 1153 break; 1154 case INPUT_CSI_DECSTBM: 1155 n = input_get(ictx, 0, 1, 1); 1156 m = input_get(ictx, 1, 1, screen_size_y(s)); 1157 screen_write_scrollregion(sctx, n - 1, m - 1); 1158 break; 1159 case INPUT_CSI_DL: 1160 screen_write_deleteline(sctx, input_get(ictx, 0, 1, 1)); 1161 break; 1162 case INPUT_CSI_DSR: 1163 switch (input_get(ictx, 0, 0, 0)) { 1164 case 5: 1165 input_reply(ictx, "\033[0n"); 1166 break; 1167 case 6: 1168 input_reply(ictx, "\033[%u;%uR", s->cy + 1, s->cx + 1); 1169 break; 1170 default: 1171 log_debug("%s: unknown '%c'", __func__, ictx->ch); 1172 break; 1173 } 1174 break; 1175 case INPUT_CSI_ED: 1176 switch (input_get(ictx, 0, 0, 0)) { 1177 case 0: 1178 screen_write_clearendofscreen(sctx); 1179 break; 1180 case 1: 1181 screen_write_clearstartofscreen(sctx); 1182 break; 1183 case 2: 1184 screen_write_clearscreen(sctx); 1185 break; 1186 case 3: 1187 switch (input_get(ictx, 1, 0, 0)) { 1188 case 0: 1189 /* 1190 * Linux console extension to clear history 1191 * (for example before locking the screen). 1192 */ 1193 screen_write_clearhistory(sctx); 1194 break; 1195 } 1196 break; 1197 default: 1198 log_debug("%s: unknown '%c'", __func__, ictx->ch); 1199 break; 1200 } 1201 break; 1202 case INPUT_CSI_EL: 1203 switch (input_get(ictx, 0, 0, 0)) { 1204 case 0: 1205 screen_write_clearendofline(sctx); 1206 break; 1207 case 1: 1208 screen_write_clearstartofline(sctx); 1209 break; 1210 case 2: 1211 screen_write_clearline(sctx); 1212 break; 1213 default: 1214 log_debug("%s: unknown '%c'", __func__, ictx->ch); 1215 break; 1216 } 1217 break; 1218 case INPUT_CSI_HPA: 1219 n = input_get(ictx, 0, 1, 1); 1220 screen_write_cursormove(sctx, n - 1, s->cy); 1221 break; 1222 case INPUT_CSI_ICH: 1223 screen_write_insertcharacter(sctx, input_get(ictx, 0, 1, 1)); 1224 break; 1225 case INPUT_CSI_IL: 1226 screen_write_insertline(sctx, input_get(ictx, 0, 1, 1)); 1227 break; 1228 case INPUT_CSI_RCP: 1229 memcpy(&ictx->cell, &ictx->old_cell, sizeof ictx->cell); 1230 screen_write_cursormove(sctx, ictx->old_cx, ictx->old_cy); 1231 break; 1232 case INPUT_CSI_RM: 1233 switch (input_get(ictx, 0, 0, -1)) { 1234 case 4: /* IRM */ 1235 screen_write_insertmode(&ictx->ctx, 0); 1236 break; 1237 default: 1238 log_debug("%s: unknown '%c'", __func__, ictx->ch); 1239 break; 1240 } 1241 break; 1242 case INPUT_CSI_RM_PRIVATE: 1243 switch (input_get(ictx, 0, 0, -1)) { 1244 case 1: /* GATM */ 1245 screen_write_kcursormode(&ictx->ctx, 0); 1246 break; 1247 case 3: /* DECCOLM */ 1248 screen_write_cursormove(&ictx->ctx, 0, 0); 1249 screen_write_clearscreen(&ictx->ctx); 1250 break; 1251 case 25: /* TCEM */ 1252 screen_write_cursormode(&ictx->ctx, 0); 1253 break; 1254 case 1000: 1255 case 1001: 1256 case 1002: 1257 case 1003: 1258 screen_write_mousemode_off(&ictx->ctx); 1259 break; 1260 case 1005: 1261 screen_write_utf8mousemode(&ictx->ctx, 0); 1262 break; 1263 case 47: 1264 case 1047: 1265 window_pane_alternate_off(wp, &ictx->cell, 0); 1266 break; 1267 case 1049: 1268 window_pane_alternate_off(wp, &ictx->cell, 1); 1269 break; 1270 case 2004: 1271 screen_write_bracketpaste(&ictx->ctx, 0); 1272 break; 1273 default: 1274 log_debug("%s: unknown '%c'", __func__, ictx->ch); 1275 break; 1276 } 1277 break; 1278 case INPUT_CSI_SCP: 1279 memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell); 1280 ictx->old_cx = s->cx; 1281 ictx->old_cy = s->cy; 1282 break; 1283 case INPUT_CSI_SGR: 1284 input_csi_dispatch_sgr(ictx); 1285 break; 1286 case INPUT_CSI_SM: 1287 switch (input_get(ictx, 0, 0, -1)) { 1288 case 4: /* IRM */ 1289 screen_write_insertmode(&ictx->ctx, 1); 1290 break; 1291 default: 1292 log_debug("%s: unknown '%c'", __func__, ictx->ch); 1293 break; 1294 } 1295 break; 1296 case INPUT_CSI_SM_PRIVATE: 1297 switch (input_get(ictx, 0, 0, -1)) { 1298 case 1: /* GATM */ 1299 screen_write_kcursormode(&ictx->ctx, 1); 1300 break; 1301 case 3: /* DECCOLM */ 1302 screen_write_cursormove(&ictx->ctx, 0, 0); 1303 screen_write_clearscreen(&ictx->ctx); 1304 break; 1305 case 25: /* TCEM */ 1306 screen_write_cursormode(&ictx->ctx, 1); 1307 break; 1308 case 1000: 1309 screen_write_mousemode_on( 1310 &ictx->ctx, MODE_MOUSE_STANDARD); 1311 break; 1312 case 1002: 1313 screen_write_mousemode_on( 1314 &ictx->ctx, MODE_MOUSE_BUTTON); 1315 break; 1316 case 1003: 1317 screen_write_mousemode_on(&ictx->ctx, MODE_MOUSE_ANY); 1318 break; 1319 case 1005: 1320 screen_write_utf8mousemode(&ictx->ctx, 1); 1321 break; 1322 case 47: 1323 case 1047: 1324 window_pane_alternate_on(wp, &ictx->cell, 0); 1325 break; 1326 case 1049: 1327 window_pane_alternate_on(wp, &ictx->cell, 1); 1328 break; 1329 case 2004: 1330 screen_write_bracketpaste(&ictx->ctx, 1); 1331 break; 1332 default: 1333 log_debug("%s: unknown '%c'", __func__, ictx->ch); 1334 break; 1335 } 1336 break; 1337 case INPUT_CSI_TBC: 1338 switch (input_get(ictx, 0, 0, 0)) { 1339 case 0: 1340 if (s->cx < screen_size_x(s)) 1341 bit_clear(s->tabs, s->cx); 1342 break; 1343 case 3: 1344 bit_nclear(s->tabs, 0, screen_size_x(s) - 1); 1345 break; 1346 default: 1347 log_debug("%s: unknown '%c'", __func__, ictx->ch); 1348 break; 1349 } 1350 break; 1351 case INPUT_CSI_VPA: 1352 n = input_get(ictx, 0, 1, 1); 1353 screen_write_cursormove(sctx, s->cx, n - 1); 1354 break; 1355 case INPUT_CSI_DECSCUSR: 1356 n = input_get(ictx, 0, 0, 0); 1357 screen_set_cursor_style(s, n); 1358 break; 1359 } 1360 1361 return (0); 1362} 1363 1364/* Handle CSI SGR. */ 1365void 1366input_csi_dispatch_sgr(struct input_ctx *ictx) 1367{ 1368 struct grid_cell *gc = &ictx->cell; 1369 u_int i; 1370 int n, m; 1371 u_char attr; 1372 1373 if (ictx->param_list_len == 0) { 1374 attr = gc->attr; 1375 memcpy(gc, &grid_default_cell, sizeof *gc); 1376 gc->attr |= (attr & GRID_ATTR_CHARSET); 1377 return; 1378 } 1379 1380 for (i = 0; i < ictx->param_list_len; i++) { 1381 n = input_get(ictx, i, 0, 0); 1382 1383 if (n == 38 || n == 48) { 1384 i++; 1385 if (input_get(ictx, i, 0, -1) != 5) 1386 continue; 1387 1388 i++; 1389 m = input_get(ictx, i, 0, -1); 1390 if (m == -1) { 1391 if (n == 38) { 1392 gc->flags &= ~GRID_FLAG_FG256; 1393 gc->fg = 8; 1394 } else if (n == 48) { 1395 gc->flags &= ~GRID_FLAG_BG256; 1396 gc->bg = 8; 1397 } 1398 1399 } else { 1400 if (n == 38) { 1401 gc->flags |= GRID_FLAG_FG256; 1402 gc->fg = m; 1403 } else if (n == 48) { 1404 gc->flags |= GRID_FLAG_BG256; 1405 gc->bg = m; 1406 } 1407 } 1408 continue; 1409 } 1410 1411 switch (n) { 1412 case 0: 1413 case 10: 1414 attr = gc->attr; 1415 memcpy(gc, &grid_default_cell, sizeof *gc); 1416 gc->attr |= (attr & GRID_ATTR_CHARSET); 1417 break; 1418 case 1: 1419 gc->attr |= GRID_ATTR_BRIGHT; 1420 break; 1421 case 2: 1422 gc->attr |= GRID_ATTR_DIM; 1423 break; 1424 case 3: 1425 gc->attr |= GRID_ATTR_ITALICS; 1426 break; 1427 case 4: 1428 gc->attr |= GRID_ATTR_UNDERSCORE; 1429 break; 1430 case 5: 1431 gc->attr |= GRID_ATTR_BLINK; 1432 break; 1433 case 7: 1434 gc->attr |= GRID_ATTR_REVERSE; 1435 break; 1436 case 8: 1437 gc->attr |= GRID_ATTR_HIDDEN; 1438 break; 1439 case 22: 1440 gc->attr &= ~(GRID_ATTR_BRIGHT|GRID_ATTR_DIM); 1441 break; 1442 case 23: 1443 gc->attr &= ~GRID_ATTR_ITALICS; 1444 break; 1445 case 24: 1446 gc->attr &= ~GRID_ATTR_UNDERSCORE; 1447 break; 1448 case 25: 1449 gc->attr &= ~GRID_ATTR_BLINK; 1450 break; 1451 case 27: 1452 gc->attr &= ~GRID_ATTR_REVERSE; 1453 break; 1454 case 30: 1455 case 31: 1456 case 32: 1457 case 33: 1458 case 34: 1459 case 35: 1460 case 36: 1461 case 37: 1462 gc->flags &= ~GRID_FLAG_FG256; 1463 gc->fg = n - 30; 1464 break; 1465 case 39: 1466 gc->flags &= ~GRID_FLAG_FG256; 1467 gc->fg = 8; 1468 break; 1469 case 40: 1470 case 41: 1471 case 42: 1472 case 43: 1473 case 44: 1474 case 45: 1475 case 46: 1476 case 47: 1477 gc->flags &= ~GRID_FLAG_BG256; 1478 gc->bg = n - 40; 1479 break; 1480 case 49: 1481 gc->flags &= ~GRID_FLAG_BG256; 1482 gc->bg = 8; 1483 break; 1484 case 90: 1485 case 91: 1486 case 92: 1487 case 93: 1488 case 94: 1489 case 95: 1490 case 96: 1491 case 97: 1492 gc->flags &= ~GRID_FLAG_FG256; 1493 gc->fg = n; 1494 break; 1495 case 100: 1496 case 101: 1497 case 102: 1498 case 103: 1499 case 104: 1500 case 105: 1501 case 106: 1502 case 107: 1503 gc->flags &= ~GRID_FLAG_BG256; 1504 gc->bg = n - 10; 1505 break; 1506 } 1507 } 1508} 1509 1510/* DCS terminator (ST) received. */ 1511int 1512input_dcs_dispatch(struct input_ctx *ictx) 1513{ 1514 const char prefix[] = "tmux;"; 1515 const u_int prefix_len = (sizeof prefix) - 1; 1516 1517 if (ictx->flags & INPUT_DISCARD) 1518 return (0); 1519 1520 log_debug("%s: \"%s\"", __func__, ictx->input_buf); 1521 1522 /* Check for tmux prefix. */ 1523 if (ictx->input_len >= prefix_len && 1524 strncmp(ictx->input_buf, prefix, prefix_len) == 0) { 1525 screen_write_rawstring(&ictx->ctx, 1526 ictx->input_buf + prefix_len, ictx->input_len - prefix_len); 1527 } 1528 1529 return (0); 1530} 1531 1532/* OSC string started. */ 1533void 1534input_enter_osc(struct input_ctx *ictx) 1535{ 1536 log_debug("%s", __func__); 1537 1538 input_clear(ictx); 1539} 1540 1541/* OSC terminator (ST) received. */ 1542void 1543input_exit_osc(struct input_ctx *ictx) 1544{ 1545 u_char *p = ictx->input_buf; 1546 int option; 1547 1548 if (ictx->flags & INPUT_DISCARD) 1549 return; 1550 if (ictx->input_len < 1 || *p < '0' || *p > '9') 1551 return; 1552 1553 log_debug("%s: \"%s\"", __func__, p); 1554 1555 option = 0; 1556 while (*p >= '0' && *p <= '9') 1557 option = option * 10 + *p++ - '0'; 1558 if (*p == ';') 1559 p++; 1560 1561 switch (option) { 1562 case 0: 1563 case 2: 1564 screen_set_title(ictx->ctx.s, p); 1565 server_status_window(ictx->wp->window); 1566 break; 1567 case 12: 1568 if (*p != '?') /* ? is colour request */ 1569 screen_set_cursor_colour(ictx->ctx.s, p); 1570 break; 1571 case 112: 1572 if (*p == '\0') /* no arguments allowed */ 1573 screen_set_cursor_colour(ictx->ctx.s, ""); 1574 break; 1575 default: 1576 log_debug("%s: unknown '%u'", __func__, option); 1577 break; 1578 } 1579} 1580 1581/* APC string started. */ 1582void 1583input_enter_apc(struct input_ctx *ictx) 1584{ 1585 log_debug("%s", __func__); 1586 1587 input_clear(ictx); 1588} 1589 1590/* APC terminator (ST) received. */ 1591void 1592input_exit_apc(struct input_ctx *ictx) 1593{ 1594 if (ictx->flags & INPUT_DISCARD) 1595 return; 1596 log_debug("%s: \"%s\"", __func__, ictx->input_buf); 1597 1598 screen_set_title(ictx->ctx.s, ictx->input_buf); 1599 server_status_window(ictx->wp->window); 1600} 1601 1602/* Rename string started. */ 1603void 1604input_enter_rename(struct input_ctx *ictx) 1605{ 1606 log_debug("%s", __func__); 1607 1608 input_clear(ictx); 1609} 1610 1611/* Rename terminator (ST) received. */ 1612void 1613input_exit_rename(struct input_ctx *ictx) 1614{ 1615 if (ictx->flags & INPUT_DISCARD) 1616 return; 1617 if (!options_get_number(&ictx->wp->window->options, "allow-rename")) 1618 return; 1619 log_debug("%s: \"%s\"", __func__, ictx->input_buf); 1620 1621 window_set_name(ictx->wp->window, ictx->input_buf); 1622 options_set_number(&ictx->wp->window->options, "automatic-rename", 0); 1623 1624 server_status_window(ictx->wp->window); 1625} 1626 1627/* Open UTF-8 character. */ 1628int 1629input_utf8_open(struct input_ctx *ictx) 1630{ 1631 if (!options_get_number(&ictx->wp->window->options, "utf8")) { 1632 /* Print, and do not switch state. */ 1633 input_print(ictx); 1634 return (-1); 1635 } 1636 log_debug("%s", __func__); 1637 1638 utf8_open(&ictx->utf8data, ictx->ch); 1639 return (0); 1640} 1641 1642/* Append to UTF-8 character. */ 1643int 1644input_utf8_add(struct input_ctx *ictx) 1645{ 1646 log_debug("%s", __func__); 1647 1648 utf8_append(&ictx->utf8data, ictx->ch); 1649 return (0); 1650} 1651 1652/* Close UTF-8 string. */ 1653int 1654input_utf8_close(struct input_ctx *ictx) 1655{ 1656 log_debug("%s", __func__); 1657 1658 utf8_append(&ictx->utf8data, ictx->ch); 1659 1660 ictx->cell.flags |= GRID_FLAG_UTF8; 1661 screen_write_cell(&ictx->ctx, &ictx->cell, &ictx->utf8data); 1662 ictx->cell.flags &= ~GRID_FLAG_UTF8; 1663 1664 return (0); 1665} 1666