Use xfree not free, from Tiago Cunha.
[tmux-openbsd.git] / input.c
blob3da950d541b4ed05f69d53d572d46ea072e79b46
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_DECSTBM,
130 INPUT_CSI_DL,
131 INPUT_CSI_DSR,
132 INPUT_CSI_ED,
133 INPUT_CSI_EL,
134 INPUT_CSI_HPA,
135 INPUT_CSI_ICH,
136 INPUT_CSI_IL,
137 INPUT_CSI_RM,
138 INPUT_CSI_RM_PRIVATE,
139 INPUT_CSI_SGR,
140 INPUT_CSI_SM,
141 INPUT_CSI_SM_PRIVATE,
142 INPUT_CSI_TBC,
143 INPUT_CSI_VPA,
146 /* Control (CSI) command table. */
147 const struct input_table_entry input_csi_table[] = {
148 { '@', "", INPUT_CSI_ICH },
149 { 'A', "", INPUT_CSI_CUU },
150 { 'B', "", INPUT_CSI_CUD },
151 { 'C', "", INPUT_CSI_CUF },
152 { 'D', "", INPUT_CSI_CUB },
153 { 'G', "", INPUT_CSI_HPA },
154 { 'H', "", INPUT_CSI_CUP },
155 { 'J', "", INPUT_CSI_ED },
156 { 'K', "", INPUT_CSI_EL },
157 { 'L', "", INPUT_CSI_IL },
158 { 'M', "", INPUT_CSI_DL },
159 { 'P', "", INPUT_CSI_DCH },
160 { 'Z', "", INPUT_CSI_CBT },
161 { 'c', "", INPUT_CSI_DA },
162 { 'd', "", INPUT_CSI_VPA },
163 { 'f', "", INPUT_CSI_CUP },
164 { 'g', "", INPUT_CSI_TBC },
165 { 'h', "", INPUT_CSI_SM },
166 { 'h', "?", INPUT_CSI_SM_PRIVATE },
167 { 'l', "", INPUT_CSI_RM },
168 { 'l', "?", INPUT_CSI_RM_PRIVATE },
169 { 'm', "", INPUT_CSI_SGR },
170 { 'n', "", INPUT_CSI_DSR },
171 { 'r', "", INPUT_CSI_DECSTBM },
174 /* Input transition. */
175 struct input_transition {
176 int first;
177 int last;
179 int (*handler)(struct input_ctx *);
180 const struct input_state *state;
183 /* Input state. */
184 struct input_state {
185 const char *name;
186 void (*enter)(struct input_ctx *);
187 void (*exit)(struct input_ctx *);
188 const struct input_transition *transitions;
191 /* State transitions available from all states. */
192 #define INPUT_STATE_ANYWHERE \
193 { 0x18, 0x18, input_c0_dispatch, &input_state_ground }, \
194 { 0x1a, 0x1a, input_c0_dispatch, &input_state_ground }, \
195 { 0x1b, 0x1b, NULL, &input_state_esc_enter }
197 /* Forward declarations of state tables. */
198 const struct input_transition input_state_ground_table[];
199 const struct input_transition input_state_esc_enter_table[];
200 const struct input_transition input_state_esc_intermediate_table[];
201 const struct input_transition input_state_csi_enter_table[];
202 const struct input_transition input_state_csi_parameter_table[];
203 const struct input_transition input_state_csi_intermediate_table[];
204 const struct input_transition input_state_csi_ignore_table[];
205 const struct input_transition input_state_dcs_enter_table[];
206 const struct input_transition input_state_dcs_parameter_table[];
207 const struct input_transition input_state_dcs_intermediate_table[];
208 const struct input_transition input_state_dcs_handler_table[];
209 const struct input_transition input_state_dcs_escape_table[];
210 const struct input_transition input_state_dcs_ignore_table[];
211 const struct input_transition input_state_osc_string_table[];
212 const struct input_transition input_state_apc_string_table[];
213 const struct input_transition input_state_rename_string_table[];
214 const struct input_transition input_state_consume_st_table[];
215 const struct input_transition input_state_utf8_three_table[];
216 const struct input_transition input_state_utf8_two_table[];
217 const struct input_transition input_state_utf8_one_table[];
219 /* ground state definition. */
220 const struct input_state input_state_ground = {
221 "ground",
222 NULL, NULL,
223 input_state_ground_table
226 /* esc_enter state definition. */
227 const struct input_state input_state_esc_enter = {
228 "esc_enter",
229 input_clear, NULL,
230 input_state_esc_enter_table
233 /* esc_intermediate state definition. */
234 const struct input_state input_state_esc_intermediate = {
235 "esc_intermediate",
236 NULL, NULL,
237 input_state_esc_intermediate_table
240 /* csi_enter state definition. */
241 const struct input_state input_state_csi_enter = {
242 "csi_enter",
243 input_clear, NULL,
244 input_state_csi_enter_table
247 /* csi_parameter state definition. */
248 const struct input_state input_state_csi_parameter = {
249 "csi_parameter",
250 NULL, NULL,
251 input_state_csi_parameter_table
254 /* csi_intermediate state definition. */
255 const struct input_state input_state_csi_intermediate = {
256 "csi_intermediate",
257 NULL, NULL,
258 input_state_csi_intermediate_table
261 /* csi_ignore state definition. */
262 const struct input_state input_state_csi_ignore = {
263 "csi_ignore",
264 NULL, NULL,
265 input_state_csi_ignore_table
268 /* dcs_enter state definition. */
269 const struct input_state input_state_dcs_enter = {
270 "dcs_enter",
271 input_clear, NULL,
272 input_state_dcs_enter_table
275 /* dcs_parameter state definition. */
276 const struct input_state input_state_dcs_parameter = {
277 "dcs_parameter",
278 NULL, NULL,
279 input_state_dcs_parameter_table
282 /* dcs_intermediate state definition. */
283 const struct input_state input_state_dcs_intermediate = {
284 "dcs_intermediate",
285 NULL, NULL,
286 input_state_dcs_intermediate_table
289 /* dcs_handler state definition. */
290 const struct input_state input_state_dcs_handler = {
291 "dcs_handler",
292 NULL, NULL,
293 input_state_dcs_handler_table
296 /* dcs_escape state definition. */
297 const struct input_state input_state_dcs_escape = {
298 "dcs_escape",
299 NULL, NULL,
300 input_state_dcs_escape_table
303 /* dcs_ignore state definition. */
304 const struct input_state input_state_dcs_ignore = {
305 "dcs_ignore",
306 NULL, NULL,
307 input_state_dcs_ignore_table
310 /* osc_string state definition. */
311 const struct input_state input_state_osc_string = {
312 "osc_string",
313 input_enter_osc, input_exit_osc,
314 input_state_osc_string_table
317 /* apc_string state definition. */
318 const struct input_state input_state_apc_string = {
319 "apc_string",
320 input_enter_apc, input_exit_apc,
321 input_state_apc_string_table
324 /* rename_string state definition. */
325 const struct input_state input_state_rename_string = {
326 "rename_string",
327 input_enter_rename, input_exit_rename,
328 input_state_rename_string_table
331 /* consume_st state definition. */
332 const struct input_state input_state_consume_st = {
333 "consume_st",
334 NULL, NULL,
335 input_state_consume_st_table
338 /* utf8_three state definition. */
339 const struct input_state input_state_utf8_three = {
340 "utf8_three",
341 NULL, NULL,
342 input_state_utf8_three_table
345 /* utf8_two state definition. */
346 const struct input_state input_state_utf8_two = {
347 "utf8_two",
348 NULL, NULL,
349 input_state_utf8_two_table
352 /* utf8_one state definition. */
353 const struct input_state input_state_utf8_one = {
354 "utf8_one",
355 NULL, NULL,
356 input_state_utf8_one_table
359 /* ground state table. */
360 const struct input_transition input_state_ground_table[] = {
361 INPUT_STATE_ANYWHERE,
363 { 0x00, 0x17, input_c0_dispatch, NULL },
364 { 0x19, 0x19, input_c0_dispatch, NULL },
365 { 0x1c, 0x1f, input_c0_dispatch, NULL },
366 { 0x20, 0x7e, input_print, NULL },
367 { 0x7f, 0x7f, NULL, NULL },
368 { 0x80, 0xc1, input_print, NULL },
369 { 0xc2, 0xdf, input_utf8_open, &input_state_utf8_one },
370 { 0xe0, 0xef, input_utf8_open, &input_state_utf8_two },
371 { 0xf0, 0xf4, input_utf8_open, &input_state_utf8_three },
372 { 0xf5, 0xff, input_print, NULL },
374 { -1, -1, NULL, NULL }
377 /* esc_enter state table. */
378 const struct input_transition input_state_esc_enter_table[] = {
379 INPUT_STATE_ANYWHERE,
381 { 0x00, 0x17, input_c0_dispatch, NULL },
382 { 0x19, 0x19, input_c0_dispatch, NULL },
383 { 0x1c, 0x1f, input_c0_dispatch, NULL },
384 { 0x20, 0x2f, input_intermediate, &input_state_esc_intermediate },
385 { 0x30, 0x4f, input_esc_dispatch, &input_state_ground },
386 { 0x50, 0x50, NULL, &input_state_dcs_enter },
387 { 0x51, 0x57, input_esc_dispatch, &input_state_ground },
388 { 0x58, 0x58, NULL, &input_state_consume_st },
389 { 0x59, 0x59, input_esc_dispatch, &input_state_ground },
390 { 0x5a, 0x5a, input_esc_dispatch, &input_state_ground },
391 { 0x5b, 0x5b, NULL, &input_state_csi_enter },
392 { 0x5c, 0x5c, input_esc_dispatch, &input_state_ground },
393 { 0x5d, 0x5d, NULL, &input_state_osc_string },
394 { 0x5e, 0x5e, NULL, &input_state_consume_st },
395 { 0x5f, 0x5f, NULL, &input_state_apc_string },
396 { 0x60, 0x6a, input_esc_dispatch, &input_state_ground },
397 { 0x6b, 0x6b, NULL, &input_state_rename_string },
398 { 0x6c, 0x7e, input_esc_dispatch, &input_state_ground },
399 { 0x7f, 0xff, NULL, NULL },
401 { -1, -1, NULL, NULL }
404 /* esc_interm state table. */
405 const struct input_transition input_state_esc_intermediate_table[] = {
406 INPUT_STATE_ANYWHERE,
408 { 0x00, 0x17, input_c0_dispatch, NULL },
409 { 0x19, 0x19, input_c0_dispatch, NULL },
410 { 0x1c, 0x1f, input_c0_dispatch, NULL },
411 { 0x20, 0x2f, input_intermediate, NULL },
412 { 0x30, 0x7e, input_esc_dispatch, &input_state_ground },
413 { 0x7f, 0xff, NULL, NULL },
415 { -1, -1, NULL, NULL }
418 /* csi_enter state table. */
419 const struct input_transition input_state_csi_enter_table[] = {
420 INPUT_STATE_ANYWHERE,
422 { 0x00, 0x17, input_c0_dispatch, NULL },
423 { 0x19, 0x19, input_c0_dispatch, NULL },
424 { 0x1c, 0x1f, input_c0_dispatch, NULL },
425 { 0x20, 0x2f, input_intermediate, &input_state_csi_intermediate },
426 { 0x30, 0x39, input_parameter, &input_state_csi_parameter },
427 { 0x3a, 0x3a, NULL, &input_state_csi_ignore },
428 { 0x3b, 0x3b, input_parameter, &input_state_csi_parameter },
429 { 0x3c, 0x3f, input_intermediate, &input_state_csi_parameter },
430 { 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
431 { 0x7f, 0xff, NULL, NULL },
433 { -1, -1, NULL, NULL }
436 /* csi_parameter state table. */
437 const struct input_transition input_state_csi_parameter_table[] = {
438 INPUT_STATE_ANYWHERE,
440 { 0x00, 0x17, input_c0_dispatch, NULL },
441 { 0x19, 0x19, input_c0_dispatch, NULL },
442 { 0x1c, 0x1f, input_c0_dispatch, NULL },
443 { 0x20, 0x2f, input_intermediate, &input_state_csi_intermediate },
444 { 0x30, 0x39, input_parameter, NULL },
445 { 0x3a, 0x3a, NULL, &input_state_csi_ignore },
446 { 0x3b, 0x3b, input_parameter, NULL },
447 { 0x3c, 0x3f, NULL, &input_state_csi_ignore },
448 { 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
449 { 0x7f, 0xff, NULL, NULL },
451 { -1, -1, NULL, NULL }
454 /* csi_intermediate state table. */
455 const struct input_transition input_state_csi_intermediate_table[] = {
456 INPUT_STATE_ANYWHERE,
458 { 0x00, 0x17, input_c0_dispatch, NULL },
459 { 0x19, 0x19, input_c0_dispatch, NULL },
460 { 0x1c, 0x1f, input_c0_dispatch, NULL },
461 { 0x20, 0x2f, input_intermediate, NULL },
462 { 0x30, 0x3f, NULL, &input_state_csi_ignore },
463 { 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
464 { 0x7f, 0xff, NULL, NULL },
466 { -1, -1, NULL, NULL }
469 /* csi_ignore state table. */
470 const struct input_transition input_state_csi_ignore_table[] = {
471 INPUT_STATE_ANYWHERE,
473 { 0x00, 0x17, input_c0_dispatch, NULL },
474 { 0x19, 0x19, input_c0_dispatch, NULL },
475 { 0x1c, 0x1f, input_c0_dispatch, NULL },
476 { 0x20, 0x3f, NULL, NULL },
477 { 0x40, 0x7e, NULL, &input_state_ground },
478 { 0x7f, 0xff, NULL, NULL },
480 { -1, -1, NULL, NULL }
483 /* dcs_enter state table. */
484 const struct input_transition input_state_dcs_enter_table[] = {
485 INPUT_STATE_ANYWHERE,
487 { 0x00, 0x17, NULL, NULL },
488 { 0x19, 0x19, NULL, NULL },
489 { 0x1c, 0x1f, NULL, NULL },
490 { 0x20, 0x2f, input_intermediate, &input_state_dcs_intermediate },
491 { 0x30, 0x39, input_parameter, &input_state_dcs_parameter },
492 { 0x3a, 0x3a, NULL, &input_state_dcs_ignore },
493 { 0x3b, 0x3b, input_parameter, &input_state_dcs_parameter },
494 { 0x3c, 0x3f, input_intermediate, &input_state_dcs_parameter },
495 { 0x40, 0x7e, input_input, &input_state_dcs_handler },
496 { 0x7f, 0xff, NULL, NULL },
498 { -1, -1, NULL, NULL }
501 /* dcs_parameter state table. */
502 const struct input_transition input_state_dcs_parameter_table[] = {
503 INPUT_STATE_ANYWHERE,
505 { 0x00, 0x17, NULL, NULL },
506 { 0x19, 0x19, NULL, NULL },
507 { 0x1c, 0x1f, NULL, NULL },
508 { 0x20, 0x2f, input_intermediate, &input_state_dcs_intermediate },
509 { 0x30, 0x39, input_parameter, NULL },
510 { 0x3a, 0x3a, NULL, &input_state_dcs_ignore },
511 { 0x3b, 0x3b, input_parameter, NULL },
512 { 0x3c, 0x3f, NULL, &input_state_dcs_ignore },
513 { 0x40, 0x7e, input_input, &input_state_dcs_handler },
514 { 0x7f, 0xff, NULL, NULL },
516 { -1, -1, NULL, NULL }
519 /* dcs_interm state table. */
520 const struct input_transition input_state_dcs_intermediate_table[] = {
521 INPUT_STATE_ANYWHERE,
523 { 0x00, 0x17, NULL, NULL },
524 { 0x19, 0x19, NULL, NULL },
525 { 0x1c, 0x1f, NULL, NULL },
526 { 0x20, 0x2f, input_intermediate, NULL },
527 { 0x30, 0x3f, NULL, &input_state_dcs_ignore },
528 { 0x40, 0x7e, input_input, &input_state_dcs_handler },
529 { 0x7f, 0xff, NULL, NULL },
531 { -1, -1, NULL, NULL }
534 /* dcs_handler state table. */
535 const struct input_transition input_state_dcs_handler_table[] = {
536 /* No INPUT_STATE_ANYWHERE */
538 { 0x00, 0x1a, input_input, NULL },
539 { 0x1b, 0x1b, NULL, &input_state_dcs_escape },
540 { 0x1c, 0xff, input_input, NULL },
542 { -1, -1, NULL, NULL }
545 /* dcs_escape state table. */
546 const struct input_transition input_state_dcs_escape_table[] = {
547 /* No INPUT_STATE_ANYWHERE */
549 { 0x00, 0x5b, input_input, &input_state_dcs_handler },
550 { 0x5c, 0x5c, input_dcs_dispatch, &input_state_ground },
551 { 0x5d, 0xff, input_input, &input_state_dcs_handler },
553 { -1, -1, NULL, NULL }
556 /* device_ignore state table. */
557 const struct input_transition input_state_dcs_ignore_table[] = {
558 INPUT_STATE_ANYWHERE,
560 { 0x00, 0x17, NULL, NULL },
561 { 0x19, 0x19, NULL, NULL },
562 { 0x1c, 0x1f, NULL, NULL },
563 { 0x20, 0xff, NULL, NULL },
565 { -1, -1, NULL, NULL }
568 /* osc_string state table. */
569 const struct input_transition input_state_osc_string_table[] = {
570 INPUT_STATE_ANYWHERE,
572 { 0x00, 0x06, NULL, NULL },
573 { 0x07, 0x07, NULL, &input_state_ground },
574 { 0x08, 0x17, NULL, NULL },
575 { 0x19, 0x19, NULL, NULL },
576 { 0x1c, 0x1f, NULL, NULL },
577 { 0x20, 0xff, input_input, NULL },
579 { -1, -1, NULL, NULL }
582 /* apc_string state table. */
583 const struct input_transition input_state_apc_string_table[] = {
584 INPUT_STATE_ANYWHERE,
586 { 0x00, 0x17, NULL, NULL },
587 { 0x19, 0x19, NULL, NULL },
588 { 0x1c, 0x1f, NULL, NULL },
589 { 0x20, 0xff, input_input, NULL },
591 { -1, -1, NULL, NULL }
594 /* rename_string state table. */
595 const struct input_transition input_state_rename_string_table[] = {
596 INPUT_STATE_ANYWHERE,
598 { 0x00, 0x17, NULL, NULL },
599 { 0x19, 0x19, NULL, NULL },
600 { 0x1c, 0x1f, NULL, NULL },
601 { 0x20, 0xff, input_input, NULL },
603 { -1, -1, NULL, NULL }
606 /* consume_st state table. */
607 const struct input_transition input_state_consume_st_table[] = {
608 INPUT_STATE_ANYWHERE,
610 { 0x00, 0x17, NULL, NULL },
611 { 0x19, 0x19, NULL, NULL },
612 { 0x1c, 0x1f, NULL, NULL },
613 { 0x20, 0xff, NULL, NULL },
615 { -1, -1, NULL, NULL }
618 /* utf8_three state table. */
619 const struct input_transition input_state_utf8_three_table[] = {
620 /* No INPUT_STATE_ANYWHERE */
622 { 0x00, 0x7f, NULL, &input_state_ground },
623 { 0x80, 0xbf, input_utf8_add, &input_state_utf8_two },
624 { 0xc0, 0xff, NULL, &input_state_ground },
626 { -1, -1, NULL, NULL }
629 /* utf8_two state table. */
630 const struct input_transition input_state_utf8_two_table[] = {
631 /* No INPUT_STATE_ANYWHERE */
633 { 0x00, 0x7f, NULL, &input_state_ground },
634 { 0x80, 0xbf, input_utf8_add, &input_state_utf8_one },
635 { 0xc0, 0xff, NULL, &input_state_ground },
637 { -1, -1, NULL, NULL }
640 /* utf8_one state table. */
641 const struct input_transition input_state_utf8_one_table[] = {
642 /* No INPUT_STATE_ANYWHERE */
644 { 0x00, 0x7f, NULL, &input_state_ground },
645 { 0x80, 0xbf, input_utf8_close, &input_state_ground },
646 { 0xc0, 0xff, NULL, &input_state_ground },
648 { -1, -1, NULL, NULL }
651 /* Input table compare. */
653 input_table_compare(const void *key, const void *value)
655 const struct input_ctx *ictx = key;
656 const struct input_table_entry *entry = value;
658 if (ictx->ch != entry->ch)
659 return (ictx->ch - entry->ch);
660 return (strcmp(ictx->interm_buf, entry->interm));
663 /* Initialise input parser. */
664 void
665 input_init(struct window_pane *wp)
667 struct input_ctx *ictx = &wp->ictx;
669 memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell);
671 memcpy(&ictx->old_cell, &grid_default_cell, sizeof ictx->old_cell);
672 ictx->old_cx = 0;
673 ictx->old_cy = 0;
675 *ictx->interm_buf = '\0';
676 ictx->interm_len = 0;
678 *ictx->param_buf = '\0';
679 ictx->param_len = 0;
681 ictx->state = &input_state_ground;
682 ictx->flags = 0;
685 /* Destroy input parser. */
686 void
687 input_free(unused struct window_pane *wp)
691 /* Parse input. */
692 void
693 input_parse(struct window_pane *wp)
695 struct input_ctx *ictx = &wp->ictx;
696 const struct input_transition *itr;
697 struct evbuffer *evb = wp->event->input;
698 u_char *buf;
699 size_t len, off;
701 if (EVBUFFER_LENGTH(evb) == 0)
702 return;
704 wp->window->flags |= WINDOW_ACTIVITY;
705 wp->window->flags &= ~WINDOW_SILENCE;
708 * Open the screen. Use NULL wp if there is a mode set as don't want to
709 * update the tty.
711 if (wp->mode == NULL)
712 screen_write_start(&ictx->ctx, wp, &wp->base);
713 else
714 screen_write_start(&ictx->ctx, NULL, &wp->base);
715 ictx->wp = wp;
717 buf = EVBUFFER_DATA(evb);
718 len = EVBUFFER_LENGTH(evb);
719 off = 0;
721 /* Parse the input. */
722 while (off < len) {
723 ictx->ch = buf[off++];
724 log_debug("%s: '%c' %s", __func__, ictx->ch, ictx->state->name);
726 /* Find the transition. */
727 itr = ictx->state->transitions;
728 while (itr->first != -1 && itr->last != -1) {
729 if (ictx->ch >= itr->first && ictx->ch <= itr->last)
730 break;
731 itr++;
733 if (itr->first == -1 || itr->last == -1) {
734 /* No transition? Eh? */
735 fatalx("No transition from state!");
739 * Execute the handler, if any. Don't switch state if it
740 * returns non-zero.
742 if (itr->handler != NULL && itr->handler(ictx) != 0)
743 continue;
745 /* And switch state, if necessary. */
746 if (itr->state != NULL) {
747 if (ictx->state->exit != NULL)
748 ictx->state->exit(ictx);
749 ictx->state = itr->state;
750 if (ictx->state->enter != NULL)
751 ictx->state->enter(ictx);
755 /* Close the screen. */
756 screen_write_stop(&ictx->ctx);
758 evbuffer_drain(evb, len);
761 /* Split the parameter list (if any). */
763 input_split(struct input_ctx *ictx)
766 const char *errstr;
767 char *ptr, *out;
768 int n;
770 ictx->param_list_len = 0;
771 if (ictx->param_len == 0)
772 return (0);
774 ptr = ictx->param_buf;
775 while ((out = strsep(&ptr, ";")) != NULL) {
776 if (*out == '\0')
777 n = -1;
778 else {
779 n = strtonum(out, 0, INT_MAX, &errstr);
780 if (errstr != NULL)
781 return (-1);
784 ictx->param_list[ictx->param_list_len++] = n;
785 if (ictx->param_list_len == nitems(ictx->param_list))
786 return (-1);
789 return (0);
792 /* Get an argument or return default value..*/
794 input_get(struct input_ctx *ictx, u_int validx, int minval, int defval)
796 int retval;
798 if (validx >= ictx->param_list_len)
799 return (defval);
801 retval = ictx->param_list[validx];
802 if (retval == -1)
803 return (defval);
804 if (retval < minval)
805 return (minval);
806 return (retval);
809 /* Reply to terminal query. */
810 void
811 input_reply(struct input_ctx *ictx, const char *fmt, ...)
813 va_list ap;
814 char *reply;
816 va_start(ap, fmt);
817 vasprintf(&reply, fmt, ap);
818 va_end(ap);
820 bufferevent_write(ictx->wp->event, reply, strlen(reply));
821 xfree(reply);
824 /* Clear saved state. */
825 void
826 input_clear(struct input_ctx *ictx)
828 *ictx->interm_buf = '\0';
829 ictx->interm_len = 0;
831 *ictx->param_buf = '\0';
832 ictx->param_len = 0;
834 *ictx->input_buf = '\0';
835 ictx->input_len = 0;
837 ictx->flags &= ~INPUT_DISCARD;
840 /* Output this character to the screen. */
842 input_print(struct input_ctx *ictx)
844 ictx->cell.data = ictx->ch;
845 screen_write_cell(&ictx->ctx, &ictx->cell, NULL);
847 return (0);
850 /* Collect intermediate string. */
852 input_intermediate(struct input_ctx *ictx)
854 if (ictx->interm_len == (sizeof ictx->interm_buf) - 1)
855 ictx->flags |= INPUT_DISCARD;
856 else {
857 ictx->interm_buf[ictx->interm_len++] = ictx->ch;
858 ictx->interm_buf[ictx->interm_len] = '\0';
861 return (0);
864 /* Collect parameter string. */
866 input_parameter(struct input_ctx *ictx)
868 if (ictx->param_len == (sizeof ictx->param_buf) - 1)
869 ictx->flags |= INPUT_DISCARD;
870 else {
871 ictx->param_buf[ictx->param_len++] = ictx->ch;
872 ictx->param_buf[ictx->param_len] = '\0';
875 return (0);
878 /* Collect input string. */
880 input_input(struct input_ctx *ictx)
882 if (ictx->input_len == (sizeof ictx->input_buf) - 1)
883 ictx->flags |= INPUT_DISCARD;
884 else {
885 ictx->input_buf[ictx->input_len++] = ictx->ch;
886 ictx->input_buf[ictx->input_len] = '\0';
889 return (0);
892 /* Execute C0 control sequence. */
894 input_c0_dispatch(struct input_ctx *ictx)
896 struct screen_write_ctx *sctx = &ictx->ctx;
897 struct window_pane *wp = ictx->wp;
898 struct screen *s = sctx->s;
900 log_debug("%s: '%c", __func__, ictx->ch);
902 switch (ictx->ch) {
903 case '\000': /* NUL */
904 break;
905 case '\007': /* BEL */
906 wp->window->flags |= WINDOW_BELL;
907 break;
908 case '\010': /* BS */
909 screen_write_backspace(sctx);
910 break;
911 case '\011': /* HT */
912 /* Don't tab beyond the end of the line. */
913 if (s->cx >= screen_size_x(s) - 1)
914 break;
916 /* Find the next tab point, or use the last column if none. */
917 do {
918 s->cx++;
919 if (bit_test(s->tabs, s->cx))
920 break;
921 } while (s->cx < screen_size_x(s) - 1);
922 break;
923 case '\012': /* LF */
924 case '\013': /* VT */
925 case '\014': /* FF */
926 screen_write_linefeed(sctx, 0);
927 break;
928 case '\015': /* CR */
929 screen_write_carriagereturn(sctx);
930 break;
931 case '\016': /* SO */
932 ictx->cell.attr |= GRID_ATTR_CHARSET;
933 break;
934 case '\017': /* SI */
935 ictx->cell.attr &= ~GRID_ATTR_CHARSET;
936 break;
937 default:
938 log_debug("%s: unknown '%c'", __func__, ictx->ch);
939 break;
942 return (0);
945 /* Execute escape sequence. */
947 input_esc_dispatch(struct input_ctx *ictx)
949 struct screen_write_ctx *sctx = &ictx->ctx;
950 struct screen *s = sctx->s;
951 struct input_table_entry *entry;
953 if (ictx->flags & INPUT_DISCARD)
954 return (0);
955 log_debug("%s: '%c', %s", __func__, ictx->ch, ictx->interm_buf);
957 entry = bsearch(ictx, input_esc_table, nitems(input_esc_table),
958 sizeof input_esc_table[0], input_table_compare);
959 if (entry == NULL) {
960 log_debug("%s: unknown '%c'", __func__, ictx->ch);
961 return (0);
964 switch (entry->type) {
965 case INPUT_ESC_RIS:
966 memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell);
967 memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
968 ictx->old_cx = 0;
969 ictx->old_cy = 0;
971 screen_reset_tabs(sctx->s);
973 screen_write_scrollregion(sctx, 0, screen_size_y(sctx->s) - 1);
975 screen_write_insertmode(sctx, 0);
976 screen_write_kcursormode(sctx, 0);
977 screen_write_kkeypadmode(sctx, 0);
978 screen_write_mousemode_off(sctx);
980 screen_write_clearscreen(sctx);
981 screen_write_cursormove(sctx, 0, 0);
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_DA:
1083 switch (input_get(ictx, 0, 0, 0)) {
1084 case 0:
1085 input_reply(ictx, "\033[?1;2c");
1086 break;
1087 default:
1088 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1089 break;
1091 break;
1092 case INPUT_CSI_DCH:
1093 screen_write_deletecharacter(sctx, input_get(ictx, 0, 1, 1));
1094 break;
1095 case INPUT_CSI_DECSTBM:
1096 n = input_get(ictx, 0, 1, 1);
1097 m = input_get(ictx, 1, 1, screen_size_y(s));
1098 screen_write_scrollregion(sctx, n - 1, m - 1);
1099 break;
1100 case INPUT_CSI_DL:
1101 screen_write_deleteline(sctx, input_get(ictx, 0, 1, 1));
1102 break;
1103 case INPUT_CSI_DSR:
1104 switch (input_get(ictx, 0, 0, 0)) {
1105 case 5:
1106 input_reply(ictx, "\033[0n");
1107 break;
1108 case 6:
1109 input_reply(ictx, "\033[%u;%uR", s->cy + 1, s->cx + 1);
1110 break;
1111 default:
1112 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1113 break;
1115 break;
1116 case INPUT_CSI_ED:
1117 switch (input_get(ictx, 0, 0, 0)) {
1118 case 0:
1119 screen_write_clearendofscreen(sctx);
1120 break;
1121 case 1:
1122 screen_write_clearstartofscreen(sctx);
1123 break;
1124 case 2:
1125 screen_write_clearscreen(sctx);
1126 break;
1127 default:
1128 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1129 break;
1131 break;
1132 case INPUT_CSI_EL:
1133 switch (input_get(ictx, 0, 0, 0)) {
1134 case 0:
1135 screen_write_clearendofline(sctx);
1136 break;
1137 case 1:
1138 screen_write_clearstartofline(sctx);
1139 break;
1140 case 2:
1141 screen_write_clearline(sctx);
1142 break;
1143 default:
1144 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1145 break;
1147 break;
1148 case INPUT_CSI_HPA:
1149 n = input_get(ictx, 0, 1, 1);
1150 screen_write_cursormove(sctx, n - 1, s->cy);
1151 break;
1152 case INPUT_CSI_ICH:
1153 screen_write_insertcharacter(sctx, input_get(ictx, 0, 1, 1));
1154 break;
1155 case INPUT_CSI_IL:
1156 screen_write_insertline(sctx, input_get(ictx, 0, 1, 1));
1157 break;
1158 case INPUT_CSI_RM:
1159 switch (input_get(ictx, 0, 0, -1)) {
1160 case 4: /* IRM */
1161 screen_write_insertmode(&ictx->ctx, 0);
1162 break;
1163 default:
1164 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1165 break;
1167 break;
1168 case INPUT_CSI_RM_PRIVATE:
1169 switch (input_get(ictx, 0, 0, -1)) {
1170 case 1: /* GATM */
1171 screen_write_kcursormode(&ictx->ctx, 0);
1172 break;
1173 case 3: /* DECCOLM */
1174 screen_write_cursormove(&ictx->ctx, 0, 0);
1175 screen_write_clearscreen(&ictx->ctx);
1176 break;
1177 case 25: /* TCEM */
1178 screen_write_cursormode(&ictx->ctx, 0);
1179 break;
1180 case 1000:
1181 case 1001:
1182 case 1002:
1183 case 1003:
1184 screen_write_mousemode_off(&ictx->ctx);
1185 break;
1186 case 1005:
1187 screen_write_utf8mousemode(&ictx->ctx, 0);
1188 break;
1189 case 1049:
1190 window_pane_alternate_off(wp, &ictx->cell);
1191 break;
1192 default:
1193 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1194 break;
1196 break;
1197 case INPUT_CSI_SGR:
1198 input_csi_dispatch_sgr(ictx);
1199 break;
1200 case INPUT_CSI_SM:
1201 switch (input_get(ictx, 0, 0, -1)) {
1202 case 4: /* IRM */
1203 screen_write_insertmode(&ictx->ctx, 1);
1204 break;
1205 default:
1206 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1207 break;
1209 break;
1210 case INPUT_CSI_SM_PRIVATE:
1211 switch (input_get(ictx, 0, 0, -1)) {
1212 case 1: /* GATM */
1213 screen_write_kcursormode(&ictx->ctx, 1);
1214 break;
1215 case 3: /* DECCOLM */
1216 screen_write_cursormove(&ictx->ctx, 0, 0);
1217 screen_write_clearscreen(&ictx->ctx);
1218 break;
1219 case 25: /* TCEM */
1220 screen_write_cursormode(&ictx->ctx, 1);
1221 break;
1222 case 1000:
1223 screen_write_mousemode_on(
1224 &ictx->ctx, MODE_MOUSE_STANDARD);
1225 break;
1226 case 1002:
1227 screen_write_mousemode_on(
1228 &ictx->ctx, MODE_MOUSE_BUTTON);
1229 break;
1230 case 1003:
1231 screen_write_mousemode_on(&ictx->ctx, MODE_MOUSE_ANY);
1232 break;
1233 case 1005:
1234 screen_write_utf8mousemode(&ictx->ctx, 1);
1235 break;
1236 case 1049:
1237 window_pane_alternate_on(wp, &ictx->cell);
1238 break;
1239 default:
1240 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1241 break;
1243 break;
1244 case INPUT_CSI_TBC:
1245 switch (input_get(ictx, 0, 0, 0)) {
1246 case 0:
1247 if (s->cx < screen_size_x(s))
1248 bit_clear(s->tabs, s->cx);
1249 break;
1250 case 3:
1251 bit_nclear(s->tabs, 0, screen_size_x(s) - 1);
1252 break;
1253 default:
1254 log_debug("%s: unknown '%c'", __func__, ictx->ch);
1255 break;
1257 break;
1258 case INPUT_CSI_VPA:
1259 n = input_get(ictx, 0, 1, 1);
1260 screen_write_cursormove(sctx, s->cx, n - 1);
1261 break;
1264 return (0);
1267 /* Handle CSI SGR. */
1268 void
1269 input_csi_dispatch_sgr(struct input_ctx *ictx)
1271 struct grid_cell *gc = &ictx->cell;
1272 u_int i;
1273 int n, m;
1274 u_char attr;
1276 if (ictx->param_list_len == 0) {
1277 attr = gc->attr;
1278 memcpy(gc, &grid_default_cell, sizeof *gc);
1279 gc->attr |= (attr & GRID_ATTR_CHARSET);
1280 return;
1283 for (i = 0; i < ictx->param_list_len; i++) {
1284 n = input_get(ictx, i, 0, 0);
1286 if (n == 38 || n == 48) {
1287 i++;
1288 if (input_get(ictx, i, 0, -1) != 5)
1289 continue;
1291 i++;
1292 m = input_get(ictx, i, 0, -1);
1293 if (m == -1) {
1294 if (n == 38) {
1295 gc->flags &= ~GRID_FLAG_FG256;
1296 gc->fg = 8;
1297 } else if (n == 48) {
1298 gc->flags &= ~GRID_FLAG_BG256;
1299 gc->bg = 8;
1302 } else {
1303 if (n == 38) {
1304 gc->flags |= GRID_FLAG_FG256;
1305 gc->fg = m;
1306 } else if (n == 48) {
1307 gc->flags |= GRID_FLAG_BG256;
1308 gc->bg = m;
1311 continue;
1314 switch (n) {
1315 case 0:
1316 case 10:
1317 attr = gc->attr;
1318 memcpy(gc, &grid_default_cell, sizeof *gc);
1319 gc->attr |= (attr & GRID_ATTR_CHARSET);
1320 break;
1321 case 1:
1322 gc->attr |= GRID_ATTR_BRIGHT;
1323 break;
1324 case 2:
1325 gc->attr |= GRID_ATTR_DIM;
1326 break;
1327 case 3:
1328 gc->attr |= GRID_ATTR_ITALICS;
1329 break;
1330 case 4:
1331 gc->attr |= GRID_ATTR_UNDERSCORE;
1332 break;
1333 case 5:
1334 gc->attr |= GRID_ATTR_BLINK;
1335 break;
1336 case 7:
1337 gc->attr |= GRID_ATTR_REVERSE;
1338 break;
1339 case 8:
1340 gc->attr |= GRID_ATTR_HIDDEN;
1341 break;
1342 case 22:
1343 gc->attr &= ~(GRID_ATTR_BRIGHT|GRID_ATTR_DIM);
1344 break;
1345 case 23:
1346 gc->attr &= ~GRID_ATTR_ITALICS;
1347 break;
1348 case 24:
1349 gc->attr &= ~GRID_ATTR_UNDERSCORE;
1350 break;
1351 case 25:
1352 gc->attr &= ~GRID_ATTR_BLINK;
1353 break;
1354 case 27:
1355 gc->attr &= ~GRID_ATTR_REVERSE;
1356 break;
1357 case 30:
1358 case 31:
1359 case 32:
1360 case 33:
1361 case 34:
1362 case 35:
1363 case 36:
1364 case 37:
1365 gc->flags &= ~GRID_FLAG_FG256;
1366 gc->fg = n - 30;
1367 break;
1368 case 39:
1369 gc->flags &= ~GRID_FLAG_FG256;
1370 gc->fg = 8;
1371 break;
1372 case 40:
1373 case 41:
1374 case 42:
1375 case 43:
1376 case 44:
1377 case 45:
1378 case 46:
1379 case 47:
1380 gc->flags &= ~GRID_FLAG_BG256;
1381 gc->bg = n - 40;
1382 break;
1383 case 49:
1384 gc->flags &= ~GRID_FLAG_BG256;
1385 gc->bg = 8;
1386 break;
1387 case 90:
1388 case 91:
1389 case 92:
1390 case 93:
1391 case 94:
1392 case 95:
1393 case 96:
1394 case 97:
1395 gc->flags &= ~GRID_FLAG_FG256;
1396 gc->fg = n;
1397 break;
1398 case 100:
1399 case 101:
1400 case 102:
1401 case 103:
1402 case 104:
1403 case 105:
1404 case 106:
1405 case 107:
1406 gc->flags &= ~GRID_FLAG_BG256;
1407 gc->bg = n;
1408 break;
1413 /* DCS terminator (ST) received. */
1415 input_dcs_dispatch(struct input_ctx *ictx)
1417 const char prefix[] = "tmux;";
1418 const u_int prefix_len = (sizeof prefix) - 1;
1420 if (ictx->flags & INPUT_DISCARD)
1421 return (0);
1423 log_debug("%s: \"%s\"", __func__, ictx->input_buf);
1425 /* Check for tmux prefix. */
1426 if (ictx->input_len >= prefix_len &&
1427 strncmp(ictx->input_buf, prefix, prefix_len) == 0) {
1428 screen_write_rawstring(&ictx->ctx,
1429 ictx->input_buf + prefix_len, ictx->input_len - prefix_len);
1432 return (0);
1435 /* OSC string started. */
1436 void
1437 input_enter_osc(struct input_ctx *ictx)
1439 log_debug("%s", __func__);
1441 input_clear(ictx);
1444 /* OSC terminator (ST) received. */
1445 void
1446 input_exit_osc(struct input_ctx *ictx)
1448 if (ictx->flags & INPUT_DISCARD)
1449 return;
1450 log_debug("%s: \"%s\"", __func__, ictx->input_buf);
1452 if (ictx->input_len < 2 || ictx->input_buf[1] != ';')
1453 return;
1454 if (ictx->input_buf[0] != '0' && ictx->input_buf[0] != '2')
1455 return;
1457 screen_set_title(ictx->ctx.s, ictx->input_buf + 2);
1458 server_status_window(ictx->wp->window);
1461 /* APC string started. */
1462 void
1463 input_enter_apc(struct input_ctx *ictx)
1465 log_debug("%s", __func__);
1467 input_clear(ictx);
1470 /* APC terminator (ST) received. */
1471 void
1472 input_exit_apc(struct input_ctx *ictx)
1474 if (ictx->flags & INPUT_DISCARD)
1475 return;
1476 log_debug("%s: \"%s\"", __func__, ictx->input_buf);
1478 screen_set_title(ictx->ctx.s, ictx->input_buf);
1479 server_status_window(ictx->wp->window);
1482 /* Rename string started. */
1483 void
1484 input_enter_rename(struct input_ctx *ictx)
1486 log_debug("%s", __func__);
1488 input_clear(ictx);
1491 /* Rename terminator (ST) received. */
1492 void
1493 input_exit_rename(struct input_ctx *ictx)
1495 if (ictx->flags & INPUT_DISCARD)
1496 return;
1497 log_debug("%s: \"%s\"", __func__, ictx->input_buf);
1499 xfree(ictx->wp->window->name);
1500 ictx->wp->window->name = xstrdup(ictx->input_buf);
1501 options_set_number(&ictx->wp->window->options, "automatic-rename", 0);
1503 server_status_window(ictx->wp->window);
1506 /* Open UTF-8 character. */
1508 input_utf8_open(struct input_ctx *ictx)
1510 if (!options_get_number(&ictx->wp->window->options, "utf8")) {
1511 /* Print, and do not switch state. */
1512 input_print(ictx);
1513 return (-1);
1515 log_debug("%s", __func__);
1517 utf8_open(&ictx->utf8data, ictx->ch);
1518 return (0);
1521 /* Append to UTF-8 character. */
1523 input_utf8_add(struct input_ctx *ictx)
1525 log_debug("%s", __func__);
1527 utf8_append(&ictx->utf8data, ictx->ch);
1528 return (0);
1531 /* Close UTF-8 string. */
1533 input_utf8_close(struct input_ctx *ictx)
1535 log_debug("%s", __func__);
1537 utf8_append(&ictx->utf8data, ictx->ch);
1539 ictx->cell.flags |= GRID_FLAG_UTF8;
1540 screen_write_cell(&ictx->ctx, &ictx->cell, &ictx->utf8data);
1541 ictx->cell.flags &= ~GRID_FLAG_UTF8;
1543 return (0);