Use single stdout and stderr for control clients.
[tmux-openbsd.git] / input.c
blob0dcdee9670a12491b0f704a3672cd28f9908f179
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 struct input_transition;
51 int input_split(struct input_ctx *);
52 int input_get(struct input_ctx *, u_int, int, int);
53 void input_reply(struct input_ctx *, const char *, ...);
54 void input_set_state(struct window_pane *, const struct input_transition *);
56 /* Transition entry/exit handlers. */
57 void input_clear(struct input_ctx *);
58 void input_enter_osc(struct input_ctx *);
59 void input_exit_osc(struct input_ctx *);
60 void input_enter_apc(struct input_ctx *);
61 void input_exit_apc(struct input_ctx *);
62 void input_enter_rename(struct input_ctx *);
63 void input_exit_rename(struct input_ctx *);
65 /* Input state handlers. */
66 int input_print(struct input_ctx *);
67 int input_intermediate(struct input_ctx *);
68 int input_parameter(struct input_ctx *);
69 int input_input(struct input_ctx *);
70 int input_c0_dispatch(struct input_ctx *);
71 int input_esc_dispatch(struct input_ctx *);
72 int input_csi_dispatch(struct input_ctx *);
73 void input_csi_dispatch_sgr(struct input_ctx *);
74 int input_dcs_dispatch(struct input_ctx *);
75 int input_utf8_open(struct input_ctx *);
76 int input_utf8_add(struct input_ctx *);
77 int input_utf8_close(struct input_ctx *);
79 /* Command table comparison function. */
80 int input_table_compare(const void *, const void *);
82 /* Command table entry. */
83 struct input_table_entry {
84 int ch;
85 const char *interm;
86 int type;
89 /* Escape commands. */
90 enum input_esc_type {
91 INPUT_ESC_DECALN,
92 INPUT_ESC_DECKPAM,
93 INPUT_ESC_DECKPNM,
94 INPUT_ESC_DECRC,
95 INPUT_ESC_DECSC,
96 INPUT_ESC_HTS,
97 INPUT_ESC_IND,
98 INPUT_ESC_NEL,
99 INPUT_ESC_RI,
100 INPUT_ESC_RIS,
101 INPUT_ESC_SCSOFF_G0,
102 INPUT_ESC_SCSON_G0,
105 /* Escape command table. */
106 const struct input_table_entry input_esc_table[] = {
107 { '0', "(", INPUT_ESC_SCSOFF_G0 },
108 { '7', "", INPUT_ESC_DECSC },
109 { '8', "", INPUT_ESC_DECRC },
110 { '8', "#", INPUT_ESC_DECALN },
111 { '=', "", INPUT_ESC_DECKPAM },
112 { '>', "", INPUT_ESC_DECKPNM },
113 { 'B', "(", INPUT_ESC_SCSON_G0 },
114 { 'D', "", INPUT_ESC_IND },
115 { 'E', "", INPUT_ESC_NEL },
116 { 'H', "", INPUT_ESC_HTS },
117 { 'M', "", INPUT_ESC_RI },
118 { 'c', "", INPUT_ESC_RIS },
121 /* Control (CSI) commands. */
122 enum input_csi_type {
123 INPUT_CSI_CBT,
124 INPUT_CSI_CNL,
125 INPUT_CSI_CPL,
126 INPUT_CSI_CUB,
127 INPUT_CSI_CUD,
128 INPUT_CSI_CUF,
129 INPUT_CSI_CUP,
130 INPUT_CSI_CUU,
131 INPUT_CSI_DA,
132 INPUT_CSI_DA_TWO,
133 INPUT_CSI_DCH,
134 INPUT_CSI_DECSCUSR,
135 INPUT_CSI_DECSTBM,
136 INPUT_CSI_DL,
137 INPUT_CSI_DSR,
138 INPUT_CSI_ECH,
139 INPUT_CSI_ED,
140 INPUT_CSI_EL,
141 INPUT_CSI_HPA,
142 INPUT_CSI_ICH,
143 INPUT_CSI_IL,
144 INPUT_CSI_RCP,
145 INPUT_CSI_RM,
146 INPUT_CSI_RM_PRIVATE,
147 INPUT_CSI_SCP,
148 INPUT_CSI_SGR,
149 INPUT_CSI_SM,
150 INPUT_CSI_SM_PRIVATE,
151 INPUT_CSI_TBC,
152 INPUT_CSI_VPA,
155 /* Control (CSI) command table. */
156 const struct input_table_entry input_csi_table[] = {
157 { '@', "", INPUT_CSI_ICH },
158 { 'A', "", INPUT_CSI_CUU },
159 { 'B', "", INPUT_CSI_CUD },
160 { 'C', "", INPUT_CSI_CUF },
161 { 'D', "", INPUT_CSI_CUB },
162 { 'E', "", INPUT_CSI_CNL },
163 { 'F', "", INPUT_CSI_CPL },
164 { 'G', "", INPUT_CSI_HPA },
165 { 'H', "", INPUT_CSI_CUP },
166 { 'J', "", INPUT_CSI_ED },
167 { 'K', "", INPUT_CSI_EL },
168 { 'L', "", INPUT_CSI_IL },
169 { 'M', "", INPUT_CSI_DL },
170 { 'P', "", INPUT_CSI_DCH },
171 { 'X', "", INPUT_CSI_ECH },
172 { 'Z', "", INPUT_CSI_CBT },
173 { 'c', "", INPUT_CSI_DA },
174 { 'c', ">", INPUT_CSI_DA_TWO },
175 { 'd', "", INPUT_CSI_VPA },
176 { 'f', "", INPUT_CSI_CUP },
177 { 'g', "", INPUT_CSI_TBC },
178 { 'h', "", INPUT_CSI_SM },
179 { 'h', "?", INPUT_CSI_SM_PRIVATE },
180 { 'l', "", INPUT_CSI_RM },
181 { 'l', "?", INPUT_CSI_RM_PRIVATE },
182 { 'm', "", INPUT_CSI_SGR },
183 { 'n', "", INPUT_CSI_DSR },
184 { 'q', " ", INPUT_CSI_DECSCUSR },
185 { 'r', "", INPUT_CSI_DECSTBM },
186 { 's', "", INPUT_CSI_SCP },
187 { 'u', "", INPUT_CSI_RCP },
190 /* Input transition. */
191 struct input_transition {
192 int first;
193 int last;
195 int (*handler)(struct input_ctx *);
196 const struct input_state *state;
199 /* Input state. */
200 struct input_state {
201 const char *name;
202 void (*enter)(struct input_ctx *);
203 void (*exit)(struct input_ctx *);
204 const struct input_transition *transitions;
207 /* State transitions available from all states. */
208 #define INPUT_STATE_ANYWHERE \
209 { 0x18, 0x18, input_c0_dispatch, &input_state_ground }, \
210 { 0x1a, 0x1a, input_c0_dispatch, &input_state_ground }, \
211 { 0x1b, 0x1b, NULL, &input_state_esc_enter }
213 /* Forward declarations of state tables. */
214 const struct input_transition input_state_ground_table[];
215 const struct input_transition input_state_esc_enter_table[];
216 const struct input_transition input_state_esc_intermediate_table[];
217 const struct input_transition input_state_csi_enter_table[];
218 const struct input_transition input_state_csi_parameter_table[];
219 const struct input_transition input_state_csi_intermediate_table[];
220 const struct input_transition input_state_csi_ignore_table[];
221 const struct input_transition input_state_dcs_enter_table[];
222 const struct input_transition input_state_dcs_parameter_table[];
223 const struct input_transition input_state_dcs_intermediate_table[];
224 const struct input_transition input_state_dcs_handler_table[];
225 const struct input_transition input_state_dcs_escape_table[];
226 const struct input_transition input_state_dcs_ignore_table[];
227 const struct input_transition input_state_osc_string_table[];
228 const struct input_transition input_state_apc_string_table[];
229 const struct input_transition input_state_rename_string_table[];
230 const struct input_transition input_state_consume_st_table[];
231 const struct input_transition input_state_utf8_three_table[];
232 const struct input_transition input_state_utf8_two_table[];
233 const struct input_transition input_state_utf8_one_table[];
235 /* ground state definition. */
236 const struct input_state input_state_ground = {
237 "ground",
238 NULL, NULL,
239 input_state_ground_table
242 /* esc_enter state definition. */
243 const struct input_state input_state_esc_enter = {
244 "esc_enter",
245 input_clear, NULL,
246 input_state_esc_enter_table
249 /* esc_intermediate state definition. */
250 const struct input_state input_state_esc_intermediate = {
251 "esc_intermediate",
252 NULL, NULL,
253 input_state_esc_intermediate_table
256 /* csi_enter state definition. */
257 const struct input_state input_state_csi_enter = {
258 "csi_enter",
259 input_clear, NULL,
260 input_state_csi_enter_table
263 /* csi_parameter state definition. */
264 const struct input_state input_state_csi_parameter = {
265 "csi_parameter",
266 NULL, NULL,
267 input_state_csi_parameter_table
270 /* csi_intermediate state definition. */
271 const struct input_state input_state_csi_intermediate = {
272 "csi_intermediate",
273 NULL, NULL,
274 input_state_csi_intermediate_table
277 /* csi_ignore state definition. */
278 const struct input_state input_state_csi_ignore = {
279 "csi_ignore",
280 NULL, NULL,
281 input_state_csi_ignore_table
284 /* dcs_enter state definition. */
285 const struct input_state input_state_dcs_enter = {
286 "dcs_enter",
287 input_clear, NULL,
288 input_state_dcs_enter_table
291 /* dcs_parameter state definition. */
292 const struct input_state input_state_dcs_parameter = {
293 "dcs_parameter",
294 NULL, NULL,
295 input_state_dcs_parameter_table
298 /* dcs_intermediate state definition. */
299 const struct input_state input_state_dcs_intermediate = {
300 "dcs_intermediate",
301 NULL, NULL,
302 input_state_dcs_intermediate_table
305 /* dcs_handler state definition. */
306 const struct input_state input_state_dcs_handler = {
307 "dcs_handler",
308 NULL, NULL,
309 input_state_dcs_handler_table
312 /* dcs_escape state definition. */
313 const struct input_state input_state_dcs_escape = {
314 "dcs_escape",
315 NULL, NULL,
316 input_state_dcs_escape_table
319 /* dcs_ignore state definition. */
320 const struct input_state input_state_dcs_ignore = {
321 "dcs_ignore",
322 NULL, NULL,
323 input_state_dcs_ignore_table
326 /* osc_string state definition. */
327 const struct input_state input_state_osc_string = {
328 "osc_string",
329 input_enter_osc, input_exit_osc,
330 input_state_osc_string_table
333 /* apc_string state definition. */
334 const struct input_state input_state_apc_string = {
335 "apc_string",
336 input_enter_apc, input_exit_apc,
337 input_state_apc_string_table
340 /* rename_string state definition. */
341 const struct input_state input_state_rename_string = {
342 "rename_string",
343 input_enter_rename, input_exit_rename,
344 input_state_rename_string_table
347 /* consume_st state definition. */
348 const struct input_state input_state_consume_st = {
349 "consume_st",
350 NULL, NULL,
351 input_state_consume_st_table
354 /* utf8_three state definition. */
355 const struct input_state input_state_utf8_three = {
356 "utf8_three",
357 NULL, NULL,
358 input_state_utf8_three_table
361 /* utf8_two state definition. */
362 const struct input_state input_state_utf8_two = {
363 "utf8_two",
364 NULL, NULL,
365 input_state_utf8_two_table
368 /* utf8_one state definition. */
369 const struct input_state input_state_utf8_one = {
370 "utf8_one",
371 NULL, NULL,
372 input_state_utf8_one_table
375 /* ground state table. */
376 const struct input_transition input_state_ground_table[] = {
377 INPUT_STATE_ANYWHERE,
379 { 0x00, 0x17, input_c0_dispatch, NULL },
380 { 0x19, 0x19, input_c0_dispatch, NULL },
381 { 0x1c, 0x1f, input_c0_dispatch, NULL },
382 { 0x20, 0x7e, input_print, NULL },
383 { 0x7f, 0x7f, NULL, NULL },
384 { 0x80, 0xc1, input_print, NULL },
385 { 0xc2, 0xdf, input_utf8_open, &input_state_utf8_one },
386 { 0xe0, 0xef, input_utf8_open, &input_state_utf8_two },
387 { 0xf0, 0xf4, input_utf8_open, &input_state_utf8_three },
388 { 0xf5, 0xff, input_print, NULL },
390 { -1, -1, NULL, NULL }
393 /* esc_enter state table. */
394 const struct input_transition input_state_esc_enter_table[] = {
395 INPUT_STATE_ANYWHERE,
397 { 0x00, 0x17, input_c0_dispatch, NULL },
398 { 0x19, 0x19, input_c0_dispatch, NULL },
399 { 0x1c, 0x1f, input_c0_dispatch, NULL },
400 { 0x20, 0x2f, input_intermediate, &input_state_esc_intermediate },
401 { 0x30, 0x4f, input_esc_dispatch, &input_state_ground },
402 { 0x50, 0x50, NULL, &input_state_dcs_enter },
403 { 0x51, 0x57, input_esc_dispatch, &input_state_ground },
404 { 0x58, 0x58, NULL, &input_state_consume_st },
405 { 0x59, 0x59, input_esc_dispatch, &input_state_ground },
406 { 0x5a, 0x5a, input_esc_dispatch, &input_state_ground },
407 { 0x5b, 0x5b, NULL, &input_state_csi_enter },
408 { 0x5c, 0x5c, input_esc_dispatch, &input_state_ground },
409 { 0x5d, 0x5d, NULL, &input_state_osc_string },
410 { 0x5e, 0x5e, NULL, &input_state_consume_st },
411 { 0x5f, 0x5f, NULL, &input_state_apc_string },
412 { 0x60, 0x6a, input_esc_dispatch, &input_state_ground },
413 { 0x6b, 0x6b, NULL, &input_state_rename_string },
414 { 0x6c, 0x7e, input_esc_dispatch, &input_state_ground },
415 { 0x7f, 0xff, NULL, NULL },
417 { -1, -1, NULL, NULL }
420 /* esc_interm state table. */
421 const struct input_transition input_state_esc_intermediate_table[] = {
422 INPUT_STATE_ANYWHERE,
424 { 0x00, 0x17, input_c0_dispatch, NULL },
425 { 0x19, 0x19, input_c0_dispatch, NULL },
426 { 0x1c, 0x1f, input_c0_dispatch, NULL },
427 { 0x20, 0x2f, input_intermediate, NULL },
428 { 0x30, 0x7e, input_esc_dispatch, &input_state_ground },
429 { 0x7f, 0xff, NULL, NULL },
431 { -1, -1, NULL, NULL }
434 /* csi_enter state table. */
435 const struct input_transition input_state_csi_enter_table[] = {
436 INPUT_STATE_ANYWHERE,
438 { 0x00, 0x17, input_c0_dispatch, NULL },
439 { 0x19, 0x19, input_c0_dispatch, NULL },
440 { 0x1c, 0x1f, input_c0_dispatch, NULL },
441 { 0x20, 0x2f, input_intermediate, &input_state_csi_intermediate },
442 { 0x30, 0x39, input_parameter, &input_state_csi_parameter },
443 { 0x3a, 0x3a, NULL, &input_state_csi_ignore },
444 { 0x3b, 0x3b, input_parameter, &input_state_csi_parameter },
445 { 0x3c, 0x3f, input_intermediate, &input_state_csi_parameter },
446 { 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
447 { 0x7f, 0xff, NULL, NULL },
449 { -1, -1, NULL, NULL }
452 /* csi_parameter state table. */
453 const struct input_transition input_state_csi_parameter_table[] = {
454 INPUT_STATE_ANYWHERE,
456 { 0x00, 0x17, input_c0_dispatch, NULL },
457 { 0x19, 0x19, input_c0_dispatch, NULL },
458 { 0x1c, 0x1f, input_c0_dispatch, NULL },
459 { 0x20, 0x2f, input_intermediate, &input_state_csi_intermediate },
460 { 0x30, 0x39, input_parameter, NULL },
461 { 0x3a, 0x3a, NULL, &input_state_csi_ignore },
462 { 0x3b, 0x3b, input_parameter, NULL },
463 { 0x3c, 0x3f, NULL, &input_state_csi_ignore },
464 { 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
465 { 0x7f, 0xff, NULL, NULL },
467 { -1, -1, NULL, NULL }
470 /* csi_intermediate state table. */
471 const struct input_transition input_state_csi_intermediate_table[] = {
472 INPUT_STATE_ANYWHERE,
474 { 0x00, 0x17, input_c0_dispatch, NULL },
475 { 0x19, 0x19, input_c0_dispatch, NULL },
476 { 0x1c, 0x1f, input_c0_dispatch, NULL },
477 { 0x20, 0x2f, input_intermediate, NULL },
478 { 0x30, 0x3f, NULL, &input_state_csi_ignore },
479 { 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
480 { 0x7f, 0xff, NULL, NULL },
482 { -1, -1, NULL, NULL }
485 /* csi_ignore state table. */
486 const struct input_transition input_state_csi_ignore_table[] = {
487 INPUT_STATE_ANYWHERE,
489 { 0x00, 0x17, input_c0_dispatch, NULL },
490 { 0x19, 0x19, input_c0_dispatch, NULL },
491 { 0x1c, 0x1f, input_c0_dispatch, NULL },
492 { 0x20, 0x3f, NULL, NULL },
493 { 0x40, 0x7e, NULL, &input_state_ground },
494 { 0x7f, 0xff, NULL, NULL },
496 { -1, -1, NULL, NULL }
499 /* dcs_enter state table. */
500 const struct input_transition input_state_dcs_enter_table[] = {
501 INPUT_STATE_ANYWHERE,
503 { 0x00, 0x17, NULL, NULL },
504 { 0x19, 0x19, NULL, NULL },
505 { 0x1c, 0x1f, NULL, NULL },
506 { 0x20, 0x2f, input_intermediate, &input_state_dcs_intermediate },
507 { 0x30, 0x39, input_parameter, &input_state_dcs_parameter },
508 { 0x3a, 0x3a, NULL, &input_state_dcs_ignore },
509 { 0x3b, 0x3b, input_parameter, &input_state_dcs_parameter },
510 { 0x3c, 0x3f, input_intermediate, &input_state_dcs_parameter },
511 { 0x40, 0x7e, input_input, &input_state_dcs_handler },
512 { 0x7f, 0xff, NULL, NULL },
514 { -1, -1, NULL, NULL }
517 /* dcs_parameter state table. */
518 const struct input_transition input_state_dcs_parameter_table[] = {
519 INPUT_STATE_ANYWHERE,
521 { 0x00, 0x17, NULL, NULL },
522 { 0x19, 0x19, NULL, NULL },
523 { 0x1c, 0x1f, NULL, NULL },
524 { 0x20, 0x2f, input_intermediate, &input_state_dcs_intermediate },
525 { 0x30, 0x39, input_parameter, NULL },
526 { 0x3a, 0x3a, NULL, &input_state_dcs_ignore },
527 { 0x3b, 0x3b, input_parameter, NULL },
528 { 0x3c, 0x3f, NULL, &input_state_dcs_ignore },
529 { 0x40, 0x7e, input_input, &input_state_dcs_handler },
530 { 0x7f, 0xff, NULL, NULL },
532 { -1, -1, NULL, NULL }
535 /* dcs_interm state table. */
536 const struct input_transition input_state_dcs_intermediate_table[] = {
537 INPUT_STATE_ANYWHERE,
539 { 0x00, 0x17, NULL, NULL },
540 { 0x19, 0x19, NULL, NULL },
541 { 0x1c, 0x1f, NULL, NULL },
542 { 0x20, 0x2f, input_intermediate, NULL },
543 { 0x30, 0x3f, NULL, &input_state_dcs_ignore },
544 { 0x40, 0x7e, input_input, &input_state_dcs_handler },
545 { 0x7f, 0xff, NULL, NULL },
547 { -1, -1, NULL, NULL }
550 /* dcs_handler state table. */
551 const struct input_transition input_state_dcs_handler_table[] = {
552 /* No INPUT_STATE_ANYWHERE */
554 { 0x00, 0x1a, input_input, NULL },
555 { 0x1b, 0x1b, NULL, &input_state_dcs_escape },
556 { 0x1c, 0xff, input_input, NULL },
558 { -1, -1, NULL, NULL }
561 /* dcs_escape state table. */
562 const struct input_transition input_state_dcs_escape_table[] = {
563 /* No INPUT_STATE_ANYWHERE */
565 { 0x00, 0x5b, input_input, &input_state_dcs_handler },
566 { 0x5c, 0x5c, input_dcs_dispatch, &input_state_ground },
567 { 0x5d, 0xff, input_input, &input_state_dcs_handler },
569 { -1, -1, NULL, NULL }
572 /* dcs_ignore state table. */
573 const struct input_transition input_state_dcs_ignore_table[] = {
574 INPUT_STATE_ANYWHERE,
576 { 0x00, 0x17, NULL, NULL },
577 { 0x19, 0x19, NULL, NULL },
578 { 0x1c, 0x1f, NULL, NULL },
579 { 0x20, 0xff, NULL, NULL },
581 { -1, -1, NULL, NULL }
584 /* osc_string state table. */
585 const struct input_transition input_state_osc_string_table[] = {
586 INPUT_STATE_ANYWHERE,
588 { 0x00, 0x06, NULL, NULL },
589 { 0x07, 0x07, NULL, &input_state_ground },
590 { 0x08, 0x17, NULL, NULL },
591 { 0x19, 0x19, NULL, NULL },
592 { 0x1c, 0x1f, NULL, NULL },
593 { 0x20, 0xff, input_input, NULL },
595 { -1, -1, NULL, NULL }
598 /* apc_string state table. */
599 const struct input_transition input_state_apc_string_table[] = {
600 INPUT_STATE_ANYWHERE,
602 { 0x00, 0x17, NULL, NULL },
603 { 0x19, 0x19, NULL, NULL },
604 { 0x1c, 0x1f, NULL, NULL },
605 { 0x20, 0xff, input_input, NULL },
607 { -1, -1, NULL, NULL }
610 /* rename_string state table. */
611 const struct input_transition input_state_rename_string_table[] = {
612 INPUT_STATE_ANYWHERE,
614 { 0x00, 0x17, NULL, NULL },
615 { 0x19, 0x19, NULL, NULL },
616 { 0x1c, 0x1f, NULL, NULL },
617 { 0x20, 0xff, input_input, NULL },
619 { -1, -1, NULL, NULL }
622 /* consume_st state table. */
623 const struct input_transition input_state_consume_st_table[] = {
624 INPUT_STATE_ANYWHERE,
626 { 0x00, 0x17, NULL, NULL },
627 { 0x19, 0x19, NULL, NULL },
628 { 0x1c, 0x1f, NULL, NULL },
629 { 0x20, 0xff, NULL, NULL },
631 { -1, -1, NULL, NULL }
634 /* utf8_three state table. */
635 const struct input_transition input_state_utf8_three_table[] = {
636 /* No INPUT_STATE_ANYWHERE */
638 { 0x00, 0x7f, NULL, &input_state_ground },
639 { 0x80, 0xbf, input_utf8_add, &input_state_utf8_two },
640 { 0xc0, 0xff, NULL, &input_state_ground },
642 { -1, -1, NULL, NULL }
645 /* utf8_two state table. */
646 const struct input_transition input_state_utf8_two_table[] = {
647 /* No INPUT_STATE_ANYWHERE */
649 { 0x00, 0x7f, NULL, &input_state_ground },
650 { 0x80, 0xbf, input_utf8_add, &input_state_utf8_one },
651 { 0xc0, 0xff, NULL, &input_state_ground },
653 { -1, -1, NULL, NULL }
656 /* utf8_one state table. */
657 const struct input_transition input_state_utf8_one_table[] = {
658 /* No INPUT_STATE_ANYWHERE */
660 { 0x00, 0x7f, NULL, &input_state_ground },
661 { 0x80, 0xbf, input_utf8_close, &input_state_ground },
662 { 0xc0, 0xff, NULL, &input_state_ground },
664 { -1, -1, NULL, NULL }
667 /* Input table compare. */
669 input_table_compare(const void *key, const void *value)
671 const struct input_ctx *ictx = key;
672 const struct input_table_entry *entry = value;
674 if (ictx->ch != entry->ch)
675 return (ictx->ch - entry->ch);
676 return (strcmp(ictx->interm_buf, entry->interm));
679 /* Initialise input parser. */
680 void
681 input_init(struct window_pane *wp)
683 struct input_ctx *ictx = &wp->ictx;
685 memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell);
687 memcpy(&ictx->old_cell, &grid_default_cell, sizeof ictx->old_cell);
688 ictx->old_cx = 0;
689 ictx->old_cy = 0;
691 *ictx->interm_buf = '\0';
692 ictx->interm_len = 0;
694 *ictx->param_buf = '\0';
695 ictx->param_len = 0;
697 ictx->state = &input_state_ground;
698 ictx->flags = 0;
700 ictx->since_ground = evbuffer_new();
703 /* Destroy input parser. */
704 void
705 input_free(struct window_pane *wp)
707 if (wp != NULL)
708 evbuffer_free(wp->ictx.since_ground);
711 /* Change input state. */
712 void
713 input_set_state(struct window_pane *wp, const struct input_transition *itr)
715 struct input_ctx *ictx = &wp->ictx;
716 struct evbuffer *ground_evb = ictx->since_ground;
718 if (ictx->state->exit != NULL)
719 ictx->state->exit(ictx);
721 if (itr->state == &input_state_ground)
722 evbuffer_drain(ground_evb, EVBUFFER_LENGTH(ground_evb));
724 ictx->state = itr->state;
725 if (ictx->state->enter != NULL)
726 ictx->state->enter(ictx);
729 /* Parse input. */
730 void
731 input_parse(struct window_pane *wp)
733 struct input_ctx *ictx = &wp->ictx;
734 const struct input_transition *itr;
735 struct evbuffer *evb = wp->event->input;
736 u_char *buf;
737 size_t len, off;
739 if (EVBUFFER_LENGTH(evb) == 0)
740 return;
742 wp->window->flags |= WINDOW_ACTIVITY;
743 wp->window->flags &= ~WINDOW_SILENCE;
746 * Open the screen. Use NULL wp if there is a mode set as don't want to
747 * update the tty.
749 if (wp->mode == NULL)
750 screen_write_start(&ictx->ctx, wp, &wp->base);
751 else
752 screen_write_start(&ictx->ctx, NULL, &wp->base);
753 ictx->wp = wp;
755 buf = EVBUFFER_DATA(evb);
756 len = EVBUFFER_LENGTH(evb);
757 notify_input(wp, evb);
758 off = 0;
760 /* Parse the input. */
761 while (off < len) {
762 ictx->ch = buf[off++];
763 log_debug("%s: '%c' %s", __func__, ictx->ch, ictx->state->name);
765 /* Find the transition. */
766 itr = ictx->state->transitions;
767 while (itr->first != -1 && itr->last != -1) {
768 if (ictx->ch >= itr->first && ictx->ch <= itr->last)
769 break;
770 itr++;
772 if (itr->first == -1 || itr->last == -1) {
773 /* No transition? Eh? */
774 fatalx("No transition from state!");
778 * Execute the handler, if any. Don't switch state if it
779 * returns non-zero.
781 if (itr->handler != NULL && itr->handler(ictx) != 0)
782 continue;
784 /* And switch state, if necessary. */
785 if (itr->state != NULL)
786 input_set_state(wp, itr);
788 /* If not in ground state, save input. */
789 if (ictx->state != &input_state_ground)
790 evbuffer_add(ictx->since_ground, &ictx->ch, 1);
793 /* Close the screen. */
794 screen_write_stop(&ictx->ctx);
796 evbuffer_drain(evb, len);
799 /* Split the parameter list (if any). */
801 input_split(struct input_ctx *ictx)
804 const char *errstr;
805 char *ptr, *out;
806 int n;
808 ictx->param_list_len = 0;
809 if (ictx->param_len == 0)
810 return (0);
812 ptr = ictx->param_buf;
813 while ((out = strsep(&ptr, ";")) != NULL) {
814 if (*out == '\0')
815 n = -1;
816 else {
817 n = strtonum(out, 0, INT_MAX, &errstr);
818 if (errstr != NULL)
819 return (-1);
822 ictx->param_list[ictx->param_list_len++] = n;
823 if (ictx->param_list_len == nitems(ictx->param_list))
824 return (-1);
827 return (0);
830 /* Get an argument or return default value. */
832 input_get(struct input_ctx *ictx, u_int validx, int minval, int defval)
834 int retval;
836 if (validx >= ictx->param_list_len)
837 return (defval);
839 retval = ictx->param_list[validx];
840 if (retval == -1)
841 return (defval);
842 if (retval < minval)
843 return (minval);
844 return (retval);
847 /* Reply to terminal query. */
848 void
849 input_reply(struct input_ctx *ictx, const char *fmt, ...)
851 va_list ap;
852 char *reply;
854 va_start(ap, fmt);
855 vasprintf(&reply, fmt, ap);
856 va_end(ap);
858 bufferevent_write(ictx->wp->event, reply, strlen(reply));
859 free(reply);
862 /* Clear saved state. */
863 void
864 input_clear(struct input_ctx *ictx)
866 *ictx->interm_buf = '\0';
867 ictx->interm_len = 0;
869 *ictx->param_buf = '\0';
870 ictx->param_len = 0;
872 *ictx->input_buf = '\0';
873 ictx->input_len = 0;
875 ictx->flags &= ~INPUT_DISCARD;
878 /* Output this character to the screen. */
880 input_print(struct input_ctx *ictx)
882 grid_cell_one(&ictx->cell, ictx->ch);
883 screen_write_cell(&ictx->ctx, &ictx->cell);
885 return (0);
888 /* Collect intermediate string. */
890 input_intermediate(struct input_ctx *ictx)
892 if (ictx->interm_len == (sizeof ictx->interm_buf) - 1)
893 ictx->flags |= INPUT_DISCARD;
894 else {
895 ictx->interm_buf[ictx->interm_len++] = ictx->ch;
896 ictx->interm_buf[ictx->interm_len] = '\0';
899 return (0);
902 /* Collect parameter string. */
904 input_parameter(struct input_ctx *ictx)
906 if (ictx->param_len == (sizeof ictx->param_buf) - 1)
907 ictx->flags |= INPUT_DISCARD;
908 else {
909 ictx->param_buf[ictx->param_len++] = ictx->ch;
910 ictx->param_buf[ictx->param_len] = '\0';
913 return (0);
916 /* Collect input string. */
918 input_input(struct input_ctx *ictx)
920 if (ictx->input_len == (sizeof ictx->input_buf) - 1)
921 ictx->flags |= INPUT_DISCARD;
922 else {
923 ictx->input_buf[ictx->input_len++] = ictx->ch;
924 ictx->input_buf[ictx->input_len] = '\0';
927 return (0);
930 /* Execute C0 control sequence. */
932 input_c0_dispatch(struct input_ctx *ictx)
934 struct screen_write_ctx *sctx = &ictx->ctx;
935 struct window_pane *wp = ictx->wp;
936 struct screen *s = sctx->s;
937 u_int trigger;
939 log_debug("%s: '%c", __func__, ictx->ch);
941 switch (ictx->ch) {
942 case '\000': /* NUL */
943 break;
944 case '\007': /* BEL */
945 wp->window->flags |= WINDOW_BELL;
946 break;
947 case '\010': /* BS */
948 screen_write_backspace(sctx);
949 goto count_c0;
950 case '\011': /* HT */
951 /* Don't tab beyond the end of the line. */
952 if (s->cx >= screen_size_x(s) - 1)
953 break;
955 /* Find the next tab point, or use the last column if none. */
956 do {
957 s->cx++;
958 if (bit_test(s->tabs, s->cx))
959 break;
960 } while (s->cx < screen_size_x(s) - 1);
961 break;
962 case '\012': /* LF */
963 case '\013': /* VT */
964 case '\014': /* FF */
965 screen_write_linefeed(sctx, 0);
966 goto count_c0;
967 case '\015': /* CR */
968 screen_write_carriagereturn(sctx);
969 goto count_c0;
970 case '\016': /* SO */
971 ictx->cell.attr |= GRID_ATTR_CHARSET;
972 break;
973 case '\017': /* SI */
974 ictx->cell.attr &= ~GRID_ATTR_CHARSET;
975 break;
976 default:
977 log_debug("%s: unknown '%c'", __func__, ictx->ch);
978 break;
981 return (0);
983 count_c0:
984 trigger = options_get_number(&wp->window->options, "c0-change-trigger");
985 if (++wp->changes == trigger) {
986 wp->flags |= PANE_DROP;
987 window_pane_timer_start(wp);
990 return (0);
993 /* Execute escape sequence. */
995 input_esc_dispatch(struct input_ctx *ictx)
997 struct screen_write_ctx *sctx = &ictx->ctx;
998 struct screen *s = sctx->s;
999 struct input_table_entry *entry;
1001 if (ictx->flags & INPUT_DISCARD)
1002 return (0);
1003 log_debug("%s: '%c', %s", __func__, ictx->ch, ictx->interm_buf);
1005 entry = bsearch(ictx, input_esc_table, nitems(input_esc_table),
1006 sizeof input_esc_table[0], input_table_compare);
1007 if (entry == NULL) {
1008 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1009 return (0);
1012 switch (entry->type) {
1013 case INPUT_ESC_RIS:
1014 memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell);
1015 memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
1016 ictx->old_cx = 0;
1017 ictx->old_cy = 0;
1019 screen_write_reset(sctx);
1020 break;
1021 case INPUT_ESC_IND:
1022 screen_write_linefeed(sctx, 0);
1023 break;
1024 case INPUT_ESC_NEL:
1025 screen_write_carriagereturn(sctx);
1026 screen_write_linefeed(sctx, 0);
1027 break;
1028 case INPUT_ESC_HTS:
1029 if (s->cx < screen_size_x(s))
1030 bit_set(s->tabs, s->cx);
1031 break;
1032 case INPUT_ESC_RI:
1033 screen_write_reverseindex(sctx);
1034 break;
1035 case INPUT_ESC_DECKPAM:
1036 screen_write_mode_set(sctx, MODE_KKEYPAD);
1037 break;
1038 case INPUT_ESC_DECKPNM:
1039 screen_write_mode_clear(sctx, MODE_KKEYPAD);
1040 break;
1041 case INPUT_ESC_DECSC:
1042 memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
1043 ictx->old_cx = s->cx;
1044 ictx->old_cy = s->cy;
1045 break;
1046 case INPUT_ESC_DECRC:
1047 memcpy(&ictx->cell, &ictx->old_cell, sizeof ictx->cell);
1048 screen_write_cursormove(sctx, ictx->old_cx, ictx->old_cy);
1049 break;
1050 case INPUT_ESC_DECALN:
1051 screen_write_alignmenttest(sctx);
1052 break;
1053 case INPUT_ESC_SCSON_G0:
1055 * Not really supported, but fake it up enough for those that
1056 * use it to switch character sets (by redefining G0 to
1057 * graphics set, rather than switching to G1).
1059 ictx->cell.attr &= ~GRID_ATTR_CHARSET;
1060 break;
1061 case INPUT_ESC_SCSOFF_G0:
1062 ictx->cell.attr |= GRID_ATTR_CHARSET;
1063 break;
1066 return (0);
1069 /* Execute control sequence. */
1071 input_csi_dispatch(struct input_ctx *ictx)
1073 struct screen_write_ctx *sctx = &ictx->ctx;
1074 struct window_pane *wp = ictx->wp;
1075 struct screen *s = sctx->s;
1076 struct input_table_entry *entry;
1077 int n, m;
1079 if (ictx->flags & INPUT_DISCARD)
1080 return (0);
1081 if (input_split(ictx) != 0)
1082 return (0);
1083 log_debug("%s: '%c' \"%s\" \"%s\"",
1084 __func__, ictx->ch, ictx->interm_buf, ictx->param_buf);
1086 entry = bsearch(ictx, input_csi_table, nitems(input_csi_table),
1087 sizeof input_csi_table[0], input_table_compare);
1088 if (entry == NULL) {
1089 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1090 return (0);
1093 switch (entry->type) {
1094 case INPUT_CSI_CBT:
1095 /* Find the previous tab point, n times. */
1096 n = input_get(ictx, 0, 1, 1);
1097 while (s->cx > 0 && n-- > 0) {
1099 s->cx--;
1100 while (s->cx > 0 && !bit_test(s->tabs, s->cx));
1102 break;
1103 case INPUT_CSI_CUB:
1104 screen_write_cursorleft(sctx, input_get(ictx, 0, 1, 1));
1105 break;
1106 case INPUT_CSI_CUD:
1107 screen_write_cursordown(sctx, input_get(ictx, 0, 1, 1));
1108 break;
1109 case INPUT_CSI_CUF:
1110 screen_write_cursorright(sctx, input_get(ictx, 0, 1, 1));
1111 break;
1112 case INPUT_CSI_CUP:
1113 n = input_get(ictx, 0, 1, 1);
1114 m = input_get(ictx, 1, 1, 1);
1115 screen_write_cursormove(sctx, m - 1, n - 1);
1116 break;
1117 case INPUT_CSI_CUU:
1118 screen_write_cursorup(sctx, input_get(ictx, 0, 1, 1));
1119 break;
1120 case INPUT_CSI_CNL:
1121 screen_write_carriagereturn(sctx);
1122 screen_write_cursordown(sctx, input_get(ictx, 0, 1, 1));
1123 break;
1124 case INPUT_CSI_CPL:
1125 screen_write_carriagereturn(sctx);
1126 screen_write_cursorup(sctx, input_get(ictx, 0, 1, 1));
1127 break;
1128 case INPUT_CSI_DA:
1129 switch (input_get(ictx, 0, 0, 0)) {
1130 case 0:
1131 input_reply(ictx, "\033[?1;2c");
1132 break;
1133 default:
1134 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1135 break;
1137 break;
1138 case INPUT_CSI_DA_TWO:
1139 switch (input_get(ictx, 0, 0, 0)) {
1140 case 0:
1141 input_reply(ictx, "\033[>0;95;0c");
1142 break;
1143 default:
1144 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1145 break;
1147 break;
1148 case INPUT_CSI_ECH:
1149 screen_write_clearcharacter(sctx, input_get(ictx, 0, 1, 1));
1150 break;
1151 case INPUT_CSI_DCH:
1152 screen_write_deletecharacter(sctx, input_get(ictx, 0, 1, 1));
1153 break;
1154 case INPUT_CSI_DECSTBM:
1155 n = input_get(ictx, 0, 1, 1);
1156 m = input_get(ictx, 1, 1, screen_size_y(s));
1157 screen_write_scrollregion(sctx, n - 1, m - 1);
1158 break;
1159 case INPUT_CSI_DL:
1160 screen_write_deleteline(sctx, input_get(ictx, 0, 1, 1));
1161 break;
1162 case INPUT_CSI_DSR:
1163 switch (input_get(ictx, 0, 0, 0)) {
1164 case 5:
1165 input_reply(ictx, "\033[0n");
1166 break;
1167 case 6:
1168 input_reply(ictx, "\033[%u;%uR", s->cy + 1, s->cx + 1);
1169 break;
1170 default:
1171 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1172 break;
1174 break;
1175 case INPUT_CSI_ED:
1176 switch (input_get(ictx, 0, 0, 0)) {
1177 case 0:
1178 screen_write_clearendofscreen(sctx);
1179 break;
1180 case 1:
1181 screen_write_clearstartofscreen(sctx);
1182 break;
1183 case 2:
1184 screen_write_clearscreen(sctx);
1185 break;
1186 case 3:
1187 switch (input_get(ictx, 1, 0, 0)) {
1188 case 0:
1190 * Linux console extension to clear history
1191 * (for example before locking the screen).
1193 screen_write_clearhistory(sctx);
1194 break;
1196 break;
1197 default:
1198 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1199 break;
1201 break;
1202 case INPUT_CSI_EL:
1203 switch (input_get(ictx, 0, 0, 0)) {
1204 case 0:
1205 screen_write_clearendofline(sctx);
1206 break;
1207 case 1:
1208 screen_write_clearstartofline(sctx);
1209 break;
1210 case 2:
1211 screen_write_clearline(sctx);
1212 break;
1213 default:
1214 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1215 break;
1217 break;
1218 case INPUT_CSI_HPA:
1219 n = input_get(ictx, 0, 1, 1);
1220 screen_write_cursormove(sctx, n - 1, s->cy);
1221 break;
1222 case INPUT_CSI_ICH:
1223 screen_write_insertcharacter(sctx, input_get(ictx, 0, 1, 1));
1224 break;
1225 case INPUT_CSI_IL:
1226 screen_write_insertline(sctx, input_get(ictx, 0, 1, 1));
1227 break;
1228 case INPUT_CSI_RCP:
1229 memcpy(&ictx->cell, &ictx->old_cell, sizeof ictx->cell);
1230 screen_write_cursormove(sctx, ictx->old_cx, ictx->old_cy);
1231 break;
1232 case INPUT_CSI_RM:
1233 switch (input_get(ictx, 0, 0, -1)) {
1234 case 4: /* IRM */
1235 screen_write_mode_clear(&ictx->ctx, MODE_INSERT);
1236 break;
1237 default:
1238 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1239 break;
1241 break;
1242 case INPUT_CSI_RM_PRIVATE:
1243 switch (input_get(ictx, 0, 0, -1)) {
1244 case 1: /* GATM */
1245 screen_write_mode_clear(&ictx->ctx, MODE_KCURSOR);
1246 break;
1247 case 3: /* DECCOLM */
1248 screen_write_cursormove(&ictx->ctx, 0, 0);
1249 screen_write_clearscreen(&ictx->ctx);
1250 break;
1251 case 7: /* DECAWM */
1252 screen_write_mode_clear(&ictx->ctx, MODE_WRAP);
1253 break;
1254 case 25: /* TCEM */
1255 screen_write_mode_clear(&ictx->ctx, MODE_CURSOR);
1256 break;
1257 case 1000:
1258 case 1001:
1259 case 1002:
1260 case 1003:
1261 screen_write_mode_clear(&ictx->ctx, ALL_MOUSE_MODES);
1262 break;
1263 case 1004:
1264 screen_write_mode_clear(&ictx->ctx, MODE_FOCUSON);
1265 break;
1266 case 1005:
1267 screen_write_mode_clear(&ictx->ctx, MODE_MOUSE_UTF8);
1268 break;
1269 case 1006:
1270 screen_write_mode_clear(&ictx->ctx, MODE_MOUSE_SGR);
1271 break;
1272 case 47:
1273 case 1047:
1274 window_pane_alternate_off(wp, &ictx->cell, 0);
1275 break;
1276 case 1049:
1277 window_pane_alternate_off(wp, &ictx->cell, 1);
1278 break;
1279 case 2004:
1280 screen_write_mode_clear(&ictx->ctx, MODE_BRACKETPASTE);
1281 break;
1282 default:
1283 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1284 break;
1286 break;
1287 case INPUT_CSI_SCP:
1288 memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
1289 ictx->old_cx = s->cx;
1290 ictx->old_cy = s->cy;
1291 break;
1292 case INPUT_CSI_SGR:
1293 input_csi_dispatch_sgr(ictx);
1294 break;
1295 case INPUT_CSI_SM:
1296 switch (input_get(ictx, 0, 0, -1)) {
1297 case 4: /* IRM */
1298 screen_write_mode_set(&ictx->ctx, MODE_INSERT);
1299 break;
1300 default:
1301 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1302 break;
1304 break;
1305 case INPUT_CSI_SM_PRIVATE:
1306 switch (input_get(ictx, 0, 0, -1)) {
1307 case 1: /* GATM */
1308 screen_write_mode_set(&ictx->ctx, MODE_KCURSOR);
1309 break;
1310 case 3: /* DECCOLM */
1311 screen_write_cursormove(&ictx->ctx, 0, 0);
1312 screen_write_clearscreen(&ictx->ctx);
1313 break;
1314 case 7: /* DECAWM */
1315 screen_write_mode_set(&ictx->ctx, MODE_WRAP);
1316 break;
1317 case 25: /* TCEM */
1318 screen_write_mode_set(&ictx->ctx, MODE_CURSOR);
1319 break;
1320 case 1000:
1321 screen_write_mode_clear(&ictx->ctx, ALL_MOUSE_MODES);
1322 screen_write_mode_set(&ictx->ctx, MODE_MOUSE_STANDARD);
1323 break;
1324 case 1002:
1325 screen_write_mode_clear(&ictx->ctx, ALL_MOUSE_MODES);
1326 screen_write_mode_set(&ictx->ctx, MODE_MOUSE_BUTTON);
1327 break;
1328 case 1003:
1329 screen_write_mode_clear(&ictx->ctx, ALL_MOUSE_MODES);
1330 screen_write_mode_set(&ictx->ctx, MODE_MOUSE_ANY);
1331 break;
1332 case 1004:
1333 if (s->mode & MODE_FOCUSON)
1334 break;
1335 screen_write_mode_set(&ictx->ctx, MODE_FOCUSON);
1336 wp->flags &= ~PANE_FOCUSED; /* force update if needed */
1337 break;
1338 case 1005:
1339 screen_write_mode_set(&ictx->ctx, MODE_MOUSE_UTF8);
1340 break;
1341 case 1006:
1342 screen_write_mode_set(&ictx->ctx, MODE_MOUSE_SGR);
1343 break;
1344 case 47:
1345 case 1047:
1346 window_pane_alternate_on(wp, &ictx->cell, 0);
1347 break;
1348 case 1049:
1349 window_pane_alternate_on(wp, &ictx->cell, 1);
1350 break;
1351 case 2004:
1352 screen_write_mode_set(&ictx->ctx, MODE_BRACKETPASTE);
1353 break;
1354 default:
1355 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1356 break;
1358 break;
1359 case INPUT_CSI_TBC:
1360 switch (input_get(ictx, 0, 0, 0)) {
1361 case 0:
1362 if (s->cx < screen_size_x(s))
1363 bit_clear(s->tabs, s->cx);
1364 break;
1365 case 3:
1366 bit_nclear(s->tabs, 0, screen_size_x(s) - 1);
1367 break;
1368 default:
1369 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1370 break;
1372 break;
1373 case INPUT_CSI_VPA:
1374 n = input_get(ictx, 0, 1, 1);
1375 screen_write_cursormove(sctx, s->cx, n - 1);
1376 break;
1377 case INPUT_CSI_DECSCUSR:
1378 n = input_get(ictx, 0, 0, 0);
1379 screen_set_cursor_style(s, n);
1380 break;
1383 return (0);
1386 /* Handle CSI SGR. */
1387 void
1388 input_csi_dispatch_sgr(struct input_ctx *ictx)
1390 struct grid_cell *gc = &ictx->cell;
1391 u_int i;
1392 int n, m;
1393 u_char attr;
1395 if (ictx->param_list_len == 0) {
1396 attr = gc->attr;
1397 memcpy(gc, &grid_default_cell, sizeof *gc);
1398 gc->attr |= (attr & GRID_ATTR_CHARSET);
1399 return;
1402 for (i = 0; i < ictx->param_list_len; i++) {
1403 n = input_get(ictx, i, 0, 0);
1405 if (n == 38 || n == 48) {
1406 i++;
1407 if (input_get(ictx, i, 0, -1) != 5)
1408 continue;
1410 i++;
1411 m = input_get(ictx, i, 0, -1);
1412 if (m == -1) {
1413 if (n == 38) {
1414 gc->flags &= ~GRID_FLAG_FG256;
1415 gc->fg = 8;
1416 } else if (n == 48) {
1417 gc->flags &= ~GRID_FLAG_BG256;
1418 gc->bg = 8;
1421 } else {
1422 if (n == 38) {
1423 gc->flags |= GRID_FLAG_FG256;
1424 gc->fg = m;
1425 } else if (n == 48) {
1426 gc->flags |= GRID_FLAG_BG256;
1427 gc->bg = m;
1430 continue;
1433 switch (n) {
1434 case 0:
1435 case 10:
1436 attr = gc->attr;
1437 memcpy(gc, &grid_default_cell, sizeof *gc);
1438 gc->attr |= (attr & GRID_ATTR_CHARSET);
1439 break;
1440 case 1:
1441 gc->attr |= GRID_ATTR_BRIGHT;
1442 break;
1443 case 2:
1444 gc->attr |= GRID_ATTR_DIM;
1445 break;
1446 case 3:
1447 gc->attr |= GRID_ATTR_ITALICS;
1448 break;
1449 case 4:
1450 gc->attr |= GRID_ATTR_UNDERSCORE;
1451 break;
1452 case 5:
1453 gc->attr |= GRID_ATTR_BLINK;
1454 break;
1455 case 7:
1456 gc->attr |= GRID_ATTR_REVERSE;
1457 break;
1458 case 8:
1459 gc->attr |= GRID_ATTR_HIDDEN;
1460 break;
1461 case 22:
1462 gc->attr &= ~(GRID_ATTR_BRIGHT|GRID_ATTR_DIM);
1463 break;
1464 case 23:
1465 gc->attr &= ~GRID_ATTR_ITALICS;
1466 break;
1467 case 24:
1468 gc->attr &= ~GRID_ATTR_UNDERSCORE;
1469 break;
1470 case 25:
1471 gc->attr &= ~GRID_ATTR_BLINK;
1472 break;
1473 case 27:
1474 gc->attr &= ~GRID_ATTR_REVERSE;
1475 break;
1476 case 30:
1477 case 31:
1478 case 32:
1479 case 33:
1480 case 34:
1481 case 35:
1482 case 36:
1483 case 37:
1484 gc->flags &= ~GRID_FLAG_FG256;
1485 gc->fg = n - 30;
1486 break;
1487 case 39:
1488 gc->flags &= ~GRID_FLAG_FG256;
1489 gc->fg = 8;
1490 break;
1491 case 40:
1492 case 41:
1493 case 42:
1494 case 43:
1495 case 44:
1496 case 45:
1497 case 46:
1498 case 47:
1499 gc->flags &= ~GRID_FLAG_BG256;
1500 gc->bg = n - 40;
1501 break;
1502 case 49:
1503 gc->flags &= ~GRID_FLAG_BG256;
1504 gc->bg = 8;
1505 break;
1506 case 90:
1507 case 91:
1508 case 92:
1509 case 93:
1510 case 94:
1511 case 95:
1512 case 96:
1513 case 97:
1514 gc->flags &= ~GRID_FLAG_FG256;
1515 gc->fg = n;
1516 break;
1517 case 100:
1518 case 101:
1519 case 102:
1520 case 103:
1521 case 104:
1522 case 105:
1523 case 106:
1524 case 107:
1525 gc->flags &= ~GRID_FLAG_BG256;
1526 gc->bg = n - 10;
1527 break;
1532 /* DCS terminator (ST) received. */
1534 input_dcs_dispatch(struct input_ctx *ictx)
1536 const char prefix[] = "tmux;";
1537 const u_int prefix_len = (sizeof prefix) - 1;
1539 if (ictx->flags & INPUT_DISCARD)
1540 return (0);
1542 log_debug("%s: \"%s\"", __func__, ictx->input_buf);
1544 /* Check for tmux prefix. */
1545 if (ictx->input_len >= prefix_len &&
1546 strncmp(ictx->input_buf, prefix, prefix_len) == 0) {
1547 screen_write_rawstring(&ictx->ctx,
1548 ictx->input_buf + prefix_len, ictx->input_len - prefix_len);
1551 return (0);
1554 /* OSC string started. */
1555 void
1556 input_enter_osc(struct input_ctx *ictx)
1558 log_debug("%s", __func__);
1560 input_clear(ictx);
1563 /* OSC terminator (ST) received. */
1564 void
1565 input_exit_osc(struct input_ctx *ictx)
1567 u_char *p = ictx->input_buf;
1568 int option;
1570 if (ictx->flags & INPUT_DISCARD)
1571 return;
1572 if (ictx->input_len < 1 || *p < '0' || *p > '9')
1573 return;
1575 log_debug("%s: \"%s\"", __func__, p);
1577 option = 0;
1578 while (*p >= '0' && *p <= '9')
1579 option = option * 10 + *p++ - '0';
1580 if (*p == ';')
1581 p++;
1583 switch (option) {
1584 case 0:
1585 case 2:
1586 screen_set_title(ictx->ctx.s, p);
1587 server_status_window(ictx->wp->window);
1588 break;
1589 case 12:
1590 if (*p != '?') /* ? is colour request */
1591 screen_set_cursor_colour(ictx->ctx.s, p);
1592 break;
1593 case 112:
1594 if (*p == '\0') /* no arguments allowed */
1595 screen_set_cursor_colour(ictx->ctx.s, "");
1596 break;
1597 default:
1598 log_debug("%s: unknown '%u'", __func__, option);
1599 break;
1603 /* APC string started. */
1604 void
1605 input_enter_apc(struct input_ctx *ictx)
1607 log_debug("%s", __func__);
1609 input_clear(ictx);
1612 /* APC terminator (ST) received. */
1613 void
1614 input_exit_apc(struct input_ctx *ictx)
1616 if (ictx->flags & INPUT_DISCARD)
1617 return;
1618 log_debug("%s: \"%s\"", __func__, ictx->input_buf);
1620 screen_set_title(ictx->ctx.s, ictx->input_buf);
1621 server_status_window(ictx->wp->window);
1624 /* Rename string started. */
1625 void
1626 input_enter_rename(struct input_ctx *ictx)
1628 log_debug("%s", __func__);
1630 input_clear(ictx);
1633 /* Rename terminator (ST) received. */
1634 void
1635 input_exit_rename(struct input_ctx *ictx)
1637 if (ictx->flags & INPUT_DISCARD)
1638 return;
1639 if (!options_get_number(&ictx->wp->window->options, "allow-rename"))
1640 return;
1641 log_debug("%s: \"%s\"", __func__, ictx->input_buf);
1643 window_set_name(ictx->wp->window, ictx->input_buf);
1644 options_set_number(&ictx->wp->window->options, "automatic-rename", 0);
1646 server_status_window(ictx->wp->window);
1649 /* Open UTF-8 character. */
1651 input_utf8_open(struct input_ctx *ictx)
1653 if (!options_get_number(&ictx->wp->window->options, "utf8")) {
1654 /* Print, and do not switch state. */
1655 input_print(ictx);
1656 return (-1);
1658 log_debug("%s", __func__);
1660 utf8_open(&ictx->utf8data, ictx->ch);
1661 return (0);
1664 /* Append to UTF-8 character. */
1666 input_utf8_add(struct input_ctx *ictx)
1668 log_debug("%s", __func__);
1670 utf8_append(&ictx->utf8data, ictx->ch);
1671 return (0);
1674 /* Close UTF-8 string. */
1676 input_utf8_close(struct input_ctx *ictx)
1678 log_debug("%s", __func__);
1680 utf8_append(&ictx->utf8data, ictx->ch);
1682 grid_cell_set(&ictx->cell, &ictx->utf8data);
1683 screen_write_cell(&ictx->ctx, &ictx->cell);
1685 return (0);