Check for the right return value from sscanf.
[tmux-openbsd.git] / input.c
blob3bbb7ef27d84ced95cbc10fb70888d781756f320
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_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,
151 /* Control (CSI) command table. */
152 const 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 },
184 /* Input transition. */
185 struct input_transition {
186 int first;
187 int last;
189 int (*handler)(struct input_ctx *);
190 const struct input_state *state;
193 /* Input state. */
194 struct input_state {
195 const char *name;
196 void (*enter)(struct input_ctx *);
197 void (*exit)(struct input_ctx *);
198 const struct input_transition *transitions;
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 }
207 /* Forward declarations of state tables. */
208 const struct input_transition input_state_ground_table[];
209 const struct input_transition input_state_esc_enter_table[];
210 const struct input_transition input_state_esc_intermediate_table[];
211 const struct input_transition input_state_csi_enter_table[];
212 const struct input_transition input_state_csi_parameter_table[];
213 const struct input_transition input_state_csi_intermediate_table[];
214 const struct input_transition input_state_csi_ignore_table[];
215 const struct input_transition input_state_dcs_enter_table[];
216 const struct input_transition input_state_dcs_parameter_table[];
217 const struct input_transition input_state_dcs_intermediate_table[];
218 const struct input_transition input_state_dcs_handler_table[];
219 const struct input_transition input_state_dcs_escape_table[];
220 const struct input_transition input_state_dcs_ignore_table[];
221 const struct input_transition input_state_osc_string_table[];
222 const struct input_transition input_state_apc_string_table[];
223 const struct input_transition input_state_rename_string_table[];
224 const struct input_transition input_state_consume_st_table[];
225 const struct input_transition input_state_utf8_three_table[];
226 const struct input_transition input_state_utf8_two_table[];
227 const struct input_transition input_state_utf8_one_table[];
229 /* ground state definition. */
230 const struct input_state input_state_ground = {
231 "ground",
232 NULL, NULL,
233 input_state_ground_table
236 /* esc_enter state definition. */
237 const struct input_state input_state_esc_enter = {
238 "esc_enter",
239 input_clear, NULL,
240 input_state_esc_enter_table
243 /* esc_intermediate state definition. */
244 const struct input_state input_state_esc_intermediate = {
245 "esc_intermediate",
246 NULL, NULL,
247 input_state_esc_intermediate_table
250 /* csi_enter state definition. */
251 const struct input_state input_state_csi_enter = {
252 "csi_enter",
253 input_clear, NULL,
254 input_state_csi_enter_table
257 /* csi_parameter state definition. */
258 const struct input_state input_state_csi_parameter = {
259 "csi_parameter",
260 NULL, NULL,
261 input_state_csi_parameter_table
264 /* csi_intermediate state definition. */
265 const struct input_state input_state_csi_intermediate = {
266 "csi_intermediate",
267 NULL, NULL,
268 input_state_csi_intermediate_table
271 /* csi_ignore state definition. */
272 const struct input_state input_state_csi_ignore = {
273 "csi_ignore",
274 NULL, NULL,
275 input_state_csi_ignore_table
278 /* dcs_enter state definition. */
279 const struct input_state input_state_dcs_enter = {
280 "dcs_enter",
281 input_clear, NULL,
282 input_state_dcs_enter_table
285 /* dcs_parameter state definition. */
286 const struct input_state input_state_dcs_parameter = {
287 "dcs_parameter",
288 NULL, NULL,
289 input_state_dcs_parameter_table
292 /* dcs_intermediate state definition. */
293 const struct input_state input_state_dcs_intermediate = {
294 "dcs_intermediate",
295 NULL, NULL,
296 input_state_dcs_intermediate_table
299 /* dcs_handler state definition. */
300 const struct input_state input_state_dcs_handler = {
301 "dcs_handler",
302 NULL, NULL,
303 input_state_dcs_handler_table
306 /* dcs_escape state definition. */
307 const struct input_state input_state_dcs_escape = {
308 "dcs_escape",
309 NULL, NULL,
310 input_state_dcs_escape_table
313 /* dcs_ignore state definition. */
314 const struct input_state input_state_dcs_ignore = {
315 "dcs_ignore",
316 NULL, NULL,
317 input_state_dcs_ignore_table
320 /* osc_string state definition. */
321 const struct input_state input_state_osc_string = {
322 "osc_string",
323 input_enter_osc, input_exit_osc,
324 input_state_osc_string_table
327 /* apc_string state definition. */
328 const struct input_state input_state_apc_string = {
329 "apc_string",
330 input_enter_apc, input_exit_apc,
331 input_state_apc_string_table
334 /* rename_string state definition. */
335 const struct input_state input_state_rename_string = {
336 "rename_string",
337 input_enter_rename, input_exit_rename,
338 input_state_rename_string_table
341 /* consume_st state definition. */
342 const struct input_state input_state_consume_st = {
343 "consume_st",
344 NULL, NULL,
345 input_state_consume_st_table
348 /* utf8_three state definition. */
349 const struct input_state input_state_utf8_three = {
350 "utf8_three",
351 NULL, NULL,
352 input_state_utf8_three_table
355 /* utf8_two state definition. */
356 const struct input_state input_state_utf8_two = {
357 "utf8_two",
358 NULL, NULL,
359 input_state_utf8_two_table
362 /* utf8_one state definition. */
363 const struct input_state input_state_utf8_one = {
364 "utf8_one",
365 NULL, NULL,
366 input_state_utf8_one_table
369 /* ground state table. */
370 const struct input_transition input_state_ground_table[] = {
371 INPUT_STATE_ANYWHERE,
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 },
384 { -1, -1, NULL, NULL }
387 /* esc_enter state table. */
388 const struct input_transition input_state_esc_enter_table[] = {
389 INPUT_STATE_ANYWHERE,
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 },
411 { -1, -1, NULL, NULL }
414 /* esc_interm state table. */
415 const struct input_transition input_state_esc_intermediate_table[] = {
416 INPUT_STATE_ANYWHERE,
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 },
425 { -1, -1, NULL, NULL }
428 /* csi_enter state table. */
429 const struct input_transition input_state_csi_enter_table[] = {
430 INPUT_STATE_ANYWHERE,
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 },
443 { -1, -1, NULL, NULL }
446 /* csi_parameter state table. */
447 const struct input_transition input_state_csi_parameter_table[] = {
448 INPUT_STATE_ANYWHERE,
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 },
461 { -1, -1, NULL, NULL }
464 /* csi_intermediate state table. */
465 const struct input_transition input_state_csi_intermediate_table[] = {
466 INPUT_STATE_ANYWHERE,
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 },
476 { -1, -1, NULL, NULL }
479 /* csi_ignore state table. */
480 const struct input_transition input_state_csi_ignore_table[] = {
481 INPUT_STATE_ANYWHERE,
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 },
490 { -1, -1, NULL, NULL }
493 /* dcs_enter state table. */
494 const struct input_transition input_state_dcs_enter_table[] = {
495 INPUT_STATE_ANYWHERE,
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 },
508 { -1, -1, NULL, NULL }
511 /* dcs_parameter state table. */
512 const struct input_transition input_state_dcs_parameter_table[] = {
513 INPUT_STATE_ANYWHERE,
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 },
526 { -1, -1, NULL, NULL }
529 /* dcs_interm state table. */
530 const struct input_transition input_state_dcs_intermediate_table[] = {
531 INPUT_STATE_ANYWHERE,
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 },
541 { -1, -1, NULL, NULL }
544 /* dcs_handler state table. */
545 const struct input_transition input_state_dcs_handler_table[] = {
546 /* No INPUT_STATE_ANYWHERE */
548 { 0x00, 0x1a, input_input, NULL },
549 { 0x1b, 0x1b, NULL, &input_state_dcs_escape },
550 { 0x1c, 0xff, input_input, NULL },
552 { -1, -1, NULL, NULL }
555 /* dcs_escape state table. */
556 const struct input_transition input_state_dcs_escape_table[] = {
557 /* No INPUT_STATE_ANYWHERE */
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 },
563 { -1, -1, NULL, NULL }
566 /* dcs_ignore state table. */
567 const struct input_transition input_state_dcs_ignore_table[] = {
568 INPUT_STATE_ANYWHERE,
570 { 0x00, 0x17, NULL, NULL },
571 { 0x19, 0x19, NULL, NULL },
572 { 0x1c, 0x1f, NULL, NULL },
573 { 0x20, 0xff, NULL, NULL },
575 { -1, -1, NULL, NULL }
578 /* osc_string state table. */
579 const struct input_transition input_state_osc_string_table[] = {
580 INPUT_STATE_ANYWHERE,
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 },
589 { -1, -1, NULL, NULL }
592 /* apc_string state table. */
593 const struct input_transition input_state_apc_string_table[] = {
594 INPUT_STATE_ANYWHERE,
596 { 0x00, 0x17, NULL, NULL },
597 { 0x19, 0x19, NULL, NULL },
598 { 0x1c, 0x1f, NULL, NULL },
599 { 0x20, 0xff, input_input, NULL },
601 { -1, -1, NULL, NULL }
604 /* rename_string state table. */
605 const struct input_transition input_state_rename_string_table[] = {
606 INPUT_STATE_ANYWHERE,
608 { 0x00, 0x17, NULL, NULL },
609 { 0x19, 0x19, NULL, NULL },
610 { 0x1c, 0x1f, NULL, NULL },
611 { 0x20, 0xff, input_input, NULL },
613 { -1, -1, NULL, NULL }
616 /* consume_st state table. */
617 const struct input_transition input_state_consume_st_table[] = {
618 INPUT_STATE_ANYWHERE,
620 { 0x00, 0x17, NULL, NULL },
621 { 0x19, 0x19, NULL, NULL },
622 { 0x1c, 0x1f, NULL, NULL },
623 { 0x20, 0xff, NULL, NULL },
625 { -1, -1, NULL, NULL }
628 /* utf8_three state table. */
629 const struct input_transition input_state_utf8_three_table[] = {
630 /* No INPUT_STATE_ANYWHERE */
632 { 0x00, 0x7f, NULL, &input_state_ground },
633 { 0x80, 0xbf, input_utf8_add, &input_state_utf8_two },
634 { 0xc0, 0xff, NULL, &input_state_ground },
636 { -1, -1, NULL, NULL }
639 /* utf8_two state table. */
640 const struct input_transition input_state_utf8_two_table[] = {
641 /* No INPUT_STATE_ANYWHERE */
643 { 0x00, 0x7f, NULL, &input_state_ground },
644 { 0x80, 0xbf, input_utf8_add, &input_state_utf8_one },
645 { 0xc0, 0xff, NULL, &input_state_ground },
647 { -1, -1, NULL, NULL }
650 /* utf8_one state table. */
651 const struct input_transition input_state_utf8_one_table[] = {
652 /* No INPUT_STATE_ANYWHERE */
654 { 0x00, 0x7f, NULL, &input_state_ground },
655 { 0x80, 0xbf, input_utf8_close, &input_state_ground },
656 { 0xc0, 0xff, NULL, &input_state_ground },
658 { -1, -1, NULL, NULL }
661 /* Input table compare. */
663 input_table_compare(const void *key, const void *value)
665 const struct input_ctx *ictx = key;
666 const struct input_table_entry *entry = value;
668 if (ictx->ch != entry->ch)
669 return (ictx->ch - entry->ch);
670 return (strcmp(ictx->interm_buf, entry->interm));
673 /* Initialise input parser. */
674 void
675 input_init(struct window_pane *wp)
677 struct input_ctx *ictx = &wp->ictx;
679 memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell);
681 memcpy(&ictx->old_cell, &grid_default_cell, sizeof ictx->old_cell);
682 ictx->old_cx = 0;
683 ictx->old_cy = 0;
685 *ictx->interm_buf = '\0';
686 ictx->interm_len = 0;
688 *ictx->param_buf = '\0';
689 ictx->param_len = 0;
691 ictx->state = &input_state_ground;
692 ictx->flags = 0;
695 /* Destroy input parser. */
696 void
697 input_free(unused struct window_pane *wp)
701 /* Parse input. */
702 void
703 input_parse(struct window_pane *wp)
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;
711 if (EVBUFFER_LENGTH(evb) == 0)
712 return;
714 wp->window->flags |= WINDOW_ACTIVITY;
715 wp->window->flags &= ~WINDOW_SILENCE;
718 * Open the screen. Use NULL wp if there is a mode set as don't want to
719 * update the tty.
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;
727 buf = EVBUFFER_DATA(evb);
728 len = EVBUFFER_LENGTH(evb);
729 off = 0;
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);
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++;
743 if (itr->first == -1 || itr->last == -1) {
744 /* No transition? Eh? */
745 fatalx("No transition from state!");
749 * Execute the handler, if any. Don't switch state if it
750 * returns non-zero.
752 if (itr->handler != NULL && itr->handler(ictx) != 0)
753 continue;
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);
765 /* Close the screen. */
766 screen_write_stop(&ictx->ctx);
768 evbuffer_drain(evb, len);
771 /* Split the parameter list (if any). */
773 input_split(struct input_ctx *ictx)
776 const char *errstr;
777 char *ptr, *out;
778 int n;
780 ictx->param_list_len = 0;
781 if (ictx->param_len == 0)
782 return (0);
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);
794 ictx->param_list[ictx->param_list_len++] = n;
795 if (ictx->param_list_len == nitems(ictx->param_list))
796 return (-1);
799 return (0);
802 /* Get an argument or return default value. */
804 input_get(struct input_ctx *ictx, u_int validx, int minval, int defval)
806 int retval;
808 if (validx >= ictx->param_list_len)
809 return (defval);
811 retval = ictx->param_list[validx];
812 if (retval == -1)
813 return (defval);
814 if (retval < minval)
815 return (minval);
816 return (retval);
819 /* Reply to terminal query. */
820 void
821 input_reply(struct input_ctx *ictx, const char *fmt, ...)
823 va_list ap;
824 char *reply;
826 va_start(ap, fmt);
827 vasprintf(&reply, fmt, ap);
828 va_end(ap);
830 bufferevent_write(ictx->wp->event, reply, strlen(reply));
831 xfree(reply);
834 /* Clear saved state. */
835 void
836 input_clear(struct input_ctx *ictx)
838 *ictx->interm_buf = '\0';
839 ictx->interm_len = 0;
841 *ictx->param_buf = '\0';
842 ictx->param_len = 0;
844 *ictx->input_buf = '\0';
845 ictx->input_len = 0;
847 ictx->flags &= ~INPUT_DISCARD;
850 /* Output this character to the screen. */
852 input_print(struct input_ctx *ictx)
854 ictx->cell.data = ictx->ch;
855 screen_write_cell(&ictx->ctx, &ictx->cell, NULL);
857 return (0);
860 /* Collect intermediate string. */
862 input_intermediate(struct input_ctx *ictx)
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';
871 return (0);
874 /* Collect parameter string. */
876 input_parameter(struct input_ctx *ictx)
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';
885 return (0);
888 /* Collect input string. */
890 input_input(struct input_ctx *ictx)
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';
899 return (0);
902 /* Execute C0 control sequence. */
904 input_c0_dispatch(struct input_ctx *ictx)
906 struct screen_write_ctx *sctx = &ictx->ctx;
907 struct window_pane *wp = ictx->wp;
908 struct screen *s = sctx->s;
910 log_debug("%s: '%c", __func__, ictx->ch);
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;
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;
952 return (0);
955 /* Execute escape sequence. */
957 input_esc_dispatch(struct input_ctx *ictx)
959 struct screen_write_ctx *sctx = &ictx->ctx;
960 struct screen *s = sctx->s;
961 struct input_table_entry *entry;
963 if (ictx->flags & INPUT_DISCARD)
964 return (0);
965 log_debug("%s: '%c', %s", __func__, ictx->ch, ictx->interm_buf);
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);
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;
981 screen_write_reset(sctx);
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:
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).
1021 ictx->cell.attr &= ~GRID_ATTR_CHARSET;
1022 break;
1023 case INPUT_ESC_SCSOFF_G0:
1024 ictx->cell.attr |= GRID_ATTR_CHARSET;
1025 break;
1028 return (0);
1031 /* Execute control sequence. */
1033 input_csi_dispatch(struct input_ctx *ictx)
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;
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);
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);
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) {
1061 s->cx--;
1062 while (s->cx > 0 && !bit_test(s->tabs, s->cx));
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;
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;
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:
1139 * Linux console extension to clear history
1140 * (for example before locking the screen).
1142 screen_write_clearhistory(sctx);
1143 break;
1145 break;
1146 default:
1147 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1148 break;
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;
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;
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;
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;
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;
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;
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;
1296 return (0);
1299 /* Handle CSI SGR. */
1300 void
1301 input_csi_dispatch_sgr(struct input_ctx *ictx)
1303 struct grid_cell *gc = &ictx->cell;
1304 u_int i;
1305 int n, m;
1306 u_char attr;
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;
1315 for (i = 0; i < ictx->param_list_len; i++) {
1316 n = input_get(ictx, i, 0, 0);
1318 if (n == 38 || n == 48) {
1319 i++;
1320 if (input_get(ictx, i, 0, -1) != 5)
1321 continue;
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;
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;
1343 continue;
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 - 10;
1440 break;
1445 /* DCS terminator (ST) received. */
1447 input_dcs_dispatch(struct input_ctx *ictx)
1449 const char prefix[] = "tmux;";
1450 const u_int prefix_len = (sizeof prefix) - 1;
1452 if (ictx->flags & INPUT_DISCARD)
1453 return (0);
1455 log_debug("%s: \"%s\"", __func__, ictx->input_buf);
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);
1464 return (0);
1467 /* OSC string started. */
1468 void
1469 input_enter_osc(struct input_ctx *ictx)
1471 log_debug("%s", __func__);
1473 input_clear(ictx);
1476 /* OSC terminator (ST) received. */
1477 void
1478 input_exit_osc(struct input_ctx *ictx)
1480 u_char *p = ictx->input_buf;
1481 int option;
1483 if (ictx->flags & INPUT_DISCARD)
1484 return;
1485 if (ictx->input_len < 1 || *p < '0' || *p > '9')
1486 return;
1488 log_debug("%s: \"%s\"", __func__, p);
1490 option = 0;
1491 while (*p >= '0' && *p <= '9')
1492 option = option * 10 + *p++ - '0';
1493 if (*p == ';')
1494 p++;
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;
1515 /* APC string started. */
1516 void
1517 input_enter_apc(struct input_ctx *ictx)
1519 log_debug("%s", __func__);
1521 input_clear(ictx);
1524 /* APC terminator (ST) received. */
1525 void
1526 input_exit_apc(struct input_ctx *ictx)
1528 if (ictx->flags & INPUT_DISCARD)
1529 return;
1530 log_debug("%s: \"%s\"", __func__, ictx->input_buf);
1532 screen_set_title(ictx->ctx.s, ictx->input_buf);
1533 server_status_window(ictx->wp->window);
1536 /* Rename string started. */
1537 void
1538 input_enter_rename(struct input_ctx *ictx)
1540 log_debug("%s", __func__);
1542 input_clear(ictx);
1545 /* Rename terminator (ST) received. */
1546 void
1547 input_exit_rename(struct input_ctx *ictx)
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);
1555 window_set_name(ictx->wp->window, ictx->input_buf);
1556 options_set_number(&ictx->wp->window->options, "automatic-rename", 0);
1558 server_status_window(ictx->wp->window);
1561 /* Open UTF-8 character. */
1563 input_utf8_open(struct input_ctx *ictx)
1565 if (!options_get_number(&ictx->wp->window->options, "utf8")) {
1566 /* Print, and do not switch state. */
1567 input_print(ictx);
1568 return (-1);
1570 log_debug("%s", __func__);
1572 utf8_open(&ictx->utf8data, ictx->ch);
1573 return (0);
1576 /* Append to UTF-8 character. */
1578 input_utf8_add(struct input_ctx *ictx)
1580 log_debug("%s", __func__);
1582 utf8_append(&ictx->utf8data, ictx->ch);
1583 return (0);
1586 /* Close UTF-8 string. */
1588 input_utf8_close(struct input_ctx *ictx)
1590 log_debug("%s", __func__);
1592 utf8_append(&ictx->utf8data, ictx->ch);
1594 ictx->cell.flags |= GRID_FLAG_UTF8;
1595 screen_write_cell(&ictx->ctx, &ictx->cell, &ictx->utf8data);
1596 ictx->cell.flags &= ~GRID_FLAG_UTF8;
1598 return (0);