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