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>
27 * Based on the description by Paul Williams at:
29 * http://vt100.net/emu/dec_ansi_parser
31 * With the following changes:
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
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.
46 /* Helper functions. */
47 int input_split(struct input_ctx
*);
48 int input_get(struct input_ctx
*, u_int
, int, int);
49 void input_reply(struct input_ctx
*, const char *, ...);
51 /* Transition entry/exit handlers. */
52 void input_clear(struct input_ctx
*);
53 void input_enter_dcs(struct input_ctx
*);
54 void input_exit_dcs(struct input_ctx
*);
55 void input_enter_osc(struct input_ctx
*);
56 void input_exit_osc(struct input_ctx
*);
57 void input_enter_apc(struct input_ctx
*);
58 void input_exit_apc(struct input_ctx
*);
59 void input_enter_rename(struct input_ctx
*);
60 void input_exit_rename(struct input_ctx
*);
62 /* Input state handlers. */
63 int input_print(struct input_ctx
*);
64 int input_intermediate(struct input_ctx
*);
65 int input_parameter(struct input_ctx
*);
66 int input_input(struct input_ctx
*);
67 int input_c0_dispatch(struct input_ctx
*);
68 int input_esc_dispatch(struct input_ctx
*);
69 int input_csi_dispatch(struct input_ctx
*);
70 void input_csi_dispatch_sgr(struct input_ctx
*);
71 int input_utf8_open(struct input_ctx
*);
72 int input_utf8_add(struct input_ctx
*);
73 int input_utf8_close(struct input_ctx
*);
75 /* Command table comparison function. */
76 int input_table_compare(const void *, const void *);
78 /* Command table entry. */
79 struct input_table_entry
{
85 /* Escape commands. */
101 /* Escape command table. */
102 const struct input_table_entry input_esc_table
[] = {
103 { '0', "(", INPUT_ESC_SCSOFF_G0
},
104 { '7', "", INPUT_ESC_DECSC
},
105 { '8', "", INPUT_ESC_DECRC
},
106 { '8', "#", INPUT_ESC_DECALN
},
107 { '=', "", INPUT_ESC_DECKPAM
},
108 { '>', "", INPUT_ESC_DECKPNM
},
109 { 'B', "(", INPUT_ESC_SCSON_G0
},
110 { 'D', "", INPUT_ESC_IND
},
111 { 'E', "", INPUT_ESC_NEL
},
112 { 'H', "", INPUT_ESC_HTS
},
113 { 'M', "", INPUT_ESC_RI
},
114 { 'c', "", INPUT_ESC_RIS
},
117 /* Control (CSI) commands. */
118 enum input_csi_type
{
136 INPUT_CSI_RM_PRIVATE
,
139 INPUT_CSI_SM_PRIVATE
,
144 /* Control (CSI) command table. */
145 const struct input_table_entry input_csi_table
[] = {
146 { '@', "", INPUT_CSI_ICH
},
147 { 'A', "", INPUT_CSI_CUU
},
148 { 'B', "", INPUT_CSI_CUD
},
149 { 'C', "", INPUT_CSI_CUF
},
150 { 'D', "", INPUT_CSI_CUB
},
151 { 'G', "", INPUT_CSI_HPA
},
152 { 'H', "", INPUT_CSI_CUP
},
153 { 'J', "", INPUT_CSI_ED
},
154 { 'K', "", INPUT_CSI_EL
},
155 { 'L', "", INPUT_CSI_IL
},
156 { 'M', "", INPUT_CSI_DL
},
157 { 'P', "", INPUT_CSI_DCH
},
158 { 'Z', "", INPUT_CSI_CBT
},
159 { 'c', "", INPUT_CSI_DA
},
160 { 'd', "", INPUT_CSI_VPA
},
161 { 'f', "", INPUT_CSI_CUP
},
162 { 'g', "", INPUT_CSI_TBC
},
163 { 'h', "", INPUT_CSI_SM
},
164 { 'h', "?", INPUT_CSI_SM_PRIVATE
},
165 { 'l', "", INPUT_CSI_RM
},
166 { 'l', "?", INPUT_CSI_RM_PRIVATE
},
167 { 'm', "", INPUT_CSI_SGR
},
168 { 'n', "", INPUT_CSI_DSR
},
169 { 'r', "", INPUT_CSI_DECSTBM
},
172 /* Input transition. */
173 struct input_transition
{
177 int (*handler
)(struct input_ctx
*);
178 const struct input_state
*state
;
184 void (*enter
)(struct input_ctx
*);
185 void (*exit
)(struct input_ctx
*);
186 const struct input_transition
*transitions
;
189 /* State transitions available from all states. */
190 #define INPUT_STATE_ANYWHERE \
191 { 0x18, 0x18, input_c0_dispatch, &input_state_ground }, \
192 { 0x1a, 0x1a, input_c0_dispatch, &input_state_ground }, \
193 { 0x1b, 0x1b, NULL, &input_state_esc_enter }
195 /* Forward declarations of state tables. */
196 const struct input_transition input_state_ground_table
[];
197 const struct input_transition input_state_esc_enter_table
[];
198 const struct input_transition input_state_esc_intermediate_table
[];
199 const struct input_transition input_state_csi_enter_table
[];
200 const struct input_transition input_state_csi_parameter_table
[];
201 const struct input_transition input_state_csi_intermediate_table
[];
202 const struct input_transition input_state_csi_ignore_table
[];
203 const struct input_transition input_state_dcs_enter_table
[];
204 const struct input_transition input_state_dcs_parameter_table
[];
205 const struct input_transition input_state_dcs_intermediate_table
[];
206 const struct input_transition input_state_dcs_handler_table
[];
207 const struct input_transition input_state_dcs_ignore_table
[];
208 const struct input_transition input_state_osc_string_table
[];
209 const struct input_transition input_state_apc_string_table
[];
210 const struct input_transition input_state_rename_string_table
[];
211 const struct input_transition input_state_consume_st_table
[];
212 const struct input_transition input_state_utf8_three_table
[];
213 const struct input_transition input_state_utf8_two_table
[];
214 const struct input_transition input_state_utf8_one_table
[];
216 /* ground state definition. */
217 const struct input_state input_state_ground
= {
220 input_state_ground_table
223 /* esc_enter state definition. */
224 const struct input_state input_state_esc_enter
= {
227 input_state_esc_enter_table
230 /* esc_intermediate state definition. */
231 const struct input_state input_state_esc_intermediate
= {
234 input_state_esc_intermediate_table
237 /* csi_enter state definition. */
238 const struct input_state input_state_csi_enter
= {
241 input_state_csi_enter_table
244 /* csi_parameter state definition. */
245 const struct input_state input_state_csi_parameter
= {
248 input_state_csi_parameter_table
251 /* csi_intermediate state definition. */
252 const struct input_state input_state_csi_intermediate
= {
255 input_state_csi_intermediate_table
258 /* csi_ignore state definition. */
259 const struct input_state input_state_csi_ignore
= {
262 input_state_csi_ignore_table
265 /* dcs_enter state definition. */
266 const struct input_state input_state_dcs_enter
= {
269 input_state_dcs_enter_table
272 /* dcs_parameter state definition. */
273 const struct input_state input_state_dcs_parameter
= {
276 input_state_dcs_parameter_table
279 /* dcs_intermediate state definition. */
280 const struct input_state input_state_dcs_intermediate
= {
283 input_state_dcs_intermediate_table
286 /* dcs_handler state definition. */
287 const struct input_state input_state_dcs_handler
= {
289 input_enter_dcs
, input_exit_dcs
,
290 input_state_dcs_handler_table
293 /* dcs_ignore state definition. */
294 const struct input_state input_state_dcs_ignore
= {
297 input_state_dcs_ignore_table
300 /* osc_string state definition. */
301 const struct input_state input_state_osc_string
= {
303 input_enter_osc
, input_exit_osc
,
304 input_state_osc_string_table
307 /* apc_string state definition. */
308 const struct input_state input_state_apc_string
= {
310 input_enter_apc
, input_exit_apc
,
311 input_state_apc_string_table
314 /* rename_string state definition. */
315 const struct input_state input_state_rename_string
= {
317 input_enter_rename
, input_exit_rename
,
318 input_state_rename_string_table
321 /* consume_st state definition. */
322 const struct input_state input_state_consume_st
= {
325 input_state_consume_st_table
328 /* utf8_three state definition. */
329 const struct input_state input_state_utf8_three
= {
332 input_state_utf8_three_table
335 /* utf8_two state definition. */
336 const struct input_state input_state_utf8_two
= {
339 input_state_utf8_two_table
342 /* utf8_one state definition. */
343 const struct input_state input_state_utf8_one
= {
346 input_state_utf8_one_table
349 /* ground state table. */
350 const struct input_transition input_state_ground_table
[] = {
351 INPUT_STATE_ANYWHERE
,
353 { 0x00, 0x17, input_c0_dispatch
, NULL
},
354 { 0x19, 0x19, input_c0_dispatch
, NULL
},
355 { 0x1c, 0x1f, input_c0_dispatch
, NULL
},
356 { 0x20, 0x7e, input_print
, NULL
},
357 { 0x7f, 0x7f, NULL
, NULL
},
358 { 0x80, 0xc1, input_print
, NULL
},
359 { 0xc2, 0xdf, input_utf8_open
, &input_state_utf8_one
},
360 { 0xe0, 0xef, input_utf8_open
, &input_state_utf8_two
},
361 { 0xf0, 0xf4, input_utf8_open
, &input_state_utf8_three
},
362 { 0xf5, 0xff, input_print
, NULL
},
364 { -1, -1, NULL
, NULL
}
367 /* esc_enter state table. */
368 const struct input_transition input_state_esc_enter_table
[] = {
369 INPUT_STATE_ANYWHERE
,
371 { 0x00, 0x17, input_c0_dispatch
, NULL
},
372 { 0x19, 0x19, input_c0_dispatch
, NULL
},
373 { 0x1c, 0x1f, input_c0_dispatch
, NULL
},
374 { 0x20, 0x2f, input_intermediate
, &input_state_esc_intermediate
},
375 { 0x30, 0x4f, input_esc_dispatch
, &input_state_ground
},
376 { 0x50, 0x50, NULL
, &input_state_dcs_enter
},
377 { 0x51, 0x57, input_esc_dispatch
, &input_state_ground
},
378 { 0x58, 0x58, NULL
, &input_state_consume_st
},
379 { 0x59, 0x59, input_esc_dispatch
, &input_state_ground
},
380 { 0x5a, 0x5a, input_esc_dispatch
, &input_state_ground
},
381 { 0x5b, 0x5b, NULL
, &input_state_csi_enter
},
382 { 0x5c, 0x5c, input_esc_dispatch
, &input_state_ground
},
383 { 0x5d, 0x5d, NULL
, &input_state_osc_string
},
384 { 0x5e, 0x5e, NULL
, &input_state_consume_st
},
385 { 0x5f, 0x5f, NULL
, &input_state_apc_string
},
386 { 0x60, 0x6a, input_esc_dispatch
, &input_state_ground
},
387 { 0x6b, 0x6b, NULL
, &input_state_rename_string
},
388 { 0x6c, 0x7e, input_esc_dispatch
, &input_state_ground
},
389 { 0x7f, 0xff, NULL
, NULL
},
391 { -1, -1, NULL
, NULL
}
394 /* esc_interm state table. */
395 const struct input_transition input_state_esc_intermediate_table
[] = {
396 INPUT_STATE_ANYWHERE
,
398 { 0x00, 0x17, input_c0_dispatch
, NULL
},
399 { 0x19, 0x19, input_c0_dispatch
, NULL
},
400 { 0x1c, 0x1f, input_c0_dispatch
, NULL
},
401 { 0x20, 0x2f, input_intermediate
, NULL
},
402 { 0x30, 0x7e, input_esc_dispatch
, &input_state_ground
},
403 { 0x7f, 0xff, NULL
, NULL
},
405 { -1, -1, NULL
, NULL
}
408 /* csi_enter state table. */
409 const struct input_transition input_state_csi_enter_table
[] = {
410 INPUT_STATE_ANYWHERE
,
412 { 0x00, 0x17, input_c0_dispatch
, NULL
},
413 { 0x19, 0x19, input_c0_dispatch
, NULL
},
414 { 0x1c, 0x1f, input_c0_dispatch
, NULL
},
415 { 0x20, 0x2f, input_intermediate
, &input_state_csi_intermediate
},
416 { 0x30, 0x39, input_parameter
, &input_state_csi_parameter
},
417 { 0x3a, 0x3a, NULL
, &input_state_csi_ignore
},
418 { 0x3b, 0x3b, input_parameter
, &input_state_csi_parameter
},
419 { 0x3c, 0x3f, input_intermediate
, &input_state_csi_parameter
},
420 { 0x40, 0x7e, input_csi_dispatch
, &input_state_ground
},
421 { 0x7f, 0xff, NULL
, NULL
},
423 { -1, -1, NULL
, NULL
}
426 /* csi_parameter state table. */
427 const struct input_transition input_state_csi_parameter_table
[] = {
428 INPUT_STATE_ANYWHERE
,
430 { 0x00, 0x17, input_c0_dispatch
, NULL
},
431 { 0x19, 0x19, input_c0_dispatch
, NULL
},
432 { 0x1c, 0x1f, input_c0_dispatch
, NULL
},
433 { 0x20, 0x2f, input_intermediate
, &input_state_csi_intermediate
},
434 { 0x30, 0x39, input_parameter
, NULL
},
435 { 0x3a, 0x3a, NULL
, &input_state_csi_ignore
},
436 { 0x3b, 0x3b, input_parameter
, NULL
},
437 { 0x3c, 0x3f, NULL
, &input_state_csi_ignore
},
438 { 0x40, 0x7e, input_csi_dispatch
, &input_state_ground
},
439 { 0x7f, 0xff, NULL
, NULL
},
441 { -1, -1, NULL
, NULL
}
444 /* csi_intermediate state table. */
445 const struct input_transition input_state_csi_intermediate_table
[] = {
446 INPUT_STATE_ANYWHERE
,
448 { 0x00, 0x17, input_c0_dispatch
, NULL
},
449 { 0x19, 0x19, input_c0_dispatch
, NULL
},
450 { 0x1c, 0x1f, input_c0_dispatch
, NULL
},
451 { 0x20, 0x2f, input_intermediate
, NULL
},
452 { 0x30, 0x3f, NULL
, &input_state_csi_ignore
},
453 { 0x40, 0x7e, input_csi_dispatch
, &input_state_ground
},
454 { 0x7f, 0xff, NULL
, NULL
},
456 { -1, -1, NULL
, NULL
}
459 /* csi_ignore state table. */
460 const struct input_transition input_state_csi_ignore_table
[] = {
461 INPUT_STATE_ANYWHERE
,
463 { 0x00, 0x17, input_c0_dispatch
, NULL
},
464 { 0x19, 0x19, input_c0_dispatch
, NULL
},
465 { 0x1c, 0x1f, input_c0_dispatch
, NULL
},
466 { 0x20, 0x3f, NULL
, NULL
},
467 { 0x40, 0x7e, NULL
, &input_state_ground
},
468 { 0x7f, 0xff, NULL
, NULL
},
470 { -1, -1, NULL
, NULL
}
473 /* dcs_enter state table. */
474 const struct input_transition input_state_dcs_enter_table
[] = {
475 INPUT_STATE_ANYWHERE
,
477 { 0x00, 0x17, NULL
, NULL
},
478 { 0x19, 0x19, NULL
, NULL
},
479 { 0x1c, 0x1f, NULL
, NULL
},
480 { 0x20, 0x2f, input_intermediate
, &input_state_dcs_intermediate
},
481 { 0x30, 0x39, input_parameter
, &input_state_dcs_parameter
},
482 { 0x3a, 0x3a, NULL
, &input_state_dcs_ignore
},
483 { 0x3b, 0x3b, input_parameter
, &input_state_dcs_parameter
},
484 { 0x3c, 0x3f, input_intermediate
, &input_state_dcs_parameter
},
485 { 0x40, 0x7e, NULL
, &input_state_dcs_handler
},
486 { 0x7f, 0xff, NULL
, NULL
},
488 { -1, -1, NULL
, NULL
}
491 /* dcs_parameter state table. */
492 const struct input_transition input_state_dcs_parameter_table
[] = {
493 INPUT_STATE_ANYWHERE
,
495 { 0x00, 0x17, NULL
, NULL
},
496 { 0x19, 0x19, NULL
, NULL
},
497 { 0x1c, 0x1f, NULL
, NULL
},
498 { 0x20, 0x2f, input_intermediate
, &input_state_dcs_intermediate
},
499 { 0x30, 0x39, input_parameter
, NULL
},
500 { 0x3a, 0x3a, NULL
, &input_state_dcs_ignore
},
501 { 0x3b, 0x3b, input_parameter
, NULL
},
502 { 0x3c, 0x3f, NULL
, &input_state_dcs_ignore
},
503 { 0x40, 0x7e, NULL
, &input_state_dcs_handler
},
504 { 0x7f, 0xff, NULL
, NULL
},
506 { -1, -1, NULL
, NULL
}
509 /* dcs_interm state table. */
510 const struct input_transition input_state_dcs_intermediate_table
[] = {
511 INPUT_STATE_ANYWHERE
,
513 { 0x00, 0x17, NULL
, NULL
},
514 { 0x19, 0x19, NULL
, NULL
},
515 { 0x1c, 0x1f, NULL
, NULL
},
516 { 0x20, 0x2f, input_intermediate
, NULL
},
517 { 0x30, 0x3f, NULL
, &input_state_dcs_ignore
},
518 { 0x40, 0x7e, NULL
, &input_state_dcs_handler
},
519 { 0x7f, 0xff, NULL
, NULL
},
521 { -1, -1, NULL
, NULL
}
524 /* dcs_handler state table. */
525 const struct input_transition input_state_dcs_handler_table
[] = {
526 INPUT_STATE_ANYWHERE
,
528 { 0x00, 0x17, NULL
, NULL
},
529 { 0x19, 0x19, input_input
, NULL
},
530 { 0x1c, 0x1f, input_input
, NULL
},
531 { 0x20, 0x7e, input_input
, NULL
},
532 { 0x7f, 0xff, NULL
, NULL
},
534 { -1, -1, NULL
, NULL
}
537 /* device_ignore state table. */
538 const struct input_transition input_state_dcs_ignore_table
[] = {
539 INPUT_STATE_ANYWHERE
,
541 { 0x00, 0x17, NULL
, NULL
},
542 { 0x19, 0x19, NULL
, NULL
},
543 { 0x1c, 0x1f, NULL
, NULL
},
544 { 0x20, 0xff, NULL
, NULL
},
546 { -1, -1, NULL
, NULL
}
549 /* osc_string state table. */
550 const struct input_transition input_state_osc_string_table
[] = {
551 INPUT_STATE_ANYWHERE
,
553 { 0x00, 0x06, NULL
, NULL
},
554 { 0x07, 0x07, NULL
, &input_state_ground
},
555 { 0x08, 0x17, NULL
, NULL
},
556 { 0x19, 0x19, NULL
, NULL
},
557 { 0x1c, 0x1f, NULL
, NULL
},
558 { 0x20, 0xff, input_input
, NULL
},
560 { -1, -1, NULL
, NULL
}
563 /* apc_string state table. */
564 const struct input_transition input_state_apc_string_table
[] = {
565 INPUT_STATE_ANYWHERE
,
567 { 0x00, 0x17, NULL
, NULL
},
568 { 0x19, 0x19, NULL
, NULL
},
569 { 0x1c, 0x1f, NULL
, NULL
},
570 { 0x20, 0xff, input_input
, NULL
},
572 { -1, -1, NULL
, NULL
}
575 /* rename_string state table. */
576 const struct input_transition input_state_rename_string_table
[] = {
577 INPUT_STATE_ANYWHERE
,
579 { 0x00, 0x17, NULL
, NULL
},
580 { 0x19, 0x19, NULL
, NULL
},
581 { 0x1c, 0x1f, NULL
, NULL
},
582 { 0x20, 0xff, input_input
, NULL
},
584 { -1, -1, NULL
, NULL
}
587 /* consume_st state table. */
588 const struct input_transition input_state_consume_st_table
[] = {
589 INPUT_STATE_ANYWHERE
,
591 { 0x00, 0x17, NULL
, NULL
},
592 { 0x19, 0x19, NULL
, NULL
},
593 { 0x1c, 0x1f, NULL
, NULL
},
594 { 0x20, 0xff, NULL
, NULL
},
596 { -1, -1, NULL
, NULL
}
599 /* utf8_three state table. */
600 const struct input_transition input_state_utf8_three_table
[] = {
601 /* No INPUT_STATE_ANYWHERE */
603 { 0x00, 0x7f, NULL
, &input_state_ground
},
604 { 0x80, 0xbf, input_utf8_add
, &input_state_utf8_two
},
605 { 0xc0, 0xff, NULL
, &input_state_ground
},
607 { -1, -1, NULL
, NULL
}
610 /* utf8_two state table. */
611 const struct input_transition input_state_utf8_two_table
[] = {
612 /* No INPUT_STATE_ANYWHERE */
614 { 0x00, 0x7f, NULL
, &input_state_ground
},
615 { 0x80, 0xbf, input_utf8_add
, &input_state_utf8_one
},
616 { 0xc0, 0xff, NULL
, &input_state_ground
},
618 { -1, -1, NULL
, NULL
}
621 /* utf8_one state table. */
622 const struct input_transition input_state_utf8_one_table
[] = {
623 /* No INPUT_STATE_ANYWHERE */
625 { 0x00, 0x7f, NULL
, &input_state_ground
},
626 { 0x80, 0xbf, input_utf8_close
, &input_state_ground
},
627 { 0xc0, 0xff, NULL
, &input_state_ground
},
629 { -1, -1, NULL
, NULL
}
632 /* Input table compare. */
634 input_table_compare(const void *key
, const void *value
)
636 const struct input_ctx
*ictx
= key
;
637 const struct input_table_entry
*entry
= value
;
639 if (ictx
->ch
!= entry
->ch
)
640 return (ictx
->ch
- entry
->ch
);
641 return (strcmp(ictx
->interm_buf
, entry
->interm
));
644 /* Initialise input parser. */
646 input_init(struct window_pane
*wp
)
648 struct input_ctx
*ictx
= &wp
->ictx
;
650 memcpy(&ictx
->cell
, &grid_default_cell
, sizeof ictx
->cell
);
652 memcpy(&ictx
->old_cell
, &grid_default_cell
, sizeof ictx
->old_cell
);
656 *ictx
->interm_buf
= '\0';
657 ictx
->interm_len
= 0;
659 *ictx
->param_buf
= '\0';
662 ictx
->state
= &input_state_ground
;
666 /* Destroy input parser. */
668 input_free(unused
struct window_pane
*wp
)
674 input_parse(struct window_pane
*wp
)
676 struct input_ctx
*ictx
= &wp
->ictx
;
677 const struct input_transition
*itr
;
678 struct evbuffer
*evb
= wp
->event
->input
;
682 if (EVBUFFER_LENGTH(evb
) == 0)
685 wp
->window
->flags
|= WINDOW_ACTIVITY
;
686 wp
->window
->flags
&= ~WINDOW_SILENCE
;
689 * Open the screen. Use NULL wp if there is a mode set as don't want to
692 if (wp
->mode
== NULL
)
693 screen_write_start(&ictx
->ctx
, wp
, &wp
->base
);
695 screen_write_start(&ictx
->ctx
, NULL
, &wp
->base
);
698 buf
= EVBUFFER_DATA(evb
);
699 len
= EVBUFFER_LENGTH(evb
);
702 /* Parse the input. */
704 ictx
->ch
= buf
[off
++];
705 log_debug("%s: '%c' %s", __func__
, ictx
->ch
, ictx
->state
->name
);
707 /* Find the transition. */
708 itr
= ictx
->state
->transitions
;
709 while (itr
->first
!= -1 && itr
->last
!= -1) {
710 if (ictx
->ch
>= itr
->first
&& ictx
->ch
<= itr
->last
)
714 if (itr
->first
== -1 || itr
->last
== -1) {
715 /* No transition? Eh? */
716 fatalx("No transition from state!");
720 * Execute the handler, if any. Don't switch state if it
723 if (itr
->handler
!= NULL
&& itr
->handler(ictx
) != 0)
726 /* And switch state, if necessary. */
727 if (itr
->state
!= NULL
) {
728 if (ictx
->state
->exit
!= NULL
)
729 ictx
->state
->exit(ictx
);
730 ictx
->state
= itr
->state
;
731 if (ictx
->state
->enter
!= NULL
)
732 ictx
->state
->enter(ictx
);
736 /* Close the screen. */
737 screen_write_stop(&ictx
->ctx
);
739 evbuffer_drain(evb
, len
);
742 /* Split the parameter list (if any). */
744 input_split(struct input_ctx
*ictx
)
751 ictx
->param_list_len
= 0;
752 if (ictx
->param_len
== 0)
755 ptr
= ictx
->param_buf
;
756 while ((out
= strsep(&ptr
, ";")) != NULL
) {
760 n
= strtonum(out
, 0, INT_MAX
, &errstr
);
765 ictx
->param_list
[ictx
->param_list_len
++] = n
;
766 if (ictx
->param_list_len
== nitems(ictx
->param_list
))
773 /* Get an argument or return default value..*/
775 input_get(struct input_ctx
*ictx
, u_int validx
, int minval
, int defval
)
779 if (validx
>= ictx
->param_list_len
)
782 retval
= ictx
->param_list
[validx
];
790 /* Reply to terminal query. */
792 input_reply(struct input_ctx
*ictx
, const char *fmt
, ...)
798 vasprintf(&reply
, fmt
, ap
);
801 bufferevent_write(ictx
->wp
->event
, reply
, strlen(reply
));
805 /* Clear saved state. */
807 input_clear(struct input_ctx
*ictx
)
809 *ictx
->interm_buf
= '\0';
810 ictx
->interm_len
= 0;
812 *ictx
->param_buf
= '\0';
815 ictx
->flags
&= ~INPUT_DISCARD
;
818 /* Output this character to the screen. */
820 input_print(struct input_ctx
*ictx
)
822 ictx
->cell
.data
= ictx
->ch
;
823 screen_write_cell(&ictx
->ctx
, &ictx
->cell
, NULL
);
828 /* Collect intermediate string. */
830 input_intermediate(struct input_ctx
*ictx
)
832 if (ictx
->interm_len
== (sizeof ictx
->interm_buf
) - 1)
833 ictx
->flags
|= INPUT_DISCARD
;
835 ictx
->interm_buf
[ictx
->interm_len
++] = ictx
->ch
;
836 ictx
->interm_buf
[ictx
->interm_len
] = '\0';
842 /* Collect parameter string. */
844 input_parameter(struct input_ctx
*ictx
)
846 if (ictx
->param_len
== (sizeof ictx
->param_buf
) - 1)
847 ictx
->flags
|= INPUT_DISCARD
;
849 ictx
->param_buf
[ictx
->param_len
++] = ictx
->ch
;
850 ictx
->param_buf
[ictx
->param_len
] = '\0';
856 /* Collect input string. */
858 input_input(struct input_ctx
*ictx
)
860 if (ictx
->input_len
== (sizeof ictx
->input_buf
) - 1)
861 ictx
->flags
|= INPUT_DISCARD
;
863 ictx
->input_buf
[ictx
->input_len
++] = ictx
->ch
;
864 ictx
->input_buf
[ictx
->input_len
] = '\0';
870 /* Execute C0 control sequence. */
872 input_c0_dispatch(struct input_ctx
*ictx
)
874 struct screen_write_ctx
*sctx
= &ictx
->ctx
;
875 struct window_pane
*wp
= ictx
->wp
;
876 struct screen
*s
= sctx
->s
;
878 log_debug("%s: '%c", __func__
, ictx
->ch
);
881 case '\000': /* NUL */
883 case '\007': /* BEL */
884 wp
->window
->flags
|= WINDOW_BELL
;
886 case '\010': /* BS */
887 screen_write_backspace(sctx
);
889 case '\011': /* HT */
890 /* Don't tab beyond the end of the line. */
891 if (s
->cx
>= screen_size_x(s
) - 1)
894 /* Find the next tab point, or use the last column if none. */
897 if (bit_test(s
->tabs
, s
->cx
))
899 } while (s
->cx
< screen_size_x(s
) - 1);
901 case '\012': /* LF */
902 case '\013': /* VT */
903 case '\014': /* FF */
904 screen_write_linefeed(sctx
, 0);
906 case '\015': /* CR */
907 screen_write_carriagereturn(sctx
);
909 case '\016': /* SO */
910 ictx
->cell
.attr
|= GRID_ATTR_CHARSET
;
912 case '\017': /* SI */
913 ictx
->cell
.attr
&= ~GRID_ATTR_CHARSET
;
916 log_debug("%s: unknown '%c'", __func__
, ictx
->ch
);
923 /* Execute escape sequence. */
925 input_esc_dispatch(struct input_ctx
*ictx
)
927 struct screen_write_ctx
*sctx
= &ictx
->ctx
;
928 struct screen
*s
= sctx
->s
;
929 struct input_table_entry
*entry
;
931 if (ictx
->flags
& INPUT_DISCARD
)
933 log_debug("%s: '%c', %s", __func__
, ictx
->ch
, ictx
->interm_buf
);
935 entry
= bsearch(ictx
, input_esc_table
, nitems(input_esc_table
),
936 sizeof input_esc_table
[0], input_table_compare
);
938 log_debug("%s: unknown '%c'", __func__
, ictx
->ch
);
942 switch (entry
->type
) {
944 memcpy(&ictx
->cell
, &grid_default_cell
, sizeof ictx
->cell
);
945 memcpy(&ictx
->old_cell
, &ictx
->cell
, sizeof ictx
->old_cell
);
949 screen_reset_tabs(sctx
->s
);
951 screen_write_scrollregion(sctx
, 0, screen_size_y(sctx
->s
) - 1);
953 screen_write_insertmode(sctx
, 0);
954 screen_write_kcursormode(sctx
, 0);
955 screen_write_kkeypadmode(sctx
, 0);
956 screen_write_mousemode_off(sctx
);
958 screen_write_clearscreen(sctx
);
959 screen_write_cursormove(sctx
, 0, 0);
962 screen_write_linefeed(sctx
, 0);
965 screen_write_carriagereturn(sctx
);
966 screen_write_linefeed(sctx
, 0);
969 if (s
->cx
< screen_size_x(s
))
970 bit_set(s
->tabs
, s
->cx
);
973 screen_write_reverseindex(sctx
);
975 case INPUT_ESC_DECKPAM
:
976 screen_write_kkeypadmode(sctx
, 1);
978 case INPUT_ESC_DECKPNM
:
979 screen_write_kkeypadmode(sctx
, 0);
981 case INPUT_ESC_DECSC
:
982 memcpy(&ictx
->old_cell
, &ictx
->cell
, sizeof ictx
->old_cell
);
983 ictx
->old_cx
= s
->cx
;
984 ictx
->old_cy
= s
->cy
;
986 case INPUT_ESC_DECRC
:
987 memcpy(&ictx
->cell
, &ictx
->old_cell
, sizeof ictx
->cell
);
988 screen_write_cursormove(sctx
, ictx
->old_cx
, ictx
->old_cy
);
990 case INPUT_ESC_DECALN
:
991 screen_write_alignmenttest(sctx
);
993 case INPUT_ESC_SCSON_G0
:
995 * Not really supported, but fake it up enough for those that
996 * use it to switch character sets (by redefining G0 to
997 * graphics set, rather than switching to G1).
999 ictx
->cell
.attr
&= ~GRID_ATTR_CHARSET
;
1001 case INPUT_ESC_SCSOFF_G0
:
1002 ictx
->cell
.attr
|= GRID_ATTR_CHARSET
;
1009 /* Execute control sequence. */
1011 input_csi_dispatch(struct input_ctx
*ictx
)
1013 struct screen_write_ctx
*sctx
= &ictx
->ctx
;
1014 struct window_pane
*wp
= ictx
->wp
;
1015 struct screen
*s
= sctx
->s
;
1016 struct input_table_entry
*entry
;
1019 if (ictx
->flags
& INPUT_DISCARD
)
1021 if (input_split(ictx
) != 0)
1023 log_debug("%s: '%c' \"%s\" \"%s\"",
1024 __func__
, ictx
->ch
, ictx
->interm_buf
, ictx
->param_buf
);
1026 entry
= bsearch(ictx
, input_csi_table
, nitems(input_csi_table
),
1027 sizeof input_csi_table
[0], input_table_compare
);
1028 if (entry
== NULL
) {
1029 log_debug("%s: unknown '%c'", __func__
, ictx
->ch
);
1033 switch (entry
->type
) {
1035 /* Find the previous tab point, n times. */
1036 n
= input_get(ictx
, 0, 1, 1);
1037 while (s
->cx
> 0 && n
-- > 0) {
1040 while (s
->cx
> 0 && !bit_test(s
->tabs
, s
->cx
));
1044 screen_write_cursorleft(sctx
, input_get(ictx
, 0, 1, 1));
1047 screen_write_cursordown(sctx
, input_get(ictx
, 0, 1, 1));
1050 screen_write_cursorright(sctx
, input_get(ictx
, 0, 1, 1));
1053 n
= input_get(ictx
, 0, 1, 1);
1054 m
= input_get(ictx
, 1, 1, 1);
1055 screen_write_cursormove(sctx
, m
- 1, n
- 1);
1058 screen_write_cursorup(sctx
, input_get(ictx
, 0, 1, 1));
1061 switch (input_get(ictx
, 0, 0, 0)) {
1063 input_reply(ictx
, "\033[?1;2c");
1066 log_debug("%s: unknown '%c'", __func__
, ictx
->ch
);
1071 screen_write_deletecharacter(sctx
, input_get(ictx
, 0, 1, 1));
1073 case INPUT_CSI_DECSTBM
:
1074 n
= input_get(ictx
, 0, 1, 1);
1075 m
= input_get(ictx
, 1, 1, screen_size_y(s
));
1076 screen_write_scrollregion(sctx
, n
- 1, m
- 1);
1079 screen_write_deleteline(sctx
, input_get(ictx
, 0, 1, 1));
1082 switch (input_get(ictx
, 0, 0, 0)) {
1084 input_reply(ictx
, "\033[0n");
1087 input_reply(ictx
, "\033[%u;%uR", s
->cy
+ 1, s
->cx
+ 1);
1090 log_debug("%s: unknown '%c'", __func__
, ictx
->ch
);
1095 switch (input_get(ictx
, 0, 0, 0)) {
1097 screen_write_clearendofscreen(sctx
);
1100 screen_write_clearstartofscreen(sctx
);
1103 screen_write_clearscreen(sctx
);
1106 log_debug("%s: unknown '%c'", __func__
, ictx
->ch
);
1111 switch (input_get(ictx
, 0, 0, 0)) {
1113 screen_write_clearendofline(sctx
);
1116 screen_write_clearstartofline(sctx
);
1119 screen_write_clearline(sctx
);
1122 log_debug("%s: unknown '%c'", __func__
, ictx
->ch
);
1127 n
= input_get(ictx
, 0, 1, 1);
1128 screen_write_cursormove(sctx
, n
- 1, s
->cy
);
1131 screen_write_insertcharacter(sctx
, input_get(ictx
, 0, 1, 1));
1134 screen_write_insertline(sctx
, input_get(ictx
, 0, 1, 1));
1137 switch (input_get(ictx
, 0, 0, -1)) {
1139 screen_write_insertmode(&ictx
->ctx
, 0);
1142 log_debug("%s: unknown '%c'", __func__
, ictx
->ch
);
1146 case INPUT_CSI_RM_PRIVATE
:
1147 switch (input_get(ictx
, 0, 0, -1)) {
1149 screen_write_kcursormode(&ictx
->ctx
, 0);
1151 case 3: /* DECCOLM */
1152 screen_write_cursormove(&ictx
->ctx
, 0, 0);
1153 screen_write_clearscreen(&ictx
->ctx
);
1156 screen_write_cursormode(&ictx
->ctx
, 0);
1162 screen_write_mousemode_off(&ictx
->ctx
);
1165 screen_write_utf8mousemode(&ictx
->ctx
, 0);
1168 window_pane_alternate_off(wp
, &ictx
->cell
);
1171 log_debug("%s: unknown '%c'", __func__
, ictx
->ch
);
1176 input_csi_dispatch_sgr(ictx
);
1179 switch (input_get(ictx
, 0, 0, -1)) {
1181 screen_write_insertmode(&ictx
->ctx
, 1);
1184 log_debug("%s: unknown '%c'", __func__
, ictx
->ch
);
1188 case INPUT_CSI_SM_PRIVATE
:
1189 switch (input_get(ictx
, 0, 0, -1)) {
1191 screen_write_kcursormode(&ictx
->ctx
, 1);
1193 case 3: /* DECCOLM */
1194 screen_write_cursormove(&ictx
->ctx
, 0, 0);
1195 screen_write_clearscreen(&ictx
->ctx
);
1198 screen_write_cursormode(&ictx
->ctx
, 1);
1201 screen_write_mousemode_on(
1202 &ictx
->ctx
, MODE_MOUSE_STANDARD
);
1205 screen_write_mousemode_on(
1206 &ictx
->ctx
, MODE_MOUSE_HIGHLIGHT
);
1209 screen_write_mousemode_on(
1210 &ictx
->ctx
, MODE_MOUSE_BUTTON
);
1213 screen_write_mousemode_on(&ictx
->ctx
, MODE_MOUSE_ANY
);
1216 screen_write_utf8mousemode(&ictx
->ctx
, 1);
1219 window_pane_alternate_on(wp
, &ictx
->cell
);
1222 log_debug("%s: unknown '%c'", __func__
, ictx
->ch
);
1227 switch (input_get(ictx
, 0, 0, 0)) {
1229 if (s
->cx
< screen_size_x(s
))
1230 bit_clear(s
->tabs
, s
->cx
);
1233 bit_nclear(s
->tabs
, 0, screen_size_x(s
) - 1);
1236 log_debug("%s: unknown '%c'", __func__
, ictx
->ch
);
1241 n
= input_get(ictx
, 0, 1, 1);
1242 screen_write_cursormove(sctx
, s
->cx
, n
- 1);
1249 /* Handle CSI SGR. */
1251 input_csi_dispatch_sgr(struct input_ctx
*ictx
)
1253 struct grid_cell
*gc
= &ictx
->cell
;
1258 if (ictx
->param_list_len
== 0) {
1260 memcpy(gc
, &grid_default_cell
, sizeof *gc
);
1261 gc
->attr
|= (attr
& GRID_ATTR_CHARSET
);
1265 for (i
= 0; i
< ictx
->param_list_len
; i
++) {
1266 n
= input_get(ictx
, i
, 0, 0);
1268 if (n
== 38 || n
== 48) {
1270 if (input_get(ictx
, i
, 0, -1) != 5)
1274 m
= input_get(ictx
, i
, 0, -1);
1277 gc
->flags
&= ~GRID_FLAG_FG256
;
1279 } else if (n
== 48) {
1280 gc
->flags
&= ~GRID_FLAG_BG256
;
1286 gc
->flags
|= GRID_FLAG_FG256
;
1288 } else if (n
== 48) {
1289 gc
->flags
|= GRID_FLAG_BG256
;
1300 memcpy(gc
, &grid_default_cell
, sizeof *gc
);
1301 gc
->attr
|= (attr
& GRID_ATTR_CHARSET
);
1304 gc
->attr
|= GRID_ATTR_BRIGHT
;
1307 gc
->attr
|= GRID_ATTR_DIM
;
1310 gc
->attr
|= GRID_ATTR_ITALICS
;
1313 gc
->attr
|= GRID_ATTR_UNDERSCORE
;
1316 gc
->attr
|= GRID_ATTR_BLINK
;
1319 gc
->attr
|= GRID_ATTR_REVERSE
;
1322 gc
->attr
|= GRID_ATTR_HIDDEN
;
1325 gc
->attr
&= ~(GRID_ATTR_BRIGHT
|GRID_ATTR_DIM
);
1328 gc
->attr
&= ~GRID_ATTR_ITALICS
;
1331 gc
->attr
&= ~GRID_ATTR_UNDERSCORE
;
1334 gc
->attr
&= ~GRID_ATTR_BLINK
;
1337 gc
->attr
&= ~GRID_ATTR_REVERSE
;
1347 gc
->flags
&= ~GRID_FLAG_FG256
;
1351 gc
->flags
&= ~GRID_FLAG_FG256
;
1362 gc
->flags
&= ~GRID_FLAG_BG256
;
1366 gc
->flags
&= ~GRID_FLAG_BG256
;
1377 gc
->flags
&= ~GRID_FLAG_FG256
;
1388 gc
->flags
&= ~GRID_FLAG_BG256
;
1395 /* DCS string started. */
1397 input_enter_dcs(struct input_ctx
*ictx
)
1399 log_debug("%s", __func__
);
1401 ictx
->input_len
= 0;
1404 /* DCS terminator (ST) received. */
1406 input_exit_dcs(unused
struct input_ctx
*ictx
)
1408 log_debug("%s", __func__
);
1411 /* OSC string started. */
1413 input_enter_osc(struct input_ctx
*ictx
)
1415 log_debug("%s", __func__
);
1417 ictx
->input_len
= 0;
1420 /* OSC terminator (ST) received. */
1422 input_exit_osc(struct input_ctx
*ictx
)
1424 if (ictx
->flags
& INPUT_DISCARD
)
1426 log_debug("%s: \"%s\"", __func__
, ictx
->input_buf
);
1428 if (ictx
->input_len
< 2 || ictx
->input_buf
[1] != ';')
1430 if (ictx
->input_buf
[0] != '0' && ictx
->input_buf
[0] != '2')
1433 screen_set_title(ictx
->ctx
.s
, ictx
->input_buf
+ 2);
1434 server_status_window(ictx
->wp
->window
);
1437 /* APC string started. */
1439 input_enter_apc(struct input_ctx
*ictx
)
1441 log_debug("%s", __func__
);
1443 ictx
->input_len
= 0;
1446 /* APC terminator (ST) received. */
1448 input_exit_apc(struct input_ctx
*ictx
)
1450 if (ictx
->flags
& INPUT_DISCARD
)
1452 log_debug("%s: \"%s\"", __func__
, ictx
->input_buf
);
1454 screen_set_title(ictx
->ctx
.s
, ictx
->input_buf
);
1455 server_status_window(ictx
->wp
->window
);
1458 /* Rename string started. */
1460 input_enter_rename(struct input_ctx
*ictx
)
1462 log_debug("%s", __func__
);
1464 ictx
->input_len
= 0;
1467 /* Rename terminator (ST) received. */
1469 input_exit_rename(struct input_ctx
*ictx
)
1471 if (ictx
->flags
& INPUT_DISCARD
)
1473 log_debug("%s: \"%s\"", __func__
, ictx
->input_buf
);
1475 xfree(ictx
->wp
->window
->name
);
1476 ictx
->wp
->window
->name
= xstrdup(ictx
->input_buf
);
1477 options_set_number(&ictx
->wp
->window
->options
, "automatic-rename", 0);
1479 server_status_window(ictx
->wp
->window
);
1482 /* Open UTF-8 character. */
1484 input_utf8_open(struct input_ctx
*ictx
)
1486 if (!options_get_number(&ictx
->wp
->window
->options
, "utf8")) {
1487 /* Print, and do not switch state. */
1491 log_debug("%s", __func__
);
1493 utf8_open(&ictx
->utf8data
, ictx
->ch
);
1497 /* Append to UTF-8 character. */
1499 input_utf8_add(struct input_ctx
*ictx
)
1501 log_debug("%s", __func__
);
1503 utf8_append(&ictx
->utf8data
, ictx
->ch
);
1507 /* Close UTF-8 string. */
1509 input_utf8_close(struct input_ctx
*ictx
)
1511 log_debug("%s", __func__
);
1513 utf8_append(&ictx
->utf8data
, ictx
->ch
);
1515 ictx
->cell
.flags
|= GRID_FLAG_UTF8
;
1516 screen_write_cell(&ictx
->ctx
, &ictx
->cell
, &ictx
->utf8data
);
1517 ictx
->cell
.flags
&= ~GRID_FLAG_UTF8
;