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