Change the way the working directory for new processes is discovered. If
[tmux-openbsd.git] / input.c
bloba914aa5a6b7c5e396435f5c6904aec572875d063
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_RM,
139 INPUT_CSI_RM_PRIVATE,
140 INPUT_CSI_SGR,
141 INPUT_CSI_SM,
142 INPUT_CSI_SM_PRIVATE,
143 INPUT_CSI_TBC,
144 INPUT_CSI_VPA,
147 /* Control (CSI) command table. */
148 const struct input_table_entry input_csi_table[] = {
149 { '@', "", INPUT_CSI_ICH },
150 { 'A', "", INPUT_CSI_CUU },
151 { 'B', "", INPUT_CSI_CUD },
152 { 'C', "", INPUT_CSI_CUF },
153 { 'D', "", INPUT_CSI_CUB },
154 { 'G', "", INPUT_CSI_HPA },
155 { 'H', "", INPUT_CSI_CUP },
156 { 'J', "", INPUT_CSI_ED },
157 { 'K', "", INPUT_CSI_EL },
158 { 'L', "", INPUT_CSI_IL },
159 { 'M', "", INPUT_CSI_DL },
160 { 'P', "", INPUT_CSI_DCH },
161 { 'Z', "", INPUT_CSI_CBT },
162 { 'c', "", INPUT_CSI_DA },
163 { 'd', "", INPUT_CSI_VPA },
164 { 'f', "", INPUT_CSI_CUP },
165 { 'g', "", INPUT_CSI_TBC },
166 { 'h', "", INPUT_CSI_SM },
167 { 'h', "?", INPUT_CSI_SM_PRIVATE },
168 { 'l', "", INPUT_CSI_RM },
169 { 'l', "?", INPUT_CSI_RM_PRIVATE },
170 { 'm', "", INPUT_CSI_SGR },
171 { 'n', "", INPUT_CSI_DSR },
172 { 'q', " ", INPUT_CSI_DECSCUSR },
173 { 'r', "", INPUT_CSI_DECSTBM },
176 /* Input transition. */
177 struct input_transition {
178 int first;
179 int last;
181 int (*handler)(struct input_ctx *);
182 const struct input_state *state;
185 /* Input state. */
186 struct input_state {
187 const char *name;
188 void (*enter)(struct input_ctx *);
189 void (*exit)(struct input_ctx *);
190 const struct input_transition *transitions;
193 /* State transitions available from all states. */
194 #define INPUT_STATE_ANYWHERE \
195 { 0x18, 0x18, input_c0_dispatch, &input_state_ground }, \
196 { 0x1a, 0x1a, input_c0_dispatch, &input_state_ground }, \
197 { 0x1b, 0x1b, NULL, &input_state_esc_enter }
199 /* Forward declarations of state tables. */
200 const struct input_transition input_state_ground_table[];
201 const struct input_transition input_state_esc_enter_table[];
202 const struct input_transition input_state_esc_intermediate_table[];
203 const struct input_transition input_state_csi_enter_table[];
204 const struct input_transition input_state_csi_parameter_table[];
205 const struct input_transition input_state_csi_intermediate_table[];
206 const struct input_transition input_state_csi_ignore_table[];
207 const struct input_transition input_state_dcs_enter_table[];
208 const struct input_transition input_state_dcs_parameter_table[];
209 const struct input_transition input_state_dcs_intermediate_table[];
210 const struct input_transition input_state_dcs_handler_table[];
211 const struct input_transition input_state_dcs_escape_table[];
212 const struct input_transition input_state_dcs_ignore_table[];
213 const struct input_transition input_state_osc_string_table[];
214 const struct input_transition input_state_apc_string_table[];
215 const struct input_transition input_state_rename_string_table[];
216 const struct input_transition input_state_consume_st_table[];
217 const struct input_transition input_state_utf8_three_table[];
218 const struct input_transition input_state_utf8_two_table[];
219 const struct input_transition input_state_utf8_one_table[];
221 /* ground state definition. */
222 const struct input_state input_state_ground = {
223 "ground",
224 NULL, NULL,
225 input_state_ground_table
228 /* esc_enter state definition. */
229 const struct input_state input_state_esc_enter = {
230 "esc_enter",
231 input_clear, NULL,
232 input_state_esc_enter_table
235 /* esc_intermediate state definition. */
236 const struct input_state input_state_esc_intermediate = {
237 "esc_intermediate",
238 NULL, NULL,
239 input_state_esc_intermediate_table
242 /* csi_enter state definition. */
243 const struct input_state input_state_csi_enter = {
244 "csi_enter",
245 input_clear, NULL,
246 input_state_csi_enter_table
249 /* csi_parameter state definition. */
250 const struct input_state input_state_csi_parameter = {
251 "csi_parameter",
252 NULL, NULL,
253 input_state_csi_parameter_table
256 /* csi_intermediate state definition. */
257 const struct input_state input_state_csi_intermediate = {
258 "csi_intermediate",
259 NULL, NULL,
260 input_state_csi_intermediate_table
263 /* csi_ignore state definition. */
264 const struct input_state input_state_csi_ignore = {
265 "csi_ignore",
266 NULL, NULL,
267 input_state_csi_ignore_table
270 /* dcs_enter state definition. */
271 const struct input_state input_state_dcs_enter = {
272 "dcs_enter",
273 input_clear, NULL,
274 input_state_dcs_enter_table
277 /* dcs_parameter state definition. */
278 const struct input_state input_state_dcs_parameter = {
279 "dcs_parameter",
280 NULL, NULL,
281 input_state_dcs_parameter_table
284 /* dcs_intermediate state definition. */
285 const struct input_state input_state_dcs_intermediate = {
286 "dcs_intermediate",
287 NULL, NULL,
288 input_state_dcs_intermediate_table
291 /* dcs_handler state definition. */
292 const struct input_state input_state_dcs_handler = {
293 "dcs_handler",
294 NULL, NULL,
295 input_state_dcs_handler_table
298 /* dcs_escape state definition. */
299 const struct input_state input_state_dcs_escape = {
300 "dcs_escape",
301 NULL, NULL,
302 input_state_dcs_escape_table
305 /* dcs_ignore state definition. */
306 const struct input_state input_state_dcs_ignore = {
307 "dcs_ignore",
308 NULL, NULL,
309 input_state_dcs_ignore_table
312 /* osc_string state definition. */
313 const struct input_state input_state_osc_string = {
314 "osc_string",
315 input_enter_osc, input_exit_osc,
316 input_state_osc_string_table
319 /* apc_string state definition. */
320 const struct input_state input_state_apc_string = {
321 "apc_string",
322 input_enter_apc, input_exit_apc,
323 input_state_apc_string_table
326 /* rename_string state definition. */
327 const struct input_state input_state_rename_string = {
328 "rename_string",
329 input_enter_rename, input_exit_rename,
330 input_state_rename_string_table
333 /* consume_st state definition. */
334 const struct input_state input_state_consume_st = {
335 "consume_st",
336 NULL, NULL,
337 input_state_consume_st_table
340 /* utf8_three state definition. */
341 const struct input_state input_state_utf8_three = {
342 "utf8_three",
343 NULL, NULL,
344 input_state_utf8_three_table
347 /* utf8_two state definition. */
348 const struct input_state input_state_utf8_two = {
349 "utf8_two",
350 NULL, NULL,
351 input_state_utf8_two_table
354 /* utf8_one state definition. */
355 const struct input_state input_state_utf8_one = {
356 "utf8_one",
357 NULL, NULL,
358 input_state_utf8_one_table
361 /* ground state table. */
362 const struct input_transition input_state_ground_table[] = {
363 INPUT_STATE_ANYWHERE,
365 { 0x00, 0x17, input_c0_dispatch, NULL },
366 { 0x19, 0x19, input_c0_dispatch, NULL },
367 { 0x1c, 0x1f, input_c0_dispatch, NULL },
368 { 0x20, 0x7e, input_print, NULL },
369 { 0x7f, 0x7f, NULL, NULL },
370 { 0x80, 0xc1, input_print, NULL },
371 { 0xc2, 0xdf, input_utf8_open, &input_state_utf8_one },
372 { 0xe0, 0xef, input_utf8_open, &input_state_utf8_two },
373 { 0xf0, 0xf4, input_utf8_open, &input_state_utf8_three },
374 { 0xf5, 0xff, input_print, NULL },
376 { -1, -1, NULL, NULL }
379 /* esc_enter state table. */
380 const struct input_transition input_state_esc_enter_table[] = {
381 INPUT_STATE_ANYWHERE,
383 { 0x00, 0x17, input_c0_dispatch, NULL },
384 { 0x19, 0x19, input_c0_dispatch, NULL },
385 { 0x1c, 0x1f, input_c0_dispatch, NULL },
386 { 0x20, 0x2f, input_intermediate, &input_state_esc_intermediate },
387 { 0x30, 0x4f, input_esc_dispatch, &input_state_ground },
388 { 0x50, 0x50, NULL, &input_state_dcs_enter },
389 { 0x51, 0x57, input_esc_dispatch, &input_state_ground },
390 { 0x58, 0x58, NULL, &input_state_consume_st },
391 { 0x59, 0x59, input_esc_dispatch, &input_state_ground },
392 { 0x5a, 0x5a, input_esc_dispatch, &input_state_ground },
393 { 0x5b, 0x5b, NULL, &input_state_csi_enter },
394 { 0x5c, 0x5c, input_esc_dispatch, &input_state_ground },
395 { 0x5d, 0x5d, NULL, &input_state_osc_string },
396 { 0x5e, 0x5e, NULL, &input_state_consume_st },
397 { 0x5f, 0x5f, NULL, &input_state_apc_string },
398 { 0x60, 0x6a, input_esc_dispatch, &input_state_ground },
399 { 0x6b, 0x6b, NULL, &input_state_rename_string },
400 { 0x6c, 0x7e, input_esc_dispatch, &input_state_ground },
401 { 0x7f, 0xff, NULL, NULL },
403 { -1, -1, NULL, NULL }
406 /* esc_interm state table. */
407 const struct input_transition input_state_esc_intermediate_table[] = {
408 INPUT_STATE_ANYWHERE,
410 { 0x00, 0x17, input_c0_dispatch, NULL },
411 { 0x19, 0x19, input_c0_dispatch, NULL },
412 { 0x1c, 0x1f, input_c0_dispatch, NULL },
413 { 0x20, 0x2f, input_intermediate, NULL },
414 { 0x30, 0x7e, input_esc_dispatch, &input_state_ground },
415 { 0x7f, 0xff, NULL, NULL },
417 { -1, -1, NULL, NULL }
420 /* csi_enter state table. */
421 const struct input_transition input_state_csi_enter_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, &input_state_csi_intermediate },
428 { 0x30, 0x39, input_parameter, &input_state_csi_parameter },
429 { 0x3a, 0x3a, NULL, &input_state_csi_ignore },
430 { 0x3b, 0x3b, input_parameter, &input_state_csi_parameter },
431 { 0x3c, 0x3f, input_intermediate, &input_state_csi_parameter },
432 { 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
433 { 0x7f, 0xff, NULL, NULL },
435 { -1, -1, NULL, NULL }
438 /* csi_parameter state table. */
439 const struct input_transition input_state_csi_parameter_table[] = {
440 INPUT_STATE_ANYWHERE,
442 { 0x00, 0x17, input_c0_dispatch, NULL },
443 { 0x19, 0x19, input_c0_dispatch, NULL },
444 { 0x1c, 0x1f, input_c0_dispatch, NULL },
445 { 0x20, 0x2f, input_intermediate, &input_state_csi_intermediate },
446 { 0x30, 0x39, input_parameter, NULL },
447 { 0x3a, 0x3a, NULL, &input_state_csi_ignore },
448 { 0x3b, 0x3b, input_parameter, NULL },
449 { 0x3c, 0x3f, NULL, &input_state_csi_ignore },
450 { 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
451 { 0x7f, 0xff, NULL, NULL },
453 { -1, -1, NULL, NULL }
456 /* csi_intermediate state table. */
457 const struct input_transition input_state_csi_intermediate_table[] = {
458 INPUT_STATE_ANYWHERE,
460 { 0x00, 0x17, input_c0_dispatch, NULL },
461 { 0x19, 0x19, input_c0_dispatch, NULL },
462 { 0x1c, 0x1f, input_c0_dispatch, NULL },
463 { 0x20, 0x2f, input_intermediate, NULL },
464 { 0x30, 0x3f, NULL, &input_state_csi_ignore },
465 { 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
466 { 0x7f, 0xff, NULL, NULL },
468 { -1, -1, NULL, NULL }
471 /* csi_ignore state table. */
472 const struct input_transition input_state_csi_ignore_table[] = {
473 INPUT_STATE_ANYWHERE,
475 { 0x00, 0x17, input_c0_dispatch, NULL },
476 { 0x19, 0x19, input_c0_dispatch, NULL },
477 { 0x1c, 0x1f, input_c0_dispatch, NULL },
478 { 0x20, 0x3f, NULL, NULL },
479 { 0x40, 0x7e, NULL, &input_state_ground },
480 { 0x7f, 0xff, NULL, NULL },
482 { -1, -1, NULL, NULL }
485 /* dcs_enter state table. */
486 const struct input_transition input_state_dcs_enter_table[] = {
487 INPUT_STATE_ANYWHERE,
489 { 0x00, 0x17, NULL, NULL },
490 { 0x19, 0x19, NULL, NULL },
491 { 0x1c, 0x1f, NULL, NULL },
492 { 0x20, 0x2f, input_intermediate, &input_state_dcs_intermediate },
493 { 0x30, 0x39, input_parameter, &input_state_dcs_parameter },
494 { 0x3a, 0x3a, NULL, &input_state_dcs_ignore },
495 { 0x3b, 0x3b, input_parameter, &input_state_dcs_parameter },
496 { 0x3c, 0x3f, input_intermediate, &input_state_dcs_parameter },
497 { 0x40, 0x7e, input_input, &input_state_dcs_handler },
498 { 0x7f, 0xff, NULL, NULL },
500 { -1, -1, NULL, NULL }
503 /* dcs_parameter state table. */
504 const struct input_transition input_state_dcs_parameter_table[] = {
505 INPUT_STATE_ANYWHERE,
507 { 0x00, 0x17, NULL, NULL },
508 { 0x19, 0x19, NULL, NULL },
509 { 0x1c, 0x1f, NULL, NULL },
510 { 0x20, 0x2f, input_intermediate, &input_state_dcs_intermediate },
511 { 0x30, 0x39, input_parameter, NULL },
512 { 0x3a, 0x3a, NULL, &input_state_dcs_ignore },
513 { 0x3b, 0x3b, input_parameter, NULL },
514 { 0x3c, 0x3f, NULL, &input_state_dcs_ignore },
515 { 0x40, 0x7e, input_input, &input_state_dcs_handler },
516 { 0x7f, 0xff, NULL, NULL },
518 { -1, -1, NULL, NULL }
521 /* dcs_interm state table. */
522 const struct input_transition input_state_dcs_intermediate_table[] = {
523 INPUT_STATE_ANYWHERE,
525 { 0x00, 0x17, NULL, NULL },
526 { 0x19, 0x19, NULL, NULL },
527 { 0x1c, 0x1f, NULL, NULL },
528 { 0x20, 0x2f, input_intermediate, NULL },
529 { 0x30, 0x3f, NULL, &input_state_dcs_ignore },
530 { 0x40, 0x7e, input_input, &input_state_dcs_handler },
531 { 0x7f, 0xff, NULL, NULL },
533 { -1, -1, NULL, NULL }
536 /* dcs_handler state table. */
537 const struct input_transition input_state_dcs_handler_table[] = {
538 /* No INPUT_STATE_ANYWHERE */
540 { 0x00, 0x1a, input_input, NULL },
541 { 0x1b, 0x1b, NULL, &input_state_dcs_escape },
542 { 0x1c, 0xff, input_input, NULL },
544 { -1, -1, NULL, NULL }
547 /* dcs_escape state table. */
548 const struct input_transition input_state_dcs_escape_table[] = {
549 /* No INPUT_STATE_ANYWHERE */
551 { 0x00, 0x5b, input_input, &input_state_dcs_handler },
552 { 0x5c, 0x5c, input_dcs_dispatch, &input_state_ground },
553 { 0x5d, 0xff, input_input, &input_state_dcs_handler },
555 { -1, -1, NULL, NULL }
558 /* dcs_ignore state table. */
559 const struct input_transition input_state_dcs_ignore_table[] = {
560 INPUT_STATE_ANYWHERE,
562 { 0x00, 0x17, NULL, NULL },
563 { 0x19, 0x19, NULL, NULL },
564 { 0x1c, 0x1f, NULL, NULL },
565 { 0x20, 0xff, NULL, NULL },
567 { -1, -1, NULL, NULL }
570 /* osc_string state table. */
571 const struct input_transition input_state_osc_string_table[] = {
572 INPUT_STATE_ANYWHERE,
574 { 0x00, 0x06, NULL, NULL },
575 { 0x07, 0x07, NULL, &input_state_ground },
576 { 0x08, 0x17, NULL, NULL },
577 { 0x19, 0x19, NULL, NULL },
578 { 0x1c, 0x1f, NULL, NULL },
579 { 0x20, 0xff, input_input, NULL },
581 { -1, -1, NULL, NULL }
584 /* apc_string state table. */
585 const struct input_transition input_state_apc_string_table[] = {
586 INPUT_STATE_ANYWHERE,
588 { 0x00, 0x17, NULL, NULL },
589 { 0x19, 0x19, NULL, NULL },
590 { 0x1c, 0x1f, NULL, NULL },
591 { 0x20, 0xff, input_input, NULL },
593 { -1, -1, NULL, NULL }
596 /* rename_string state table. */
597 const struct input_transition input_state_rename_string_table[] = {
598 INPUT_STATE_ANYWHERE,
600 { 0x00, 0x17, NULL, NULL },
601 { 0x19, 0x19, NULL, NULL },
602 { 0x1c, 0x1f, NULL, NULL },
603 { 0x20, 0xff, input_input, NULL },
605 { -1, -1, NULL, NULL }
608 /* consume_st state table. */
609 const struct input_transition input_state_consume_st_table[] = {
610 INPUT_STATE_ANYWHERE,
612 { 0x00, 0x17, NULL, NULL },
613 { 0x19, 0x19, NULL, NULL },
614 { 0x1c, 0x1f, NULL, NULL },
615 { 0x20, 0xff, NULL, NULL },
617 { -1, -1, NULL, NULL }
620 /* utf8_three state table. */
621 const struct input_transition input_state_utf8_three_table[] = {
622 /* No INPUT_STATE_ANYWHERE */
624 { 0x00, 0x7f, NULL, &input_state_ground },
625 { 0x80, 0xbf, input_utf8_add, &input_state_utf8_two },
626 { 0xc0, 0xff, NULL, &input_state_ground },
628 { -1, -1, NULL, NULL }
631 /* utf8_two state table. */
632 const struct input_transition input_state_utf8_two_table[] = {
633 /* No INPUT_STATE_ANYWHERE */
635 { 0x00, 0x7f, NULL, &input_state_ground },
636 { 0x80, 0xbf, input_utf8_add, &input_state_utf8_one },
637 { 0xc0, 0xff, NULL, &input_state_ground },
639 { -1, -1, NULL, NULL }
642 /* utf8_one state table. */
643 const struct input_transition input_state_utf8_one_table[] = {
644 /* No INPUT_STATE_ANYWHERE */
646 { 0x00, 0x7f, NULL, &input_state_ground },
647 { 0x80, 0xbf, input_utf8_close, &input_state_ground },
648 { 0xc0, 0xff, NULL, &input_state_ground },
650 { -1, -1, NULL, NULL }
653 /* Input table compare. */
655 input_table_compare(const void *key, const void *value)
657 const struct input_ctx *ictx = key;
658 const struct input_table_entry *entry = value;
660 if (ictx->ch != entry->ch)
661 return (ictx->ch - entry->ch);
662 return (strcmp(ictx->interm_buf, entry->interm));
665 /* Initialise input parser. */
666 void
667 input_init(struct window_pane *wp)
669 struct input_ctx *ictx = &wp->ictx;
671 memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell);
673 memcpy(&ictx->old_cell, &grid_default_cell, sizeof ictx->old_cell);
674 ictx->old_cx = 0;
675 ictx->old_cy = 0;
677 *ictx->interm_buf = '\0';
678 ictx->interm_len = 0;
680 *ictx->param_buf = '\0';
681 ictx->param_len = 0;
683 ictx->state = &input_state_ground;
684 ictx->flags = 0;
687 /* Destroy input parser. */
688 void
689 input_free(unused struct window_pane *wp)
693 /* Parse input. */
694 void
695 input_parse(struct window_pane *wp)
697 struct input_ctx *ictx = &wp->ictx;
698 const struct input_transition *itr;
699 struct evbuffer *evb = wp->event->input;
700 u_char *buf;
701 size_t len, off;
703 if (EVBUFFER_LENGTH(evb) == 0)
704 return;
706 wp->window->flags |= WINDOW_ACTIVITY;
707 wp->window->flags &= ~WINDOW_SILENCE;
710 * Open the screen. Use NULL wp if there is a mode set as don't want to
711 * update the tty.
713 if (wp->mode == NULL)
714 screen_write_start(&ictx->ctx, wp, &wp->base);
715 else
716 screen_write_start(&ictx->ctx, NULL, &wp->base);
717 ictx->wp = wp;
719 buf = EVBUFFER_DATA(evb);
720 len = EVBUFFER_LENGTH(evb);
721 off = 0;
723 /* Parse the input. */
724 while (off < len) {
725 ictx->ch = buf[off++];
726 log_debug("%s: '%c' %s", __func__, ictx->ch, ictx->state->name);
728 /* Find the transition. */
729 itr = ictx->state->transitions;
730 while (itr->first != -1 && itr->last != -1) {
731 if (ictx->ch >= itr->first && ictx->ch <= itr->last)
732 break;
733 itr++;
735 if (itr->first == -1 || itr->last == -1) {
736 /* No transition? Eh? */
737 fatalx("No transition from state!");
741 * Execute the handler, if any. Don't switch state if it
742 * returns non-zero.
744 if (itr->handler != NULL && itr->handler(ictx) != 0)
745 continue;
747 /* And switch state, if necessary. */
748 if (itr->state != NULL) {
749 if (ictx->state->exit != NULL)
750 ictx->state->exit(ictx);
751 ictx->state = itr->state;
752 if (ictx->state->enter != NULL)
753 ictx->state->enter(ictx);
757 /* Close the screen. */
758 screen_write_stop(&ictx->ctx);
760 evbuffer_drain(evb, len);
763 /* Split the parameter list (if any). */
765 input_split(struct input_ctx *ictx)
768 const char *errstr;
769 char *ptr, *out;
770 int n;
772 ictx->param_list_len = 0;
773 if (ictx->param_len == 0)
774 return (0);
776 ptr = ictx->param_buf;
777 while ((out = strsep(&ptr, ";")) != NULL) {
778 if (*out == '\0')
779 n = -1;
780 else {
781 n = strtonum(out, 0, INT_MAX, &errstr);
782 if (errstr != NULL)
783 return (-1);
786 ictx->param_list[ictx->param_list_len++] = n;
787 if (ictx->param_list_len == nitems(ictx->param_list))
788 return (-1);
791 return (0);
794 /* Get an argument or return default value. */
796 input_get(struct input_ctx *ictx, u_int validx, int minval, int defval)
798 int retval;
800 if (validx >= ictx->param_list_len)
801 return (defval);
803 retval = ictx->param_list[validx];
804 if (retval == -1)
805 return (defval);
806 if (retval < minval)
807 return (minval);
808 return (retval);
811 /* Reply to terminal query. */
812 void
813 input_reply(struct input_ctx *ictx, const char *fmt, ...)
815 va_list ap;
816 char *reply;
818 va_start(ap, fmt);
819 vasprintf(&reply, fmt, ap);
820 va_end(ap);
822 bufferevent_write(ictx->wp->event, reply, strlen(reply));
823 xfree(reply);
826 /* Clear saved state. */
827 void
828 input_clear(struct input_ctx *ictx)
830 *ictx->interm_buf = '\0';
831 ictx->interm_len = 0;
833 *ictx->param_buf = '\0';
834 ictx->param_len = 0;
836 *ictx->input_buf = '\0';
837 ictx->input_len = 0;
839 ictx->flags &= ~INPUT_DISCARD;
842 /* Output this character to the screen. */
844 input_print(struct input_ctx *ictx)
846 ictx->cell.data = ictx->ch;
847 screen_write_cell(&ictx->ctx, &ictx->cell, NULL);
849 return (0);
852 /* Collect intermediate string. */
854 input_intermediate(struct input_ctx *ictx)
856 if (ictx->interm_len == (sizeof ictx->interm_buf) - 1)
857 ictx->flags |= INPUT_DISCARD;
858 else {
859 ictx->interm_buf[ictx->interm_len++] = ictx->ch;
860 ictx->interm_buf[ictx->interm_len] = '\0';
863 return (0);
866 /* Collect parameter string. */
868 input_parameter(struct input_ctx *ictx)
870 if (ictx->param_len == (sizeof ictx->param_buf) - 1)
871 ictx->flags |= INPUT_DISCARD;
872 else {
873 ictx->param_buf[ictx->param_len++] = ictx->ch;
874 ictx->param_buf[ictx->param_len] = '\0';
877 return (0);
880 /* Collect input string. */
882 input_input(struct input_ctx *ictx)
884 if (ictx->input_len == (sizeof ictx->input_buf) - 1)
885 ictx->flags |= INPUT_DISCARD;
886 else {
887 ictx->input_buf[ictx->input_len++] = ictx->ch;
888 ictx->input_buf[ictx->input_len] = '\0';
891 return (0);
894 /* Execute C0 control sequence. */
896 input_c0_dispatch(struct input_ctx *ictx)
898 struct screen_write_ctx *sctx = &ictx->ctx;
899 struct window_pane *wp = ictx->wp;
900 struct screen *s = sctx->s;
902 log_debug("%s: '%c", __func__, ictx->ch);
904 switch (ictx->ch) {
905 case '\000': /* NUL */
906 break;
907 case '\007': /* BEL */
908 wp->window->flags |= WINDOW_BELL;
909 break;
910 case '\010': /* BS */
911 screen_write_backspace(sctx);
912 break;
913 case '\011': /* HT */
914 /* Don't tab beyond the end of the line. */
915 if (s->cx >= screen_size_x(s) - 1)
916 break;
918 /* Find the next tab point, or use the last column if none. */
919 do {
920 s->cx++;
921 if (bit_test(s->tabs, s->cx))
922 break;
923 } while (s->cx < screen_size_x(s) - 1);
924 break;
925 case '\012': /* LF */
926 case '\013': /* VT */
927 case '\014': /* FF */
928 screen_write_linefeed(sctx, 0);
929 break;
930 case '\015': /* CR */
931 screen_write_carriagereturn(sctx);
932 break;
933 case '\016': /* SO */
934 ictx->cell.attr |= GRID_ATTR_CHARSET;
935 break;
936 case '\017': /* SI */
937 ictx->cell.attr &= ~GRID_ATTR_CHARSET;
938 break;
939 default:
940 log_debug("%s: unknown '%c'", __func__, ictx->ch);
941 break;
944 return (0);
947 /* Execute escape sequence. */
949 input_esc_dispatch(struct input_ctx *ictx)
951 struct screen_write_ctx *sctx = &ictx->ctx;
952 struct screen *s = sctx->s;
953 struct input_table_entry *entry;
955 if (ictx->flags & INPUT_DISCARD)
956 return (0);
957 log_debug("%s: '%c', %s", __func__, ictx->ch, ictx->interm_buf);
959 entry = bsearch(ictx, input_esc_table, nitems(input_esc_table),
960 sizeof input_esc_table[0], input_table_compare);
961 if (entry == NULL) {
962 log_debug("%s: unknown '%c'", __func__, ictx->ch);
963 return (0);
966 switch (entry->type) {
967 case INPUT_ESC_RIS:
968 memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell);
969 memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
970 ictx->old_cx = 0;
971 ictx->old_cy = 0;
973 screen_reset_tabs(sctx->s);
975 screen_write_scrollregion(sctx, 0, screen_size_y(sctx->s) - 1);
977 screen_write_insertmode(sctx, 0);
978 screen_write_kcursormode(sctx, 0);
979 screen_write_kkeypadmode(sctx, 0);
980 screen_write_mousemode_off(sctx);
982 screen_write_clearscreen(sctx);
983 screen_write_cursormove(sctx, 0, 0);
984 break;
985 case INPUT_ESC_IND:
986 screen_write_linefeed(sctx, 0);
987 break;
988 case INPUT_ESC_NEL:
989 screen_write_carriagereturn(sctx);
990 screen_write_linefeed(sctx, 0);
991 break;
992 case INPUT_ESC_HTS:
993 if (s->cx < screen_size_x(s))
994 bit_set(s->tabs, s->cx);
995 break;
996 case INPUT_ESC_RI:
997 screen_write_reverseindex(sctx);
998 break;
999 case INPUT_ESC_DECKPAM:
1000 screen_write_kkeypadmode(sctx, 1);
1001 break;
1002 case INPUT_ESC_DECKPNM:
1003 screen_write_kkeypadmode(sctx, 0);
1004 break;
1005 case INPUT_ESC_DECSC:
1006 memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
1007 ictx->old_cx = s->cx;
1008 ictx->old_cy = s->cy;
1009 break;
1010 case INPUT_ESC_DECRC:
1011 memcpy(&ictx->cell, &ictx->old_cell, sizeof ictx->cell);
1012 screen_write_cursormove(sctx, ictx->old_cx, ictx->old_cy);
1013 break;
1014 case INPUT_ESC_DECALN:
1015 screen_write_alignmenttest(sctx);
1016 break;
1017 case INPUT_ESC_SCSON_G0:
1019 * Not really supported, but fake it up enough for those that
1020 * use it to switch character sets (by redefining G0 to
1021 * graphics set, rather than switching to G1).
1023 ictx->cell.attr &= ~GRID_ATTR_CHARSET;
1024 break;
1025 case INPUT_ESC_SCSOFF_G0:
1026 ictx->cell.attr |= GRID_ATTR_CHARSET;
1027 break;
1030 return (0);
1033 /* Execute control sequence. */
1035 input_csi_dispatch(struct input_ctx *ictx)
1037 struct screen_write_ctx *sctx = &ictx->ctx;
1038 struct window_pane *wp = ictx->wp;
1039 struct screen *s = sctx->s;
1040 struct input_table_entry *entry;
1041 int n, m;
1043 if (ictx->flags & INPUT_DISCARD)
1044 return (0);
1045 if (input_split(ictx) != 0)
1046 return (0);
1047 log_debug("%s: '%c' \"%s\" \"%s\"",
1048 __func__, ictx->ch, ictx->interm_buf, ictx->param_buf);
1050 entry = bsearch(ictx, input_csi_table, nitems(input_csi_table),
1051 sizeof input_csi_table[0], input_table_compare);
1052 if (entry == NULL) {
1053 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1054 return (0);
1057 switch (entry->type) {
1058 case INPUT_CSI_CBT:
1059 /* Find the previous tab point, n times. */
1060 n = input_get(ictx, 0, 1, 1);
1061 while (s->cx > 0 && n-- > 0) {
1063 s->cx--;
1064 while (s->cx > 0 && !bit_test(s->tabs, s->cx));
1066 break;
1067 case INPUT_CSI_CUB:
1068 screen_write_cursorleft(sctx, input_get(ictx, 0, 1, 1));
1069 break;
1070 case INPUT_CSI_CUD:
1071 screen_write_cursordown(sctx, input_get(ictx, 0, 1, 1));
1072 break;
1073 case INPUT_CSI_CUF:
1074 screen_write_cursorright(sctx, input_get(ictx, 0, 1, 1));
1075 break;
1076 case INPUT_CSI_CUP:
1077 n = input_get(ictx, 0, 1, 1);
1078 m = input_get(ictx, 1, 1, 1);
1079 screen_write_cursormove(sctx, m - 1, n - 1);
1080 break;
1081 case INPUT_CSI_CUU:
1082 screen_write_cursorup(sctx, input_get(ictx, 0, 1, 1));
1083 break;
1084 case INPUT_CSI_DA:
1085 switch (input_get(ictx, 0, 0, 0)) {
1086 case 0:
1087 input_reply(ictx, "\033[?1;2c");
1088 break;
1089 default:
1090 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1091 break;
1093 break;
1094 case INPUT_CSI_DCH:
1095 screen_write_deletecharacter(sctx, input_get(ictx, 0, 1, 1));
1096 break;
1097 case INPUT_CSI_DECSTBM:
1098 n = input_get(ictx, 0, 1, 1);
1099 m = input_get(ictx, 1, 1, screen_size_y(s));
1100 screen_write_scrollregion(sctx, n - 1, m - 1);
1101 break;
1102 case INPUT_CSI_DL:
1103 screen_write_deleteline(sctx, input_get(ictx, 0, 1, 1));
1104 break;
1105 case INPUT_CSI_DSR:
1106 switch (input_get(ictx, 0, 0, 0)) {
1107 case 5:
1108 input_reply(ictx, "\033[0n");
1109 break;
1110 case 6:
1111 input_reply(ictx, "\033[%u;%uR", s->cy + 1, s->cx + 1);
1112 break;
1113 default:
1114 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1115 break;
1117 break;
1118 case INPUT_CSI_ED:
1119 switch (input_get(ictx, 0, 0, 0)) {
1120 case 0:
1121 screen_write_clearendofscreen(sctx);
1122 break;
1123 case 1:
1124 screen_write_clearstartofscreen(sctx);
1125 break;
1126 case 2:
1127 screen_write_clearscreen(sctx);
1128 break;
1129 case 3:
1130 switch (input_get(ictx, 1, 0, 0)) {
1131 case 0:
1133 * Linux console extension to clear history
1134 * (for example before locking the screen).
1136 screen_write_clearhistory(sctx);
1137 break;
1139 break;
1140 default:
1141 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1142 break;
1144 break;
1145 case INPUT_CSI_EL:
1146 switch (input_get(ictx, 0, 0, 0)) {
1147 case 0:
1148 screen_write_clearendofline(sctx);
1149 break;
1150 case 1:
1151 screen_write_clearstartofline(sctx);
1152 break;
1153 case 2:
1154 screen_write_clearline(sctx);
1155 break;
1156 default:
1157 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1158 break;
1160 break;
1161 case INPUT_CSI_HPA:
1162 n = input_get(ictx, 0, 1, 1);
1163 screen_write_cursormove(sctx, n - 1, s->cy);
1164 break;
1165 case INPUT_CSI_ICH:
1166 screen_write_insertcharacter(sctx, input_get(ictx, 0, 1, 1));
1167 break;
1168 case INPUT_CSI_IL:
1169 screen_write_insertline(sctx, input_get(ictx, 0, 1, 1));
1170 break;
1171 case INPUT_CSI_RM:
1172 switch (input_get(ictx, 0, 0, -1)) {
1173 case 4: /* IRM */
1174 screen_write_insertmode(&ictx->ctx, 0);
1175 break;
1176 default:
1177 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1178 break;
1180 break;
1181 case INPUT_CSI_RM_PRIVATE:
1182 switch (input_get(ictx, 0, 0, -1)) {
1183 case 1: /* GATM */
1184 screen_write_kcursormode(&ictx->ctx, 0);
1185 break;
1186 case 3: /* DECCOLM */
1187 screen_write_cursormove(&ictx->ctx, 0, 0);
1188 screen_write_clearscreen(&ictx->ctx);
1189 break;
1190 case 25: /* TCEM */
1191 screen_write_cursormode(&ictx->ctx, 0);
1192 break;
1193 case 1000:
1194 case 1001:
1195 case 1002:
1196 case 1003:
1197 screen_write_mousemode_off(&ictx->ctx);
1198 break;
1199 case 1005:
1200 screen_write_utf8mousemode(&ictx->ctx, 0);
1201 break;
1202 case 1049:
1203 window_pane_alternate_off(wp, &ictx->cell);
1204 break;
1205 default:
1206 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1207 break;
1209 break;
1210 case INPUT_CSI_SGR:
1211 input_csi_dispatch_sgr(ictx);
1212 break;
1213 case INPUT_CSI_SM:
1214 switch (input_get(ictx, 0, 0, -1)) {
1215 case 4: /* IRM */
1216 screen_write_insertmode(&ictx->ctx, 1);
1217 break;
1218 default:
1219 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1220 break;
1222 break;
1223 case INPUT_CSI_SM_PRIVATE:
1224 switch (input_get(ictx, 0, 0, -1)) {
1225 case 1: /* GATM */
1226 screen_write_kcursormode(&ictx->ctx, 1);
1227 break;
1228 case 3: /* DECCOLM */
1229 screen_write_cursormove(&ictx->ctx, 0, 0);
1230 screen_write_clearscreen(&ictx->ctx);
1231 break;
1232 case 25: /* TCEM */
1233 screen_write_cursormode(&ictx->ctx, 1);
1234 break;
1235 case 1000:
1236 screen_write_mousemode_on(
1237 &ictx->ctx, MODE_MOUSE_STANDARD);
1238 break;
1239 case 1002:
1240 screen_write_mousemode_on(
1241 &ictx->ctx, MODE_MOUSE_BUTTON);
1242 break;
1243 case 1003:
1244 screen_write_mousemode_on(&ictx->ctx, MODE_MOUSE_ANY);
1245 break;
1246 case 1005:
1247 screen_write_utf8mousemode(&ictx->ctx, 1);
1248 break;
1249 case 1049:
1250 window_pane_alternate_on(wp, &ictx->cell);
1251 break;
1252 default:
1253 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1254 break;
1256 break;
1257 case INPUT_CSI_TBC:
1258 switch (input_get(ictx, 0, 0, 0)) {
1259 case 0:
1260 if (s->cx < screen_size_x(s))
1261 bit_clear(s->tabs, s->cx);
1262 break;
1263 case 3:
1264 bit_nclear(s->tabs, 0, screen_size_x(s) - 1);
1265 break;
1266 default:
1267 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1268 break;
1270 break;
1271 case INPUT_CSI_VPA:
1272 n = input_get(ictx, 0, 1, 1);
1273 screen_write_cursormove(sctx, s->cx, n - 1);
1274 break;
1275 case INPUT_CSI_DECSCUSR:
1276 n = input_get(ictx, 0, 0, 0);
1277 screen_set_cursor_style(s, n);
1278 break;
1281 return (0);
1284 /* Handle CSI SGR. */
1285 void
1286 input_csi_dispatch_sgr(struct input_ctx *ictx)
1288 struct grid_cell *gc = &ictx->cell;
1289 u_int i;
1290 int n, m;
1291 u_char attr;
1293 if (ictx->param_list_len == 0) {
1294 attr = gc->attr;
1295 memcpy(gc, &grid_default_cell, sizeof *gc);
1296 gc->attr |= (attr & GRID_ATTR_CHARSET);
1297 return;
1300 for (i = 0; i < ictx->param_list_len; i++) {
1301 n = input_get(ictx, i, 0, 0);
1303 if (n == 38 || n == 48) {
1304 i++;
1305 if (input_get(ictx, i, 0, -1) != 5)
1306 continue;
1308 i++;
1309 m = input_get(ictx, i, 0, -1);
1310 if (m == -1) {
1311 if (n == 38) {
1312 gc->flags &= ~GRID_FLAG_FG256;
1313 gc->fg = 8;
1314 } else if (n == 48) {
1315 gc->flags &= ~GRID_FLAG_BG256;
1316 gc->bg = 8;
1319 } else {
1320 if (n == 38) {
1321 gc->flags |= GRID_FLAG_FG256;
1322 gc->fg = m;
1323 } else if (n == 48) {
1324 gc->flags |= GRID_FLAG_BG256;
1325 gc->bg = m;
1328 continue;
1331 switch (n) {
1332 case 0:
1333 case 10:
1334 attr = gc->attr;
1335 memcpy(gc, &grid_default_cell, sizeof *gc);
1336 gc->attr |= (attr & GRID_ATTR_CHARSET);
1337 break;
1338 case 1:
1339 gc->attr |= GRID_ATTR_BRIGHT;
1340 break;
1341 case 2:
1342 gc->attr |= GRID_ATTR_DIM;
1343 break;
1344 case 3:
1345 gc->attr |= GRID_ATTR_ITALICS;
1346 break;
1347 case 4:
1348 gc->attr |= GRID_ATTR_UNDERSCORE;
1349 break;
1350 case 5:
1351 gc->attr |= GRID_ATTR_BLINK;
1352 break;
1353 case 7:
1354 gc->attr |= GRID_ATTR_REVERSE;
1355 break;
1356 case 8:
1357 gc->attr |= GRID_ATTR_HIDDEN;
1358 break;
1359 case 22:
1360 gc->attr &= ~(GRID_ATTR_BRIGHT|GRID_ATTR_DIM);
1361 break;
1362 case 23:
1363 gc->attr &= ~GRID_ATTR_ITALICS;
1364 break;
1365 case 24:
1366 gc->attr &= ~GRID_ATTR_UNDERSCORE;
1367 break;
1368 case 25:
1369 gc->attr &= ~GRID_ATTR_BLINK;
1370 break;
1371 case 27:
1372 gc->attr &= ~GRID_ATTR_REVERSE;
1373 break;
1374 case 30:
1375 case 31:
1376 case 32:
1377 case 33:
1378 case 34:
1379 case 35:
1380 case 36:
1381 case 37:
1382 gc->flags &= ~GRID_FLAG_FG256;
1383 gc->fg = n - 30;
1384 break;
1385 case 39:
1386 gc->flags &= ~GRID_FLAG_FG256;
1387 gc->fg = 8;
1388 break;
1389 case 40:
1390 case 41:
1391 case 42:
1392 case 43:
1393 case 44:
1394 case 45:
1395 case 46:
1396 case 47:
1397 gc->flags &= ~GRID_FLAG_BG256;
1398 gc->bg = n - 40;
1399 break;
1400 case 49:
1401 gc->flags &= ~GRID_FLAG_BG256;
1402 gc->bg = 8;
1403 break;
1404 case 90:
1405 case 91:
1406 case 92:
1407 case 93:
1408 case 94:
1409 case 95:
1410 case 96:
1411 case 97:
1412 gc->flags &= ~GRID_FLAG_FG256;
1413 gc->fg = n;
1414 break;
1415 case 100:
1416 case 101:
1417 case 102:
1418 case 103:
1419 case 104:
1420 case 105:
1421 case 106:
1422 case 107:
1423 gc->flags &= ~GRID_FLAG_BG256;
1424 gc->bg = n;
1425 break;
1430 /* DCS terminator (ST) received. */
1432 input_dcs_dispatch(struct input_ctx *ictx)
1434 const char prefix[] = "tmux;";
1435 const u_int prefix_len = (sizeof prefix) - 1;
1437 if (ictx->flags & INPUT_DISCARD)
1438 return (0);
1440 log_debug("%s: \"%s\"", __func__, ictx->input_buf);
1442 /* Check for tmux prefix. */
1443 if (ictx->input_len >= prefix_len &&
1444 strncmp(ictx->input_buf, prefix, prefix_len) == 0) {
1445 screen_write_rawstring(&ictx->ctx,
1446 ictx->input_buf + prefix_len, ictx->input_len - prefix_len);
1449 return (0);
1452 /* OSC string started. */
1453 void
1454 input_enter_osc(struct input_ctx *ictx)
1456 log_debug("%s", __func__);
1458 input_clear(ictx);
1461 /* OSC terminator (ST) received. */
1462 void
1463 input_exit_osc(struct input_ctx *ictx)
1465 u_char *p = ictx->input_buf;
1466 int option;
1468 if (ictx->flags & INPUT_DISCARD)
1469 return;
1470 if (ictx->input_len < 1 || *p < '0' || *p > '9')
1471 return;
1473 log_debug("%s: \"%s\"", __func__, p);
1475 option = 0;
1476 while (*p >= '0' && *p <= '9')
1477 option = option * 10 + *p++ - '0';
1478 if (*p == ';')
1479 p++;
1481 switch (option) {
1482 case 0:
1483 case 2:
1484 screen_set_title(ictx->ctx.s, p);
1485 server_status_window(ictx->wp->window);
1486 break;
1487 case 12:
1488 screen_set_cursor_colour(ictx->ctx.s, p);
1489 break;
1490 case 112:
1491 if (*p == '\0') /* No arguments allowed. */
1492 screen_set_cursor_colour(ictx->ctx.s, "");
1493 break;
1494 default:
1495 log_debug("%s: unknown '%u'", __func__, option);
1496 break;
1500 /* APC string started. */
1501 void
1502 input_enter_apc(struct input_ctx *ictx)
1504 log_debug("%s", __func__);
1506 input_clear(ictx);
1509 /* APC terminator (ST) received. */
1510 void
1511 input_exit_apc(struct input_ctx *ictx)
1513 if (ictx->flags & INPUT_DISCARD)
1514 return;
1515 log_debug("%s: \"%s\"", __func__, ictx->input_buf);
1517 screen_set_title(ictx->ctx.s, ictx->input_buf);
1518 server_status_window(ictx->wp->window);
1521 /* Rename string started. */
1522 void
1523 input_enter_rename(struct input_ctx *ictx)
1525 log_debug("%s", __func__);
1527 input_clear(ictx);
1530 /* Rename terminator (ST) received. */
1531 void
1532 input_exit_rename(struct input_ctx *ictx)
1534 if (ictx->flags & INPUT_DISCARD)
1535 return;
1536 log_debug("%s: \"%s\"", __func__, ictx->input_buf);
1538 xfree(ictx->wp->window->name);
1539 ictx->wp->window->name = xstrdup(ictx->input_buf);
1540 options_set_number(&ictx->wp->window->options, "automatic-rename", 0);
1542 server_status_window(ictx->wp->window);
1545 /* Open UTF-8 character. */
1547 input_utf8_open(struct input_ctx *ictx)
1549 if (!options_get_number(&ictx->wp->window->options, "utf8")) {
1550 /* Print, and do not switch state. */
1551 input_print(ictx);
1552 return (-1);
1554 log_debug("%s", __func__);
1556 utf8_open(&ictx->utf8data, ictx->ch);
1557 return (0);
1560 /* Append to UTF-8 character. */
1562 input_utf8_add(struct input_ctx *ictx)
1564 log_debug("%s", __func__);
1566 utf8_append(&ictx->utf8data, ictx->ch);
1567 return (0);
1570 /* Close UTF-8 string. */
1572 input_utf8_close(struct input_ctx *ictx)
1574 log_debug("%s", __func__);
1576 utf8_append(&ictx->utf8data, ictx->ch);
1578 ictx->cell.flags |= GRID_FLAG_UTF8;
1579 screen_write_cell(&ictx->ctx, &ictx->cell, &ictx->utf8data);
1580 ictx->cell.flags &= ~GRID_FLAG_UTF8;
1582 return (0);