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