[BACK]Return to input.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / tmux

Annotation of src/usr.bin/tmux/input.c, Revision 1.37

1.37    ! nicm        1: /* $OpenBSD: input.c,v 1.36 2011/03/03 08:53:14 nicm Exp $ */
1.1       nicm        2:
                      3: /*
                      4:  * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
                      5:  *
                      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.
                      9:  *
                     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.
                     17:  */
                     18:
                     19: #include <sys/types.h>
                     20:
                     21: #include <stdlib.h>
                     22: #include <string.h>
                     23:
                     24: #include "tmux.h"
                     25:
1.28      nicm       26: /*
                     27:  * Based on the description by Paul Williams at:
                     28:  *
                     29:  * http://vt100.net/emu/dec_ansi_parser
                     30:  *
                     31:  * With the following changes:
                     32:  *
                     33:  * - 7-bit only.
                     34:  *
                     35:  * - Support for UTF-8.
                     36:  *
                     37:  * - OSC (but not APC) may be terminated by \007 as well as ST.
                     38:  *
                     39:  * - A state for APC similar to OSC. Some terminals appear to use this to set
                     40:  *   the title.
                     41:  *
                     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.
1.37    ! nicm       44:  *
        !            45:  * - Special handling for ESC inside a DCS to allow arbitrary byte sequences to
        !            46:  *   be passed to the underlying teminal(s).
1.28      nicm       47:  */
                     48:
                     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 *, ...);
                     53:
                     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 *);
                     62:
                     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 *);
1.37    ! nicm       72: int    input_dcs_dispatch(struct input_ctx *);
1.28      nicm       73: int    input_utf8_open(struct input_ctx *);
                     74: int    input_utf8_add(struct input_ctx *);
                     75: int    input_utf8_close(struct input_ctx *);
                     76:
                     77: /* Command table comparison function. */
                     78: int    input_table_compare(const void *, const void *);
                     79:
                     80: /* Command table entry. */
                     81: struct input_table_entry {
                     82:        int             ch;
                     83:        const char     *interm;
                     84:        int             type;
1.1       nicm       85: };
                     86:
1.28      nicm       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,
                    101: };
1.1       nicm      102:
1.28      nicm      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 },
                    117: };
1.1       nicm      118:
1.28      nicm      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,
                    144: };
1.1       nicm      145:
1.28      nicm      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 },
                    172: };
1.1       nicm      173:
1.28      nicm      174: /* Input transition. */
                    175: struct input_transition {
                    176:        int                             first;
                    177:        int                             last;
1.1       nicm      178:
1.28      nicm      179:        int                             (*handler)(struct input_ctx *);
                    180:        const struct input_state       *state;
                    181: };
1.1       nicm      182:
1.28      nicm      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;
                    189: };
1.1       nicm      190:
1.28      nicm      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 }
                    196:
                    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[];
1.37    ! nicm      209: const struct input_transition input_state_dcs_escape_table[];
1.28      nicm      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[];
                    218:
                    219: /* ground state definition. */
                    220: const struct input_state input_state_ground = {
                    221:        "ground",
                    222:        NULL, NULL,
                    223:        input_state_ground_table
                    224: };
1.1       nicm      225:
1.28      nicm      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
                    231: };
1.1       nicm      232:
1.28      nicm      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
                    238: };
1.1       nicm      239:
1.28      nicm      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
                    245: };
1.1       nicm      246:
1.28      nicm      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
                    252: };
1.1       nicm      253:
1.28      nicm      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
                    259: };
1.1       nicm      260:
1.28      nicm      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
                    266: };
1.1       nicm      267:
1.28      nicm      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
                    273: };
1.1       nicm      274:
1.28      nicm      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
                    280: };
1.1       nicm      281:
1.28      nicm      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
                    287: };
1.1       nicm      288:
1.28      nicm      289: /* dcs_handler state definition. */
                    290: const struct input_state input_state_dcs_handler = {
                    291:        "dcs_handler",
1.37    ! nicm      292:        NULL, NULL,
1.28      nicm      293:        input_state_dcs_handler_table
                    294: };
1.1       nicm      295:
1.37    ! nicm      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
        !           301: };
        !           302:
1.28      nicm      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
                    308: };
1.1       nicm      309:
1.28      nicm      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
                    315: };
1.1       nicm      316:
1.28      nicm      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
                    322: };
1.1       nicm      323:
1.28      nicm      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
                    329: };
1.1       nicm      330:
1.28      nicm      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
                    336: };
1.1       nicm      337:
1.28      nicm      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
                    343: };
1.1       nicm      344:
1.28      nicm      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
                    350: };
1.1       nicm      351:
1.28      nicm      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
                    357: };
1.1       nicm      358:
1.28      nicm      359: /* ground state table. */
                    360: const struct input_transition input_state_ground_table[] = {
                    361:        INPUT_STATE_ANYWHERE,
                    362:
                    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 },
1.1       nicm      373:
1.28      nicm      374:        { -1, -1, NULL, NULL }
                    375: };
1.13      nicm      376:
1.28      nicm      377: /* esc_enter state table. */
                    378: const struct input_transition input_state_esc_enter_table[] = {
                    379:        INPUT_STATE_ANYWHERE,
                    380:
                    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 },
1.29      nicm      398:        { 0x6c, 0x7e, input_esc_dispatch, &input_state_ground },
1.28      nicm      399:        { 0x7f, 0xff, NULL,               NULL },
1.1       nicm      400:
1.28      nicm      401:        { -1, -1, NULL, NULL }
                    402: };
1.1       nicm      403:
1.28      nicm      404: /* esc_interm state table. */
                    405: const struct input_transition input_state_esc_intermediate_table[] = {
                    406:        INPUT_STATE_ANYWHERE,
                    407:
                    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 },
1.1       nicm      414:
1.28      nicm      415:        { -1, -1, NULL, NULL }
                    416: };
1.1       nicm      417:
1.28      nicm      418: /* csi_enter state table. */
                    419: const struct input_transition input_state_csi_enter_table[] = {
                    420:        INPUT_STATE_ANYWHERE,
                    421:
                    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 },
1.1       nicm      432:
1.28      nicm      433:        { -1, -1, NULL, NULL }
                    434: };
1.1       nicm      435:
1.28      nicm      436: /* csi_parameter state table. */
                    437: const struct input_transition input_state_csi_parameter_table[] = {
                    438:        INPUT_STATE_ANYWHERE,
                    439:
                    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 },
1.1       nicm      450:
1.28      nicm      451:        { -1, -1, NULL, NULL }
                    452: };
1.1       nicm      453:
1.28      nicm      454: /* csi_intermediate state table. */
                    455: const struct input_transition input_state_csi_intermediate_table[] = {
                    456:        INPUT_STATE_ANYWHERE,
                    457:
                    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 },
1.1       nicm      465:
1.28      nicm      466:        { -1, -1, NULL, NULL }
                    467: };
1.1       nicm      468:
1.28      nicm      469: /* csi_ignore state table. */
                    470: const struct input_transition input_state_csi_ignore_table[] = {
                    471:        INPUT_STATE_ANYWHERE,
                    472:
                    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 },
1.1       nicm      479:
1.28      nicm      480:        { -1, -1, NULL, NULL }
                    481: };
1.1       nicm      482:
1.28      nicm      483: /* dcs_enter state table. */
                    484: const struct input_transition input_state_dcs_enter_table[] = {
                    485:        INPUT_STATE_ANYWHERE,
                    486:
                    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 },
1.37    ! nicm      495:        { 0x40, 0x7e, input_input,        &input_state_dcs_handler },
1.28      nicm      496:        { 0x7f, 0xff, NULL,               NULL },
1.1       nicm      497:
1.28      nicm      498:        { -1, -1, NULL, NULL }
                    499: };
1.1       nicm      500:
1.28      nicm      501: /* dcs_parameter state table. */
                    502: const struct input_transition input_state_dcs_parameter_table[] = {
                    503:        INPUT_STATE_ANYWHERE,
                    504:
                    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 },
1.37    ! nicm      513:        { 0x40, 0x7e, input_input,        &input_state_dcs_handler },
1.28      nicm      514:        { 0x7f, 0xff, NULL,               NULL },
1.1       nicm      515:
1.28      nicm      516:        { -1, -1, NULL, NULL }
                    517: };
1.1       nicm      518:
1.28      nicm      519: /* dcs_interm state table. */
                    520: const struct input_transition input_state_dcs_intermediate_table[] = {
                    521:        INPUT_STATE_ANYWHERE,
                    522:
                    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 },
1.37    ! nicm      528:        { 0x40, 0x7e, input_input,        &input_state_dcs_handler },
1.28      nicm      529:        { 0x7f, 0xff, NULL,               NULL },
1.1       nicm      530:
1.28      nicm      531:        { -1, -1, NULL, NULL }
                    532: };
1.1       nicm      533:
1.28      nicm      534: /* dcs_handler state table. */
                    535: const struct input_transition input_state_dcs_handler_table[] = {
1.37    ! nicm      536:        /* No INPUT_STATE_ANYWHERE */
        !           537:
        !           538:        { 0x00, 0x1a, input_input,  NULL },
        !           539:        { 0x1b, 0x1b, NULL,         &input_state_dcs_escape },
        !           540:        { 0x1c, 0xff, input_input,  NULL },
        !           541:
        !           542:        { -1, -1, NULL, NULL }
        !           543: };
        !           544:
        !           545: /* dcs_escape state table. */
        !           546: const struct input_transition input_state_dcs_escape_table[] = {
        !           547:        /* No INPUT_STATE_ANYWHERE */
1.28      nicm      548:
1.37    ! nicm      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 },
1.1       nicm      552:
1.28      nicm      553:        { -1, -1, NULL, NULL }
                    554: };
1.1       nicm      555:
1.28      nicm      556: /* device_ignore state table. */
                    557: const struct input_transition input_state_dcs_ignore_table[] = {
                    558:        INPUT_STATE_ANYWHERE,
                    559:
                    560:        { 0x00, 0x17, NULL,         NULL },
                    561:        { 0x19, 0x19, NULL,         NULL },
                    562:        { 0x1c, 0x1f, NULL,         NULL },
                    563:        { 0x20, 0xff, NULL,         NULL },
1.1       nicm      564:
1.28      nicm      565:        { -1, -1, NULL, NULL }
                    566: };
1.1       nicm      567:
1.28      nicm      568: /* osc_string state table. */
                    569: const struct input_transition input_state_osc_string_table[] = {
                    570:        INPUT_STATE_ANYWHERE,
                    571:
                    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 },
1.1       nicm      578:
1.28      nicm      579:        { -1, -1, NULL, NULL }
                    580: };
1.1       nicm      581:
1.28      nicm      582: /* apc_string state table. */
                    583: const struct input_transition input_state_apc_string_table[] = {
                    584:        INPUT_STATE_ANYWHERE,
                    585:
                    586:        { 0x00, 0x17, NULL,         NULL },
                    587:        { 0x19, 0x19, NULL,         NULL },
                    588:        { 0x1c, 0x1f, NULL,         NULL },
                    589:        { 0x20, 0xff, input_input,  NULL },
1.1       nicm      590:
1.28      nicm      591:        { -1, -1, NULL, NULL }
                    592: };
1.1       nicm      593:
1.28      nicm      594: /* rename_string state table. */
                    595: const struct input_transition input_state_rename_string_table[] = {
                    596:        INPUT_STATE_ANYWHERE,
                    597:
                    598:        { 0x00, 0x17, NULL,         NULL },
                    599:        { 0x19, 0x19, NULL,         NULL },
                    600:        { 0x1c, 0x1f, NULL,         NULL },
                    601:        { 0x20, 0xff, input_input,  NULL },
1.1       nicm      602:
1.28      nicm      603:        { -1, -1, NULL, NULL }
                    604: };
1.1       nicm      605:
1.28      nicm      606: /* consume_st state table. */
                    607: const struct input_transition input_state_consume_st_table[] = {
                    608:        INPUT_STATE_ANYWHERE,
                    609:
                    610:        { 0x00, 0x17, NULL,         NULL },
                    611:        { 0x19, 0x19, NULL,         NULL },
                    612:        { 0x1c, 0x1f, NULL,         NULL },
                    613:        { 0x20, 0xff, NULL,         NULL },
1.6       nicm      614:
1.28      nicm      615:        { -1, -1, NULL, NULL }
                    616: };
1.6       nicm      617:
1.28      nicm      618: /* utf8_three state table. */
                    619: const struct input_transition input_state_utf8_three_table[] = {
                    620:        /* No INPUT_STATE_ANYWHERE */
                    621:
                    622:        { 0x00, 0x7f, NULL,             &input_state_ground },
                    623:        { 0x80, 0xbf, input_utf8_add,   &input_state_utf8_two },
                    624:        { 0xc0, 0xff, NULL,             &input_state_ground },
1.4       nicm      625:
1.28      nicm      626:        { -1, -1, NULL, NULL }
                    627: };
1.1       nicm      628:
1.28      nicm      629: /* utf8_two state table. */
                    630: const struct input_transition input_state_utf8_two_table[] = {
                    631:        /* No INPUT_STATE_ANYWHERE */
                    632:
                    633:        { 0x00, 0x7f, NULL,           &input_state_ground },
                    634:        { 0x80, 0xbf, input_utf8_add, &input_state_utf8_one },
                    635:        { 0xc0, 0xff, NULL,           &input_state_ground },
1.1       nicm      636:
1.28      nicm      637:        { -1, -1, NULL, NULL }
                    638: };
1.1       nicm      639:
1.28      nicm      640: /* utf8_one state table. */
                    641: const struct input_transition input_state_utf8_one_table[] = {
                    642:        /* No INPUT_STATE_ANYWHERE */
                    643:
                    644:        { 0x00, 0x7f, NULL,             &input_state_ground },
                    645:        { 0x80, 0xbf, input_utf8_close, &input_state_ground },
                    646:        { 0xc0, 0xff, NULL,             &input_state_ground },
1.1       nicm      647:
1.28      nicm      648:        { -1, -1, NULL, NULL }
                    649: };
1.1       nicm      650:
1.28      nicm      651: /* Input table compare. */
                    652: int
                    653: input_table_compare(const void *key, const void *value)
1.1       nicm      654: {
1.28      nicm      655:        const struct input_ctx          *ictx = key;
                    656:        const struct input_table_entry  *entry = value;
1.1       nicm      657:
1.28      nicm      658:        if (ictx->ch != entry->ch)
                    659:                return (ictx->ch - entry->ch);
                    660:        return (strcmp(ictx->interm_buf, entry->interm));
1.1       nicm      661: }
                    662:
1.28      nicm      663: /* Initialise input parser. */
1.1       nicm      664: void
1.28      nicm      665: input_init(struct window_pane *wp)
1.1       nicm      666: {
1.28      nicm      667:        struct input_ctx        *ictx = &wp->ictx;
1.1       nicm      668:
1.28      nicm      669:        memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell);
1.1       nicm      670:
1.28      nicm      671:        memcpy(&ictx->old_cell, &grid_default_cell, sizeof ictx->old_cell);
                    672:        ictx->old_cx = 0;
                    673:        ictx->old_cy = 0;
1.1       nicm      674:
1.28      nicm      675:        *ictx->interm_buf = '\0';
                    676:        ictx->interm_len = 0;
1.1       nicm      677:
1.28      nicm      678:        *ictx->param_buf = '\0';
                    679:        ictx->param_len = 0;
1.1       nicm      680:
1.28      nicm      681:        ictx->state = &input_state_ground;
                    682:        ictx->flags = 0;
1.1       nicm      683: }
                    684:
1.28      nicm      685: /* Destroy input parser. */
1.1       nicm      686: void
1.28      nicm      687: input_free(unused struct window_pane *wp)
1.1       nicm      688: {
                    689: }
                    690:
1.28      nicm      691: /* Parse input. */
1.1       nicm      692: void
1.28      nicm      693: input_parse(struct window_pane *wp)
1.1       nicm      694: {
1.28      nicm      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;
1.1       nicm      700:
1.28      nicm      701:        if (EVBUFFER_LENGTH(evb) == 0)
                    702:                return;
1.30      nicm      703:
1.28      nicm      704:        wp->window->flags |= WINDOW_ACTIVITY;
1.30      nicm      705:        wp->window->flags &= ~WINDOW_SILENCE;
1.1       nicm      706:
1.28      nicm      707:        /*
                    708:         * Open the screen. Use NULL wp if there is a mode set as don't want to
                    709:         * update the tty.
                    710:         */
                    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;
1.7       nicm      716:
1.28      nicm      717:        buf = EVBUFFER_DATA(evb);
                    718:        len = EVBUFFER_LENGTH(evb);
                    719:        off = 0;
                    720:
                    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);
                    725:
                    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)
1.7       nicm      730:                                break;
1.28      nicm      731:                        itr++;
1.1       nicm      732:                }
1.28      nicm      733:                if (itr->first == -1 || itr->last == -1) {
                    734:                        /* No transition? Eh? */
                    735:                        fatalx("No transition from state!");
1.3       nicm      736:                }
1.1       nicm      737:
                    738:                /*
1.28      nicm      739:                 * Execute the handler, if any. Don't switch state if it
                    740:                 * returns non-zero.
1.1       nicm      741:                 */
1.31      nicm      742:                if (itr->handler != NULL && itr->handler(ictx) != 0)
1.28      nicm      743:                        continue;
                    744:
                    745:                /* And switch state, if necessary. */
1.31      nicm      746:                if (itr->state != NULL) {
1.28      nicm      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);
1.1       nicm      752:                }
                    753:        }
                    754:
1.28      nicm      755:        /* Close the screen. */
                    756:        screen_write_stop(&ictx->ctx);
1.1       nicm      757:
1.28      nicm      758:        evbuffer_drain(evb, len);
1.1       nicm      759: }
                    760:
1.28      nicm      761: /* Split the parameter list (if any). */
                    762: int
                    763: input_split(struct input_ctx *ictx)
1.1       nicm      764:
                    765: {
1.28      nicm      766:        const char      *errstr;
                    767:        char            *ptr, *out;
                    768:        int              n;
1.1       nicm      769:
1.28      nicm      770:        ictx->param_list_len = 0;
                    771:        if (ictx->param_len == 0)
                    772:                return (0);
1.1       nicm      773:
1.28      nicm      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);
                    782:                }
1.1       nicm      783:
1.28      nicm      784:                ictx->param_list[ictx->param_list_len++] = n;
                    785:                if (ictx->param_list_len == nitems(ictx->param_list))
                    786:                        return (-1);
                    787:        }
1.1       nicm      788:
1.28      nicm      789:        return (0);
1.1       nicm      790: }
                    791:
1.28      nicm      792: /* Get an argument or return default value..*/
                    793: int
                    794: input_get(struct input_ctx *ictx, u_int validx, int minval, int defval)
1.1       nicm      795: {
1.28      nicm      796:        int     retval;
1.1       nicm      797:
1.28      nicm      798:        if (validx >= ictx->param_list_len)
                    799:            return (defval);
1.1       nicm      800:
1.28      nicm      801:        retval = ictx->param_list[validx];
                    802:        if (retval == -1)
                    803:                return (defval);
                    804:        if (retval < minval)
                    805:                return (minval);
                    806:        return (retval);
1.1       nicm      807: }
                    808:
1.28      nicm      809: /* Reply to terminal query. */
1.1       nicm      810: void
1.28      nicm      811: input_reply(struct input_ctx *ictx, const char *fmt, ...)
1.1       nicm      812: {
1.28      nicm      813:        va_list ap;
                    814:        char   *reply;
1.1       nicm      815:
1.28      nicm      816:        va_start(ap, fmt);
                    817:        vasprintf(&reply, fmt, ap);
                    818:        va_end(ap);
1.1       nicm      819:
1.28      nicm      820:        bufferevent_write(ictx->wp->event, reply, strlen(reply));
                    821:        xfree(reply);
1.8       nicm      822: }
                    823:
1.28      nicm      824: /* Clear saved state. */
1.8       nicm      825: void
1.28      nicm      826: input_clear(struct input_ctx *ictx)
1.8       nicm      827: {
1.28      nicm      828:        *ictx->interm_buf = '\0';
                    829:        ictx->interm_len = 0;
1.8       nicm      830:
1.28      nicm      831:        *ictx->param_buf = '\0';
                    832:        ictx->param_len = 0;
1.8       nicm      833:
1.35      nicm      834:        *ictx->input_buf = '\0';
                    835:        ictx->input_len = 0;
                    836:
1.28      nicm      837:        ictx->flags &= ~INPUT_DISCARD;
1.14      nicm      838: }
                    839:
1.28      nicm      840: /* Output this character to the screen. */
                    841: int
                    842: input_print(struct input_ctx *ictx)
1.14      nicm      843: {
1.28      nicm      844:        ictx->cell.data = ictx->ch;
                    845:        screen_write_cell(&ictx->ctx, &ictx->cell, NULL);
1.14      nicm      846:
1.28      nicm      847:        return (0);
1.1       nicm      848: }
                    849:
1.28      nicm      850: /* Collect intermediate string. */
                    851: int
                    852: input_intermediate(struct input_ctx *ictx)
1.1       nicm      853: {
1.28      nicm      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';
                    859:        }
1.1       nicm      860:
1.28      nicm      861:        return (0);
1.1       nicm      862: }
                    863:
1.28      nicm      864: /* Collect parameter string. */
                    865: int
                    866: input_parameter(struct input_ctx *ictx)
1.1       nicm      867: {
1.28      nicm      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';
                    873:        }
1.1       nicm      874:
1.28      nicm      875:        return (0);
1.1       nicm      876: }
                    877:
1.28      nicm      878: /* Collect input string. */
                    879: int
                    880: input_input(struct input_ctx *ictx)
1.1       nicm      881: {
1.28      nicm      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';
                    887:        }
1.1       nicm      888:
1.28      nicm      889:        return (0);
1.1       nicm      890: }
                    891:
1.28      nicm      892: /* Execute C0 control sequence. */
                    893: int
                    894: input_c0_dispatch(struct input_ctx *ictx)
1.1       nicm      895: {
1.28      nicm      896:        struct screen_write_ctx *sctx = &ictx->ctx;
                    897:        struct window_pane      *wp = ictx->wp;
                    898:        struct screen           *s = sctx->s;
1.1       nicm      899:
1.28      nicm      900:        log_debug("%s: '%c", __func__, ictx->ch);
1.1       nicm      901:
1.28      nicm      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;
1.1       nicm      915:
1.28      nicm      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;
                    940:        }
1.1       nicm      941:
1.28      nicm      942:        return (0);
1.7       nicm      943: }
                    944:
1.28      nicm      945: /* Execute escape sequence. */
                    946: int
                    947: input_esc_dispatch(struct input_ctx *ictx)
1.7       nicm      948: {
1.31      nicm      949:        struct screen_write_ctx         *sctx = &ictx->ctx;
                    950:        struct screen                   *s = sctx->s;
                    951:        struct input_table_entry        *entry;
1.7       nicm      952:
1.28      nicm      953:        if (ictx->flags & INPUT_DISCARD)
                    954:                return (0);
                    955:        log_debug("%s: '%c', %s", __func__, ictx->ch, ictx->interm_buf);
1.7       nicm      956:
1.28      nicm      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);
                    962:        }
1.7       nicm      963:
1.28      nicm      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;
1.1       nicm      970:
1.28      nicm      971:                screen_reset_tabs(sctx->s);
1.1       nicm      972:
1.28      nicm      973:                screen_write_scrollregion(sctx, 0, screen_size_y(sctx->s) - 1);
1.1       nicm      974:
1.28      nicm      975:                screen_write_insertmode(sctx, 0);
                    976:                screen_write_kcursormode(sctx, 0);
                    977:                screen_write_kkeypadmode(sctx, 0);
1.32      nicm      978:                screen_write_mousemode_off(sctx);
1.1       nicm      979:
1.28      nicm      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);
1.1       nicm     1002:                break;
1.28      nicm     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:
                   1016:                /*
                   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).
                   1020:                 */
                   1021:                ictx->cell.attr &= ~GRID_ATTR_CHARSET;
1.1       nicm     1022:                break;
1.28      nicm     1023:        case INPUT_ESC_SCSOFF_G0:
                   1024:                ictx->cell.attr |= GRID_ATTR_CHARSET;
1.1       nicm     1025:                break;
                   1026:        }
1.28      nicm     1027:
                   1028:        return (0);
1.1       nicm     1029: }
                   1030:
1.28      nicm     1031: /* Execute control sequence. */
                   1032: int
                   1033: input_csi_dispatch(struct input_ctx *ictx)
1.1       nicm     1034: {
1.28      nicm     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;
1.1       nicm     1040:
1.28      nicm     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);
1.1       nicm     1047:
1.28      nicm     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);
                   1053:        }
1.1       nicm     1054:
1.28      nicm     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) {
                   1060:                        do
                   1061:                                s->cx--;
                   1062:                        while (s->cx > 0 && !bit_test(s->tabs, s->cx));
                   1063:                }
                   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;
                   1090:                }
                   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);
1.1       nicm     1099:                break;
1.28      nicm     1100:        case INPUT_CSI_DL:
                   1101:                screen_write_deleteline(sctx, input_get(ictx, 0, 1, 1));
1.1       nicm     1102:                break;
1.28      nicm     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;
                   1114:                }
                   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;
                   1130:                }
                   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;
                   1146:                }
                   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;
                   1166:                }
1.1       nicm     1167:                break;
1.28      nicm     1168:        case INPUT_CSI_RM_PRIVATE:
                   1169:                switch (input_get(ictx, 0, 0, -1)) {
1.1       nicm     1170:                case 1:         /* GATM */
1.28      nicm     1171:                        screen_write_kcursormode(&ictx->ctx, 0);
1.1       nicm     1172:                        break;
1.17      nicm     1173:                case 3:         /* DECCOLM */
1.24      nicm     1174:                        screen_write_cursormove(&ictx->ctx, 0, 0);
1.17      nicm     1175:                        screen_write_clearscreen(&ictx->ctx);
                   1176:                        break;
1.1       nicm     1177:                case 25:        /* TCEM */
1.28      nicm     1178:                        screen_write_cursormode(&ictx->ctx, 0);
1.1       nicm     1179:                        break;
                   1180:                case 1000:
1.32      nicm     1181:                case 1001:
                   1182:                case 1002:
                   1183:                case 1003:
                   1184:                        screen_write_mousemode_off(&ictx->ctx);
1.1       nicm     1185:                        break;
1.33      nicm     1186:                case 1005:
                   1187:                        screen_write_utf8mousemode(&ictx->ctx, 0);
                   1188:                        break;
1.9       nicm     1189:                case 1049:
1.28      nicm     1190:                        window_pane_alternate_off(wp, &ictx->cell);
1.9       nicm     1191:                        break;
1.1       nicm     1192:                default:
1.28      nicm     1193:                        log_debug("%s: unknown '%c'", __func__, ictx->ch);
1.1       nicm     1194:                        break;
                   1195:                }
1.28      nicm     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)) {
1.1       nicm     1202:                case 4:         /* IRM */
                   1203:                        screen_write_insertmode(&ictx->ctx, 1);
                   1204:                        break;
                   1205:                default:
1.28      nicm     1206:                        log_debug("%s: unknown '%c'", __func__, ictx->ch);
1.1       nicm     1207:                        break;
                   1208:                }
1.28      nicm     1209:                break;
                   1210:        case INPUT_CSI_SM_PRIVATE:
                   1211:                switch (input_get(ictx, 0, 0, -1)) {
1.1       nicm     1212:                case 1:         /* GATM */
1.28      nicm     1213:                        screen_write_kcursormode(&ictx->ctx, 1);
1.17      nicm     1214:                        break;
                   1215:                case 3:         /* DECCOLM */
1.24      nicm     1216:                        screen_write_cursormove(&ictx->ctx, 0, 0);
1.17      nicm     1217:                        screen_write_clearscreen(&ictx->ctx);
1.1       nicm     1218:                        break;
                   1219:                case 25:        /* TCEM */
1.28      nicm     1220:                        screen_write_cursormode(&ictx->ctx, 1);
1.1       nicm     1221:                        break;
                   1222:                case 1000:
1.32      nicm     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);
1.33      nicm     1232:                        break;
                   1233:                case 1005:
                   1234:                        screen_write_utf8mousemode(&ictx->ctx, 1);
1.9       nicm     1235:                        break;
                   1236:                case 1049:
1.28      nicm     1237:                        window_pane_alternate_on(wp, &ictx->cell);
1.1       nicm     1238:                        break;
                   1239:                default:
1.28      nicm     1240:                        log_debug("%s: unknown '%c'", __func__, ictx->ch);
1.1       nicm     1241:                        break;
                   1242:                }
1.28      nicm     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);
1.1       nicm     1249:                        break;
1.28      nicm     1250:                case 3:
                   1251:                        bit_nclear(s->tabs, 0, screen_size_x(s) - 1);
1.1       nicm     1252:                        break;
                   1253:                default:
1.28      nicm     1254:                        log_debug("%s: unknown '%c'", __func__, ictx->ch);
1.1       nicm     1255:                        break;
                   1256:                }
1.28      nicm     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;
1.1       nicm     1262:        }
                   1263:
1.28      nicm     1264:        return (0);
1.1       nicm     1265: }
                   1266:
1.28      nicm     1267: /* Handle CSI SGR. */
1.1       nicm     1268: void
1.28      nicm     1269: input_csi_dispatch_sgr(struct input_ctx *ictx)
1.1       nicm     1270: {
1.28      nicm     1271:        struct grid_cell        *gc = &ictx->cell;
                   1272:        u_int                    i;
                   1273:        int                      n, m;
                   1274:        u_char                   attr;
1.1       nicm     1275:
1.28      nicm     1276:        if (ictx->param_list_len == 0) {
1.1       nicm     1277:                attr = gc->attr;
                   1278:                memcpy(gc, &grid_default_cell, sizeof *gc);
1.24      nicm     1279:                gc->attr |= (attr & GRID_ATTR_CHARSET);
1.1       nicm     1280:                return;
                   1281:        }
                   1282:
1.28      nicm     1283:        for (i = 0; i < ictx->param_list_len; i++) {
                   1284:                n = input_get(ictx, i, 0, 0);
1.1       nicm     1285:
1.28      nicm     1286:                if (n == 38 || n == 48) {
1.1       nicm     1287:                        i++;
1.28      nicm     1288:                        if (input_get(ictx, i, 0, -1) != 5)
1.1       nicm     1289:                                continue;
                   1290:
                   1291:                        i++;
1.28      nicm     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;
1.36      nicm     1299:                                        gc->bg = 8;
1.28      nicm     1300:                                }
                   1301:
                   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;
                   1309:                                }
1.1       nicm     1310:                        }
                   1311:                        continue;
                   1312:                }
                   1313:
1.28      nicm     1314:                switch (n) {
1.1       nicm     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;
1.28      nicm     1366:                        gc->fg = n - 30;
1.1       nicm     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;
1.28      nicm     1381:                        gc->bg = n - 40;
1.1       nicm     1382:                        break;
                   1383:                case 49:
                   1384:                        gc->flags &= ~GRID_FLAG_BG256;
                   1385:                        gc->bg = 8;
1.20      nicm     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:
1.26      nicm     1395:                        gc->flags &= ~GRID_FLAG_FG256;
1.28      nicm     1396:                        gc->fg = n;
1.20      nicm     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:
1.26      nicm     1406:                        gc->flags &= ~GRID_FLAG_BG256;
1.28      nicm     1407:                        gc->bg = n;
1.1       nicm     1408:                        break;
                   1409:                }
                   1410:        }
1.28      nicm     1411: }
                   1412:
1.37    ! nicm     1413: /* DCS terminator (ST) received. */
        !          1414: int
        !          1415: input_dcs_dispatch(struct input_ctx *ictx)
1.28      nicm     1416: {
1.37    ! nicm     1417:        const char      prefix[] = "tmux;";
        !          1418:        const u_int     prefix_len = (sizeof prefix) - 1;
        !          1419:
        !          1420:        if (ictx->flags & INPUT_DISCARD)
        !          1421:                return (0);
        !          1422:
        !          1423:        log_debug("%s: \"%s\"", __func__, ictx->input_buf);
1.28      nicm     1424:
1.37    ! nicm     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);
        !          1430:        }
1.28      nicm     1431:
1.37    ! nicm     1432:        return (0);
1.28      nicm     1433: }
                   1434:
                   1435: /* OSC string started. */
                   1436: void
                   1437: input_enter_osc(struct input_ctx *ictx)
                   1438: {
                   1439:        log_debug("%s", __func__);
                   1440:
1.35      nicm     1441:        input_clear(ictx);
1.28      nicm     1442: }
                   1443:
                   1444: /* OSC terminator (ST) received. */
                   1445: void
                   1446: input_exit_osc(struct input_ctx *ictx)
                   1447: {
                   1448:        if (ictx->flags & INPUT_DISCARD)
                   1449:                return;
                   1450:        log_debug("%s: \"%s\"", __func__, ictx->input_buf);
                   1451:
                   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;
                   1456:
                   1457:        screen_set_title(ictx->ctx.s, ictx->input_buf + 2);
                   1458:        server_status_window(ictx->wp->window);
                   1459: }
                   1460:
                   1461: /* APC string started. */
                   1462: void
                   1463: input_enter_apc(struct input_ctx *ictx)
                   1464: {
                   1465:        log_debug("%s", __func__);
                   1466:
1.35      nicm     1467:        input_clear(ictx);
1.28      nicm     1468: }
                   1469:
                   1470: /* APC terminator (ST) received. */
                   1471: void
                   1472: input_exit_apc(struct input_ctx *ictx)
                   1473: {
                   1474:        if (ictx->flags & INPUT_DISCARD)
                   1475:                return;
                   1476:        log_debug("%s: \"%s\"", __func__, ictx->input_buf);
                   1477:
                   1478:        screen_set_title(ictx->ctx.s, ictx->input_buf);
                   1479:        server_status_window(ictx->wp->window);
                   1480: }
                   1481:
                   1482: /* Rename string started. */
                   1483: void
                   1484: input_enter_rename(struct input_ctx *ictx)
                   1485: {
                   1486:        log_debug("%s", __func__);
                   1487:
1.35      nicm     1488:        input_clear(ictx);
1.28      nicm     1489: }
                   1490:
                   1491: /* Rename terminator (ST) received. */
                   1492: void
                   1493: input_exit_rename(struct input_ctx *ictx)
                   1494: {
                   1495:        if (ictx->flags & INPUT_DISCARD)
                   1496:                return;
                   1497:        log_debug("%s: \"%s\"", __func__, ictx->input_buf);
                   1498:
                   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);
                   1502:
                   1503:        server_status_window(ictx->wp->window);
                   1504: }
                   1505:
                   1506: /* Open UTF-8 character. */
                   1507: int
                   1508: input_utf8_open(struct input_ctx *ictx)
                   1509: {
                   1510:        if (!options_get_number(&ictx->wp->window->options, "utf8")) {
                   1511:                /* Print, and do not switch state. */
                   1512:                input_print(ictx);
                   1513:                return (-1);
                   1514:        }
                   1515:        log_debug("%s", __func__);
                   1516:
                   1517:        utf8_open(&ictx->utf8data, ictx->ch);
                   1518:        return (0);
                   1519: }
                   1520:
                   1521: /* Append to UTF-8 character. */
                   1522: int
                   1523: input_utf8_add(struct input_ctx *ictx)
                   1524: {
                   1525:        log_debug("%s", __func__);
                   1526:
                   1527:        utf8_append(&ictx->utf8data, ictx->ch);
                   1528:        return (0);
                   1529: }
                   1530:
                   1531: /* Close UTF-8 string. */
                   1532: int
                   1533: input_utf8_close(struct input_ctx *ictx)
                   1534: {
                   1535:        log_debug("%s", __func__);
                   1536:
                   1537:        utf8_append(&ictx->utf8data, ictx->ch);
                   1538:
                   1539:        ictx->cell.flags |= GRID_FLAG_UTF8;
                   1540:        screen_write_cell(&ictx->ctx, &ictx->cell, &ictx->utf8data);
                   1541:        ictx->cell.flags &= ~GRID_FLAG_UTF8;
                   1542:
                   1543:        return (0);
1.1       nicm     1544: }