diff options
author | Nicholas Marriott <nicm@openbsd.org> | 2010-03-22 19:02:54 +0000 |
---|---|---|
committer | Nicholas Marriott <nicm@openbsd.org> | 2010-03-22 19:02:54 +0000 |
commit | 4baafd81262a2b1961e9b710b6f9c9cff9b2b828 (patch) | |
tree | 00bd93a3847fb471c468f59f08ba735c49034e8f /input.c | |
parent | 48dd72005e879336ea2439fb3422296be664cc76 (diff) |
New input parser based on http://vt100.net/emu/dec_ansi_parser.
Diffstat (limited to 'input.c')
-rw-r--r-- | input.c | 2281 |
1 files changed, 1136 insertions, 1145 deletions
@@ -18,1395 +18,1259 @@ #include <sys/types.h> -#include <stdint.h> #include <stdlib.h> #include <string.h> #include "tmux.h" -#define INPUT_C0CONTROL(ch) (ch <= 0x1f) -#define INPUT_INTERMEDIATE(ch) (ch == 0xa0 || (ch >= 0x20 && ch <= 0x2f)) -#define INPUT_PARAMETER(ch) (ch >= 0x30 && ch <= 0x3f) -#define INPUT_UPPERCASE(ch) (ch >= 0x40 && ch <= 0x5f) -#define INPUT_LOWERCASE(ch) (ch >= 0x60 && ch <= 0x7e) -#define INPUT_DELETE(ch) (ch == 0x7f) -#define INPUT_C1CONTROL(ch) (ch >= 0x80 && ch <= 0x9f) -#define INPUT_G1DISPLAYABLE(ch) (ch >= 0xa1 && ch <= 0xfe) -#define INPUT_SPECIAL(ch) (ch == 0xff) - -int input_get_argument(struct input_ctx *, u_int, uint16_t *, uint16_t); -void input_new_argument(struct input_ctx *); -int input_add_argument(struct input_ctx *, u_char); - -void input_start_string(struct input_ctx *, int); -void input_abort_string(struct input_ctx *); -int input_add_string(struct input_ctx *, u_char); -char *input_get_string(struct input_ctx *); - -void input_state(struct input_ctx *, void *); - -void input_state_first(u_char, struct input_ctx *); -void input_state_escape(u_char, struct input_ctx *); -void input_state_intermediate(u_char, struct input_ctx *); -void input_state_sequence_first(u_char, struct input_ctx *); -void input_state_sequence_next(u_char, struct input_ctx *); -void input_state_sequence_intermediate(u_char, struct input_ctx *); -void input_state_string_next(u_char, struct input_ctx *); -void input_state_string_escape(u_char, struct input_ctx *); -void input_state_utf8(u_char, struct input_ctx *); - -void input_handle_character(u_char, struct input_ctx *); -void input_handle_c0_control(u_char, struct input_ctx *); -void input_handle_c1_control(u_char, struct input_ctx *); -void input_handle_private_two(u_char, struct input_ctx *); -void input_handle_standard_two(u_char, struct input_ctx *); -void input_handle_sequence(u_char, struct input_ctx *); - -void input_handle_sequence_cuu(struct input_ctx *); -void input_handle_sequence_cud(struct input_ctx *); -void input_handle_sequence_cuf(struct input_ctx *); -void input_handle_sequence_cub(struct input_ctx *); -void input_handle_sequence_dch(struct input_ctx *); -void input_handle_sequence_cbt(struct input_ctx *); -void input_handle_sequence_da(struct input_ctx *); -void input_handle_sequence_dl(struct input_ctx *); -void input_handle_sequence_ich(struct input_ctx *); -void input_handle_sequence_il(struct input_ctx *); -void input_handle_sequence_vpa(struct input_ctx *); -void input_handle_sequence_hpa(struct input_ctx *); -void input_handle_sequence_cup(struct input_ctx *); -void input_handle_sequence_cup(struct input_ctx *); -void input_handle_sequence_tbc(struct input_ctx *); -void input_handle_sequence_ed(struct input_ctx *); -void input_handle_sequence_el(struct input_ctx *); -void input_handle_sequence_sm(struct input_ctx *); -void input_handle_sequence_rm(struct input_ctx *); -void input_handle_sequence_decstbm(struct input_ctx *); -void input_handle_sequence_sgr(struct input_ctx *); -void input_handle_sequence_dsr(struct input_ctx *); - -int input_sequence_cmp(const void *, const void *); - -struct input_sequence_entry { - u_char ch; - void (*fn)(struct input_ctx *); -}; -const struct input_sequence_entry input_sequence_table[] = { - { '@', input_handle_sequence_ich }, - { 'A', input_handle_sequence_cuu }, - { 'B', input_handle_sequence_cud }, - { 'C', input_handle_sequence_cuf }, - { 'D', input_handle_sequence_cub }, - { 'G', input_handle_sequence_hpa }, - { 'H', input_handle_sequence_cup }, - { 'J', input_handle_sequence_ed }, - { 'K', input_handle_sequence_el }, - { 'L', input_handle_sequence_il }, - { 'M', input_handle_sequence_dl }, - { 'P', input_handle_sequence_dch }, - { 'Z', input_handle_sequence_cbt }, - { 'c', input_handle_sequence_da }, - { 'd', input_handle_sequence_vpa }, - { 'f', input_handle_sequence_cup }, - { 'g', input_handle_sequence_tbc }, - { 'h', input_handle_sequence_sm }, - { 'l', input_handle_sequence_rm }, - { 'm', input_handle_sequence_sgr }, - { 'n', input_handle_sequence_dsr }, - { 'r', input_handle_sequence_decstbm }, +/* + * Based on the description by Paul Williams at: + * + * http://vt100.net/emu/dec_ansi_parser + * + * With the following changes: + * + * - 7-bit only. + * + * - Support for UTF-8. + * + * - OSC (but not APC) may be terminated by \007 as well as ST. + * + * - A state for APC similar to OSC. Some terminals appear to use this to set + * the title. + * + * - A state for the screen \033k...\033\\ sequence to rename a window. This is + * pretty stupid but not supporting it is more trouble than it is worth. + */ + +/* Helper functions. */ +int input_split(struct input_ctx *); +int input_get(struct input_ctx *, u_int, int, int); +void input_reply(struct input_ctx *, const char *, ...); + +/* Transition entry/exit handlers. */ +void input_clear(struct input_ctx *); +void input_enter_dcs(struct input_ctx *); +void input_exit_dcs(struct input_ctx *); +void input_enter_osc(struct input_ctx *); +void input_exit_osc(struct input_ctx *); +void input_enter_apc(struct input_ctx *); +void input_exit_apc(struct input_ctx *); +void input_enter_rename(struct input_ctx *); +void input_exit_rename(struct input_ctx *); + +/* Input state handlers. */ +int input_print(struct input_ctx *); +int input_intermediate(struct input_ctx *); +int input_parameter(struct input_ctx *); +int input_input(struct input_ctx *); +int input_c0_dispatch(struct input_ctx *); +int input_esc_dispatch(struct input_ctx *); +int input_csi_dispatch(struct input_ctx *); +void input_csi_dispatch_sgr(struct input_ctx *); +int input_utf8_open(struct input_ctx *); +int input_utf8_add(struct input_ctx *); +int input_utf8_close(struct input_ctx *); + +/* Command table comparison function. */ +int input_table_compare(const void *, const void *); + +/* Command table entry. */ +struct input_table_entry { + int ch; + const char *interm; + int type; }; -int -input_sequence_cmp(const void *a, const void *b) -{ - int ai = ((const struct input_sequence_entry *) a)->ch; - int bi = ((const struct input_sequence_entry *) b)->ch; +/* Escape commands. */ +enum input_esc_type { + INPUT_ESC_DECALN, + INPUT_ESC_DECKPAM, + INPUT_ESC_DECKPNM, + INPUT_ESC_DECRC, + INPUT_ESC_DECSC, + INPUT_ESC_HTS, + INPUT_ESC_IND, + INPUT_ESC_NEL, + INPUT_ESC_RI, + INPUT_ESC_RIS, + INPUT_ESC_SCSOFF_G0, + INPUT_ESC_SCSON_G0, +}; - return (ai - bi); -} +/* Escape command table. */ +const struct input_table_entry input_esc_table[] = { + { '0', "(", INPUT_ESC_SCSOFF_G0 }, + { '7', "", INPUT_ESC_DECSC }, + { '8', "", INPUT_ESC_DECRC }, + { '8', "#", INPUT_ESC_DECALN }, + { '=', "", INPUT_ESC_DECKPAM }, + { '>', "", INPUT_ESC_DECKPNM }, + { 'B', "(", INPUT_ESC_SCSON_G0 }, + { 'D', "", INPUT_ESC_IND }, + { 'E', "", INPUT_ESC_NEL }, + { 'H', "", INPUT_ESC_HTS }, + { 'M', "", INPUT_ESC_RI }, + { 'c', "", INPUT_ESC_RIS }, +}; -void -input_new_argument(struct input_ctx *ictx) -{ - struct input_arg *arg; +/* Control (CSI) commands. */ +enum input_csi_type { + INPUT_CSI_CBT, + INPUT_CSI_CUB, + INPUT_CSI_CUD, + INPUT_CSI_CUF, + INPUT_CSI_CUP, + INPUT_CSI_CUU, + INPUT_CSI_DA, + INPUT_CSI_DCH, + INPUT_CSI_DECSTBM, + INPUT_CSI_DL, + INPUT_CSI_DSR, + INPUT_CSI_ED, + INPUT_CSI_EL, + INPUT_CSI_HPA, + INPUT_CSI_ICH, + INPUT_CSI_IL, + INPUT_CSI_RM, + INPUT_CSI_RM_PRIVATE, + INPUT_CSI_SGR, + INPUT_CSI_SM, + INPUT_CSI_SM_PRIVATE, + INPUT_CSI_TBC, + INPUT_CSI_VPA, +}; - ARRAY_EXPAND(&ictx->args, 1); +/* Control (CSI) command table. */ +const struct input_table_entry input_csi_table[] = { + { '@', "", INPUT_CSI_ICH }, + { 'A', "", INPUT_CSI_CUU }, + { 'B', "", INPUT_CSI_CUD }, + { 'C', "", INPUT_CSI_CUF }, + { 'D', "", INPUT_CSI_CUB }, + { 'G', "", INPUT_CSI_HPA }, + { 'H', "", INPUT_CSI_CUP }, + { 'J', "", INPUT_CSI_ED }, + { 'K', "", INPUT_CSI_EL }, + { 'L', "", INPUT_CSI_IL }, + { 'M', "", INPUT_CSI_DL }, + { 'P', "", INPUT_CSI_DCH }, + { 'Z', "", INPUT_CSI_CBT }, + { 'c', "", INPUT_CSI_DA }, + { 'd', "", INPUT_CSI_VPA }, + { 'f', "", INPUT_CSI_CUP }, + { 'g', "", INPUT_CSI_TBC }, + { 'h', "", INPUT_CSI_SM }, + { 'h', "?", INPUT_CSI_SM_PRIVATE }, + { 'l', "", INPUT_CSI_RM }, + { 'l', "?", INPUT_CSI_RM_PRIVATE }, + { 'm', "", INPUT_CSI_SGR }, + { 'n', "", INPUT_CSI_DSR }, + { 'r', "", INPUT_CSI_DECSTBM }, +}; - arg = &ARRAY_LAST(&ictx->args); - arg->used = 0; -} +/* Input transition. */ +struct input_transition { + int first; + int last; -int -input_add_argument(struct input_ctx *ictx, u_char ch) -{ - struct input_arg *arg; - - if (ARRAY_LENGTH(&ictx->args) == 0) - return (0); + int (*handler)(struct input_ctx *); + const struct input_state *state; +}; - arg = &ARRAY_LAST(&ictx->args); - if (arg->used > (sizeof arg->data) - 1) - return (-1); - arg->data[arg->used++] = ch; +/* Input state. */ +struct input_state { + const char *name; + void (*enter)(struct input_ctx *); + void (*exit)(struct input_ctx *); + const struct input_transition *transitions; +}; - return (0); -} +/* State transitions available from all states. */ +#define INPUT_STATE_ANYWHERE \ + { 0x18, 0x18, input_c0_dispatch, &input_state_ground }, \ + { 0x1a, 0x1a, input_c0_dispatch, &input_state_ground }, \ + { 0x1b, 0x1b, NULL, &input_state_esc_enter } + +/* Forward declarations of state tables. */ +const struct input_transition input_state_ground_table[]; +const struct input_transition input_state_esc_enter_table[]; +const struct input_transition input_state_esc_intermediate_table[]; +const struct input_transition input_state_csi_enter_table[]; +const struct input_transition input_state_csi_parameter_table[]; +const struct input_transition input_state_csi_intermediate_table[]; +const struct input_transition input_state_csi_ignore_table[]; +const struct input_transition input_state_dcs_enter_table[]; +const struct input_transition input_state_dcs_parameter_table[]; +const struct input_transition input_state_dcs_intermediate_table[]; +const struct input_transition input_state_dcs_handler_table[]; +const struct input_transition input_state_dcs_ignore_table[]; +const struct input_transition input_state_osc_string_table[]; +const struct input_transition input_state_apc_string_table[]; +const struct input_transition input_state_rename_string_table[]; +const struct input_transition input_state_consume_st_table[]; +const struct input_transition input_state_utf8_three_table[]; +const struct input_transition input_state_utf8_two_table[]; +const struct input_transition input_state_utf8_one_table[]; + +/* ground state definition. */ +const struct input_state input_state_ground = { + "ground", + NULL, NULL, + input_state_ground_table +}; -int -input_get_argument(struct input_ctx *ictx, u_int i, uint16_t *n, uint16_t d) -{ - struct input_arg *arg; - const char *errstr; +/* esc_enter state definition. */ +const struct input_state input_state_esc_enter = { + "esc_enter", + input_clear, NULL, + input_state_esc_enter_table +}; - *n = d; - if (i >= ARRAY_LENGTH(&ictx->args)) - return (0); +/* esc_intermediate state definition. */ +const struct input_state input_state_esc_intermediate = { + "esc_intermediate", + NULL, NULL, + input_state_esc_intermediate_table +}; - arg = &ARRAY_ITEM(&ictx->args, i); - if (*arg->data == '\0') - return (0); +/* csi_enter state definition. */ +const struct input_state input_state_csi_enter = { + "csi_enter", + input_clear, NULL, + input_state_csi_enter_table +}; - *n = strtonum(arg->data, 0, UINT16_MAX, &errstr); - if (errstr != NULL) - return (-1); - return (0); -} +/* csi_parameter state definition. */ +const struct input_state input_state_csi_parameter = { + "csi_parameter", + NULL, NULL, + input_state_csi_parameter_table +}; -void -input_start_string(struct input_ctx *ictx, int type) -{ - ictx->string_type = type; - ictx->string_len = 0; -} +/* csi_intermediate state definition. */ +const struct input_state input_state_csi_intermediate = { + "csi_intermediate", + NULL, NULL, + input_state_csi_intermediate_table +}; -void -input_abort_string(struct input_ctx *ictx) -{ - if (ictx->string_buf != NULL) - xfree(ictx->string_buf); - ictx->string_buf = NULL; -} +/* csi_ignore state definition. */ +const struct input_state input_state_csi_ignore = { + "csi_ignore", + NULL, NULL, + input_state_csi_ignore_table +}; -int -input_add_string(struct input_ctx *ictx, u_char ch) -{ - ictx->string_buf = xrealloc(ictx->string_buf, 1, ictx->string_len + 1); - ictx->string_buf[ictx->string_len++] = ch; +/* dcs_enter state definition. */ +const struct input_state input_state_dcs_enter = { + "dcs_enter", + input_clear, NULL, + input_state_dcs_enter_table +}; - if (ictx->string_len >= MAXSTRINGLEN) { - input_abort_string(ictx); - return (1); - } +/* dcs_parameter state definition. */ +const struct input_state input_state_dcs_parameter = { + "dcs_parameter", + NULL, NULL, + input_state_dcs_parameter_table +}; - return (0); -} +/* dcs_intermediate state definition. */ +const struct input_state input_state_dcs_intermediate = { + "dcs_intermediate", + NULL, NULL, + input_state_dcs_intermediate_table +}; -char * -input_get_string(struct input_ctx *ictx) -{ - char *s; +/* dcs_handler state definition. */ +const struct input_state input_state_dcs_handler = { + "dcs_handler", + input_enter_dcs, input_exit_dcs, + input_state_dcs_handler_table +}; - if (ictx->string_buf == NULL || input_add_string(ictx, '\0') != 0) - return (xstrdup("")); +/* dcs_ignore state definition. */ +const struct input_state input_state_dcs_ignore = { + "dcs_ignore", + NULL, NULL, + input_state_dcs_ignore_table +}; - s = ictx->string_buf; - ictx->string_buf = NULL; - return (s); -} +/* osc_string state definition. */ +const struct input_state input_state_osc_string = { + "osc_string", + input_enter_osc, input_exit_osc, + input_state_osc_string_table +}; -void -input_state(struct input_ctx *ictx, void *state) -{ - ictx->state = state; -} +/* apc_string state definition. */ +const struct input_state input_state_apc_string = { + "apc_string", + input_enter_apc, input_exit_apc, + input_state_apc_string_table +}; -void -input_init(struct window_pane *wp) -{ - struct input_ctx *ictx = &wp->ictx; +/* rename_string state definition. */ +const struct input_state input_state_rename_string = { + "rename_string", + input_enter_rename, input_exit_rename, + input_state_rename_string_table +}; - ARRAY_INIT(&ictx->args); +/* consume_st state definition. */ +const struct input_state input_state_consume_st = { + "consume_st", + NULL, NULL, + input_state_consume_st_table +}; - ictx->string_len = 0; - ictx->string_buf = NULL; +/* utf8_three state definition. */ +const struct input_state input_state_utf8_three = { + "utf8_three", + NULL, NULL, + input_state_utf8_three_table +}; - memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell); +/* utf8_two state definition. */ +const struct input_state input_state_utf8_two = { + "utf8_two", + NULL, NULL, + input_state_utf8_two_table +}; - memcpy(&ictx->saved_cell, &grid_default_cell, sizeof ictx->saved_cell); - ictx->saved_cx = 0; - ictx->saved_cy = 0; +/* utf8_one state definition. */ +const struct input_state input_state_utf8_one = { + "utf8_one", + NULL, NULL, + input_state_utf8_one_table +}; - input_state(ictx, input_state_first); +/* ground state table. */ +const struct input_transition input_state_ground_table[] = { + INPUT_STATE_ANYWHERE, + + { 0x00, 0x17, input_c0_dispatch, NULL }, + { 0x19, 0x19, input_c0_dispatch, NULL }, + { 0x1c, 0x1f, input_c0_dispatch, NULL }, + { 0x20, 0x7e, input_print, NULL }, + { 0x7f, 0x7f, NULL, NULL }, + { 0x80, 0xc1, input_print, NULL }, + { 0xc2, 0xdf, input_utf8_open, &input_state_utf8_one }, + { 0xe0, 0xef, input_utf8_open, &input_state_utf8_two }, + { 0xf0, 0xf4, input_utf8_open, &input_state_utf8_three }, + { 0xf5, 0xff, input_print, NULL }, + + { -1, -1, NULL, NULL } +}; - ictx->was = 0; -} +/* esc_enter state table. */ +const struct input_transition input_state_esc_enter_table[] = { + INPUT_STATE_ANYWHERE, + + { 0x00, 0x17, input_c0_dispatch, NULL }, + { 0x19, 0x19, input_c0_dispatch, NULL }, + { 0x1c, 0x1f, input_c0_dispatch, NULL }, + { 0x20, 0x2f, input_intermediate, &input_state_esc_intermediate }, + { 0x30, 0x4f, input_esc_dispatch, &input_state_ground }, + { 0x50, 0x50, NULL, &input_state_dcs_enter }, + { 0x51, 0x57, input_esc_dispatch, &input_state_ground }, + { 0x58, 0x58, NULL, &input_state_consume_st }, + { 0x59, 0x59, input_esc_dispatch, &input_state_ground }, + { 0x5a, 0x5a, input_esc_dispatch, &input_state_ground }, + { 0x5b, 0x5b, NULL, &input_state_csi_enter }, + { 0x5c, 0x5c, input_esc_dispatch, &input_state_ground }, + { 0x5d, 0x5d, NULL, &input_state_osc_string }, + { 0x5e, 0x5e, NULL, &input_state_consume_st }, + { 0x5f, 0x5f, NULL, &input_state_apc_string }, + { 0x60, 0x6a, input_esc_dispatch, &input_state_ground }, + { 0x6b, 0x6b, NULL, &input_state_rename_string }, + { 0x6c, 0x7c, input_esc_dispatch, &input_state_ground }, + { 0x7f, 0xff, NULL, NULL }, + + { -1, -1, NULL, NULL } +}; -void -input_free(struct window_pane *wp) -{ - if (wp->ictx.string_buf != NULL) - xfree(wp->ictx.string_buf); +/* esc_interm state table. */ +const struct input_transition input_state_esc_intermediate_table[] = { + INPUT_STATE_ANYWHERE, - ARRAY_FREE(&wp->ictx.args); -} + { 0x00, 0x17, input_c0_dispatch, NULL }, + { 0x19, 0x19, input_c0_dispatch, NULL }, + { 0x1c, 0x1f, input_c0_dispatch, NULL }, + { 0x20, 0x2f, input_intermediate, NULL }, + { 0x30, 0x7e, input_esc_dispatch, &input_state_ground }, + { 0x7f, 0xff, NULL, NULL }, -void -input_parse(struct window_pane *wp) -{ - struct input_ctx *ictx = &wp->ictx; - u_char ch; + { -1, -1, NULL, NULL } +}; - if (EVBUFFER_LENGTH(wp->event->input) == ictx->was) - return; - wp->window->flags |= WINDOW_ACTIVITY; +/* csi_enter state table. */ +const struct input_transition input_state_csi_enter_table[] = { + INPUT_STATE_ANYWHERE, + + { 0x00, 0x17, input_c0_dispatch, NULL }, + { 0x19, 0x19, input_c0_dispatch, NULL }, + { 0x1c, 0x1f, input_c0_dispatch, NULL }, + { 0x20, 0x2f, input_intermediate, &input_state_csi_intermediate }, + { 0x30, 0x39, input_parameter, &input_state_csi_parameter }, + { 0x3a, 0x3a, NULL, &input_state_csi_ignore }, + { 0x3b, 0x3b, input_parameter, &input_state_csi_parameter }, + { 0x3c, 0x3f, input_intermediate, &input_state_csi_parameter }, + { 0x40, 0x7e, input_csi_dispatch, &input_state_ground }, + { 0x7f, 0xff, NULL, NULL }, + + { -1, -1, NULL, NULL } +}; - ictx->buf = EVBUFFER_DATA(wp->event->input); - ictx->len = EVBUFFER_LENGTH(wp->event->input); - ictx->off = 0; +/* csi_parameter state table. */ +const struct input_transition input_state_csi_parameter_table[] = { + INPUT_STATE_ANYWHERE, + + { 0x00, 0x17, input_c0_dispatch, NULL }, + { 0x19, 0x19, input_c0_dispatch, NULL }, + { 0x1c, 0x1f, input_c0_dispatch, NULL }, + { 0x20, 0x2f, input_intermediate, &input_state_csi_intermediate }, + { 0x30, 0x39, input_parameter, NULL }, + { 0x3a, 0x3a, NULL, &input_state_csi_ignore }, + { 0x3b, 0x3b, input_parameter, NULL }, + { 0x3c, 0x3f, NULL, &input_state_csi_ignore }, + { 0x40, 0x7e, input_csi_dispatch, &input_state_ground }, + { 0x7f, 0xff, NULL, NULL }, + + { -1, -1, NULL, NULL } +}; - ictx->wp = wp; +/* csi_intermediate state table. */ +const struct input_transition input_state_csi_intermediate_table[] = { + INPUT_STATE_ANYWHERE, - /* If there is a mode set, don't want to update the screen. */ - if (wp->mode == NULL) - screen_write_start(&ictx->ctx, wp, &wp->base); - else - screen_write_start(&ictx->ctx, NULL, &wp->base); + { 0x00, 0x17, input_c0_dispatch, NULL }, + { 0x19, 0x19, input_c0_dispatch, NULL }, + { 0x1c, 0x1f, input_c0_dispatch, NULL }, + { 0x20, 0x2f, input_intermediate, NULL }, + { 0x30, 0x3f, NULL, &input_state_csi_ignore }, + { 0x40, 0x7e, input_csi_dispatch, &input_state_ground }, + { 0x7f, 0xff, NULL, NULL }, - while (ictx->off < ictx->len) { - ch = ictx->buf[ictx->off++]; - ictx->state(ch, ictx); - } + { -1, -1, NULL, NULL } +}; - screen_write_stop(&ictx->ctx); +/* csi_ignore state table. */ +const struct input_transition input_state_csi_ignore_table[] = { + INPUT_STATE_ANYWHERE, - evbuffer_drain(wp->event->input, ictx->len); - ictx->was = EVBUFFER_LENGTH(wp->event->input); -} + { 0x00, 0x17, input_c0_dispatch, NULL }, + { 0x19, 0x19, input_c0_dispatch, NULL }, + { 0x1c, 0x1f, input_c0_dispatch, NULL }, + { 0x20, 0x3f, NULL, NULL }, + { 0x40, 0x7e, NULL, &input_state_ground }, + { 0x7f, 0xff, NULL, NULL }, -void -input_state_first(u_char ch, struct input_ctx *ictx) -{ - ictx->intermediate = '\0'; + { -1, -1, NULL, NULL } +}; - if (INPUT_C0CONTROL(ch)) { - if (ch == 0x1b) - input_state(ictx, input_state_escape); - else - input_handle_c0_control(ch, ictx); - return; - } +/* dcs_enter state table. */ +const struct input_transition input_state_dcs_enter_table[] = { + INPUT_STATE_ANYWHERE, + + { 0x00, 0x17, NULL, NULL }, + { 0x19, 0x19, NULL, NULL }, + { 0x1c, 0x1f, NULL, NULL }, + { 0x20, 0x2f, input_intermediate, &input_state_dcs_intermediate }, + { 0x30, 0x39, input_parameter, &input_state_dcs_parameter }, + { 0x3a, 0x3a, NULL, &input_state_dcs_ignore }, + { 0x3b, 0x3b, input_parameter, &input_state_dcs_parameter }, + { 0x3c, 0x3f, input_intermediate, &input_state_dcs_parameter }, + { 0x40, 0x7e, NULL, &input_state_dcs_handler }, + { 0x7f, 0xff, NULL, NULL }, + + { -1, -1, NULL, NULL } +}; -#if 0 - if (INPUT_C1CONTROL(ch)) { - ch -= 0x40; - if (ch == '[') - input_state(ictx, input_state_sequence_first); - else if (ch == ']') { - input_start_string(ictx, STRING_SYSTEM); - input_state(ictx, input_state_string_next); - } else if (ch == '_') { - input_start_string(ictx, STRING_APPLICATION); - input_state(ictx, input_state_string_next); - } else - input_handle_c1_control(ch, ictx); - return; - } -#endif +/* dcs_parameter state table. */ +const struct input_transition input_state_dcs_parameter_table[] = { + INPUT_STATE_ANYWHERE, + + { 0x00, 0x17, NULL, NULL }, + { 0x19, 0x19, NULL, NULL }, + { 0x1c, 0x1f, NULL, NULL }, + { 0x20, 0x2f, input_intermediate, &input_state_dcs_intermediate }, + { 0x30, 0x39, input_parameter, NULL }, + { 0x3a, 0x3a, NULL, &input_state_dcs_ignore }, + { 0x3b, 0x3b, input_parameter, NULL }, + { 0x3c, 0x3f, NULL, &input_state_dcs_ignore }, + { 0x40, 0x7e, NULL, &input_state_dcs_handler }, + { 0x7f, 0xff, NULL, NULL }, + + { -1, -1, NULL, NULL } +}; - if (INPUT_DELETE(ch)) - return; +/* dcs_interm state table. */ +const struct input_transition input_state_dcs_intermediate_table[] = { + INPUT_STATE_ANYWHERE, - input_handle_character(ch, ictx); -} + { 0x00, 0x17, NULL, NULL }, + { 0x19, 0x19, NULL, NULL }, + { 0x1c, 0x1f, NULL, NULL }, + { 0x20, 0x2f, input_intermediate, NULL }, + { 0x30, 0x3f, NULL, &input_state_dcs_ignore }, + { 0x40, 0x7e, NULL, &input_state_dcs_handler }, + { 0x7f, 0xff, NULL, NULL }, -void -input_state_escape(u_char ch, struct input_ctx *ictx) -{ - /* Treat C1 control and G1 displayable as 7-bit equivalent. */ - if (INPUT_C1CONTROL(ch) || INPUT_G1DISPLAYABLE(ch)) - ch &= 0x7f; + { -1, -1, NULL, NULL } +}; - if (INPUT_C0CONTROL(ch)) { - input_handle_c0_control(ch, ictx); - return; - } +/* dcs_handler state table. */ +const struct input_transition input_state_dcs_handler_table[] = { + INPUT_STATE_ANYWHERE, - if (INPUT_INTERMEDIATE(ch)) { - log_debug2(":: in1 %zu: %hhu (%c)", ictx->off, ch, ch); - ictx->intermediate = ch; - input_state(ictx, input_state_intermediate); - return; - } + { 0x00, 0x17, NULL, NULL }, + { 0x19, 0x19, input_input, NULL }, + { 0x1c, 0x1f, input_input, NULL }, + { 0x20, 0x7e, input_input, NULL }, + { 0x7f, 0xff, NULL, NULL }, - if (INPUT_PARAMETER(ch)) { - input_state(ictx, input_state_first); - input_handle_private_two(ch, ictx); - return; - } + { -1, -1, NULL, NULL } +}; - if (INPUT_UPPERCASE(ch)) { - if (ch == '[') - input_state(ictx, input_state_sequence_first); - else if (ch == ']') { - input_start_string(ictx, STRING_SYSTEM); - input_state(ictx, input_state_string_next); - } else if (ch == '_') { - input_start_string(ictx, STRING_APPLICATION); - input_state(ictx, input_state_string_next); - } else { - input_state(ictx, input_state_first); - input_handle_c1_control(ch, ictx); - } - return; - } +/* device_ignore state table. */ +const struct input_transition input_state_dcs_ignore_table[] = { + INPUT_STATE_ANYWHERE, - if (INPUT_LOWERCASE(ch)) { - input_state(ictx, input_state_first); - input_handle_standard_two(ch, ictx); - return; - } + { 0x00, 0x17, NULL, NULL }, + { 0x19, 0x19, NULL, NULL }, + { 0x1c, 0x1f, NULL, NULL }, + { 0x20, 0xff, NULL, NULL }, - input_state(ictx, input_state_first); -} + { -1, -1, NULL, NULL } +}; -void -input_state_intermediate(u_char ch, struct input_ctx *ictx) -{ - if (INPUT_INTERMEDIATE(ch)) { - /* Multiple intermediates currently ignored. */ - log_debug2(":: in2 %zu: %hhu (%c)", ictx->off, ch, ch); - return; - } +/* osc_string state table. */ +const struct input_transition input_state_osc_string_table[] = { + INPUT_STATE_ANYWHERE, - if (INPUT_PARAMETER(ch)) { - input_state(ictx, input_state_first); - input_handle_private_two(ch, ictx); - return; - } + { 0x00, 0x06, NULL, NULL }, + { 0x07, 0x07, NULL, &input_state_ground }, + { 0x08, 0x17, NULL, NULL }, + { 0x19, 0x19, NULL, NULL }, + { 0x1c, 0x1f, NULL, NULL }, + { 0x20, 0xff, input_input, NULL }, - if (INPUT_UPPERCASE(ch) || INPUT_LOWERCASE(ch)) { - input_state(ictx, input_state_first); - input_handle_standard_two(ch, ictx); - return; - } + { -1, -1, NULL, NULL } +}; - input_state(ictx, input_state_first); -} +/* apc_string state table. */ +const struct input_transition input_state_apc_string_table[] = { + INPUT_STATE_ANYWHERE, -void -input_state_sequence_first(u_char ch, struct input_ctx *ictx) -{ - ictx->private = '\0'; - ARRAY_CLEAR(&ictx->args); - - /* Most C0 control are accepted within CSI. */ - if (INPUT_C0CONTROL(ch)) { - if (ch == 0x1b) { /* ESC */ - /* Abort sequence and begin with new. */ - input_state(ictx, input_state_escape); - return; - } else if (ch == 0x18 || ch == 0x1a) { /* CAN and SUB */ - /* Abort sequence. */ - input_state(ictx, input_state_first); - return; - } + { 0x00, 0x17, NULL, NULL }, + { 0x19, 0x19, NULL, NULL }, + { 0x1c, 0x1f, NULL, NULL }, + { 0x20, 0xff, input_input, NULL }, - /* Handle C0 immediately. */ - input_handle_c0_control(ch, ictx); + { -1, -1, NULL, NULL } +}; - /* - * Just come back to this state, in case the next character - * is the start of a private sequence. - */ - return; - } +/* rename_string state table. */ +const struct input_transition input_state_rename_string_table[] = { + INPUT_STATE_ANYWHERE, - input_state(ictx, input_state_sequence_next); + { 0x00, 0x17, NULL, NULL }, + { 0x19, 0x19, NULL, NULL }, + { 0x1c, 0x1f, NULL, NULL }, + { 0x20, 0xff, input_input, NULL }, - /* Private sequence: always the first character. */ - if (ch >= 0x3c && ch <= 0x3f) { - ictx->private = ch; - return; - } + { -1, -1, NULL, NULL } +}; - /* Pass character on directly. */ - input_state_sequence_next(ch, ictx); -} +/* consume_st state table. */ +const struct input_transition input_state_consume_st_table[] = { + INPUT_STATE_ANYWHERE, -void -input_state_sequence_next(u_char ch, struct input_ctx *ictx) -{ - if (INPUT_INTERMEDIATE(ch)) { - if (input_add_argument(ictx, '\0') != 0) - input_state(ictx, input_state_first); - else { - log_debug2(":: si1 %zu: %hhu (%c)", ictx->off, ch, ch); - input_state(ictx, input_state_sequence_intermediate); - } - return; - } + { 0x00, 0x17, NULL, NULL }, + { 0x19, 0x19, NULL, NULL }, + { 0x1c, 0x1f, NULL, NULL }, + { 0x20, 0xff, NULL, NULL }, - if (INPUT_PARAMETER(ch)) { - if (ARRAY_EMPTY(&ictx->args)) - input_new_argument(ictx); - - if (ch == ';') { - if (input_add_argument(ictx, '\0') != 0) - input_state(ictx, input_state_first); - else - input_new_argument(ictx); - } else if (input_add_argument(ictx, ch) != 0) - input_state(ictx, input_state_first); - return; - } + { -1, -1, NULL, NULL } +}; - if (INPUT_UPPERCASE(ch) || INPUT_LOWERCASE(ch)) { - if (input_add_argument(ictx, '\0') != 0) - input_state(ictx, input_state_first); - else { - input_state(ictx, input_state_first); - input_handle_sequence(ch, ictx); - } - return; - } +/* utf8_three state table. */ +const struct input_transition input_state_utf8_three_table[] = { + /* No INPUT_STATE_ANYWHERE */ - /* Most C0 control are accepted within CSI. */ - if (INPUT_C0CONTROL(ch)) { - if (ch == 0x1b) { /* ESC */ - /* Abort sequence and begin with new. */ - input_state(ictx, input_state_escape); - return; - } else if (ch == 0x18 || ch == 0x1a) { /* CAN and SUB */ - /* Abort sequence. */ - input_state(ictx, input_state_first); - return; - } + { 0x00, 0x7f, NULL, &input_state_ground }, + { 0x80, 0xbf, input_utf8_add, &input_state_utf8_two }, + { 0xc0, 0xff, NULL, &input_state_ground }, - /* Handle C0 immediately. */ - input_handle_c0_control(ch, ictx); + { -1, -1, NULL, NULL } +}; - return; - } +/* utf8_two state table. */ +const struct input_transition input_state_utf8_two_table[] = { + /* No INPUT_STATE_ANYWHERE */ - input_state(ictx, input_state_first); -} + { 0x00, 0x7f, NULL, &input_state_ground }, + { 0x80, 0xbf, input_utf8_add, &input_state_utf8_one }, + { 0xc0, 0xff, NULL, &input_state_ground }, -void -input_state_sequence_intermediate(u_char ch, struct input_ctx *ictx) -{ - if (INPUT_INTERMEDIATE(ch)) { - log_debug2(":: si2 %zu: %hhu (%c)", ictx->off, ch, ch); - return; - } - - if (INPUT_UPPERCASE(ch) || INPUT_LOWERCASE(ch)) { - input_state(ictx, input_state_first); - input_handle_sequence(ch, ictx); - return; - } + { -1, -1, NULL, NULL } +}; - input_state(ictx, input_state_first); -} +/* utf8_one state table. */ +const struct input_transition input_state_utf8_one_table[] = { + /* No INPUT_STATE_ANYWHERE */ -void -input_state_string_next(u_char ch, struct input_ctx *ictx) -{ - if (ch == 0x1b) { - input_state(ictx, input_state_string_escape); - return; - } - if (ch == 0x07) { - input_state_string_escape(ch, ictx); - return; - } + { 0x00, 0x7f, NULL, &input_state_ground }, + { 0x80, 0xbf, input_utf8_close, &input_state_ground }, + { 0xc0, 0xff, NULL, &input_state_ground }, - if (ch >= 0x20) { - if (input_add_string(ictx, ch) != 0) - input_state(ictx, input_state_first); - return; - } -} + { -1, -1, NULL, NULL } +}; -void -input_state_string_escape(u_char ch, struct input_ctx *ictx) +/* Input table compare. */ +int +input_table_compare(const void *key, const void *value) { - char *s; - - if (ch == '\007' || ch == '\\') { - input_state(ictx, input_state_first); - switch (ictx->string_type) { - case STRING_SYSTEM: - if (ch != '\007') - return; - s = input_get_string(ictx); - if ((s[0] != '0' && s[0] != '2') || s[1] != ';') { - xfree(s); - return; - } - screen_set_title(ictx->ctx.s, s + 2); - server_status_window(ictx->wp->window); - xfree(s); - break; - case STRING_APPLICATION: - if (ch != '\\') - return; - s = input_get_string(ictx); - screen_set_title(ictx->ctx.s, s); - server_status_window(ictx->wp->window); - xfree(s); - break; - case STRING_NAME: - if (ch != '\\') - return; - xfree(ictx->wp->window->name); - ictx->wp->window->name = input_get_string(ictx); - server_status_window(ictx->wp->window); - break; - } - return; - } + const struct input_ctx *ictx = key; + const struct input_table_entry *entry = value; - input_state(ictx, input_state_string_next); - input_state_string_next(ch, ictx); + if (ictx->ch != entry->ch) + return (ictx->ch - entry->ch); + return (strcmp(ictx->interm_buf, entry->interm)); } +/* Initialise input parser. */ void -input_state_utf8(u_char ch, struct input_ctx *ictx) +input_init(struct window_pane *wp) { - log_debug2("-- utf8 next: %zu: %hhu (%c)", ictx->off, ch, ch); + struct input_ctx *ictx = &wp->ictx; - if (utf8_append(&ictx->utf8data, ch)) - return; /* more to come */ - input_state(ictx, input_state_first); + memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell); - ictx->cell.flags |= GRID_FLAG_UTF8; - screen_write_cell(&ictx->ctx, &ictx->cell, &ictx->utf8data); - ictx->cell.flags &= ~GRID_FLAG_UTF8; -} + memcpy(&ictx->old_cell, &grid_default_cell, sizeof ictx->old_cell); + ictx->old_cx = 0; + ictx->old_cy = 0; -void -input_handle_character(u_char ch, struct input_ctx *ictx) -{ - struct window_pane *wp = ictx->wp; + *ictx->interm_buf = '\0'; + ictx->interm_len = 0; - if (ch > 0x7f && options_get_number(&wp->window->options, "utf8")) { - if (utf8_open(&ictx->utf8data, ch)) { - log_debug2("-- utf8 size %zu: %zu: %hhu (%c)", - ictx->utf8data.size, ictx->off, ch, |