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