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