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