Add \033[s and \033[u to save and restore cursor position.
[tmux-openbsd.git] / input.c
blobed1f87605af1af539b4e30c2e0bf419263fedc85
1 /* $OpenBSD$ */
3 /*
4 * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
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.
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.
19 #include <sys/types.h>
21 #include <stdlib.h>
22 #include <string.h>
24 #include "tmux.h"
27 * Based on the description by Paul Williams at:
29 * http://vt100.net/emu/dec_ansi_parser
31 * With the following changes:
33 * - 7-bit only.
35 * - Support for UTF-8.
37 * - OSC (but not APC) may be terminated by \007 as well as ST.
39 * - A state for APC similar to OSC. Some terminals appear to use this to set
40 * the title.
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.
45 * - Special handling for ESC inside a DCS to allow arbitrary byte sequences to
46 * be passed to the underlying teminal(s).
49 /* Helper functions. */
50 int input_split(struct input_ctx *);
51 int input_get(struct input_ctx *, u_int, int, int);
52 void input_reply(struct input_ctx *, const char *, ...);
54 /* Transition entry/exit handlers. */
55 void input_clear(struct input_ctx *);
56 void input_enter_osc(struct input_ctx *);
57 void input_exit_osc(struct input_ctx *);
58 void input_enter_apc(struct input_ctx *);
59 void input_exit_apc(struct input_ctx *);
60 void input_enter_rename(struct input_ctx *);
61 void input_exit_rename(struct input_ctx *);
63 /* Input state handlers. */
64 int input_print(struct input_ctx *);
65 int input_intermediate(struct input_ctx *);
66 int input_parameter(struct input_ctx *);
67 int input_input(struct input_ctx *);
68 int input_c0_dispatch(struct input_ctx *);
69 int input_esc_dispatch(struct input_ctx *);
70 int input_csi_dispatch(struct input_ctx *);
71 void input_csi_dispatch_sgr(struct input_ctx *);
72 int input_dcs_dispatch(struct input_ctx *);
73 int input_utf8_open(struct input_ctx *);
74 int input_utf8_add(struct input_ctx *);
75 int input_utf8_close(struct input_ctx *);
77 /* Command table comparison function. */
78 int input_table_compare(const void *, const void *);
80 /* Command table entry. */
81 struct input_table_entry {
82 int ch;
83 const char *interm;
84 int type;
87 /* Escape commands. */
88 enum input_esc_type {
89 INPUT_ESC_DECALN,
90 INPUT_ESC_DECKPAM,
91 INPUT_ESC_DECKPNM,
92 INPUT_ESC_DECRC,
93 INPUT_ESC_DECSC,
94 INPUT_ESC_HTS,
95 INPUT_ESC_IND,
96 INPUT_ESC_NEL,
97 INPUT_ESC_RI,
98 INPUT_ESC_RIS,
99 INPUT_ESC_SCSOFF_G0,
100 INPUT_ESC_SCSON_G0,
103 /* Escape command table. */
104 const struct input_table_entry input_esc_table[] = {
105 { '0', "(", INPUT_ESC_SCSOFF_G0 },
106 { '7', "", INPUT_ESC_DECSC },
107 { '8', "", INPUT_ESC_DECRC },
108 { '8', "#", INPUT_ESC_DECALN },
109 { '=', "", INPUT_ESC_DECKPAM },
110 { '>', "", INPUT_ESC_DECKPNM },
111 { 'B', "(", INPUT_ESC_SCSON_G0 },
112 { 'D', "", INPUT_ESC_IND },
113 { 'E', "", INPUT_ESC_NEL },
114 { 'H', "", INPUT_ESC_HTS },
115 { 'M', "", INPUT_ESC_RI },
116 { 'c', "", INPUT_ESC_RIS },
119 /* Control (CSI) commands. */
120 enum input_csi_type {
121 INPUT_CSI_CBT,
122 INPUT_CSI_CUB,
123 INPUT_CSI_CUD,
124 INPUT_CSI_CUF,
125 INPUT_CSI_CUP,
126 INPUT_CSI_CUU,
127 INPUT_CSI_DA,
128 INPUT_CSI_DCH,
129 INPUT_CSI_DECSCUSR,
130 INPUT_CSI_DECSTBM,
131 INPUT_CSI_DL,
132 INPUT_CSI_DSR,
133 INPUT_CSI_ED,
134 INPUT_CSI_EL,
135 INPUT_CSI_HPA,
136 INPUT_CSI_ICH,
137 INPUT_CSI_IL,
138 INPUT_CSI_RCP,
139 INPUT_CSI_RM,
140 INPUT_CSI_RM_PRIVATE,
141 INPUT_CSI_SCP,
142 INPUT_CSI_SGR,
143 INPUT_CSI_SM,
144 INPUT_CSI_SM_PRIVATE,
145 INPUT_CSI_TBC,
146 INPUT_CSI_VPA,
149 /* Control (CSI) command table. */
150 const struct input_table_entry input_csi_table[] = {
151 { '@', "", INPUT_CSI_ICH },
152 { 'A', "", INPUT_CSI_CUU },
153 { 'B', "", INPUT_CSI_CUD },
154 { 'C', "", INPUT_CSI_CUF },
155 { 'D', "", INPUT_CSI_CUB },
156 { 'G', "", INPUT_CSI_HPA },
157 { 'H', "", INPUT_CSI_CUP },
158 { 'J', "", INPUT_CSI_ED },
159 { 'K', "", INPUT_CSI_EL },
160 { 'L', "", INPUT_CSI_IL },
161 { 'M', "", INPUT_CSI_DL },
162 { 'P', "", INPUT_CSI_DCH },
163 { 'Z', "", INPUT_CSI_CBT },
164 { 'c', "", INPUT_CSI_DA },
165 { 'd', "", INPUT_CSI_VPA },
166 { 'f', "", INPUT_CSI_CUP },
167 { 'g', "", INPUT_CSI_TBC },
168 { 'h', "", INPUT_CSI_SM },
169 { 'h', "?", INPUT_CSI_SM_PRIVATE },
170 { 'l', "", INPUT_CSI_RM },
171 { 'l', "?", INPUT_CSI_RM_PRIVATE },
172 { 'm', "", INPUT_CSI_SGR },
173 { 'n', "", INPUT_CSI_DSR },
174 { 'q', " ", INPUT_CSI_DECSCUSR },
175 { 'r', "", INPUT_CSI_DECSTBM },
176 { 's', "", INPUT_CSI_SCP },
177 { 'u', "", INPUT_CSI_RCP },
180 /* Input transition. */
181 struct input_transition {
182 int first;
183 int last;
185 int (*handler)(struct input_ctx *);
186 const struct input_state *state;
189 /* Input state. */
190 struct input_state {
191 const char *name;
192 void (*enter)(struct input_ctx *);
193 void (*exit)(struct input_ctx *);
194 const struct input_transition *transitions;
197 /* State transitions available from all states. */
198 #define INPUT_STATE_ANYWHERE \
199 { 0x18, 0x18, input_c0_dispatch, &input_state_ground }, \
200 { 0x1a, 0x1a, input_c0_dispatch, &input_state_ground }, \
201 { 0x1b, 0x1b, NULL, &input_state_esc_enter }
203 /* Forward declarations of state tables. */
204 const struct input_transition input_state_ground_table[];
205 const struct input_transition input_state_esc_enter_table[];
206 const struct input_transition input_state_esc_intermediate_table[];
207 const struct input_transition input_state_csi_enter_table[];
208 const struct input_transition input_state_csi_parameter_table[];
209 const struct input_transition input_state_csi_intermediate_table[];
210 const struct input_transition input_state_csi_ignore_table[];
211 const struct input_transition input_state_dcs_enter_table[];
212 const struct input_transition input_state_dcs_parameter_table[];
213 const struct input_transition input_state_dcs_intermediate_table[];
214 const struct input_transition input_state_dcs_handler_table[];
215 const struct input_transition input_state_dcs_escape_table[];
216 const struct input_transition input_state_dcs_ignore_table[];
217 const struct input_transition input_state_osc_string_table[];
218 const struct input_transition input_state_apc_string_table[];
219 const struct input_transition input_state_rename_string_table[];
220 const struct input_transition input_state_consume_st_table[];
221 const struct input_transition input_state_utf8_three_table[];
222 const struct input_transition input_state_utf8_two_table[];
223 const struct input_transition input_state_utf8_one_table[];
225 /* ground state definition. */
226 const struct input_state input_state_ground = {
227 "ground",
228 NULL, NULL,
229 input_state_ground_table
232 /* esc_enter state definition. */
233 const struct input_state input_state_esc_enter = {
234 "esc_enter",
235 input_clear, NULL,
236 input_state_esc_enter_table
239 /* esc_intermediate state definition. */
240 const struct input_state input_state_esc_intermediate = {
241 "esc_intermediate",
242 NULL, NULL,
243 input_state_esc_intermediate_table
246 /* csi_enter state definition. */
247 const struct input_state input_state_csi_enter = {
248 "csi_enter",
249 input_clear, NULL,
250 input_state_csi_enter_table
253 /* csi_parameter state definition. */
254 const struct input_state input_state_csi_parameter = {
255 "csi_parameter",
256 NULL, NULL,
257 input_state_csi_parameter_table
260 /* csi_intermediate state definition. */
261 const struct input_state input_state_csi_intermediate = {
262 "csi_intermediate",
263 NULL, NULL,
264 input_state_csi_intermediate_table
267 /* csi_ignore state definition. */
268 const struct input_state input_state_csi_ignore = {
269 "csi_ignore",
270 NULL, NULL,
271 input_state_csi_ignore_table
274 /* dcs_enter state definition. */
275 const struct input_state input_state_dcs_enter = {
276 "dcs_enter",
277 input_clear, NULL,
278 input_state_dcs_enter_table
281 /* dcs_parameter state definition. */
282 const struct input_state input_state_dcs_parameter = {
283 "dcs_parameter",
284 NULL, NULL,
285 input_state_dcs_parameter_table
288 /* dcs_intermediate state definition. */
289 const struct input_state input_state_dcs_intermediate = {
290 "dcs_intermediate",
291 NULL, NULL,
292 input_state_dcs_intermediate_table
295 /* dcs_handler state definition. */
296 const struct input_state input_state_dcs_handler = {
297 "dcs_handler",
298 NULL, NULL,
299 input_state_dcs_handler_table
302 /* dcs_escape state definition. */
303 const struct input_state input_state_dcs_escape = {
304 "dcs_escape",
305 NULL, NULL,
306 input_state_dcs_escape_table
309 /* dcs_ignore state definition. */
310 const struct input_state input_state_dcs_ignore = {
311 "dcs_ignore",
312 NULL, NULL,
313 input_state_dcs_ignore_table
316 /* osc_string state definition. */
317 const struct input_state input_state_osc_string = {
318 "osc_string",
319 input_enter_osc, input_exit_osc,
320 input_state_osc_string_table
323 /* apc_string state definition. */
324 const struct input_state input_state_apc_string = {
325 "apc_string",
326 input_enter_apc, input_exit_apc,
327 input_state_apc_string_table
330 /* rename_string state definition. */
331 const struct input_state input_state_rename_string = {
332 "rename_string",
333 input_enter_rename, input_exit_rename,
334 input_state_rename_string_table
337 /* consume_st state definition. */
338 const struct input_state input_state_consume_st = {
339 "consume_st",
340 NULL, NULL,
341 input_state_consume_st_table
344 /* utf8_three state definition. */
345 const struct input_state input_state_utf8_three = {
346 "utf8_three",
347 NULL, NULL,
348 input_state_utf8_three_table
351 /* utf8_two state definition. */
352 const struct input_state input_state_utf8_two = {
353 "utf8_two",
354 NULL, NULL,
355 input_state_utf8_two_table
358 /* utf8_one state definition. */
359 const struct input_state input_state_utf8_one = {
360 "utf8_one",
361 NULL, NULL,
362 input_state_utf8_one_table
365 /* ground state table. */
366 const struct input_transition input_state_ground_table[] = {
367 INPUT_STATE_ANYWHERE,
369 { 0x00, 0x17, input_c0_dispatch, NULL },
370 { 0x19, 0x19, input_c0_dispatch, NULL },
371 { 0x1c, 0x1f, input_c0_dispatch, NULL },
372 { 0x20, 0x7e, input_print, NULL },
373 { 0x7f, 0x7f, NULL, NULL },
374 { 0x80, 0xc1, input_print, NULL },
375 { 0xc2, 0xdf, input_utf8_open, &input_state_utf8_one },
376 { 0xe0, 0xef, input_utf8_open, &input_state_utf8_two },
377 { 0xf0, 0xf4, input_utf8_open, &input_state_utf8_three },
378 { 0xf5, 0xff, input_print, NULL },
380 { -1, -1, NULL, NULL }
383 /* esc_enter state table. */
384 const struct input_transition input_state_esc_enter_table[] = {
385 INPUT_STATE_ANYWHERE,
387 { 0x00, 0x17, input_c0_dispatch, NULL },
388 { 0x19, 0x19, input_c0_dispatch, NULL },
389 { 0x1c, 0x1f, input_c0_dispatch, NULL },
390 { 0x20, 0x2f, input_intermediate, &input_state_esc_intermediate },
391 { 0x30, 0x4f, input_esc_dispatch, &input_state_ground },
392 { 0x50, 0x50, NULL, &input_state_dcs_enter },
393 { 0x51, 0x57, input_esc_dispatch, &input_state_ground },
394 { 0x58, 0x58, NULL, &input_state_consume_st },
395 { 0x59, 0x59, input_esc_dispatch, &input_state_ground },
396 { 0x5a, 0x5a, input_esc_dispatch, &input_state_ground },
397 { 0x5b, 0x5b, NULL, &input_state_csi_enter },
398 { 0x5c, 0x5c, input_esc_dispatch, &input_state_ground },
399 { 0x5d, 0x5d, NULL, &input_state_osc_string },
400 { 0x5e, 0x5e, NULL, &input_state_consume_st },
401 { 0x5f, 0x5f, NULL, &input_state_apc_string },
402 { 0x60, 0x6a, input_esc_dispatch, &input_state_ground },
403 { 0x6b, 0x6b, NULL, &input_state_rename_string },
404 { 0x6c, 0x7e, input_esc_dispatch, &input_state_ground },
405 { 0x7f, 0xff, NULL, NULL },
407 { -1, -1, NULL, NULL }
410 /* esc_interm state table. */
411 const struct input_transition input_state_esc_intermediate_table[] = {
412 INPUT_STATE_ANYWHERE,
414 { 0x00, 0x17, input_c0_dispatch, NULL },
415 { 0x19, 0x19, input_c0_dispatch, NULL },
416 { 0x1c, 0x1f, input_c0_dispatch, NULL },
417 { 0x20, 0x2f, input_intermediate, NULL },
418 { 0x30, 0x7e, input_esc_dispatch, &input_state_ground },
419 { 0x7f, 0xff, NULL, NULL },
421 { -1, -1, NULL, NULL }
424 /* csi_enter state table. */
425 const struct input_transition input_state_csi_enter_table[] = {
426 INPUT_STATE_ANYWHERE,
428 { 0x00, 0x17, input_c0_dispatch, NULL },
429 { 0x19, 0x19, input_c0_dispatch, NULL },
430 { 0x1c, 0x1f, input_c0_dispatch, NULL },
431 { 0x20, 0x2f, input_intermediate, &input_state_csi_intermediate },
432 { 0x30, 0x39, input_parameter, &input_state_csi_parameter },
433 { 0x3a, 0x3a, NULL, &input_state_csi_ignore },
434 { 0x3b, 0x3b, input_parameter, &input_state_csi_parameter },
435 { 0x3c, 0x3f, input_intermediate, &input_state_csi_parameter },
436 { 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
437 { 0x7f, 0xff, NULL, NULL },
439 { -1, -1, NULL, NULL }
442 /* csi_parameter state table. */
443 const struct input_transition input_state_csi_parameter_table[] = {
444 INPUT_STATE_ANYWHERE,
446 { 0x00, 0x17, input_c0_dispatch, NULL },
447 { 0x19, 0x19, input_c0_dispatch, NULL },
448 { 0x1c, 0x1f, input_c0_dispatch, NULL },
449 { 0x20, 0x2f, input_intermediate, &input_state_csi_intermediate },
450 { 0x30, 0x39, input_parameter, NULL },
451 { 0x3a, 0x3a, NULL, &input_state_csi_ignore },
452 { 0x3b, 0x3b, input_parameter, NULL },
453 { 0x3c, 0x3f, NULL, &input_state_csi_ignore },
454 { 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
455 { 0x7f, 0xff, NULL, NULL },
457 { -1, -1, NULL, NULL }
460 /* csi_intermediate state table. */
461 const struct input_transition input_state_csi_intermediate_table[] = {
462 INPUT_STATE_ANYWHERE,
464 { 0x00, 0x17, input_c0_dispatch, NULL },
465 { 0x19, 0x19, input_c0_dispatch, NULL },
466 { 0x1c, 0x1f, input_c0_dispatch, NULL },
467 { 0x20, 0x2f, input_intermediate, NULL },
468 { 0x30, 0x3f, NULL, &input_state_csi_ignore },
469 { 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
470 { 0x7f, 0xff, NULL, NULL },
472 { -1, -1, NULL, NULL }
475 /* csi_ignore state table. */
476 const struct input_transition input_state_csi_ignore_table[] = {
477 INPUT_STATE_ANYWHERE,
479 { 0x00, 0x17, input_c0_dispatch, NULL },
480 { 0x19, 0x19, input_c0_dispatch, NULL },
481 { 0x1c, 0x1f, input_c0_dispatch, NULL },
482 { 0x20, 0x3f, NULL, NULL },
483 { 0x40, 0x7e, NULL, &input_state_ground },
484 { 0x7f, 0xff, NULL, NULL },
486 { -1, -1, NULL, NULL }
489 /* dcs_enter state table. */
490 const struct input_transition input_state_dcs_enter_table[] = {
491 INPUT_STATE_ANYWHERE,
493 { 0x00, 0x17, NULL, NULL },
494 { 0x19, 0x19, NULL, NULL },
495 { 0x1c, 0x1f, NULL, NULL },
496 { 0x20, 0x2f, input_intermediate, &input_state_dcs_intermediate },
497 { 0x30, 0x39, input_parameter, &input_state_dcs_parameter },
498 { 0x3a, 0x3a, NULL, &input_state_dcs_ignore },
499 { 0x3b, 0x3b, input_parameter, &input_state_dcs_parameter },
500 { 0x3c, 0x3f, input_intermediate, &input_state_dcs_parameter },
501 { 0x40, 0x7e, input_input, &input_state_dcs_handler },
502 { 0x7f, 0xff, NULL, NULL },
504 { -1, -1, NULL, NULL }
507 /* dcs_parameter state table. */
508 const struct input_transition input_state_dcs_parameter_table[] = {
509 INPUT_STATE_ANYWHERE,
511 { 0x00, 0x17, NULL, NULL },
512 { 0x19, 0x19, NULL, NULL },
513 { 0x1c, 0x1f, NULL, NULL },
514 { 0x20, 0x2f, input_intermediate, &input_state_dcs_intermediate },
515 { 0x30, 0x39, input_parameter, NULL },
516 { 0x3a, 0x3a, NULL, &input_state_dcs_ignore },
517 { 0x3b, 0x3b, input_parameter, NULL },
518 { 0x3c, 0x3f, NULL, &input_state_dcs_ignore },
519 { 0x40, 0x7e, input_input, &input_state_dcs_handler },
520 { 0x7f, 0xff, NULL, NULL },
522 { -1, -1, NULL, NULL }
525 /* dcs_interm state table. */
526 const struct input_transition input_state_dcs_intermediate_table[] = {
527 INPUT_STATE_ANYWHERE,
529 { 0x00, 0x17, NULL, NULL },
530 { 0x19, 0x19, NULL, NULL },
531 { 0x1c, 0x1f, NULL, NULL },
532 { 0x20, 0x2f, input_intermediate, NULL },
533 { 0x30, 0x3f, NULL, &input_state_dcs_ignore },
534 { 0x40, 0x7e, input_input, &input_state_dcs_handler },
535 { 0x7f, 0xff, NULL, NULL },
537 { -1, -1, NULL, NULL }
540 /* dcs_handler state table. */
541 const struct input_transition input_state_dcs_handler_table[] = {
542 /* No INPUT_STATE_ANYWHERE */
544 { 0x00, 0x1a, input_input, NULL },
545 { 0x1b, 0x1b, NULL, &input_state_dcs_escape },
546 { 0x1c, 0xff, input_input, NULL },
548 { -1, -1, NULL, NULL }
551 /* dcs_escape state table. */
552 const struct input_transition input_state_dcs_escape_table[] = {
553 /* No INPUT_STATE_ANYWHERE */
555 { 0x00, 0x5b, input_input, &input_state_dcs_handler },
556 { 0x5c, 0x5c, input_dcs_dispatch, &input_state_ground },
557 { 0x5d, 0xff, input_input, &input_state_dcs_handler },
559 { -1, -1, NULL, NULL }
562 /* dcs_ignore state table. */
563 const struct input_transition input_state_dcs_ignore_table[] = {
564 INPUT_STATE_ANYWHERE,
566 { 0x00, 0x17, NULL, NULL },
567 { 0x19, 0x19, NULL, NULL },
568 { 0x1c, 0x1f, NULL, NULL },
569 { 0x20, 0xff, NULL, NULL },
571 { -1, -1, NULL, NULL }
574 /* osc_string state table. */
575 const struct input_transition input_state_osc_string_table[] = {
576 INPUT_STATE_ANYWHERE,
578 { 0x00, 0x06, NULL, NULL },
579 { 0x07, 0x07, NULL, &input_state_ground },
580 { 0x08, 0x17, NULL, NULL },
581 { 0x19, 0x19, NULL, NULL },
582 { 0x1c, 0x1f, NULL, NULL },
583 { 0x20, 0xff, input_input, NULL },
585 { -1, -1, NULL, NULL }
588 /* apc_string state table. */
589 const struct input_transition input_state_apc_string_table[] = {
590 INPUT_STATE_ANYWHERE,
592 { 0x00, 0x17, NULL, NULL },
593 { 0x19, 0x19, NULL, NULL },
594 { 0x1c, 0x1f, NULL, NULL },
595 { 0x20, 0xff, input_input, NULL },
597 { -1, -1, NULL, NULL }
600 /* rename_string state table. */
601 const struct input_transition input_state_rename_string_table[] = {
602 INPUT_STATE_ANYWHERE,
604 { 0x00, 0x17, NULL, NULL },
605 { 0x19, 0x19, NULL, NULL },
606 { 0x1c, 0x1f, NULL, NULL },
607 { 0x20, 0xff, input_input, NULL },
609 { -1, -1, NULL, NULL }
612 /* consume_st state table. */
613 const struct input_transition input_state_consume_st_table[] = {
614 INPUT_STATE_ANYWHERE,
616 { 0x00, 0x17, NULL, NULL },
617 { 0x19, 0x19, NULL, NULL },
618 { 0x1c, 0x1f, NULL, NULL },
619 { 0x20, 0xff, NULL, NULL },
621 { -1, -1, NULL, NULL }
624 /* utf8_three state table. */
625 const struct input_transition input_state_utf8_three_table[] = {
626 /* No INPUT_STATE_ANYWHERE */
628 { 0x00, 0x7f, NULL, &input_state_ground },
629 { 0x80, 0xbf, input_utf8_add, &input_state_utf8_two },
630 { 0xc0, 0xff, NULL, &input_state_ground },
632 { -1, -1, NULL, NULL }
635 /* utf8_two state table. */
636 const struct input_transition input_state_utf8_two_table[] = {
637 /* No INPUT_STATE_ANYWHERE */
639 { 0x00, 0x7f, NULL, &input_state_ground },
640 { 0x80, 0xbf, input_utf8_add, &input_state_utf8_one },
641 { 0xc0, 0xff, NULL, &input_state_ground },
643 { -1, -1, NULL, NULL }
646 /* utf8_one state table. */
647 const struct input_transition input_state_utf8_one_table[] = {
648 /* No INPUT_STATE_ANYWHERE */
650 { 0x00, 0x7f, NULL, &input_state_ground },
651 { 0x80, 0xbf, input_utf8_close, &input_state_ground },
652 { 0xc0, 0xff, NULL, &input_state_ground },
654 { -1, -1, NULL, NULL }
657 /* Input table compare. */
659 input_table_compare(const void *key, const void *value)
661 const struct input_ctx *ictx = key;
662 const struct input_table_entry *entry = value;
664 if (ictx->ch != entry->ch)
665 return (ictx->ch - entry->ch);
666 return (strcmp(ictx->interm_buf, entry->interm));
669 /* Initialise input parser. */
670 void
671 input_init(struct window_pane *wp)
673 struct input_ctx *ictx = &wp->ictx;
675 memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell);
677 memcpy(&ictx->old_cell, &grid_default_cell, sizeof ictx->old_cell);
678 ictx->old_cx = 0;
679 ictx->old_cy = 0;
681 *ictx->interm_buf = '\0';
682 ictx->interm_len = 0;
684 *ictx->param_buf = '\0';
685 ictx->param_len = 0;
687 ictx->state = &input_state_ground;
688 ictx->flags = 0;
691 /* Destroy input parser. */
692 void
693 input_free(unused struct window_pane *wp)
697 /* Parse input. */
698 void
699 input_parse(struct window_pane *wp)
701 struct input_ctx *ictx = &wp->ictx;
702 const struct input_transition *itr;
703 struct evbuffer *evb = wp->event->input;
704 u_char *buf;
705 size_t len, off;
707 if (EVBUFFER_LENGTH(evb) == 0)
708 return;
710 wp->window->flags |= WINDOW_ACTIVITY;
711 wp->window->flags &= ~WINDOW_SILENCE;
714 * Open the screen. Use NULL wp if there is a mode set as don't want to
715 * update the tty.
717 if (wp->mode == NULL)
718 screen_write_start(&ictx->ctx, wp, &wp->base);
719 else
720 screen_write_start(&ictx->ctx, NULL, &wp->base);
721 ictx->wp = wp;
723 buf = EVBUFFER_DATA(evb);
724 len = EVBUFFER_LENGTH(evb);
725 off = 0;
727 /* Parse the input. */
728 while (off < len) {
729 ictx->ch = buf[off++];
730 log_debug("%s: '%c' %s", __func__, ictx->ch, ictx->state->name);
732 /* Find the transition. */
733 itr = ictx->state->transitions;
734 while (itr->first != -1 && itr->last != -1) {
735 if (ictx->ch >= itr->first && ictx->ch <= itr->last)
736 break;
737 itr++;
739 if (itr->first == -1 || itr->last == -1) {
740 /* No transition? Eh? */
741 fatalx("No transition from state!");
745 * Execute the handler, if any. Don't switch state if it
746 * returns non-zero.
748 if (itr->handler != NULL && itr->handler(ictx) != 0)
749 continue;
751 /* And switch state, if necessary. */
752 if (itr->state != NULL) {
753 if (ictx->state->exit != NULL)
754 ictx->state->exit(ictx);
755 ictx->state = itr->state;
756 if (ictx->state->enter != NULL)
757 ictx->state->enter(ictx);
761 /* Close the screen. */
762 screen_write_stop(&ictx->ctx);
764 evbuffer_drain(evb, len);
767 /* Split the parameter list (if any). */
769 input_split(struct input_ctx *ictx)
772 const char *errstr;
773 char *ptr, *out;
774 int n;
776 ictx->param_list_len = 0;
777 if (ictx->param_len == 0)
778 return (0);
780 ptr = ictx->param_buf;
781 while ((out = strsep(&ptr, ";")) != NULL) {
782 if (*out == '\0')
783 n = -1;
784 else {
785 n = strtonum(out, 0, INT_MAX, &errstr);
786 if (errstr != NULL)
787 return (-1);
790 ictx->param_list[ictx->param_list_len++] = n;
791 if (ictx->param_list_len == nitems(ictx->param_list))
792 return (-1);
795 return (0);
798 /* Get an argument or return default value. */
800 input_get(struct input_ctx *ictx, u_int validx, int minval, int defval)
802 int retval;
804 if (validx >= ictx->param_list_len)
805 return (defval);
807 retval = ictx->param_list[validx];
808 if (retval == -1)
809 return (defval);
810 if (retval < minval)
811 return (minval);
812 return (retval);
815 /* Reply to terminal query. */
816 void
817 input_reply(struct input_ctx *ictx, const char *fmt, ...)
819 va_list ap;
820 char *reply;
822 va_start(ap, fmt);
823 vasprintf(&reply, fmt, ap);
824 va_end(ap);
826 bufferevent_write(ictx->wp->event, reply, strlen(reply));
827 xfree(reply);
830 /* Clear saved state. */
831 void
832 input_clear(struct input_ctx *ictx)
834 *ictx->interm_buf = '\0';
835 ictx->interm_len = 0;
837 *ictx->param_buf = '\0';
838 ictx->param_len = 0;
840 *ictx->input_buf = '\0';
841 ictx->input_len = 0;
843 ictx->flags &= ~INPUT_DISCARD;
846 /* Output this character to the screen. */
848 input_print(struct input_ctx *ictx)
850 ictx->cell.data = ictx->ch;
851 screen_write_cell(&ictx->ctx, &ictx->cell, NULL);
853 return (0);
856 /* Collect intermediate string. */
858 input_intermediate(struct input_ctx *ictx)
860 if (ictx->interm_len == (sizeof ictx->interm_buf) - 1)
861 ictx->flags |= INPUT_DISCARD;
862 else {
863 ictx->interm_buf[ictx->interm_len++] = ictx->ch;
864 ictx->interm_buf[ictx->interm_len] = '\0';
867 return (0);
870 /* Collect parameter string. */
872 input_parameter(struct input_ctx *ictx)
874 if (ictx->param_len == (sizeof ictx->param_buf) - 1)
875 ictx->flags |= INPUT_DISCARD;
876 else {
877 ictx->param_buf[ictx->param_len++] = ictx->ch;
878 ictx->param_buf[ictx->param_len] = '\0';
881 return (0);
884 /* Collect input string. */
886 input_input(struct input_ctx *ictx)
888 if (ictx->input_len == (sizeof ictx->input_buf) - 1)
889 ictx->flags |= INPUT_DISCARD;
890 else {
891 ictx->input_buf[ictx->input_len++] = ictx->ch;
892 ictx->input_buf[ictx->input_len] = '\0';
895 return (0);
898 /* Execute C0 control sequence. */
900 input_c0_dispatch(struct input_ctx *ictx)
902 struct screen_write_ctx *sctx = &ictx->ctx;
903 struct window_pane *wp = ictx->wp;
904 struct screen *s = sctx->s;
906 log_debug("%s: '%c", __func__, ictx->ch);
908 switch (ictx->ch) {
909 case '\000': /* NUL */
910 break;
911 case '\007': /* BEL */
912 wp->window->flags |= WINDOW_BELL;
913 break;
914 case '\010': /* BS */
915 screen_write_backspace(sctx);
916 break;
917 case '\011': /* HT */
918 /* Don't tab beyond the end of the line. */
919 if (s->cx >= screen_size_x(s) - 1)
920 break;
922 /* Find the next tab point, or use the last column if none. */
923 do {
924 s->cx++;
925 if (bit_test(s->tabs, s->cx))
926 break;
927 } while (s->cx < screen_size_x(s) - 1);
928 break;
929 case '\012': /* LF */
930 case '\013': /* VT */
931 case '\014': /* FF */
932 screen_write_linefeed(sctx, 0);
933 break;
934 case '\015': /* CR */
935 screen_write_carriagereturn(sctx);
936 break;
937 case '\016': /* SO */
938 ictx->cell.attr |= GRID_ATTR_CHARSET;
939 break;
940 case '\017': /* SI */
941 ictx->cell.attr &= ~GRID_ATTR_CHARSET;
942 break;
943 default:
944 log_debug("%s: unknown '%c'", __func__, ictx->ch);
945 break;
948 return (0);
951 /* Execute escape sequence. */
953 input_esc_dispatch(struct input_ctx *ictx)
955 struct screen_write_ctx *sctx = &ictx->ctx;
956 struct screen *s = sctx->s;
957 struct input_table_entry *entry;
959 if (ictx->flags & INPUT_DISCARD)
960 return (0);
961 log_debug("%s: '%c', %s", __func__, ictx->ch, ictx->interm_buf);
963 entry = bsearch(ictx, input_esc_table, nitems(input_esc_table),
964 sizeof input_esc_table[0], input_table_compare);
965 if (entry == NULL) {
966 log_debug("%s: unknown '%c'", __func__, ictx->ch);
967 return (0);
970 switch (entry->type) {
971 case INPUT_ESC_RIS:
972 memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell);
973 memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
974 ictx->old_cx = 0;
975 ictx->old_cy = 0;
977 screen_reset_tabs(sctx->s);
979 screen_write_scrollregion(sctx, 0, screen_size_y(sctx->s) - 1);
981 screen_write_insertmode(sctx, 0);
982 screen_write_kcursormode(sctx, 0);
983 screen_write_kkeypadmode(sctx, 0);
984 screen_write_mousemode_off(sctx);
986 screen_write_clearscreen(sctx);
987 screen_write_cursormove(sctx, 0, 0);
988 break;
989 case INPUT_ESC_IND:
990 screen_write_linefeed(sctx, 0);
991 break;
992 case INPUT_ESC_NEL:
993 screen_write_carriagereturn(sctx);
994 screen_write_linefeed(sctx, 0);
995 break;
996 case INPUT_ESC_HTS:
997 if (s->cx < screen_size_x(s))
998 bit_set(s->tabs, s->cx);
999 break;
1000 case INPUT_ESC_RI:
1001 screen_write_reverseindex(sctx);
1002 break;
1003 case INPUT_ESC_DECKPAM:
1004 screen_write_kkeypadmode(sctx, 1);
1005 break;
1006 case INPUT_ESC_DECKPNM:
1007 screen_write_kkeypadmode(sctx, 0);
1008 break;
1009 case INPUT_ESC_DECSC:
1010 memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
1011 ictx->old_cx = s->cx;
1012 ictx->old_cy = s->cy;
1013 break;
1014 case INPUT_ESC_DECRC:
1015 memcpy(&ictx->cell, &ictx->old_cell, sizeof ictx->cell);
1016 screen_write_cursormove(sctx, ictx->old_cx, ictx->old_cy);
1017 break;
1018 case INPUT_ESC_DECALN:
1019 screen_write_alignmenttest(sctx);
1020 break;
1021 case INPUT_ESC_SCSON_G0:
1023 * Not really supported, but fake it up enough for those that
1024 * use it to switch character sets (by redefining G0 to
1025 * graphics set, rather than switching to G1).
1027 ictx->cell.attr &= ~GRID_ATTR_CHARSET;
1028 break;
1029 case INPUT_ESC_SCSOFF_G0:
1030 ictx->cell.attr |= GRID_ATTR_CHARSET;
1031 break;
1034 return (0);
1037 /* Execute control sequence. */
1039 input_csi_dispatch(struct input_ctx *ictx)
1041 struct screen_write_ctx *sctx = &ictx->ctx;
1042 struct window_pane *wp = ictx->wp;
1043 struct screen *s = sctx->s;
1044 struct input_table_entry *entry;
1045 int n, m;
1047 if (ictx->flags & INPUT_DISCARD)
1048 return (0);
1049 if (input_split(ictx) != 0)
1050 return (0);
1051 log_debug("%s: '%c' \"%s\" \"%s\"",
1052 __func__, ictx->ch, ictx->interm_buf, ictx->param_buf);
1054 entry = bsearch(ictx, input_csi_table, nitems(input_csi_table),
1055 sizeof input_csi_table[0], input_table_compare);
1056 if (entry == NULL) {
1057 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1058 return (0);
1061 switch (entry->type) {
1062 case INPUT_CSI_CBT:
1063 /* Find the previous tab point, n times. */
1064 n = input_get(ictx, 0, 1, 1);
1065 while (s->cx > 0 && n-- > 0) {
1067 s->cx--;
1068 while (s->cx > 0 && !bit_test(s->tabs, s->cx));
1070 break;
1071 case INPUT_CSI_CUB:
1072 screen_write_cursorleft(sctx, input_get(ictx, 0, 1, 1));
1073 break;
1074 case INPUT_CSI_CUD:
1075 screen_write_cursordown(sctx, input_get(ictx, 0, 1, 1));
1076 break;
1077 case INPUT_CSI_CUF:
1078 screen_write_cursorright(sctx, input_get(ictx, 0, 1, 1));
1079 break;
1080 case INPUT_CSI_CUP:
1081 n = input_get(ictx, 0, 1, 1);
1082 m = input_get(ictx, 1, 1, 1);
1083 screen_write_cursormove(sctx, m - 1, n - 1);
1084 break;
1085 case INPUT_CSI_CUU:
1086 screen_write_cursorup(sctx, input_get(ictx, 0, 1, 1));
1087 break;
1088 case INPUT_CSI_DA:
1089 switch (input_get(ictx, 0, 0, 0)) {
1090 case 0:
1091 input_reply(ictx, "\033[?1;2c");
1092 break;
1093 default:
1094 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1095 break;
1097 break;
1098 case INPUT_CSI_DCH:
1099 screen_write_deletecharacter(sctx, input_get(ictx, 0, 1, 1));
1100 break;
1101 case INPUT_CSI_DECSTBM:
1102 n = input_get(ictx, 0, 1, 1);
1103 m = input_get(ictx, 1, 1, screen_size_y(s));
1104 screen_write_scrollregion(sctx, n - 1, m - 1);
1105 break;
1106 case INPUT_CSI_DL:
1107 screen_write_deleteline(sctx, input_get(ictx, 0, 1, 1));
1108 break;
1109 case INPUT_CSI_DSR:
1110 switch (input_get(ictx, 0, 0, 0)) {
1111 case 5:
1112 input_reply(ictx, "\033[0n");
1113 break;
1114 case 6:
1115 input_reply(ictx, "\033[%u;%uR", s->cy + 1, s->cx + 1);
1116 break;
1117 default:
1118 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1119 break;
1121 break;
1122 case INPUT_CSI_ED:
1123 switch (input_get(ictx, 0, 0, 0)) {
1124 case 0:
1125 screen_write_clearendofscreen(sctx);
1126 break;
1127 case 1:
1128 screen_write_clearstartofscreen(sctx);
1129 break;
1130 case 2:
1131 screen_write_clearscreen(sctx);
1132 break;
1133 case 3:
1134 switch (input_get(ictx, 1, 0, 0)) {
1135 case 0:
1137 * Linux console extension to clear history
1138 * (for example before locking the screen).
1140 screen_write_clearhistory(sctx);
1141 break;
1143 break;
1144 default:
1145 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1146 break;
1148 break;
1149 case INPUT_CSI_EL:
1150 switch (input_get(ictx, 0, 0, 0)) {
1151 case 0:
1152 screen_write_clearendofline(sctx);
1153 break;
1154 case 1:
1155 screen_write_clearstartofline(sctx);
1156 break;
1157 case 2:
1158 screen_write_clearline(sctx);
1159 break;
1160 default:
1161 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1162 break;
1164 break;
1165 case INPUT_CSI_HPA:
1166 n = input_get(ictx, 0, 1, 1);
1167 screen_write_cursormove(sctx, n - 1, s->cy);
1168 break;
1169 case INPUT_CSI_ICH:
1170 screen_write_insertcharacter(sctx, input_get(ictx, 0, 1, 1));
1171 break;
1172 case INPUT_CSI_IL:
1173 screen_write_insertline(sctx, input_get(ictx, 0, 1, 1));
1174 break;
1175 case INPUT_CSI_RCP:
1176 memcpy(&ictx->cell, &ictx->old_cell, sizeof ictx->cell);
1177 screen_write_cursormove(sctx, ictx->old_cx, ictx->old_cy);
1178 break;
1179 case INPUT_CSI_RM:
1180 switch (input_get(ictx, 0, 0, -1)) {
1181 case 4: /* IRM */
1182 screen_write_insertmode(&ictx->ctx, 0);
1183 break;
1184 default:
1185 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1186 break;
1188 break;
1189 case INPUT_CSI_RM_PRIVATE:
1190 switch (input_get(ictx, 0, 0, -1)) {
1191 case 1: /* GATM */
1192 screen_write_kcursormode(&ictx->ctx, 0);
1193 break;
1194 case 3: /* DECCOLM */
1195 screen_write_cursormove(&ictx->ctx, 0, 0);
1196 screen_write_clearscreen(&ictx->ctx);
1197 break;
1198 case 25: /* TCEM */
1199 screen_write_cursormode(&ictx->ctx, 0);
1200 break;
1201 case 1000:
1202 case 1001:
1203 case 1002:
1204 case 1003:
1205 screen_write_mousemode_off(&ictx->ctx);
1206 break;
1207 case 1005:
1208 screen_write_utf8mousemode(&ictx->ctx, 0);
1209 break;
1210 case 1049:
1211 window_pane_alternate_off(wp, &ictx->cell);
1212 break;
1213 default:
1214 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1215 break;
1217 break;
1218 case INPUT_CSI_SCP:
1219 memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
1220 ictx->old_cx = s->cx;
1221 ictx->old_cy = s->cy;
1222 break;
1223 case INPUT_CSI_SGR:
1224 input_csi_dispatch_sgr(ictx);
1225 break;
1226 case INPUT_CSI_SM:
1227 switch (input_get(ictx, 0, 0, -1)) {
1228 case 4: /* IRM */
1229 screen_write_insertmode(&ictx->ctx, 1);
1230 break;
1231 default:
1232 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1233 break;
1235 break;
1236 case INPUT_CSI_SM_PRIVATE:
1237 switch (input_get(ictx, 0, 0, -1)) {
1238 case 1: /* GATM */
1239 screen_write_kcursormode(&ictx->ctx, 1);
1240 break;
1241 case 3: /* DECCOLM */
1242 screen_write_cursormove(&ictx->ctx, 0, 0);
1243 screen_write_clearscreen(&ictx->ctx);
1244 break;
1245 case 25: /* TCEM */
1246 screen_write_cursormode(&ictx->ctx, 1);
1247 break;
1248 case 1000:
1249 screen_write_mousemode_on(
1250 &ictx->ctx, MODE_MOUSE_STANDARD);
1251 break;
1252 case 1002:
1253 screen_write_mousemode_on(
1254 &ictx->ctx, MODE_MOUSE_BUTTON);
1255 break;
1256 case 1003:
1257 screen_write_mousemode_on(&ictx->ctx, MODE_MOUSE_ANY);
1258 break;
1259 case 1005:
1260 screen_write_utf8mousemode(&ictx->ctx, 1);
1261 break;
1262 case 1049:
1263 window_pane_alternate_on(wp, &ictx->cell);
1264 break;
1265 default:
1266 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1267 break;
1269 break;
1270 case INPUT_CSI_TBC:
1271 switch (input_get(ictx, 0, 0, 0)) {
1272 case 0:
1273 if (s->cx < screen_size_x(s))
1274 bit_clear(s->tabs, s->cx);
1275 break;
1276 case 3:
1277 bit_nclear(s->tabs, 0, screen_size_x(s) - 1);
1278 break;
1279 default:
1280 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1281 break;
1283 break;
1284 case INPUT_CSI_VPA:
1285 n = input_get(ictx, 0, 1, 1);
1286 screen_write_cursormove(sctx, s->cx, n - 1);
1287 break;
1288 case INPUT_CSI_DECSCUSR:
1289 n = input_get(ictx, 0, 0, 0);
1290 screen_set_cursor_style(s, n);
1291 break;
1294 return (0);
1297 /* Handle CSI SGR. */
1298 void
1299 input_csi_dispatch_sgr(struct input_ctx *ictx)
1301 struct grid_cell *gc = &ictx->cell;
1302 u_int i;
1303 int n, m;
1304 u_char attr;
1306 if (ictx->param_list_len == 0) {
1307 attr = gc->attr;
1308 memcpy(gc, &grid_default_cell, sizeof *gc);
1309 gc->attr |= (attr & GRID_ATTR_CHARSET);
1310 return;
1313 for (i = 0; i < ictx->param_list_len; i++) {
1314 n = input_get(ictx, i, 0, 0);
1316 if (n == 38 || n == 48) {
1317 i++;
1318 if (input_get(ictx, i, 0, -1) != 5)
1319 continue;
1321 i++;
1322 m = input_get(ictx, i, 0, -1);
1323 if (m == -1) {
1324 if (n == 38) {
1325 gc->flags &= ~GRID_FLAG_FG256;
1326 gc->fg = 8;
1327 } else if (n == 48) {
1328 gc->flags &= ~GRID_FLAG_BG256;
1329 gc->bg = 8;
1332 } else {
1333 if (n == 38) {
1334 gc->flags |= GRID_FLAG_FG256;
1335 gc->fg = m;
1336 } else if (n == 48) {
1337 gc->flags |= GRID_FLAG_BG256;
1338 gc->bg = m;
1341 continue;
1344 switch (n) {
1345 case 0:
1346 case 10:
1347 attr = gc->attr;
1348 memcpy(gc, &grid_default_cell, sizeof *gc);
1349 gc->attr |= (attr & GRID_ATTR_CHARSET);
1350 break;
1351 case 1:
1352 gc->attr |= GRID_ATTR_BRIGHT;
1353 break;
1354 case 2:
1355 gc->attr |= GRID_ATTR_DIM;
1356 break;
1357 case 3:
1358 gc->attr |= GRID_ATTR_ITALICS;
1359 break;
1360 case 4:
1361 gc->attr |= GRID_ATTR_UNDERSCORE;
1362 break;
1363 case 5:
1364 gc->attr |= GRID_ATTR_BLINK;
1365 break;
1366 case 7:
1367 gc->attr |= GRID_ATTR_REVERSE;
1368 break;
1369 case 8:
1370 gc->attr |= GRID_ATTR_HIDDEN;
1371 break;
1372 case 22:
1373 gc->attr &= ~(GRID_ATTR_BRIGHT|GRID_ATTR_DIM);
1374 break;
1375 case 23:
1376 gc->attr &= ~GRID_ATTR_ITALICS;
1377 break;
1378 case 24:
1379 gc->attr &= ~GRID_ATTR_UNDERSCORE;
1380 break;
1381 case 25:
1382 gc->attr &= ~GRID_ATTR_BLINK;
1383 break;
1384 case 27:
1385 gc->attr &= ~GRID_ATTR_REVERSE;
1386 break;
1387 case 30:
1388 case 31:
1389 case 32:
1390 case 33:
1391 case 34:
1392 case 35:
1393 case 36:
1394 case 37:
1395 gc->flags &= ~GRID_FLAG_FG256;
1396 gc->fg = n - 30;
1397 break;
1398 case 39:
1399 gc->flags &= ~GRID_FLAG_FG256;
1400 gc->fg = 8;
1401 break;
1402 case 40:
1403 case 41:
1404 case 42:
1405 case 43:
1406 case 44:
1407 case 45:
1408 case 46:
1409 case 47:
1410 gc->flags &= ~GRID_FLAG_BG256;
1411 gc->bg = n - 40;
1412 break;
1413 case 49:
1414 gc->flags &= ~GRID_FLAG_BG256;
1415 gc->bg = 8;
1416 break;
1417 case 90:
1418 case 91:
1419 case 92:
1420 case 93:
1421 case 94:
1422 case 95:
1423 case 96:
1424 case 97:
1425 gc->flags &= ~GRID_FLAG_FG256;
1426 gc->fg = n;
1427 break;
1428 case 100:
1429 case 101:
1430 case 102:
1431 case 103:
1432 case 104:
1433 case 105:
1434 case 106:
1435 case 107:
1436 gc->flags &= ~GRID_FLAG_BG256;
1437 gc->bg = n;
1438 break;
1443 /* DCS terminator (ST) received. */
1445 input_dcs_dispatch(struct input_ctx *ictx)
1447 const char prefix[] = "tmux;";
1448 const u_int prefix_len = (sizeof prefix) - 1;
1450 if (ictx->flags & INPUT_DISCARD)
1451 return (0);
1453 log_debug("%s: \"%s\"", __func__, ictx->input_buf);
1455 /* Check for tmux prefix. */
1456 if (ictx->input_len >= prefix_len &&
1457 strncmp(ictx->input_buf, prefix, prefix_len) == 0) {
1458 screen_write_rawstring(&ictx->ctx,
1459 ictx->input_buf + prefix_len, ictx->input_len - prefix_len);
1462 return (0);
1465 /* OSC string started. */
1466 void
1467 input_enter_osc(struct input_ctx *ictx)
1469 log_debug("%s", __func__);
1471 input_clear(ictx);
1474 /* OSC terminator (ST) received. */
1475 void
1476 input_exit_osc(struct input_ctx *ictx)
1478 u_char *p = ictx->input_buf;
1479 int option;
1481 if (ictx->flags & INPUT_DISCARD)
1482 return;
1483 if (ictx->input_len < 1 || *p < '0' || *p > '9')
1484 return;
1486 log_debug("%s: \"%s\"", __func__, p);
1488 option = 0;
1489 while (*p >= '0' && *p <= '9')
1490 option = option * 10 + *p++ - '0';
1491 if (*p == ';')
1492 p++;
1494 switch (option) {
1495 case 0:
1496 case 2:
1497 screen_set_title(ictx->ctx.s, p);
1498 server_status_window(ictx->wp->window);
1499 break;
1500 case 12:
1501 screen_set_cursor_colour(ictx->ctx.s, p);
1502 break;
1503 case 112:
1504 if (*p == '\0') /* No arguments allowed. */
1505 screen_set_cursor_colour(ictx->ctx.s, "");
1506 break;
1507 default:
1508 log_debug("%s: unknown '%u'", __func__, option);
1509 break;
1513 /* APC string started. */
1514 void
1515 input_enter_apc(struct input_ctx *ictx)
1517 log_debug("%s", __func__);
1519 input_clear(ictx);
1522 /* APC terminator (ST) received. */
1523 void
1524 input_exit_apc(struct input_ctx *ictx)
1526 if (ictx->flags & INPUT_DISCARD)
1527 return;
1528 log_debug("%s: \"%s\"", __func__, ictx->input_buf);
1530 screen_set_title(ictx->ctx.s, ictx->input_buf);
1531 server_status_window(ictx->wp->window);
1534 /* Rename string started. */
1535 void
1536 input_enter_rename(struct input_ctx *ictx)
1538 log_debug("%s", __func__);
1540 input_clear(ictx);
1543 /* Rename terminator (ST) received. */
1544 void
1545 input_exit_rename(struct input_ctx *ictx)
1547 if (ictx->flags & INPUT_DISCARD)
1548 return;
1549 log_debug("%s: \"%s\"", __func__, ictx->input_buf);
1551 xfree(ictx->wp->window->name);
1552 ictx->wp->window->name = xstrdup(ictx->input_buf);
1553 options_set_number(&ictx->wp->window->options, "automatic-rename", 0);
1555 server_status_window(ictx->wp->window);
1558 /* Open UTF-8 character. */
1560 input_utf8_open(struct input_ctx *ictx)
1562 if (!options_get_number(&ictx->wp->window->options, "utf8")) {
1563 /* Print, and do not switch state. */
1564 input_print(ictx);
1565 return (-1);
1567 log_debug("%s", __func__);
1569 utf8_open(&ictx->utf8data, ictx->ch);
1570 return (0);
1573 /* Append to UTF-8 character. */
1575 input_utf8_add(struct input_ctx *ictx)
1577 log_debug("%s", __func__);
1579 utf8_append(&ictx->utf8data, ictx->ch);
1580 return (0);
1583 /* Close UTF-8 string. */
1585 input_utf8_close(struct input_ctx *ictx)
1587 log_debug("%s", __func__);
1589 utf8_append(&ictx->utf8data, ictx->ch);
1591 ictx->cell.flags |= GRID_FLAG_UTF8;
1592 screen_write_cell(&ictx->ctx, &ictx->cell, &ictx->utf8data);
1593 ictx->cell.flags &= ~GRID_FLAG_UTF8;
1595 return (0);