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