1 /* $OpenBSD$ */ 2 3 /* 4 * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com> 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 <netinet/in.h> 22 23 #include <resolv.h> 24 #include <stdlib.h> 25 #include <string.h> 26 #include <time.h> 27 28 #include "tmux.h" 29 30 /* 31 * Based on the description by Paul Williams at: 32 * 33 * https://vt100.net/emu/dec_ansi_parser 34 * 35 * With the following changes: 36 * 37 * - 7-bit only. 38 * 39 * - Support for UTF-8. 40 * 41 * - OSC (but not APC) may be terminated by \007 as well as ST. 42 * 43 * - A state for APC similar to OSC. Some terminals appear to use this to set 44 * the title. 45 * 46 * - A state for the screen \033k...\033\\ sequence to rename a window. This is 47 * pretty stupid but not supporting it is more trouble than it is worth. 48 * 49 * - Special handling for ESC inside a DCS to allow arbitrary byte sequences to 50 * be passed to the underlying terminals. 51 */ 52 53 /* Input parser cell. */ 54 struct input_cell { 55 struct grid_cell cell; 56 int set; 57 int g0set; /* 1 if ACS */ 58 int g1set; /* 1 if ACS */ 59 }; 60 61 /* Input parser argument. */ 62 struct input_param { 63 enum { 64 INPUT_MISSING, 65 INPUT_NUMBER, 66 INPUT_STRING 67 } type; 68 union { 69 int num; 70 char *str; 71 }; 72 }; 73 74 /* Input parser context. */ 75 struct input_ctx { 76 struct window_pane *wp; 77 struct screen_write_ctx ctx; 78 79 struct input_cell cell; 80 81 struct input_cell old_cell; 82 u_int old_cx; 83 u_int old_cy; 84 85 u_char interm_buf[4]; 86 size_t interm_len; 87 88 u_char param_buf[64]; 89 size_t param_len; 90 91 #define INPUT_BUF_START 32 92 #define INPUT_BUF_LIMIT 1048576 93 u_char *input_buf; 94 size_t input_len; 95 size_t input_space; 96 97 struct input_param param_list[24]; 98 u_int param_list_len; 99 100 struct utf8_data utf8data; 101 int utf8started; 102 103 int ch; 104 int last; 105 106 int flags; 107 #define INPUT_DISCARD 0x1 108 109 const struct input_state *state; 110 111 struct event timer; 112 113 /* 114 * All input received since we were last in the ground state. Sent to 115 * control clients on connection. 116 */ 117 struct evbuffer *since_ground; 118 }; 119 120 /* Helper functions. */ 121 struct input_transition; 122 static int input_split(struct input_ctx *); 123 static int input_get(struct input_ctx *, u_int, int, int); 124 static void printflike(2, 3) input_reply(struct input_ctx *, const char *, ...); 125 static void input_set_state(struct window_pane *, 126 const struct input_transition *); 127 static void input_reset_cell(struct input_ctx *); 128 129 static void input_osc_4(struct window_pane *, const char *); 130 static void input_osc_10(struct window_pane *, const char *); 131 static void input_osc_11(struct window_pane *, const char *); 132 static void input_osc_52(struct window_pane *, const char *); 133 static void input_osc_104(struct window_pane *, const char *); 134 135 /* Transition entry/exit handlers. */ 136 static void input_clear(struct input_ctx *); 137 static void input_ground(struct input_ctx *); 138 static void input_enter_dcs(struct input_ctx *); 139 static void input_enter_osc(struct input_ctx *); 140 static void input_exit_osc(struct input_ctx *); 141 static void input_enter_apc(struct input_ctx *); 142 static void input_exit_apc(struct input_ctx *); 143 static void input_enter_rename(struct input_ctx *); 144 static void input_exit_rename(struct input_ctx *); 145 146 /* Input state handlers. */ 147 static int input_print(struct input_ctx *); 148 static int input_intermediate(struct input_ctx *); 149 static int input_parameter(struct input_ctx *); 150 static int input_input(struct input_ctx *); 151 static int input_c0_dispatch(struct input_ctx *); 152 static int input_esc_dispatch(struct input_ctx *); 153 static int input_csi_dispatch(struct input_ctx *); 154 static void input_csi_dispatch_rm(struct input_ctx *); 155 static void input_csi_dispatch_rm_private(struct input_ctx *); 156 static void input_csi_dispatch_sm(struct input_ctx *); 157 static void input_csi_dispatch_sm_private(struct input_ctx *); 158 static void input_csi_dispatch_winops(struct input_ctx *); 159 static void input_csi_dispatch_sgr_256(struct input_ctx *, int, u_int *); 160 static void input_csi_dispatch_sgr_rgb(struct input_ctx *, int, u_int *); 161 static void input_csi_dispatch_sgr(struct input_ctx *); 162 static int input_dcs_dispatch(struct input_ctx *); 163 static int input_top_bit_set(struct input_ctx *); 164 165 /* Command table comparison function. */ 166 static int input_table_compare(const void *, const void *); 167 168 /* Command table entry. */ 169 struct input_table_entry { 170 int ch; 171 const char *interm; 172 int type; 173 }; 174 175 /* Escape commands. */ 176 enum input_esc_type { 177 INPUT_ESC_DECALN, 178 INPUT_ESC_DECKPAM, 179 INPUT_ESC_DECKPNM, 180 INPUT_ESC_DECRC, 181 INPUT_ESC_DECSC, 182 INPUT_ESC_HTS, 183 INPUT_ESC_IND, 184 INPUT_ESC_NEL, 185 INPUT_ESC_RI, 186 INPUT_ESC_RIS, 187 INPUT_ESC_SCSG0_OFF, 188 INPUT_ESC_SCSG0_ON, 189 INPUT_ESC_SCSG1_OFF, 190 INPUT_ESC_SCSG1_ON, 191 INPUT_ESC_ST, 192 }; 193 194 /* Escape command table. */ 195 static const struct input_table_entry input_esc_table[] = { 196 { '0', "(", INPUT_ESC_SCSG0_ON }, 197 { '0', ")", INPUT_ESC_SCSG1_ON }, 198 { '7', "", INPUT_ESC_DECSC }, 199 { '8', "", INPUT_ESC_DECRC }, 200 { '8', "#", INPUT_ESC_DECALN }, 201 { '=', "", INPUT_ESC_DECKPAM }, 202 { '>', "", INPUT_ESC_DECKPNM }, 203 { 'B', "(", INPUT_ESC_SCSG0_OFF }, 204 { 'B', ")", INPUT_ESC_SCSG1_OFF }, 205 { 'D', "", INPUT_ESC_IND }, 206 { 'E', "", INPUT_ESC_NEL }, 207 { 'H', "", INPUT_ESC_HTS }, 208 { 'M', "", INPUT_ESC_RI }, 209 { '\\', "", INPUT_ESC_ST }, 210 { 'c', "", INPUT_ESC_RIS }, 211 }; 212 213 /* Control (CSI) commands. */ 214 enum input_csi_type { 215 INPUT_CSI_CBT, 216 INPUT_CSI_CNL, 217 INPUT_CSI_CPL, 218 INPUT_CSI_CUB, 219 INPUT_CSI_CUD, 220 INPUT_CSI_CUF, 221 INPUT_CSI_CUP, 222 INPUT_CSI_CUU, 223 INPUT_CSI_DA, 224 INPUT_CSI_DA_TWO, 225 INPUT_CSI_DCH, 226 INPUT_CSI_DECSCUSR, 227 INPUT_CSI_DECSTBM, 228 INPUT_CSI_DL, 229 INPUT_CSI_DSR, 230 INPUT_CSI_ECH, 231 INPUT_CSI_ED, 232 INPUT_CSI_EL, 233 INPUT_CSI_HPA, 234 INPUT_CSI_ICH, 235 INPUT_CSI_IL, 236 INPUT_CSI_RCP, 237 INPUT_CSI_REP, 238 INPUT_CSI_RM, 239 INPUT_CSI_RM_PRIVATE, 240 INPUT_CSI_SCP, 241 INPUT_CSI_SGR, 242 INPUT_CSI_SM, 243 INPUT_CSI_SM_PRIVATE, 244 INPUT_CSI_SU, 245 INPUT_CSI_TBC, 246 INPUT_CSI_VPA, 247 INPUT_CSI_WINOPS, 248 }; 249 250 /* Control (CSI) command table. */ 251 static const struct input_table_entry input_csi_table[] = { 252 { '@', "", INPUT_CSI_ICH }, 253 { 'A', "", INPUT_CSI_CUU }, 254 { 'B', "", INPUT_CSI_CUD }, 255 { 'C', "", INPUT_CSI_CUF }, 256 { 'D', "", INPUT_CSI_CUB }, 257 { 'E', "", INPUT_CSI_CNL }, 258 { 'F', "", INPUT_CSI_CPL }, 259 { 'G', "", INPUT_CSI_HPA }, 260 { 'H', "", INPUT_CSI_CUP }, 261 { 'J', "", INPUT_CSI_ED }, 262 { 'K', "", INPUT_CSI_EL }, 263 { 'L', "", INPUT_CSI_IL }, 264 { 'M', "", INPUT_CSI_DL }, 265 { 'P', "", INPUT_CSI_DCH }, 266 { 'S', "", INPUT_CSI_SU }, 267 { 'X', "", INPUT_CSI_ECH }, 268 { 'Z', "", INPUT_CSI_CBT }, 269 { 'b', "", INPUT_CSI_REP }, 270 { 'c', "", INPUT_CSI_DA }, 271 { 'c', ">", INPUT_CSI_DA_TWO }, 272 { 'd', "", INPUT_CSI_VPA }, 273 { 'f', "", INPUT_CSI_CUP }, 274 { 'g', "", INPUT_CSI_TBC }, 275 { 'h', "", INPUT_CSI_SM }, 276 { 'h', "?", INPUT_CSI_SM_PRIVATE }, 277 { 'l', "", INPUT_CSI_RM }, 278 { 'l', "?", INPUT_CSI_RM_PRIVATE }, 279 { 'm', "", INPUT_CSI_SGR }, 280 { 'n', "", INPUT_CSI_DSR }, 281 { 'q', " ", INPUT_CSI_DECSCUSR }, 282 { 'r', "", INPUT_CSI_DECSTBM }, 283 { 's', "", INPUT_CSI_SCP }, 284 { 't', "", INPUT_CSI_WINOPS }, 285 { 'u', "", INPUT_CSI_RCP }, 286 }; 287 288 /* Input transition. */ 289 struct input_transition { 290 int first; 291 int last; 292 293 int (*handler)(struct input_ctx *); 294 const struct input_state *state; 295 }; 296 297 /* Input state. */ 298 struct input_state { 299 const char *name; 300 void (*enter)(struct input_ctx *); 301 void (*exit)(struct input_ctx *); 302 const struct input_transition *transitions; 303 }; 304 305 /* State transitions available from all states. */ 306 #define INPUT_STATE_ANYWHERE \ 307 { 0x18, 0x18, input_c0_dispatch, &input_state_ground }, \ 308 { 0x1a, 0x1a, input_c0_dispatch, &input_state_ground }, \ 309 { 0x1b, 0x1b, NULL, &input_state_esc_enter } 310 311 /* Forward declarations of state tables. */ 312 static const struct input_transition input_state_ground_table[]; 313 static const struct input_transition input_state_esc_enter_table[]; 314 static const struct input_transition input_state_esc_intermediate_table[]; 315 static const struct input_transition input_state_csi_enter_table[]; 316 static const struct input_transition input_state_csi_parameter_table[]; 317 static const struct input_transition input_state_csi_intermediate_table[]; 318 static const struct input_transition input_state_csi_ignore_table[]; 319 static const struct input_transition input_state_dcs_enter_table[]; 320 static const struct input_transition input_state_dcs_parameter_table[]; 321 static const struct input_transition input_state_dcs_intermediate_table[]; 322 static const struct input_transition input_state_dcs_handler_table[]; 323 static const struct input_transition input_state_dcs_escape_table[]; 324 static const struct input_transition input_state_dcs_ignore_table[]; 325 static const struct input_transition input_state_osc_string_table[]; 326 static const struct input_transition input_state_apc_string_table[]; 327 static const struct input_transition input_state_rename_string_table[]; 328 static const struct input_transition input_state_consume_st_table[]; 329 330 /* ground state definition. */ 331 static const struct input_state input_state_ground = { 332 "ground", 333 input_ground, NULL, 334 input_state_ground_table 335 }; 336 337 /* esc_enter state definition. */ 338 static const struct input_state input_state_esc_enter = { 339 "esc_enter", 340 input_clear, NULL, 341 input_state_esc_enter_table 342 }; 343 344 /* esc_intermediate state definition. */ 345 static const struct input_state input_state_esc_intermediate = { 346 "esc_intermediate", 347 NULL, NULL, 348 input_state_esc_intermediate_table 349 }; 350 351 /* csi_enter state definition. */ 352 static const struct input_state input_state_csi_enter = { 353 "csi_enter", 354 input_clear, NULL, 355 input_state_csi_enter_table 356 }; 357 358 /* csi_parameter state definition. */ 359 static const struct input_state input_state_csi_parameter = { 360 "csi_parameter", 361 NULL, NULL, 362 input_state_csi_parameter_table 363 }; 364 365 /* csi_intermediate state definition. */ 366 static const struct input_state input_state_csi_intermediate = { 367 "csi_intermediate", 368 NULL, NULL, 369 input_state_csi_intermediate_table 370 }; 371 372 /* csi_ignore state definition. */ 373 static const struct input_state input_state_csi_ignore = { 374 "csi_ignore", 375 NULL, NULL, 376 input_state_csi_ignore_table 377 }; 378 379 /* dcs_enter state definition. */ 380 static const struct input_state input_state_dcs_enter = { 381 "dcs_enter", 382 input_enter_dcs, NULL, 383 input_state_dcs_enter_table 384 }; 385 386 /* dcs_parameter state definition. */ 387 static const struct input_state input_state_dcs_parameter = { 388 "dcs_parameter", 389 NULL, NULL, 390 input_state_dcs_parameter_table 391 }; 392 393 /* dcs_intermediate state definition. */ 394 static const struct input_state input_state_dcs_intermediate = { 395 "dcs_intermediate", 396 NULL, NULL, 397 input_state_dcs_intermediate_table 398 }; 399 400 /* dcs_handler state definition. */ 401 static const struct input_state input_state_dcs_handler = { 402 "dcs_handler", 403 NULL, NULL, 404 input_state_dcs_handler_table 405 }; 406 407 /* dcs_escape state definition. */ 408 static const struct input_state input_state_dcs_escape = { 409 "dcs_escape", 410 NULL, NULL, 411 input_state_dcs_escape_table 412 }; 413 414 /* dcs_ignore state definition. */ 415 static const struct input_state input_state_dcs_ignore = { 416 "dcs_ignore", 417 NULL, NULL, 418 input_state_dcs_ignore_table 419 }; 420 421 /* osc_string state definition. */ 422 static const struct input_state input_state_osc_string = { 423 "osc_string", 424 input_enter_osc, input_exit_osc, 425 input_state_osc_string_table 426 }; 427 428 /* apc_string state definition. */ 429 static const struct input_state input_state_apc_string = { 430 "apc_string", 431 input_enter_apc, input_exit_apc, 432 input_state_apc_string_table 433 }; 434 435 /* rename_string state definition. */ 436 static const struct input_state input_state_rename_string = { 437 "rename_string", 438 input_enter_rename, input_exit_rename, 439 input_state_rename_string_table 440 }; 441 442 /* consume_st state definition. */ 443 static const struct input_state input_state_consume_st = { 444 "consume_st", 445 input_enter_rename, NULL, /* rename also waits for ST */ 446 input_state_consume_st_table 447 }; 448 449 /* ground state table. */ 450 static const struct input_transition input_state_ground_table[] = { 451 INPUT_STATE_ANYWHERE, 452 453 { 0x00, 0x17, input_c0_dispatch, NULL }, 454 { 0x19, 0x19, input_c0_dispatch, NULL }, 455 { 0x1c, 0x1f, input_c0_dispatch, NULL }, 456 { 0x20, 0x7e, input_print, NULL }, 457 { 0x7f, 0x7f, NULL, NULL }, 458 { 0x80, 0xff, input_top_bit_set, NULL }, 459 460 { -1, -1, NULL, NULL } 461 }; 462 463 /* esc_enter state table. */ 464 static const struct input_transition input_state_esc_enter_table[] = { 465 INPUT_STATE_ANYWHERE, 466 467 { 0x00, 0x17, input_c0_dispatch, NULL }, 468 { 0x19, 0x19, input_c0_dispatch, NULL }, 469 { 0x1c, 0x1f, input_c0_dispatch, NULL }, 470 { 0x20, 0x2f, input_intermediate, &input_state_esc_intermediate }, 471 { 0x30, 0x4f, input_esc_dispatch, &input_state_ground }, 472 { 0x50, 0x50, NULL, &input_state_dcs_enter }, 473 { 0x51, 0x57, input_esc_dispatch, &input_state_ground }, 474 { 0x58, 0x58, NULL, &input_state_consume_st }, 475 { 0x59, 0x59, input_esc_dispatch, &input_state_ground }, 476 { 0x5a, 0x5a, input_esc_dispatch, &input_state_ground }, 477 { 0x5b, 0x5b, NULL, &input_state_csi_enter }, 478 { 0x5c, 0x5c, input_esc_dispatch, &input_state_ground }, 479 { 0x5d, 0x5d, NULL, &input_state_osc_string }, 480 { 0x5e, 0x5e, NULL, &input_state_consume_st }, 481 { 0x5f, 0x5f, NULL, &input_state_apc_string }, 482 { 0x60, 0x6a, input_esc_dispatch, &input_state_ground }, 483 { 0x6b, 0x6b, NULL, &input_state_rename_string }, 484 { 0x6c, 0x7e, input_esc_dispatch, &input_state_ground }, 485 { 0x7f, 0xff, NULL, NULL }, 486 487 { -1, -1, NULL, NULL } 488 }; 489 490 /* esc_interm state table. */ 491 static const struct input_transition input_state_esc_intermediate_table[] = { 492 INPUT_STATE_ANYWHERE, 493 494 { 0x00, 0x17, input_c0_dispatch, NULL }, 495 { 0x19, 0x19, input_c0_dispatch, NULL }, 496 { 0x1c, 0x1f, input_c0_dispatch, NULL }, 497 { 0x20, 0x2f, input_intermediate, NULL }, 498 { 0x30, 0x7e, input_esc_dispatch, &input_state_ground }, 499 { 0x7f, 0xff, NULL, NULL }, 500 501 { -1, -1, NULL, NULL } 502 }; 503 504 /* csi_enter state table. */ 505 static const struct input_transition input_state_csi_enter_table[] = { 506 INPUT_STATE_ANYWHERE, 507 508 { 0x00, 0x17, input_c0_dispatch, NULL }, 509 { 0x19, 0x19, input_c0_dispatch, NULL }, 510 { 0x1c, 0x1f, input_c0_dispatch, NULL }, 511 { 0x20, 0x2f, input_intermediate, &input_state_csi_intermediate }, 512 { 0x30, 0x39, input_parameter, &input_state_csi_parameter }, 513 { 0x3a, 0x3a, input_parameter, &input_state_csi_parameter }, 514 { 0x3b, 0x3b, input_parameter, &input_state_csi_parameter }, 515 { 0x3c, 0x3f, input_intermediate, &input_state_csi_parameter }, 516 { 0x40, 0x7e, input_csi_dispatch, &input_state_ground }, 517 { 0x7f, 0xff, NULL, NULL }, 518 519 { -1, -1, NULL, NULL } 520 }; 521 522 /* csi_parameter state table. */ 523 static const struct input_transition input_state_csi_parameter_table[] = { 524 INPUT_STATE_ANYWHERE, 525 526 { 0x00, 0x17, input_c0_dispatch, NULL }, 527 { 0x19, 0x19, input_c0_dispatch, NULL }, 528 { 0x1c, 0x1f, input_c0_dispatch, NULL }, 529 { 0x20, 0x2f, input_intermediate, &input_state_csi_intermediate }, 530 { 0x30, 0x39, input_parameter, NULL }, 531 { 0x3a, 0x3a, input_parameter, NULL }, 532 { 0x3b, 0x3b, input_parameter, NULL }, 533 { 0x3c, 0x3f, NULL, &input_state_csi_ignore }, 534 { 0x40, 0x7e, input_csi_dispatch, &input_state_ground }, 535 { 0x7f, 0xff, NULL, NULL }, 536 537 { -1, -1, NULL, NULL } 538 }; 539 540 /* csi_intermediate state table. */ 541 static const struct input_transition input_state_csi_intermediate_table[] = { 542 INPUT_STATE_ANYWHERE, 543 544 { 0x00, 0x17, input_c0_dispatch, NULL }, 545 { 0x19, 0x19, input_c0_dispatch, NULL }, 546 { 0x1c, 0x1f, input_c0_dispatch, NULL }, 547 { 0x20, 0x2f, input_intermediate, NULL }, 548 { 0x30, 0x3f, NULL, &input_state_csi_ignore }, 549 { 0x40, 0x7e, input_csi_dispatch, &input_state_ground }, 550 { 0x7f, 0xff, NULL, NULL }, 551 552 { -1, -1, NULL, NULL } 553 }; 554 555 /* csi_ignore state table. */ 556 static const struct input_transition input_state_csi_ignore_table[] = { 557 INPUT_STATE_ANYWHERE, 558 559 { 0x00, 0x17, input_c0_dispatch, NULL }, 560 { 0x19, 0x19, input_c0_dispatch, NULL }, 561 { 0x1c, 0x1f, input_c0_dispatch, NULL }, 562 { 0x20, 0x3f, NULL, NULL }, 563 { 0x40, 0x7e, NULL, &input_state_ground }, 564 { 0x7f, 0xff, NULL, NULL }, 565 566 { -1, -1, NULL, NULL } 567 }; 568 569 /* dcs_enter state table. */ 570 static const struct input_transition input_state_dcs_enter_table[] = { 571 INPUT_STATE_ANYWHERE, 572 573 { 0x00, 0x17, NULL, NULL }, 574 { 0x19, 0x19, NULL, NULL }, 575 { 0x1c, 0x1f, NULL, NULL }, 576 { 0x20, 0x2f, input_intermediate, &input_state_dcs_intermediate }, 577 { 0x30, 0x39, input_parameter, &input_state_dcs_parameter }, 578 { 0x3a, 0x3a, NULL, &input_state_dcs_ignore }, 579 { 0x3b, 0x3b, input_parameter, &input_state_dcs_parameter }, 580 { 0x3c, 0x3f, input_intermediate, &input_state_dcs_parameter }, 581 { 0x40, 0x7e, input_input, &input_state_dcs_handler }, 582 { 0x7f, 0xff, NULL, NULL }, 583 584 { -1, -1, NULL, NULL } 585 }; 586 587 /* dcs_parameter state table. */ 588 static const struct input_transition input_state_dcs_parameter_table[] = { 589 INPUT_STATE_ANYWHERE, 590 591 { 0x00, 0x17, NULL, NULL }, 592 { 0x19, 0x19, NULL, NULL }, 593 { 0x1c, 0x1f, NULL, NULL }, 594 { 0x20, 0x2f, input_intermediate, &input_state_dcs_intermediate }, 595 { 0x30, 0x39, input_parameter, NULL }, 596 { 0x3a, 0x3a, NULL, &input_state_dcs_ignore }, 597 { 0x3b, 0x3b, input_parameter, NULL }, 598 { 0x3c, 0x3f, NULL, &input_state_dcs_ignore }, 599 { 0x40, 0x7e, input_input, &input_state_dcs_handler }, 600 { 0x7f, 0xff, NULL, NULL }, 601 602 { -1, -1, NULL, NULL } 603 }; 604 605 /* dcs_interm state table. */ 606 static const struct input_transition input_state_dcs_intermediate_table[] = { 607 INPUT_STATE_ANYWHERE, 608 609 { 0x00, 0x17, NULL, NULL }, 610 { 0x19, 0x19, NULL, NULL }, 611 { 0x1c, 0x1f, NULL, NULL }, 612 { 0x20, 0x2f, input_intermediate, NULL }, 613 { 0x30, 0x3f, NULL, &input_state_dcs_ignore }, 614 { 0x40, 0x7e, input_input, &input_state_dcs_handler }, 615 { 0x7f, 0xff, NULL, NULL }, 616 617 { -1, -1, NULL, NULL } 618 }; 619 620 /* dcs_handler state table. */ 621 static const struct input_transition input_state_dcs_handler_table[] = { 622 /* No INPUT_STATE_ANYWHERE */ 623 624 { 0x00, 0x1a, input_input, NULL }, 625 { 0x1b, 0x1b, NULL, &input_state_dcs_escape }, 626 { 0x1c, 0xff, input_input, NULL }, 627 628 { -1, -1, NULL, NULL } 629 }; 630 631 /* dcs_escape state table. */ 632 static const struct input_transition input_state_dcs_escape_table[] = { 633 /* No INPUT_STATE_ANYWHERE */ 634 635 { 0x00, 0x5b, input_input, &input_state_dcs_handler }, 636 { 0x5c, 0x5c, input_dcs_dispatch, &input_state_ground }, 637 { 0x5d, 0xff, input_input, &input_state_dcs_handler }, 638 639 { -1, -1, NULL, NULL } 640 }; 641 642 /* dcs_ignore state table. */ 643 static const struct input_transition input_state_dcs_ignore_table[] = { 644 INPUT_STATE_ANYWHERE, 645 646 { 0x00, 0x17, NULL, NULL }, 647 { 0x19, 0x19, NULL, NULL }, 648 { 0x1c, 0x1f, NULL, NULL }, 649 { 0x20, 0xff, NULL, NULL }, 650 651 { -1, -1, NULL, NULL } 652 }; 653 654 /* osc_string state table. */ 655 static const struct input_transition input_state_osc_string_table[] = { 656 INPUT_STATE_ANYWHERE, 657 658 { 0x00, 0x06, NULL, NULL }, 659 { 0x07, 0x07, NULL, &input_state_ground }, 660 { 0x08, 0x17, NULL, NULL }, 661 { 0x19, 0x19, NULL, NULL }, 662 { 0x1c, 0x1f, NULL, NULL }, 663 { 0x20, 0xff, input_input, NULL }, 664 665 { -1, -1, NULL, NULL } 666 }; 667 668 /* apc_string state table. */ 669 static const struct input_transition input_state_apc_string_table[] = { 670 INPUT_STATE_ANYWHERE, 671 672 { 0x00, 0x17, NULL, NULL }, 673 { 0x19, 0x19, NULL, NULL }, 674 { 0x1c, 0x1f, NULL, NULL }, 675 { 0x20, 0xff, input_input, NULL }, 676 677 { -1, -1, NULL, NULL } 678 }; 679 680 /* rename_string state table. */ 681 static const struct input_transition input_state_rename_string_table[] = { 682 INPUT_STATE_ANYWHERE, 683 684 { 0x00, 0x17, NULL, NULL }, 685 { 0x19, 0x19, NULL, NULL }, 686 { 0x1c, 0x1f, NULL, NULL }, 687 { 0x20, 0xff, input_input, NULL }, 688 689 { -1, -1, NULL, NULL } 690 }; 691 692 /* consume_st state table. */ 693 static const struct input_transition input_state_consume_st_table[] = { 694 INPUT_STATE_ANYWHERE, 695 696 { 0x00, 0x17, NULL, NULL }, 697 { 0x19, 0x19, NULL, NULL }, 698 { 0x1c, 0x1f, NULL, NULL }, 699 { 0x20, 0xff, NULL, NULL }, 700 701 { -1, -1, NULL, NULL } 702 }; 703 704 /* Input table compare. */ 705 static int 706 input_table_compare(const void *key, const void *value) 707 { 708 const struct input_ctx *ictx = key; 709 const struct input_table_entry *entry = value; 710 711 if (ictx->ch != entry->ch) 712 return (ictx->ch - entry->ch); 713 return (strcmp((const char *)ictx->interm_buf, entry->interm)); 714 } 715 716 /* 717 * Timer - if this expires then have been waiting for a terminator for too 718 * long, so reset to ground. 719 */ 720 static void 721 input_timer_callback(__unused int fd, __unused short events, void *arg) 722 { 723 struct input_ctx *ictx = arg; 724 struct window_pane *wp = ictx->wp; 725 726 log_debug("%s: %%%u %s expired" , __func__, wp->id, ictx->state->name); 727 input_reset(wp, 0); 728 } 729 730 /* Start the timer. */ 731 static void 732 input_start_timer(struct input_ctx *ictx) 733 { 734 struct timeval tv = { .tv_usec = 100000 }; 735 736 event_del(&ictx->timer); 737 event_add(&ictx->timer, &tv); 738 } 739 740 /* Reset cell state to default. */ 741 static void 742 input_reset_cell(struct input_ctx *ictx) 743 { 744 memcpy(&ictx->cell.cell, &grid_default_cell, sizeof ictx->cell.cell); 745 ictx->cell.set = 0; 746 ictx->cell.g0set = ictx->cell.g1set = 0; 747 748 memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell); 749 ictx->old_cx = 0; 750 ictx->old_cy = 0; 751 } 752 753 /* Initialise input parser. */ 754 void 755 input_init(struct window_pane *wp) 756 { 757 struct input_ctx *ictx; 758 759 ictx = wp->ictx = xcalloc(1, sizeof *ictx); 760 761 ictx->input_space = INPUT_BUF_START; 762 ictx->input_buf = xmalloc(INPUT_BUF_START); 763 764 ictx->since_ground = evbuffer_new(); 765 766 evtimer_set(&ictx->timer, input_timer_callback, ictx); 767 768 input_reset(wp, 0); 769 } 770 771 /* Destroy input parser. */ 772 void 773 input_free(struct window_pane *wp) 774 { 775 struct input_ctx *ictx = wp->ictx; 776 u_int i; 777 778 for (i = 0; i < ictx->param_list_len; i++) { 779 if (ictx->param_list[i].type == INPUT_STRING) 780 free(ictx->param_list[i].str); 781 } 782 783 event_del(&ictx->timer); 784 785 free(ictx->input_buf); 786 evbuffer_free(ictx->since_ground); 787 788 free(ictx); 789 wp->ictx = NULL; 790 } 791 792 /* Reset input state and clear screen. */ 793 void 794 input_reset(struct window_pane *wp, int clear) 795 { 796 struct input_ctx *ictx = wp->ictx; 797 798 input_reset_cell(ictx); 799 800 if (clear) { 801 if (wp->mode == NULL) 802 screen_write_start(&ictx->ctx, wp, &wp->base); 803 else 804 screen_write_start(&ictx->ctx, NULL, &wp->base); 805 screen_write_reset(&ictx->ctx); 806 screen_write_stop(&ictx->ctx); 807 } 808 809 input_clear(ictx); 810 811 ictx->last = -1; 812 813 ictx->state = &input_state_ground; 814 ictx->flags = 0; 815 } 816 817 /* Return pending data. */ 818 struct evbuffer * 819 input_pending(struct window_pane *wp) 820 { 821 return (wp->ictx->since_ground); 822 } 823 824 /* Change input state. */ 825 static void 826 input_set_state(struct window_pane *wp, const struct input_transition *itr) 827 { 828 struct input_ctx *ictx = wp->ictx; 829 830 if (ictx->state->exit != NULL) 831 ictx->state->exit(ictx); 832 ictx->state = itr->state; 833 if (ictx->state->enter != NULL) 834 ictx->state->enter(ictx); 835 } 836 837 /* Parse input. */ 838 void 839 input_parse(struct window_pane *wp) 840 { 841 struct input_ctx *ictx = wp->ictx; 842 const struct input_transition *itr; 843 struct evbuffer *evb = wp->event->input; 844 u_char *buf; 845 size_t len, off; 846 847 if (EVBUFFER_LENGTH(evb) == 0) 848 return; 849 850 window_update_activity(wp->window); 851 wp->flags |= PANE_CHANGED; 852 853 /* 854 * Open the screen. Use NULL wp if there is a mode set as don't want to 855 * update the tty. 856 */ 857 if (wp->mode == NULL) 858 screen_write_start(&ictx->ctx, wp, &wp->base); 859 else 860 screen_write_start(&ictx->ctx, NULL, &wp->base); 861 ictx->wp = wp; 862 863 buf = EVBUFFER_DATA(evb); 864 len = EVBUFFER_LENGTH(evb); 865 off = 0; 866 867 notify_input(wp, evb); 868 869 log_debug("%s: %%%u %s, %zu bytes: %.*s", __func__, wp->id, 870 ictx->state->name, len, (int)len, buf); 871 872 /* Parse the input. */ 873 while (off < len) { 874 ictx->ch = buf[off++]; 875 876 /* Find the transition. */ 877 itr = ictx->state->transitions; 878 while (itr->first != -1 && itr->last != -1) { 879 if (ictx->ch >= itr->first && ictx->ch <= itr->last) 880 break; 881 itr++; 882 } 883 if (itr->first == -1 || itr->last == -1) { 884 /* No transition? Eh? */ 885 fatalx("no transition from state"); 886 } 887 888 /* 889 * Any state except print stops the current collection. This is 890 * an optimization to avoid checking if the attributes have 891 * changed for every character. It will stop unnecessarily for 892 * sequences that don't make a terminal change, but they should 893 * be the minority. 894 */ 895 if (itr->handler != input_print) 896 screen_write_collect_end(&ictx->ctx); 897 898 /* 899 * Execute the handler, if any. Don't switch state if it 900 * returns non-zero. 901 */ 902 if (itr->handler != NULL && itr->handler(ictx) != 0) 903 continue; 904 905 /* And switch state, if necessary. */ 906 if (itr->state != NULL) 907 input_set_state(wp, itr); 908 909 /* If not in ground state, save input. */ 910 if (ictx->state != &input_state_ground) 911 evbuffer_add(ictx->since_ground, &ictx->ch, 1); 912 } 913 914 /* Close the screen. */ 915 screen_write_stop(&ictx->ctx); 916 917 evbuffer_drain(evb, len); 918 } 919 920 /* Split the parameter list (if any). */ 921 static int 922 input_split(struct input_ctx *ictx) 923 { 924 const char *errstr; 925 char *ptr, *out; 926 struct input_param *ip; 927 u_int i; 928 929 for (i = 0; i < ictx->param_list_len; i++) { 930 if (ictx->param_list[i].type == INPUT_STRING) 931 free(ictx->param_list[i].str); 932 } 933 ictx->param_list_len = 0; 934 935 if (ictx->param_len == 0) 936 return (0); 937 ip = &ictx->param_list[0]; 938 939 ptr = (char *)ictx->param_buf; 940 while ((out = strsep(&ptr, ";")) != NULL) { 941 if (*out == '\0') 942 ip->type = INPUT_MISSING; 943 else { 944 if (strchr(out, ':') != NULL) { 945 ip->type = INPUT_STRING; 946 ip->str = xstrdup(out); 947 } else { 948 ip->type = INPUT_NUMBER; 949 ip->num = strtonum(out, 0, INT_MAX, &errstr); 950 if (errstr != NULL) 951 return (-1); 952 } 953 } 954 ip = &ictx->param_list[++ictx->param_list_len]; 955 if (ictx->param_list_len == nitems(ictx->param_list)) 956 return (-1); 957 } 958 959 for (i = 0; i < ictx->param_list_len; i++) { 960 ip = &ictx->param_list[i]; 961 if (ip->type == INPUT_MISSING) 962 log_debug("parameter %u: missing", i); 963 else if (ip->type == INPUT_STRING) 964 log_debug("parameter %u: string %s", i, ip->str); 965 else if (ip->type == INPUT_NUMBER) 966 log_debug("parameter %u: number %d", i, ip->num); 967 } 968 969 return (0); 970 } 971 972 /* Get an argument or return default value. */ 973 static int 974 input_get(struct input_ctx *ictx, u_int validx, int minval, int defval) 975 { 976 struct input_param *ip; 977 int retval; 978 979 if (validx >= ictx->param_list_len) 980 return (defval); 981 ip = &ictx->param_list[validx]; 982 if (ip->type == INPUT_MISSING) 983 return (defval); 984 if (ip->type == INPUT_STRING) 985 return (-1); 986 retval = ip->num; 987 if (retval < minval) 988 return (minval); 989 return (retval); 990 } 991 992 /* Reply to terminal query. */ 993 static void 994 input_reply(struct input_ctx *ictx, const char *fmt, ...) 995 { 996 va_list ap; 997 char *reply; 998 999 va_start(ap, fmt); 1000 xvasprintf(&reply, fmt, ap); 1001 va_end(ap); 1002 1003 bufferevent_write(ictx->wp->event, reply, strlen(reply)); 1004 free(reply); 1005 } 1006 1007 /* Clear saved state. */ 1008 static void 1009 input_clear(struct input_ctx *ictx) 1010 { 1011 event_del(&ictx->timer); 1012 1013 *ictx->interm_buf = '\0'; 1014 ictx->interm_len = 0; 1015 1016 *ictx->param_buf = '\0'; 1017 ictx->param_len = 0; 1018 1019 *ictx->input_buf = '\0'; 1020 ictx->input_len = 0; 1021 1022 ictx->flags &= ~INPUT_DISCARD; 1023 } 1024 1025 /* Reset for ground state. */ 1026 static void 1027 input_ground(struct input_ctx *ictx) 1028 { 1029 event_del(&ictx->timer); 1030 evbuffer_drain(ictx->since_ground, EVBUFFER_LENGTH(ictx->since_ground)); 1031 1032 if (ictx->input_space > INPUT_BUF_START) { 1033 ictx->input_space = INPUT_BUF_START; 1034 ictx->input_buf = xrealloc(ictx->input_buf, INPUT_BUF_START); 1035 } 1036 } 1037 1038 /* Output this character to the screen. */ 1039 static int 1040 input_print(struct input_ctx *ictx) 1041 { 1042 int set; 1043 1044 ictx->utf8started = 0; /* can't be valid UTF-8 */ 1045 1046 set = ictx->cell.set == 0 ? ictx->cell.g0set : ictx->cell.g1set; 1047 if (set == 1) 1048 ictx->cell.cell.attr |= GRID_ATTR_CHARSET; 1049 else 1050 ictx->cell.cell.attr &= ~GRID_ATTR_CHARSET; 1051 1052 utf8_set(&ictx->cell.cell.data, ictx->ch); 1053 screen_write_collect_add(&ictx->ctx, &ictx->cell.cell); 1054 ictx->last = ictx->ch; 1055 1056 ictx->cell.cell.attr &= ~GRID_ATTR_CHARSET; 1057 1058 return (0); 1059 } 1060 1061 /* Collect intermediate string. */ 1062 static int 1063 input_intermediate(struct input_ctx *ictx) 1064 { 1065 if (ictx->interm_len == (sizeof ictx->interm_buf) - 1) 1066 ictx->flags |= INPUT_DISCARD; 1067 else { 1068 ictx->interm_buf[ictx->interm_len++] = ictx->ch; 1069 ictx->interm_buf[ictx->interm_len] = '\0'; 1070 } 1071 1072 return (0); 1073 } 1074 1075 /* Collect parameter string. */ 1076 static int 1077 input_parameter(struct input_ctx *ictx) 1078 { 1079 if (ictx->param_len == (sizeof ictx->param_buf) - 1) 1080 ictx->flags |= INPUT_DISCARD; 1081 else { 1082 ictx->param_buf[ictx->param_len++] = ictx->ch; 1083 ictx->param_buf[ictx->param_len] = '\0'; 1084 } 1085 1086 return (0); 1087 } 1088 1089 /* Collect input string. */ 1090 static int 1091 input_input(struct input_ctx *ictx) 1092 { 1093 size_t available; 1094 1095 available = ictx->input_space; 1096 while (ictx->input_len + 1 >= available) { 1097 available *= 2; 1098 if (available > INPUT_BUF_LIMIT) { 1099 ictx->flags |= INPUT_DISCARD; 1100 return (0); 1101 } 1102 ictx->input_buf = xrealloc(ictx->input_buf, available); 1103 ictx->input_space = available; 1104 } 1105 ictx->input_buf[ictx->input_len++] = ictx->ch; 1106 ictx->input_buf[ictx->input_len] = '\0'; 1107 1108 return (0); 1109 } 1110 1111 /* Execute C0 control sequence. */ 1112 static int 1113 input_c0_dispatch(struct input_ctx *ictx) 1114 { 1115 struct screen_write_ctx *sctx = &ictx->ctx; 1116 struct window_pane *wp = ictx->wp; 1117 struct screen *s = sctx->s; 1118 1119 ictx->utf8started = 0; /* can't be valid UTF-8 */ 1120 1121 log_debug("%s: '%c'", __func__, ictx->ch); 1122 1123 switch (ictx->ch) { 1124 case '\000': /* NUL */ 1125 break; 1126 case '\007': /* BEL */ 1127 alerts_queue(wp->window, WINDOW_BELL); 1128 break; 1129 case '\010': /* BS */ 1130 screen_write_backspace(sctx); 1131 break; 1132 case '\011': /* HT */ 1133 /* Don't tab beyond the end of the line. */ 1134 if (s->cx >= screen_size_x(s) - 1) 1135 break; 1136 1137 /* Find the next tab point, or use the last column if none. */ 1138 do { 1139 s->cx++; 1140 if (bit_test(s->tabs, s->cx)) 1141 break; 1142 } while (s->cx < screen_size_x(s) - 1); 1143 break; 1144 case '\012': /* LF */ 1145 case '\013': /* VT */ 1146 case '\014': /* FF */ 1147 screen_write_linefeed(sctx, 0, ictx->cell.cell.bg); 1148 break; 1149 case '\015': /* CR */ 1150 screen_write_carriagereturn(sctx); 1151 break; 1152 case '\016': /* SO */ 1153 ictx->cell.set = 1; 1154 break; 1155 case '\017': /* SI */ 1156 ictx->cell.set = 0; 1157 break; 1158 default: 1159 log_debug("%s: unknown '%c'", __func__, ictx->ch); 1160 break; 1161 } 1162 1163 ictx->last = -1; 1164 return (0); 1165 } 1166 1167 /* Execute escape sequence. */ 1168 static int 1169 input_esc_dispatch(struct input_ctx *ictx) 1170 { 1171 struct screen_write_ctx *sctx = &ictx->ctx; 1172 struct screen *s = sctx->s; 1173 struct input_table_entry *entry; 1174 1175 if (ictx->flags & INPUT_DISCARD) 1176 return (0); 1177 log_debug("%s: '%c', %s", __func__, ictx->ch, ictx->interm_buf); 1178 1179 entry = bsearch(ictx, input_esc_table, nitems(input_esc_table), 1180 sizeof input_esc_table[0], input_table_compare); 1181 if (entry == NULL) { 1182 log_debug("%s: unknown '%c'", __func__, ictx->ch); 1183 return (0); 1184 } 1185 1186 switch (entry->type) { 1187 case INPUT_ESC_RIS: 1188 window_pane_reset_palette(ictx->wp); 1189 input_reset_cell(ictx); 1190 screen_write_reset(sctx); 1191 screen_write_clearhistory(sctx); 1192 break; 1193 case INPUT_ESC_IND: 1194 screen_write_linefeed(sctx, 0, ictx->cell.cell.bg); 1195 break; 1196 case INPUT_ESC_NEL: 1197 screen_write_carriagereturn(sctx); 1198 screen_write_linefeed(sctx, 0, ictx->cell.cell.bg); 1199 break; 1200 case INPUT_ESC_HTS: 1201 if (s->cx < screen_size_x(s)) 1202 bit_set(s->tabs, s->cx); 1203 break; 1204 case INPUT_ESC_RI: 1205 screen_write_reverseindex(sctx, ictx->cell.cell.bg); 1206 break; 1207 case INPUT_ESC_DECKPAM: 1208 screen_write_mode_set(sctx, MODE_KKEYPAD); 1209 break; 1210 case INPUT_ESC_DECKPNM: 1211 screen_write_mode_clear(sctx, MODE_KKEYPAD); 1212 break; 1213 case INPUT_ESC_DECSC: 1214 memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell); 1215 ictx->old_cx = s->cx; 1216 ictx->old_cy = s->cy; 1217 break; 1218 case INPUT_ESC_DECRC: 1219 memcpy(&ictx->cell, &ictx->old_cell, sizeof ictx->cell); 1220 screen_write_cursormove(sctx, ictx->old_cx, ictx->old_cy); 1221 break; 1222 case INPUT_ESC_DECALN: 1223 screen_write_alignmenttest(sctx); 1224 break; 1225 case INPUT_ESC_SCSG0_ON: 1226 ictx->cell.g0set = 1; 1227 break; 1228 case INPUT_ESC_SCSG0_OFF: 1229 ictx->cell.g0set = 0; 1230 break; 1231 case INPUT_ESC_SCSG1_ON: 1232 ictx->cell.g1set = 1; 1233 break; 1234 case INPUT_ESC_SCSG1_OFF: 1235 ictx->cell.g1set = 0; 1236 break; 1237 case INPUT_ESC_ST: 1238 /* ST terminates OSC but the state transition already did it. */ 1239 break; 1240 } 1241 1242 ictx->last = -1; 1243 return (0); 1244 } 1245 1246 /* Execute control sequence. */ 1247 static int 1248 input_csi_dispatch(struct input_ctx *ictx) 1249 { 1250 struct screen_write_ctx *sctx = &ictx->ctx; 1251 struct screen *s = sctx->s; 1252 struct input_table_entry *entry; 1253 int i, n, m; 1254 u_int cx, bg = ictx->cell.cell.bg; 1255 1256 if (ictx->flags & INPUT_DISCARD) 1257 return (0); 1258 1259 log_debug("%s: '%c' \"%s\" \"%s\"", 1260 __func__, ictx->ch, ictx->interm_buf, ictx->param_buf); 1261 1262 if (input_split(ictx) != 0) 1263 return (0); 1264 1265 entry = bsearch(ictx, input_csi_table, nitems(input_csi_table), 1266 sizeof input_csi_table[0], input_table_compare); 1267 if (entry == NULL) { 1268 log_debug("%s: unknown '%c'", __func__, ictx->ch); 1269 return (0); 1270 } 1271 1272 switch (entry->type) { 1273 case INPUT_CSI_CBT: 1274 /* Find the previous tab point, n times. */ 1275 cx = s->cx; 1276 if (cx > screen_size_x(s) - 1) 1277 cx = screen_size_x(s) - 1; 1278 n = input_get(ictx, 0, 1, 1); 1279 if (n == -1) 1280 break; 1281 while (cx > 0 && n-- > 0) { 1282 do 1283 cx--; 1284 while (cx > 0 && !bit_test(s->tabs, cx)); 1285 } 1286 s->cx = cx; 1287 break; 1288 case INPUT_CSI_CUB: 1289 n = input_get(ictx, 0, 1, 1); 1290 if (n != -1) 1291 screen_write_cursorleft(sctx, n); 1292 break; 1293 case INPUT_CSI_CUD: 1294 n = input_get(ictx, 0, 1, 1); 1295 if (n != -1) 1296 screen_write_cursordown(sctx, n); 1297 break; 1298 case INPUT_CSI_CUF: 1299 n = input_get(ictx, 0, 1, 1); 1300 if (n != -1) 1301 screen_write_cursorright(sctx, n); 1302 break; 1303 case INPUT_CSI_CUP: 1304 n = input_get(ictx, 0, 1, 1); 1305 m = input_get(ictx, 1, 1, 1); 1306 if (n != -1 && m != -1) 1307 screen_write_cursormove(sctx, m - 1, n - 1); 1308 break; 1309 case INPUT_CSI_WINOPS: 1310 input_csi_dispatch_winops(ictx); 1311 break; 1312 case INPUT_CSI_CUU: 1313 n = input_get(ictx, 0, 1, 1); 1314 if (n != -1) 1315 screen_write_cursorup(sctx, n); 1316 break; 1317 case INPUT_CSI_CNL: 1318 n = input_get(ictx, 0, 1, 1); 1319 if (n != -1) { 1320 screen_write_carriagereturn(sctx); 1321 screen_write_cursordown(sctx, n); 1322 } 1323 break; 1324 case INPUT_CSI_CPL: 1325 n = input_get(ictx, 0, 1, 1); 1326 if (n != -1) { 1327 screen_write_carriagereturn(sctx); 1328 screen_write_cursorup(sctx, n); 1329 } 1330 break; 1331 case INPUT_CSI_DA: 1332 switch (input_get(ictx, 0, 0, 0)) { 1333 case -1: 1334 break; 1335 case 0: 1336 input_reply(ictx, "\033[?1;2c"); 1337 break; 1338 default: 1339 log_debug("%s: unknown '%c'", __func__, ictx->ch); 1340 break; 1341 } 1342 break; 1343 case INPUT_CSI_DA_TWO: 1344 switch (input_get(ictx, 0, 0, 0)) { 1345 case -1: 1346 break; 1347 case 0: 1348 input_reply(ictx, "\033[>84;0;0c"); 1349 break; 1350 default: 1351 log_debug("%s: unknown '%c'", __func__, ictx->ch); 1352 break; 1353 } 1354 break; 1355 case INPUT_CSI_ECH: 1356 n = input_get(ictx, 0, 1, 1); 1357 if (n != -1) 1358 screen_write_clearcharacter(sctx, n, bg); 1359 break; 1360 case INPUT_CSI_DCH: 1361 n = input_get(ictx, 0, 1, 1); 1362 if (n != -1) 1363 screen_write_deletecharacter(sctx, n, bg); 1364 break; 1365 case INPUT_CSI_DECSTBM: 1366 n = input_get(ictx, 0, 1, 1); 1367 m = input_get(ictx, 1, 1, screen_size_y(s)); 1368 if (n != -1 && m != -1) 1369 screen_write_scrollregion(sctx, n - 1, m - 1); 1370 break; 1371 case INPUT_CSI_DL: 1372 n = input_get(ictx, 0, 1, 1); 1373 if (n != -1) 1374 screen_write_deleteline(sctx, n, bg); 1375 break; 1376 case INPUT_CSI_DSR: 1377 switch (input_get(ictx, 0, 0, 0)) { 1378 case -1: 1379 break; 1380 case 5: 1381 input_reply(ictx, "\033[0n"); 1382 break; 1383 case 6: 1384 input_reply(ictx, "\033[%u;%uR", s->cy + 1, s->cx + 1); 1385 break; 1386 default: 1387 log_debug("%s: unknown '%c'", __func__, ictx->ch); 1388 break; 1389 } 1390 break; 1391 case INPUT_CSI_ED: 1392 switch (input_get(ictx, 0, 0, 0)) { 1393 case -1: 1394 break; 1395 case 0: 1396 screen_write_clearendofscreen(sctx, bg); 1397 break; 1398 case 1: 1399 screen_write_clearstartofscreen(sctx, bg); 1400 break; 1401 case 2: 1402 screen_write_clearscreen(sctx, bg); 1403 break; 1404 case 3: 1405 if (input_get(ictx, 1, 0, 0) == 0) { 1406 /* 1407 * Linux console extension to clear history 1408 * (for example before locking the screen). 1409 */ 1410 screen_write_clearhistory(sctx); 1411 } 1412 break; 1413 default: 1414 log_debug("%s: unknown '%c'", __func__, ictx->ch); 1415 break; 1416 } 1417 break; 1418 case INPUT_CSI_EL: 1419 switch (input_get(ictx, 0, 0, 0)) { 1420 case -1: 1421 break; 1422 case 0: 1423 screen_write_clearendofline(sctx, bg); 1424 break; 1425 case 1: 1426 screen_write_clearstartofline(sctx, bg); 1427 break; 1428 case 2: 1429 screen_write_clearline(sctx, bg); 1430 break; 1431 default: 1432 log_debug("%s: unknown '%c'", __func__, ictx->ch); 1433 break; 1434 } 1435 break; 1436 case INPUT_CSI_HPA: 1437 n = input_get(ictx, 0, 1, 1); 1438 if (n != -1) 1439 screen_write_cursormove(sctx, n - 1, s->cy); 1440 break; 1441 case INPUT_CSI_ICH: 1442 n = input_get(ictx, 0, 1, 1); 1443 if (n != -1) 1444 screen_write_insertcharacter(sctx, n, bg); 1445 break; 1446 case INPUT_CSI_IL: 1447 n = input_get(ictx, 0, 1, 1); 1448 if (n != -1) 1449 screen_write_insertline(sctx, n, bg); 1450 break; 1451 case INPUT_CSI_REP: 1452 n = input_get(ictx, 0, 1, 1); 1453 if (n == -1) 1454 break; 1455 1456 if (ictx->last == -1) 1457 break; 1458 ictx->ch = ictx->last; 1459 1460 for (i = 0; i < n; i++) 1461 input_print(ictx); 1462 break; 1463 case INPUT_CSI_RCP: 1464 memcpy(&ictx->cell, &ictx->old_cell, sizeof ictx->cell); 1465 screen_write_cursormove(sctx, ictx->old_cx, ictx->old_cy); 1466 break; 1467 case INPUT_CSI_RM: 1468 input_csi_dispatch_rm(ictx); 1469 break; 1470 case INPUT_CSI_RM_PRIVATE: 1471 input_csi_dispatch_rm_private(ictx); 1472 break; 1473 case INPUT_CSI_SCP: 1474 memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell); 1475 ictx->old_cx = s->cx; 1476 ictx->old_cy = s->cy; 1477 break; 1478 case INPUT_CSI_SGR: 1479 input_csi_dispatch_sgr(ictx); 1480 break; 1481 case INPUT_CSI_SM: 1482 input_csi_dispatch_sm(ictx); 1483 break; 1484 case INPUT_CSI_SM_PRIVATE: 1485 input_csi_dispatch_sm_private(ictx); 1486 break; 1487 case INPUT_CSI_SU: 1488 n = input_get(ictx, 0, 1, 1); 1489 if (n != -1) 1490 screen_write_scrollup(sctx, n, bg); 1491 break; 1492 case INPUT_CSI_TBC: 1493 switch (input_get(ictx, 0, 0, 0)) { 1494 case -1: 1495 break; 1496 case 0: 1497 if (s->cx < screen_size_x(s)) 1498 bit_clear(s->tabs, s->cx); 1499 break; 1500 case 3: 1501 bit_nclear(s->tabs, 0, screen_size_x(s) - 1); 1502 break; 1503 default: 1504 log_debug("%s: unknown '%c'", __func__, ictx->ch); 1505 break; 1506 } 1507 break; 1508 case INPUT_CSI_VPA: 1509 n = input_get(ictx, 0, 1, 1); 1510 if (n != -1) 1511 screen_write_cursormove(sctx, s->cx, n - 1); 1512 break; 1513 case INPUT_CSI_DECSCUSR: 1514 n = input_get(ictx, 0, 0, 0); 1515 if (n != -1) 1516 screen_set_cursor_style(s, n); 1517 break; 1518 } 1519 1520 ictx->last = -1; 1521 return (0); 1522 } 1523 1524 /* Handle CSI RM. */ 1525 static void 1526 input_csi_dispatch_rm(struct input_ctx *ictx) 1527 { 1528 u_int i; 1529 1530 for (i = 0; i < ictx->param_list_len; i++) { 1531 switch (input_get(ictx, i, 0, -1)) { 1532 case -1: 1533 break; 1534 case 4: /* IRM */ 1535 screen_write_mode_clear(&ictx->ctx, MODE_INSERT); 1536 break; 1537 case 34: 1538 screen_write_mode_set(&ictx->ctx, MODE_BLINKING); 1539 break; 1540 default: 1541 log_debug("%s: unknown '%c'", __func__, ictx->ch); 1542 break; 1543 } 1544 } 1545 } 1546 1547 /* Handle CSI private RM. */ 1548 static void 1549 input_csi_dispatch_rm_private(struct input_ctx *ictx) 1550 { 1551 struct window_pane *wp = ictx->wp; 1552 u_int i; 1553 1554 for (i = 0; i < ictx->param_list_len; i++) { 1555 switch (input_get(ictx, i, 0, -1)) { 1556 case -1: 1557 break; 1558 case 1: /* DECCKM */ 1559 screen_write_mode_clear(&ictx->ctx, MODE_KCURSOR); 1560 break; 1561 case 3: /* DECCOLM */ 1562 screen_write_cursormove(&ictx->ctx, 0, 0); 1563 screen_write_clearscreen(&ictx->ctx, 1564 ictx->cell.cell.bg); 1565 break; 1566 case 7: /* DECAWM */ 1567 screen_write_mode_clear(&ictx->ctx, MODE_WRAP); 1568 break; 1569 case 12: 1570 screen_write_mode_clear(&ictx->ctx, MODE_BLINKING); 1571 break; 1572 case 25: /* TCEM */ 1573 screen_write_mode_clear(&ictx->ctx, MODE_CURSOR); 1574 break; 1575 case 1000: 1576 case 1001: 1577 case 1002: 1578 case 1003: 1579 screen_write_mode_clear(&ictx->ctx, ALL_MOUSE_MODES); 1580 break; 1581 case 1004: 1582 screen_write_mode_clear(&ictx->ctx, MODE_FOCUSON); 1583 break; 1584 case 1005: 1585 screen_write_mode_clear(&ictx->ctx, MODE_MOUSE_UTF8); 1586 break; 1587 case 1006: 1588 screen_write_mode_clear(&ictx->ctx, MODE_MOUSE_SGR); 1589 break; 1590 case 47: 1591 case 1047: 1592 window_pane_alternate_off(wp, &ictx->cell.cell, 0); 1593 break; 1594 case 1049: 1595 window_pane_alternate_off(wp, &ictx->cell.cell, 1); 1596 break; 1597 case 2004: 1598 screen_write_mode_clear(&ictx->ctx, MODE_BRACKETPASTE); 1599 break; 1600 default: 1601 log_debug("%s: unknown '%c'", __func__, ictx->ch); 1602 break; 1603 } 1604 } 1605 } 1606 1607 /* Handle CSI SM. */ 1608 static void 1609 input_csi_dispatch_sm(struct input_ctx *ictx) 1610 { 1611 u_int i; 1612 1613 for (i = 0; i < ictx->param_list_len; i++) { 1614 switch (input_get(ictx, i, 0, -1)) { 1615 case -1: 1616 break; 1617 case 4: /* IRM */ 1618 screen_write_mode_set(&ictx->ctx, MODE_INSERT); 1619 break; 1620 case 34: 1621 screen_write_mode_clear(&ictx->ctx, MODE_BLINKING); 1622 break; 1623 default: 1624 log_debug("%s: unknown '%c'", __func__, ictx->ch); 1625 break; 1626 } 1627 } 1628 } 1629 1630 /* Handle CSI private SM. */ 1631 static void 1632 input_csi_dispatch_sm_private(struct input_ctx *ictx) 1633 { 1634 struct window_pane *wp = ictx->wp; 1635 u_int i; 1636 1637 for (i = 0; i < ictx->param_list_len; i++) { 1638 switch (input_get(ictx, i, 0, -1)) { 1639 case -1: 1640 break; 1641 case 1: /* DECCKM */ 1642 screen_write_mode_set(&ictx->ctx, MODE_KCURSOR); 1643 break; 1644 case 3: /* DECCOLM */ 1645 screen_write_cursormove(&ictx->ctx, 0, 0); 1646 screen_write_clearscreen(&ictx->ctx, 1647 ictx->cell.cell.bg); 1648 break; 1649 case 7: /* DECAWM */ 1650 screen_write_mode_set(&ictx->ctx, MODE_WRAP); 1651 break; 1652 case 12: 1653 screen_write_mode_set(&ictx->ctx, MODE_BLINKING); 1654 break; 1655 case 25: /* TCEM */ 1656 screen_write_mode_set(&ictx->ctx, MODE_CURSOR); 1657 break; 1658 case 1000: 1659 screen_write_mode_clear(&ictx->ctx, ALL_MOUSE_MODES); 1660 screen_write_mode_set(&ictx->ctx, MODE_MOUSE_STANDARD); 1661 break; 1662 case 1002: 1663 screen_write_mode_clear(&ictx->ctx, ALL_MOUSE_MODES); 1664 screen_write_mode_set(&ictx->ctx, MODE_MOUSE_BUTTON); 1665 break; 1666 case 1003: 1667 screen_write_mode_clear(&ictx->ctx, ALL_MOUSE_MODES); 1668 screen_write_mode_set(&ictx->ctx, MODE_MOUSE_ALL); 1669 break; 1670 case 1004: 1671 if (ictx->ctx.s->mode & MODE_FOCUSON) 1672 break; 1673 screen_write_mode_set(&ictx->ctx, MODE_FOCUSON); 1674 wp->flags |= PANE_FOCUSPUSH; /* force update */ 1675 break; 1676 case 1005: 1677 screen_write_mode_set(&ictx->ctx, MODE_MOUSE_UTF8); 1678 break; 1679 case 1006: 1680 screen_write_mode_set(&ictx->ctx, MODE_MOUSE_SGR); 1681 break; 1682 case 47: 1683 case 1047: 1684 window_pane_alternate_on(wp, &ictx->cell.cell, 0); 1685 break; 1686 case 1049: 1687 window_pane_alternate_on(wp, &ictx->cell.cell, 1); 1688 break; 1689 case 2004: 1690 screen_write_mode_set(&ictx->ctx, MODE_BRACKETPASTE); 1691 break; 1692 default: 1693 log_debug("%s: unknown '%c'", __func__, ictx->ch); 1694 break; 1695 } 1696 } 1697 } 1698 1699 /* Handle CSI window operations. */ 1700 static void 1701 input_csi_dispatch_winops(struct input_ctx *ictx) 1702 { 1703 struct window_pane *wp = ictx->wp; 1704 int n, m; 1705 1706 m = 0; 1707 while ((n = input_get(ictx, m, 0, -1)) != -1) { 1708 switch (n) { 1709 case 1: 1710 case 2: 1711 case 5: 1712 case 6: 1713 case 7: 1714 case 11: 1715 case 13: 1716 case 14: 1717 case 19: 1718 case 20: 1719 case 21: 1720 case 24: 1721 break; 1722 case 3: 1723 case 4: 1724 case 8: 1725 m++; 1726 if (input_get(ictx, m, 0, -1) == -1) 1727 return; 1728 /* FALLTHROUGH */ 1729 case 9: 1730 case 10: 1731 m++; 1732 if (input_get(ictx, m, 0, -1) == -1) 1733 return; 1734 break; 1735 case 22: 1736 m++; 1737 switch (input_get(ictx, m, 0, -1)) { 1738 case -1: 1739 return; 1740 case 0: 1741 case 2: 1742 screen_push_title(ictx->ctx.s); 1743 break; 1744 } 1745 break; 1746 case 23: 1747 m++; 1748 switch (input_get(ictx, m, 0, -1)) { 1749 case -1: 1750 return; 1751 case 0: 1752 case 2: 1753 screen_pop_title(ictx->ctx.s); 1754 server_status_window(ictx->wp->window); 1755 break; 1756 } 1757 break; 1758 case 18: 1759 input_reply(ictx, "\033[8;%u;%ut", wp->sy, wp->sx); 1760 break; 1761 default: 1762 log_debug("%s: unknown '%c'", __func__, ictx->ch); 1763 break; 1764 } 1765 m++; 1766 } 1767 } 1768 1769 /* Helper for 256 colour SGR. */ 1770 static int 1771 input_csi_dispatch_sgr_256_do(struct input_ctx *ictx, int fgbg, int c) 1772 { 1773 struct grid_cell *gc = &ictx->cell.cell; 1774 1775 if (c == -1 || c > 255) { 1776 if (fgbg == 38) 1777 gc->fg = 8; 1778 else if (fgbg == 48) 1779 gc->bg = 8; 1780 } else { 1781 if (fgbg == 38) 1782 gc->fg = c | COLOUR_FLAG_256; 1783 else if (fgbg == 48) 1784 gc->bg = c | COLOUR_FLAG_256; 1785 } 1786 return (1); 1787 } 1788 1789 /* Handle CSI SGR for 256 colours. */ 1790 static void 1791 input_csi_dispatch_sgr_256(struct input_ctx *ictx, int fgbg, u_int *i) 1792 { 1793 int c; 1794 1795 c = input_get(ictx, (*i) + 1, 0, -1); 1796 if (input_csi_dispatch_sgr_256_do(ictx, fgbg, c)) 1797 (*i)++; 1798 } 1799 1800 /* Helper for RGB colour SGR. */ 1801 static int 1802 input_csi_dispatch_sgr_rgb_do(struct input_ctx *ictx, int fgbg, int r, int g, 1803 int b) 1804 { 1805 struct grid_cell *gc = &ictx->cell.cell; 1806 1807 if (r == -1 || r > 255) 1808 return (0); 1809 if (g == -1 || g > 255) 1810 return (0); 1811 if (b == -1 || b > 255) 1812 return (0); 1813 1814 if (fgbg == 38) 1815 gc->fg = colour_join_rgb(r, g, b); 1816 else if (fgbg == 48) 1817 gc->bg = colour_join_rgb(r, g, b); 1818 return (1); 1819 } 1820 1821 /* Handle CSI SGR for RGB colours. */ 1822 static void 1823 input_csi_dispatch_sgr_rgb(struct input_ctx *ictx, int fgbg, u_int *i) 1824 { 1825 int r, g, b; 1826 1827 r = input_get(ictx, (*i) + 1, 0, -1); 1828 g = input_get(ictx, (*i) + 2, 0, -1); 1829 b = input_get(ictx, (*i) + 3, 0, -1); 1830 if (input_csi_dispatch_sgr_rgb_do(ictx, fgbg, r, g, b)) 1831 (*i) += 3; 1832 } 1833 1834 /* Handle CSI SGR with a ISO parameter. */ 1835 static void 1836 input_csi_dispatch_sgr_colon(struct input_ctx *ictx, u_int i) 1837 { 1838 char *s = ictx->param_list[i].str, *copy, *ptr, *out; 1839 int p[8]; 1840 u_int n; 1841 const char *errstr; 1842 1843 for (n = 0; n < nitems(p); n++) 1844 p[n] = -1; 1845 n = 0; 1846 1847 ptr = copy = xstrdup(s); 1848 while ((out = strsep(&ptr, ":")) != NULL) { 1849 if (*out != '\0') { 1850 p[n++] = strtonum(out, 0, INT_MAX, &errstr); 1851 if (errstr != NULL || n == nitems(p)) { 1852 free(copy); 1853 return; 1854 } 1855 } 1856 log_debug("%s: %u = %d", __func__, n - 1, p[n - 1]); 1857 } 1858 free(copy); 1859 1860 if (n == 0 || (p[0] != 38 && p[0] != 48)) 1861 return; 1862 if (p[1] == -1) 1863 i = 2; 1864 else 1865 i = 1; 1866 switch (p[i]) { 1867 case 2: 1868 if (n < i + 4) 1869 break; 1870 input_csi_dispatch_sgr_rgb_do(ictx, p[0], p[i + 1], p[i + 2], 1871 p[i + 3]); 1872 break; 1873 case 5: 1874 if (n < i + 2) 1875 break; 1876 input_csi_dispatch_sgr_256_do(ictx, p[0], p[i + 1]); 1877 break; 1878 } 1879 } 1880 1881 /* Handle CSI SGR. */ 1882 static void 1883 input_csi_dispatch_sgr(struct input_ctx *ictx) 1884 { 1885 struct grid_cell *gc = &ictx->cell.cell; 1886 u_int i; 1887 int n; 1888 1889 if (ictx->param_list_len == 0) { 1890 memcpy(gc, &grid_default_cell, sizeof *gc); 1891 return; 1892 } 1893 1894 for (i = 0; i < ictx->param_list_len; i++) { 1895 if (ictx->param_list[i].type == INPUT_STRING) { 1896 input_csi_dispatch_sgr_colon(ictx, i); 1897 continue; 1898 } 1899 n = input_get(ictx, i, 0, 0); 1900 if (n == -1) 1901 continue; 1902 1903 if (n == 38 || n == 48) { 1904 i++; 1905 switch (input_get(ictx, i, 0, -1)) { 1906 case 2: 1907 input_csi_dispatch_sgr_rgb(ictx, n, &i); 1908 break; 1909 case 5: 1910 input_csi_dispatch_sgr_256(ictx, n, &i); 1911 break; 1912 } 1913 continue; 1914 } 1915 1916 switch (n) { 1917 case 0: 1918 memcpy(gc, &grid_default_cell, sizeof *gc); 1919 break; 1920 case 1: 1921 gc->attr |= GRID_ATTR_BRIGHT; 1922 break; 1923 case 2: 1924 gc->attr |= GRID_ATTR_DIM; 1925 break; 1926 case 3: 1927 gc->attr |= GRID_ATTR_ITALICS; 1928 break; 1929 case 4: 1930 gc->attr |= GRID_ATTR_UNDERSCORE; 1931 break; 1932 case 5: 1933 gc->attr |= GRID_ATTR_BLINK; 1934 break; 1935 case 7: 1936 gc->attr |= GRID_ATTR_REVERSE; 1937 break; 1938 case 8: 1939 gc->attr |= GRID_ATTR_HIDDEN; 1940 break; 1941 case 9: 1942 gc->attr |= GRID_ATTR_STRIKETHROUGH; 1943 break; 1944 case 22: 1945 gc->attr &= ~(GRID_ATTR_BRIGHT|GRID_ATTR_DIM); 1946 break; 1947 case 23: 1948 gc->attr &= ~GRID_ATTR_ITALICS; 1949 break; 1950 case 24: 1951 gc->attr &= ~GRID_ATTR_UNDERSCORE; 1952 break; 1953 case 25: 1954 gc->attr &= ~GRID_ATTR_BLINK; 1955 break; 1956 case 27: 1957 gc->attr &= ~GRID_ATTR_REVERSE; 1958 break; 1959 case 28: 1960 gc->attr &= ~GRID_ATTR_HIDDEN; 1961 break; 1962 case 29: 1963 gc->attr &= ~GRID_ATTR_STRIKETHROUGH; 1964 break; 1965 case 30: 1966 case 31: 1967 case 32: 1968 case 33: 1969 case 34: 1970 case 35: 1971 case 36: 1972 case 37: 1973 gc->fg = n - 30; 1974 break; 1975 case 39: 1976 gc->fg = 8; 1977 break; 1978 case 40: 1979 case 41: 1980 case 42: 1981 case 43: 1982 case 44: 1983 case 45: 1984 case 46: 1985 case 47: 1986 gc->bg = n - 40; 1987 break; 1988 case 49: 1989 gc->bg = 8; 1990 break; 1991 case 90: 1992 case 91: 1993 case 92: 1994 case 93: 1995 case 94: 1996 case 95: 1997 case 96: 1998 case 97: 1999 gc->fg = n; 2000 break; 2001 case 100: 2002 case 101: 2003 case 102: 2004 case 103: 2005 case 104: 2006 case 105: 2007 case 106: 2008 case 107: 2009 gc->bg = n - 10; 2010 break; 2011 } 2012 } 2013 } 2014 2015 /* DCS string started. */ 2016 static void 2017 input_enter_dcs(struct input_ctx *ictx) 2018 { 2019 log_debug("%s", __func__); 2020 2021 input_clear(ictx); 2022 input_start_timer(ictx); 2023 ictx->last = -1; 2024 } 2025 2026 /* DCS terminator (ST) received. */ 2027 static int 2028 input_dcs_dispatch(struct input_ctx *ictx) 2029 { 2030 const char prefix[] = "tmux;"; 2031 const u_int prefix_len = (sizeof prefix) - 1; 2032 2033 if (ictx->flags & INPUT_DISCARD) 2034 return (0); 2035 2036 log_debug("%s: \"%s\"", __func__, ictx->input_buf); 2037 2038 /* Check for tmux prefix. */ 2039 if (ictx->input_len >= prefix_len && 2040 strncmp((const char *)ictx->input_buf, prefix, prefix_len) == 0) { 2041 screen_write_rawstring(&ictx->ctx, 2042 ictx->input_buf + prefix_len, ictx->input_len - prefix_len); 2043 } 2044 2045 return (0); 2046 } 2047 2048 /* OSC string started. */ 2049 static void 2050 input_enter_osc(struct input_ctx *ictx) 2051 { 2052 log_debug("%s", __func__); 2053 2054 input_clear(ictx); 2055 input_start_timer(ictx); 2056 ictx->last = -1; 2057 } 2058 2059 /* OSC terminator (ST) received. */ 2060 static void 2061 input_exit_osc(struct input_ctx *ictx) 2062 { 2063 char *p = (char *)ictx->input_buf; 2064 u_int option; 2065 2066 if (ictx->flags & INPUT_DISCARD) 2067 return; 2068 if (ictx->input_len < 1 || *p < '0' || *p > '9') 2069 return; 2070 2071 log_debug("%s: \"%s\"", __func__, p); 2072 2073 option = 0; 2074 while (*p >= '0' && *p <= '9') 2075 option = option * 10 + *p++ - '0'; 2076 if (*p == ';') 2077 p++; 2078 2079 switch (option) { 2080 case 0: 2081 case 2: 2082 if (utf8_isvalid(p)) { 2083 screen_set_title(ictx->ctx.s, p); 2084 server_status_window(ictx->wp->window); 2085 } 2086 break; 2087 case 4: 2088 input_osc_4(ictx->wp, (char *)p); 2089 break; 2090 case 10: 2091 input_osc_10(ictx->wp, p); 2092 break; 2093 case 11: 2094 input_osc_11(ictx->wp, p); 2095 break; 2096 case 12: 2097 if (utf8_isvalid(p) && *p != '?') /* ? is colour request */ 2098 screen_set_cursor_colour(ictx->ctx.s, p); 2099 break; 2100 case 52: 2101 input_osc_52(ictx->wp, p); 2102 break; 2103 case 104: 2104 input_osc_104(ictx->wp, (char *)p); 2105 break; 2106 case 112: 2107 if (*p == '\0') /* no arguments allowed */ 2108 screen_set_cursor_colour(ictx->ctx.s, ""); 2109 break; 2110 default: 2111 log_debug("%s: unknown '%u'", __func__, option); 2112 break; 2113 } 2114 } 2115 2116 /* APC string started. */ 2117 static void 2118 input_enter_apc(struct input_ctx *ictx) 2119 { 2120 log_debug("%s", __func__); 2121 2122 input_clear(ictx); 2123 input_start_timer(ictx); 2124 ictx->last = -1; 2125 } 2126 2127 /* APC terminator (ST) received. */ 2128 static void 2129 input_exit_apc(struct input_ctx *ictx) 2130 { 2131 char *p = (char *)ictx->input_buf; 2132 if (ictx->flags & INPUT_DISCARD) 2133 return; 2134 log_debug("%s: \"%s\"", __func__, p); 2135 2136 if (!utf8_isvalid(p)) 2137 return; 2138 screen_set_title(ictx->ctx.s, p); 2139 server_status_window(ictx->wp->window); 2140 } 2141 2142 /* Rename string started. */ 2143 static void 2144 input_enter_rename(struct input_ctx *ictx) 2145 { 2146 log_debug("%s", __func__); 2147 2148 input_clear(ictx); 2149 input_start_timer(ictx); 2150 ictx->last = -1; 2151 } 2152 2153 /* Rename terminator (ST) received. */ 2154 static void 2155 input_exit_rename(struct input_ctx *ictx) 2156 { 2157 char *p = (char *)ictx->input_buf; 2158 if (ictx->flags & INPUT_DISCARD) 2159 return; 2160 if (!options_get_number(ictx->wp->window->options, "allow-rename")) 2161 return; 2162 log_debug("%s: \"%s\"", __func__, p); 2163 2164 if (!utf8_isvalid(p)) 2165 return; 2166 window_set_name(ictx->wp->window, p); 2167 options_set_number(ictx->wp->window->options, "automatic-rename", 0); 2168 server_status_window(ictx->wp->window); 2169 } 2170 2171 /* Open UTF-8 character. */ 2172 static int 2173 input_top_bit_set(struct input_ctx *ictx) 2174 { 2175 struct utf8_data *ud = &ictx->utf8data; 2176 2177 ictx->last = -1; 2178 2179 if (!ictx->utf8started) { 2180 if (utf8_open(ud, ictx->ch) != UTF8_MORE) 2181 return (0); 2182 ictx->utf8started = 1; 2183 return (0); 2184 } 2185 2186 switch (utf8_append(ud, ictx->ch)) { 2187 case UTF8_MORE: 2188 return (0); 2189 case UTF8_ERROR: 2190 ictx->utf8started = 0; 2191 return (0); 2192 case UTF8_DONE: 2193 break; 2194 } 2195 ictx->utf8started = 0; 2196 2197 log_debug("%s %hhu '%*s' (width %hhu)", __func__, ud->size, 2198 (int)ud->size, ud->data, ud->width); 2199 2200 utf8_copy(&ictx->cell.cell.data, ud); 2201 screen_write_collect_add(&ictx->ctx, &ictx->cell.cell); 2202 2203 return (0); 2204 } 2205 2206 /* Handle the OSC 4 sequence for setting (multiple) palette entries. */ 2207 static void 2208 input_osc_4(struct window_pane *wp, const char *p) 2209 { 2210 char *copy, *s, *next = NULL; 2211 long idx; 2212 u_int r, g, b; 2213 2214 copy = s = xstrdup(p); 2215 while (s != NULL && *s != '\0') { 2216 idx = strtol(s, &next, 10); 2217 if (*next++ != ';') 2218 goto bad; 2219 if (idx < 0 || idx >= 0x100) 2220 goto bad; 2221 2222 s = strsep(&next, ";"); 2223 if (sscanf(s, "rgb:%2x/%2x/%2x", &r, &g, &b) != 3) { 2224 s = next; 2225 continue; 2226 } 2227 2228 window_pane_set_palette(wp, idx, colour_join_rgb(r, g, b)); 2229 s = next; 2230 } 2231 2232 free(copy); 2233 return; 2234 2235 bad: 2236 log_debug("bad OSC 4: %s", p); 2237 free(copy); 2238 } 2239 2240 /* Handle the OSC 10 sequence for setting foreground colour. */ 2241 static void 2242 input_osc_10(struct window_pane *wp, const char *p) 2243 { 2244 u_int r, g, b; 2245 2246 if (sscanf(p, "rgb:%2x/%2x/%2x", &r, &g, &b) != 3) 2247 goto bad; 2248 2249 wp->colgc.fg = colour_join_rgb(r, g, b); 2250 wp->flags |= PANE_REDRAW; 2251 2252 return; 2253 2254 bad: 2255 log_debug("bad OSC 10: %s", p); 2256 } 2257 2258 /* Handle the OSC 11 sequence for setting background colour. */ 2259 static void 2260 input_osc_11(struct window_pane *wp, const char *p) 2261 { 2262 u_int r, g, b; 2263 2264 if (sscanf(p, "rgb:%2x/%2x/%2x", &r, &g, &b) != 3) 2265 goto bad; 2266 2267 wp->colgc.bg = colour_join_rgb(r, g, b); 2268 wp->flags |= PANE_REDRAW; 2269 2270 return; 2271 2272 bad: 2273 log_debug("bad OSC 11: %s", p); 2274 } 2275 2276 /* Handle the OSC 52 sequence for setting the clipboard. */ 2277 static void 2278 input_osc_52(struct window_pane *wp, const char *p) 2279 { 2280 char *end; 2281 size_t len; 2282 u_char *out; 2283 int outlen, state; 2284 struct screen_write_ctx ctx; 2285 2286 state = options_get_number(global_options, "set-clipboard"); 2287 if (state != 2) 2288 return; 2289 2290 if ((end = strchr(p, ';')) == NULL) 2291 return; 2292 end++; 2293 if (*end == '\0') 2294 return; 2295 2296 len = (strlen(end) / 4) * 3; 2297 if (len == 0) 2298 return; 2299 2300 out = xmalloc(len); 2301 if ((outlen = b64_pton(end, out, len)) == -1) { 2302 free(out); 2303 return; 2304 } 2305 2306 screen_write_start(&ctx, wp, NULL); 2307 screen_write_setselection(&ctx, out, outlen); 2308 screen_write_stop(&ctx); 2309 notify_pane("pane-set-clipboard", wp); 2310 2311 paste_add((char *)out, outlen); 2312 } 2313 2314 /* Handle the OSC 104 sequence for unsetting (multiple) palette entries. */ 2315 static void 2316 input_osc_104(struct window_pane *wp, const char *p) 2317 { 2318 char *copy, *s; 2319 long idx; 2320 2321 if (*p == '\0') { 2322 window_pane_reset_palette(wp); 2323 return; 2324 } 2325 2326 copy = s = xstrdup(p); 2327 while (*s != '\0') { 2328 idx = strtol(s, &s, 10); 2329 if (*s != '\0' && *s != ';') 2330 goto bad; 2331 if (idx < 0 || idx >= 0x100) 2332 goto bad; 2333 2334 window_pane_unset_palette(wp, idx); 2335 if (*s == ';') 2336 s++; 2337 } 2338 free(copy); 2339 return; 2340 2341 bad: 2342 log_debug("bad OSC 104: %s", p); 2343 free(copy); 2344 } 2345