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