Annotation of embedaddon/tmux/input.c, revision 1.1

1.1     ! misho       1: /* $OpenBSD$ */
        !             2: 
        !             3: /*
        !             4:  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
        !             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 <netinet/in.h>
        !            22: 
        !            23: #include <resolv.h>
        !            24: #include <stdlib.h>
        !            25: #include <string.h>
        !            26: #include <time.h>
        !            27: 
        !            28: #include "tmux.h"
        !            29: 
        !            30: /*
        !            31:  * Based on the description by Paul Williams at:
        !            32:  *
        !            33:  * http://vt100.net/emu/dec_ansi_parser
        !            34:  *
        !            35:  * With the following changes:
        !            36:  *
        !            37:  * - 7-bit only.
        !            38:  *
        !            39:  * - Support for UTF-8.
        !            40:  *
        !            41:  * - OSC (but not APC) may be terminated by \007 as well as ST.
        !            42:  *
        !            43:  * - A state for APC similar to OSC. Some terminals appear to use this to set
        !            44:  *   the title.
        !            45:  *
        !            46:  * - A state for the screen \033k...\033\\ sequence to rename a window. This is
        !            47:  *   pretty stupid but not supporting it is more trouble than it is worth.
        !            48:  *
        !            49:  * - Special handling for ESC inside a DCS to allow arbitrary byte sequences to
        !            50:  *   be passed to the underlying terminals.
        !            51:  */
        !            52: 
        !            53: /* Input parser cell. */
        !            54: struct input_cell {
        !            55:        struct grid_cell        cell;
        !            56:        int                     set;
        !            57:        int                     g0set;  /* 1 if ACS */
        !            58:        int                     g1set;  /* 1 if ACS */
        !            59: };
        !            60: 
        !            61: /* Input parser context. */
        !            62: struct input_ctx {
        !            63:        struct window_pane     *wp;
        !            64:        struct screen_write_ctx ctx;
        !            65: 
        !            66:        struct input_cell       cell;
        !            67: 
        !            68:        struct input_cell       old_cell;
        !            69:        u_int                   old_cx;
        !            70:        u_int                   old_cy;
        !            71: 
        !            72:        u_char                  interm_buf[4];
        !            73:        size_t                  interm_len;
        !            74: 
        !            75:        u_char                  param_buf[64];
        !            76:        size_t                  param_len;
        !            77: 
        !            78: #define INPUT_BUF_START 32
        !            79: #define INPUT_BUF_LIMIT 1048576
        !            80:        u_char                 *input_buf;
        !            81:        size_t                  input_len;
        !            82:        size_t                  input_space;
        !            83: 
        !            84:        int                     param_list[24]; /* -1 not present */
        !            85:        u_int                   param_list_len;
        !            86: 
        !            87:        struct utf8_data        utf8data;
        !            88: 
        !            89:        int                     ch;
        !            90: 
        !            91:        int                     flags;
        !            92: #define INPUT_DISCARD 0x1
        !            93: 
        !            94:        const struct input_state *state;
        !            95: 
        !            96:        /*
        !            97:         * All input received since we were last in the ground state. Sent to
        !            98:         * control clients on connection.
        !            99:         */
        !           100:        struct evbuffer         *since_ground;
        !           101: };
        !           102: 
        !           103: /* Helper functions. */
        !           104: struct input_transition;
        !           105: static int     input_split(struct input_ctx *);
        !           106: static int     input_get(struct input_ctx *, u_int, int, int);
        !           107: static void printflike(2, 3) input_reply(struct input_ctx *, const char *, ...);
        !           108: static void    input_set_state(struct window_pane *,
        !           109:                    const struct input_transition *);
        !           110: static void    input_reset_cell(struct input_ctx *);
        !           111: 
        !           112: static void    input_osc_4(struct window_pane *, const char *);
        !           113: static void    input_osc_52(struct window_pane *, const char *);
        !           114: static void    input_osc_104(struct window_pane *, const char *);
        !           115: 
        !           116: /* Transition entry/exit handlers. */
        !           117: static void    input_clear(struct input_ctx *);
        !           118: static void    input_ground(struct input_ctx *);
        !           119: static void    input_enter_osc(struct input_ctx *);
        !           120: static void    input_exit_osc(struct input_ctx *);
        !           121: static void    input_enter_apc(struct input_ctx *);
        !           122: static void    input_exit_apc(struct input_ctx *);
        !           123: static void    input_enter_rename(struct input_ctx *);
        !           124: static void    input_exit_rename(struct input_ctx *);
        !           125: 
        !           126: /* Input state handlers. */
        !           127: static int     input_print(struct input_ctx *);
        !           128: static int     input_intermediate(struct input_ctx *);
        !           129: static int     input_parameter(struct input_ctx *);
        !           130: static int     input_input(struct input_ctx *);
        !           131: static int     input_c0_dispatch(struct input_ctx *);
        !           132: static int     input_esc_dispatch(struct input_ctx *);
        !           133: static int     input_csi_dispatch(struct input_ctx *);
        !           134: static void    input_csi_dispatch_rm(struct input_ctx *);
        !           135: static void    input_csi_dispatch_rm_private(struct input_ctx *);
        !           136: static void    input_csi_dispatch_sm(struct input_ctx *);
        !           137: static void    input_csi_dispatch_sm_private(struct input_ctx *);
        !           138: static void    input_csi_dispatch_winops(struct input_ctx *);
        !           139: static void    input_csi_dispatch_sgr_256(struct input_ctx *, int, u_int *);
        !           140: static void    input_csi_dispatch_sgr_rgb(struct input_ctx *, int, u_int *);
        !           141: static void    input_csi_dispatch_sgr(struct input_ctx *);
        !           142: static int     input_dcs_dispatch(struct input_ctx *);
        !           143: static int     input_utf8_open(struct input_ctx *);
        !           144: static int     input_utf8_add(struct input_ctx *);
        !           145: static int     input_utf8_close(struct input_ctx *);
        !           146: 
        !           147: /* Command table comparison function. */
        !           148: static int     input_table_compare(const void *, const void *);
        !           149: 
        !           150: /* Command table entry. */
        !           151: struct input_table_entry {
        !           152:        int             ch;
        !           153:        const char     *interm;
        !           154:        int             type;
        !           155: };
        !           156: 
        !           157: /* Escape commands. */
        !           158: enum input_esc_type {
        !           159:        INPUT_ESC_DECALN,
        !           160:        INPUT_ESC_DECKPAM,
        !           161:        INPUT_ESC_DECKPNM,
        !           162:        INPUT_ESC_DECRC,
        !           163:        INPUT_ESC_DECSC,
        !           164:        INPUT_ESC_HTS,
        !           165:        INPUT_ESC_IND,
        !           166:        INPUT_ESC_NEL,
        !           167:        INPUT_ESC_RI,
        !           168:        INPUT_ESC_RIS,
        !           169:        INPUT_ESC_SCSG0_OFF,
        !           170:        INPUT_ESC_SCSG0_ON,
        !           171:        INPUT_ESC_SCSG1_OFF,
        !           172:        INPUT_ESC_SCSG1_ON,
        !           173:        INPUT_ESC_ST,
        !           174: };
        !           175: 
        !           176: /* Escape command table. */
        !           177: static const struct input_table_entry input_esc_table[] = {
        !           178:        { '0', "(", INPUT_ESC_SCSG0_ON },
        !           179:        { '0', ")", INPUT_ESC_SCSG1_ON },
        !           180:        { '7', "",  INPUT_ESC_DECSC },
        !           181:        { '8', "",  INPUT_ESC_DECRC },
        !           182:        { '8', "#", INPUT_ESC_DECALN },
        !           183:        { '=', "",  INPUT_ESC_DECKPAM },
        !           184:        { '>', "",  INPUT_ESC_DECKPNM },
        !           185:        { 'B', "(", INPUT_ESC_SCSG0_OFF },
        !           186:        { 'B', ")", INPUT_ESC_SCSG1_OFF },
        !           187:        { 'D', "",  INPUT_ESC_IND },
        !           188:        { 'E', "",  INPUT_ESC_NEL },
        !           189:        { 'H', "",  INPUT_ESC_HTS },
        !           190:        { 'M', "",  INPUT_ESC_RI },
        !           191:        { '\\', "", INPUT_ESC_ST },
        !           192:        { 'c', "",  INPUT_ESC_RIS },
        !           193: };
        !           194: 
        !           195: /* Control (CSI) commands. */
        !           196: enum input_csi_type {
        !           197:        INPUT_CSI_CBT,
        !           198:        INPUT_CSI_CNL,
        !           199:        INPUT_CSI_CPL,
        !           200:        INPUT_CSI_CUB,
        !           201:        INPUT_CSI_CUD,
        !           202:        INPUT_CSI_CUF,
        !           203:        INPUT_CSI_CUP,
        !           204:        INPUT_CSI_CUU,
        !           205:        INPUT_CSI_DA,
        !           206:        INPUT_CSI_DA_TWO,
        !           207:        INPUT_CSI_DCH,
        !           208:        INPUT_CSI_DECSCUSR,
        !           209:        INPUT_CSI_DECSTBM,
        !           210:        INPUT_CSI_DL,
        !           211:        INPUT_CSI_DSR,
        !           212:        INPUT_CSI_ECH,
        !           213:        INPUT_CSI_ED,
        !           214:        INPUT_CSI_EL,
        !           215:        INPUT_CSI_HPA,
        !           216:        INPUT_CSI_ICH,
        !           217:        INPUT_CSI_IL,
        !           218:        INPUT_CSI_RCP,
        !           219:        INPUT_CSI_RM,
        !           220:        INPUT_CSI_RM_PRIVATE,
        !           221:        INPUT_CSI_SCP,
        !           222:        INPUT_CSI_SGR,
        !           223:        INPUT_CSI_SM,
        !           224:        INPUT_CSI_SM_PRIVATE,
        !           225:        INPUT_CSI_SU,
        !           226:        INPUT_CSI_TBC,
        !           227:        INPUT_CSI_VPA,
        !           228:        INPUT_CSI_WINOPS,
        !           229: };
        !           230: 
        !           231: /* Control (CSI) command table. */
        !           232: static const struct input_table_entry input_csi_table[] = {
        !           233:        { '@', "",  INPUT_CSI_ICH },
        !           234:        { 'A', "",  INPUT_CSI_CUU },
        !           235:        { 'B', "",  INPUT_CSI_CUD },
        !           236:        { 'C', "",  INPUT_CSI_CUF },
        !           237:        { 'D', "",  INPUT_CSI_CUB },
        !           238:        { 'E', "",  INPUT_CSI_CNL },
        !           239:        { 'F', "",  INPUT_CSI_CPL },
        !           240:        { 'G', "",  INPUT_CSI_HPA },
        !           241:        { 'H', "",  INPUT_CSI_CUP },
        !           242:        { 'J', "",  INPUT_CSI_ED },
        !           243:        { 'K', "",  INPUT_CSI_EL },
        !           244:        { 'L', "",  INPUT_CSI_IL },
        !           245:        { 'M', "",  INPUT_CSI_DL },
        !           246:        { 'P', "",  INPUT_CSI_DCH },
        !           247:        { 'S', "",  INPUT_CSI_SU },
        !           248:        { 'X', "",  INPUT_CSI_ECH },
        !           249:        { 'Z', "",  INPUT_CSI_CBT },
        !           250:        { 'c', "",  INPUT_CSI_DA },
        !           251:        { 'c', ">", INPUT_CSI_DA_TWO },
        !           252:        { 'd', "",  INPUT_CSI_VPA },
        !           253:        { 'f', "",  INPUT_CSI_CUP },
        !           254:        { 'g', "",  INPUT_CSI_TBC },
        !           255:        { 'h', "",  INPUT_CSI_SM },
        !           256:        { 'h', "?", INPUT_CSI_SM_PRIVATE },
        !           257:        { 'l', "",  INPUT_CSI_RM },
        !           258:        { 'l', "?", INPUT_CSI_RM_PRIVATE },
        !           259:        { 'm', "",  INPUT_CSI_SGR },
        !           260:        { 'n', "",  INPUT_CSI_DSR },
        !           261:        { 'q', " ", INPUT_CSI_DECSCUSR },
        !           262:        { 'r', "",  INPUT_CSI_DECSTBM },
        !           263:        { 's', "",  INPUT_CSI_SCP },
        !           264:        { 't', "",  INPUT_CSI_WINOPS },
        !           265:        { 'u', "",  INPUT_CSI_RCP },
        !           266: };
        !           267: 
        !           268: /* Input transition. */
        !           269: struct input_transition {
        !           270:        int                             first;
        !           271:        int                             last;
        !           272: 
        !           273:        int                             (*handler)(struct input_ctx *);
        !           274:        const struct input_state       *state;
        !           275: };
        !           276: 
        !           277: /* Input state. */
        !           278: struct input_state {
        !           279:        const char                      *name;
        !           280:        void                            (*enter)(struct input_ctx *);
        !           281:        void                            (*exit)(struct input_ctx *);
        !           282:        const struct input_transition   *transitions;
        !           283: };
        !           284: 
        !           285: /* State transitions available from all states. */
        !           286: #define INPUT_STATE_ANYWHERE \
        !           287:        { 0x18, 0x18, input_c0_dispatch, &input_state_ground }, \
        !           288:        { 0x1a, 0x1a, input_c0_dispatch, &input_state_ground }, \
        !           289:        { 0x1b, 0x1b, NULL,              &input_state_esc_enter }
        !           290: 
        !           291: /* Forward declarations of state tables. */
        !           292: static const struct input_transition input_state_ground_table[];
        !           293: static const struct input_transition input_state_esc_enter_table[];
        !           294: static const struct input_transition input_state_esc_intermediate_table[];
        !           295: static const struct input_transition input_state_csi_enter_table[];
        !           296: static const struct input_transition input_state_csi_parameter_table[];
        !           297: static const struct input_transition input_state_csi_intermediate_table[];
        !           298: static const struct input_transition input_state_csi_ignore_table[];
        !           299: static const struct input_transition input_state_dcs_enter_table[];
        !           300: static const struct input_transition input_state_dcs_parameter_table[];
        !           301: static const struct input_transition input_state_dcs_intermediate_table[];
        !           302: static const struct input_transition input_state_dcs_handler_table[];
        !           303: static const struct input_transition input_state_dcs_escape_table[];
        !           304: static const struct input_transition input_state_dcs_ignore_table[];
        !           305: static const struct input_transition input_state_osc_string_table[];
        !           306: static const struct input_transition input_state_apc_string_table[];
        !           307: static const struct input_transition input_state_rename_string_table[];
        !           308: static const struct input_transition input_state_consume_st_table[];
        !           309: static const struct input_transition input_state_utf8_three_table[];
        !           310: static const struct input_transition input_state_utf8_two_table[];
        !           311: static const struct input_transition input_state_utf8_one_table[];
        !           312: 
        !           313: /* ground state definition. */
        !           314: static const struct input_state input_state_ground = {
        !           315:        "ground",
        !           316:        input_ground, NULL,
        !           317:        input_state_ground_table
        !           318: };
        !           319: 
        !           320: /* esc_enter state definition. */
        !           321: static const struct input_state input_state_esc_enter = {
        !           322:        "esc_enter",
        !           323:        input_clear, NULL,
        !           324:        input_state_esc_enter_table
        !           325: };
        !           326: 
        !           327: /* esc_intermediate state definition. */
        !           328: static const struct input_state input_state_esc_intermediate = {
        !           329:        "esc_intermediate",
        !           330:        NULL, NULL,
        !           331:        input_state_esc_intermediate_table
        !           332: };
        !           333: 
        !           334: /* csi_enter state definition. */
        !           335: static const struct input_state input_state_csi_enter = {
        !           336:        "csi_enter",
        !           337:        input_clear, NULL,
        !           338:        input_state_csi_enter_table
        !           339: };
        !           340: 
        !           341: /* csi_parameter state definition. */
        !           342: static const struct input_state input_state_csi_parameter = {
        !           343:        "csi_parameter",
        !           344:        NULL, NULL,
        !           345:        input_state_csi_parameter_table
        !           346: };
        !           347: 
        !           348: /* csi_intermediate state definition. */
        !           349: static const struct input_state input_state_csi_intermediate = {
        !           350:        "csi_intermediate",
        !           351:        NULL, NULL,
        !           352:        input_state_csi_intermediate_table
        !           353: };
        !           354: 
        !           355: /* csi_ignore state definition. */
        !           356: static const struct input_state input_state_csi_ignore = {
        !           357:        "csi_ignore",
        !           358:        NULL, NULL,
        !           359:        input_state_csi_ignore_table
        !           360: };
        !           361: 
        !           362: /* dcs_enter state definition. */
        !           363: static const struct input_state input_state_dcs_enter = {
        !           364:        "dcs_enter",
        !           365:        input_clear, NULL,
        !           366:        input_state_dcs_enter_table
        !           367: };
        !           368: 
        !           369: /* dcs_parameter state definition. */
        !           370: static const struct input_state input_state_dcs_parameter = {
        !           371:        "dcs_parameter",
        !           372:        NULL, NULL,
        !           373:        input_state_dcs_parameter_table
        !           374: };
        !           375: 
        !           376: /* dcs_intermediate state definition. */
        !           377: static const struct input_state input_state_dcs_intermediate = {
        !           378:        "dcs_intermediate",
        !           379:        NULL, NULL,
        !           380:        input_state_dcs_intermediate_table
        !           381: };
        !           382: 
        !           383: /* dcs_handler state definition. */
        !           384: static const struct input_state input_state_dcs_handler = {
        !           385:        "dcs_handler",
        !           386:        NULL, NULL,
        !           387:        input_state_dcs_handler_table
        !           388: };
        !           389: 
        !           390: /* dcs_escape state definition. */
        !           391: static const struct input_state input_state_dcs_escape = {
        !           392:        "dcs_escape",
        !           393:        NULL, NULL,
        !           394:        input_state_dcs_escape_table
        !           395: };
        !           396: 
        !           397: /* dcs_ignore state definition. */
        !           398: static const struct input_state input_state_dcs_ignore = {
        !           399:        "dcs_ignore",
        !           400:        NULL, NULL,
        !           401:        input_state_dcs_ignore_table
        !           402: };
        !           403: 
        !           404: /* osc_string state definition. */
        !           405: static const struct input_state input_state_osc_string = {
        !           406:        "osc_string",
        !           407:        input_enter_osc, input_exit_osc,
        !           408:        input_state_osc_string_table
        !           409: };
        !           410: 
        !           411: /* apc_string state definition. */
        !           412: static const struct input_state input_state_apc_string = {
        !           413:        "apc_string",
        !           414:        input_enter_apc, input_exit_apc,
        !           415:        input_state_apc_string_table
        !           416: };
        !           417: 
        !           418: /* rename_string state definition. */
        !           419: static const struct input_state input_state_rename_string = {
        !           420:        "rename_string",
        !           421:        input_enter_rename, input_exit_rename,
        !           422:        input_state_rename_string_table
        !           423: };
        !           424: 
        !           425: /* consume_st state definition. */
        !           426: static const struct input_state input_state_consume_st = {
        !           427:        "consume_st",
        !           428:        NULL, NULL,
        !           429:        input_state_consume_st_table
        !           430: };
        !           431: 
        !           432: /* utf8_three state definition. */
        !           433: static const struct input_state input_state_utf8_three = {
        !           434:        "utf8_three",
        !           435:        NULL, NULL,
        !           436:        input_state_utf8_three_table
        !           437: };
        !           438: 
        !           439: /* utf8_two state definition. */
        !           440: static const struct input_state input_state_utf8_two = {
        !           441:        "utf8_two",
        !           442:        NULL, NULL,
        !           443:        input_state_utf8_two_table
        !           444: };
        !           445: 
        !           446: /* utf8_one state definition. */
        !           447: static const struct input_state input_state_utf8_one = {
        !           448:        "utf8_one",
        !           449:        NULL, NULL,
        !           450:        input_state_utf8_one_table
        !           451: };
        !           452: 
        !           453: /* ground state table. */
        !           454: static const struct input_transition input_state_ground_table[] = {
        !           455:        INPUT_STATE_ANYWHERE,
        !           456: 
        !           457:        { 0x00, 0x17, input_c0_dispatch, NULL },
        !           458:        { 0x19, 0x19, input_c0_dispatch, NULL },
        !           459:        { 0x1c, 0x1f, input_c0_dispatch, NULL },
        !           460:        { 0x20, 0x7e, input_print,       NULL },
        !           461:        { 0x7f, 0x7f, NULL,              NULL },
        !           462:        { 0x80, 0xc1, NULL,              NULL },
        !           463:        { 0xc2, 0xdf, input_utf8_open,   &input_state_utf8_one },
        !           464:        { 0xe0, 0xef, input_utf8_open,   &input_state_utf8_two },
        !           465:        { 0xf0, 0xf4, input_utf8_open,   &input_state_utf8_three },
        !           466:        { 0xf5, 0xff, NULL,              NULL },
        !           467: 
        !           468:        { -1, -1, NULL, NULL }
        !           469: };
        !           470: 
        !           471: /* esc_enter state table. */
        !           472: static const struct input_transition input_state_esc_enter_table[] = {
        !           473:        INPUT_STATE_ANYWHERE,
        !           474: 
        !           475:        { 0x00, 0x17, input_c0_dispatch,  NULL },
        !           476:        { 0x19, 0x19, input_c0_dispatch,  NULL },
        !           477:        { 0x1c, 0x1f, input_c0_dispatch,  NULL },
        !           478:        { 0x20, 0x2f, input_intermediate, &input_state_esc_intermediate },
        !           479:        { 0x30, 0x4f, input_esc_dispatch, &input_state_ground },
        !           480:        { 0x50, 0x50, NULL,               &input_state_dcs_enter },
        !           481:        { 0x51, 0x57, input_esc_dispatch, &input_state_ground },
        !           482:        { 0x58, 0x58, NULL,               &input_state_consume_st },
        !           483:        { 0x59, 0x59, input_esc_dispatch, &input_state_ground },
        !           484:        { 0x5a, 0x5a, input_esc_dispatch, &input_state_ground },
        !           485:        { 0x5b, 0x5b, NULL,               &input_state_csi_enter },
        !           486:        { 0x5c, 0x5c, input_esc_dispatch, &input_state_ground },
        !           487:        { 0x5d, 0x5d, NULL,               &input_state_osc_string },
        !           488:        { 0x5e, 0x5e, NULL,               &input_state_consume_st },
        !           489:        { 0x5f, 0x5f, NULL,               &input_state_apc_string },
        !           490:        { 0x60, 0x6a, input_esc_dispatch, &input_state_ground },
        !           491:        { 0x6b, 0x6b, NULL,               &input_state_rename_string },
        !           492:        { 0x6c, 0x7e, input_esc_dispatch, &input_state_ground },
        !           493:        { 0x7f, 0xff, NULL,               NULL },
        !           494: 
        !           495:        { -1, -1, NULL, NULL }
        !           496: };
        !           497: 
        !           498: /* esc_interm state table. */
        !           499: static const struct input_transition input_state_esc_intermediate_table[] = {
        !           500:        INPUT_STATE_ANYWHERE,
        !           501: 
        !           502:        { 0x00, 0x17, input_c0_dispatch,  NULL },
        !           503:        { 0x19, 0x19, input_c0_dispatch,  NULL },
        !           504:        { 0x1c, 0x1f, input_c0_dispatch,  NULL },
        !           505:        { 0x20, 0x2f, input_intermediate, NULL },
        !           506:        { 0x30, 0x7e, input_esc_dispatch, &input_state_ground },
        !           507:        { 0x7f, 0xff, NULL,               NULL },
        !           508: 
        !           509:        { -1, -1, NULL, NULL }
        !           510: };
        !           511: 
        !           512: /* csi_enter state table. */
        !           513: static const struct input_transition input_state_csi_enter_table[] = {
        !           514:        INPUT_STATE_ANYWHERE,
        !           515: 
        !           516:        { 0x00, 0x17, input_c0_dispatch,  NULL },
        !           517:        { 0x19, 0x19, input_c0_dispatch,  NULL },
        !           518:        { 0x1c, 0x1f, input_c0_dispatch,  NULL },
        !           519:        { 0x20, 0x2f, input_intermediate, &input_state_csi_intermediate },
        !           520:        { 0x30, 0x39, input_parameter,    &input_state_csi_parameter },
        !           521:        { 0x3a, 0x3a, NULL,               &input_state_csi_ignore },
        !           522:        { 0x3b, 0x3b, input_parameter,    &input_state_csi_parameter },
        !           523:        { 0x3c, 0x3f, input_intermediate, &input_state_csi_parameter },
        !           524:        { 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
        !           525:        { 0x7f, 0xff, NULL,               NULL },
        !           526: 
        !           527:        { -1, -1, NULL, NULL }
        !           528: };
        !           529: 
        !           530: /* csi_parameter state table. */
        !           531: static const struct input_transition input_state_csi_parameter_table[] = {
        !           532:        INPUT_STATE_ANYWHERE,
        !           533: 
        !           534:        { 0x00, 0x17, input_c0_dispatch,  NULL },
        !           535:        { 0x19, 0x19, input_c0_dispatch,  NULL },
        !           536:        { 0x1c, 0x1f, input_c0_dispatch,  NULL },
        !           537:        { 0x20, 0x2f, input_intermediate, &input_state_csi_intermediate },
        !           538:        { 0x30, 0x39, input_parameter,    NULL },
        !           539:        { 0x3a, 0x3a, NULL,               &input_state_csi_ignore },
        !           540:        { 0x3b, 0x3b, input_parameter,    NULL },
        !           541:        { 0x3c, 0x3f, NULL,               &input_state_csi_ignore },
        !           542:        { 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
        !           543:        { 0x7f, 0xff, NULL,               NULL },
        !           544: 
        !           545:        { -1, -1, NULL, NULL }
        !           546: };
        !           547: 
        !           548: /* csi_intermediate state table. */
        !           549: static const struct input_transition input_state_csi_intermediate_table[] = {
        !           550:        INPUT_STATE_ANYWHERE,
        !           551: 
        !           552:        { 0x00, 0x17, input_c0_dispatch,  NULL },
        !           553:        { 0x19, 0x19, input_c0_dispatch,  NULL },
        !           554:        { 0x1c, 0x1f, input_c0_dispatch,  NULL },
        !           555:        { 0x20, 0x2f, input_intermediate, NULL },
        !           556:        { 0x30, 0x3f, NULL,               &input_state_csi_ignore },
        !           557:        { 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
        !           558:        { 0x7f, 0xff, NULL,               NULL },
        !           559: 
        !           560:        { -1, -1, NULL, NULL }
        !           561: };
        !           562: 
        !           563: /* csi_ignore state table. */
        !           564: static const struct input_transition input_state_csi_ignore_table[] = {
        !           565:        INPUT_STATE_ANYWHERE,
        !           566: 
        !           567:        { 0x00, 0x17, input_c0_dispatch, NULL },
        !           568:        { 0x19, 0x19, input_c0_dispatch, NULL },
        !           569:        { 0x1c, 0x1f, input_c0_dispatch, NULL },
        !           570:        { 0x20, 0x3f, NULL,              NULL },
        !           571:        { 0x40, 0x7e, NULL,              &input_state_ground },
        !           572:        { 0x7f, 0xff, NULL,              NULL },
        !           573: 
        !           574:        { -1, -1, NULL, NULL }
        !           575: };
        !           576: 
        !           577: /* dcs_enter state table. */
        !           578: static const struct input_transition input_state_dcs_enter_table[] = {
        !           579:        INPUT_STATE_ANYWHERE,
        !           580: 
        !           581:        { 0x00, 0x17, NULL,               NULL },
        !           582:        { 0x19, 0x19, NULL,               NULL },
        !           583:        { 0x1c, 0x1f, NULL,               NULL },
        !           584:        { 0x20, 0x2f, input_intermediate, &input_state_dcs_intermediate },
        !           585:        { 0x30, 0x39, input_parameter,    &input_state_dcs_parameter },
        !           586:        { 0x3a, 0x3a, NULL,               &input_state_dcs_ignore },
        !           587:        { 0x3b, 0x3b, input_parameter,    &input_state_dcs_parameter },
        !           588:        { 0x3c, 0x3f, input_intermediate, &input_state_dcs_parameter },
        !           589:        { 0x40, 0x7e, input_input,        &input_state_dcs_handler },
        !           590:        { 0x7f, 0xff, NULL,               NULL },
        !           591: 
        !           592:        { -1, -1, NULL, NULL }
        !           593: };
        !           594: 
        !           595: /* dcs_parameter state table. */
        !           596: static const struct input_transition input_state_dcs_parameter_table[] = {
        !           597:        INPUT_STATE_ANYWHERE,
        !           598: 
        !           599:        { 0x00, 0x17, NULL,               NULL },
        !           600:        { 0x19, 0x19, NULL,               NULL },
        !           601:        { 0x1c, 0x1f, NULL,               NULL },
        !           602:        { 0x20, 0x2f, input_intermediate, &input_state_dcs_intermediate },
        !           603:        { 0x30, 0x39, input_parameter,    NULL },
        !           604:        { 0x3a, 0x3a, NULL,               &input_state_dcs_ignore },
        !           605:        { 0x3b, 0x3b, input_parameter,    NULL },
        !           606:        { 0x3c, 0x3f, NULL,               &input_state_dcs_ignore },
        !           607:        { 0x40, 0x7e, input_input,        &input_state_dcs_handler },
        !           608:        { 0x7f, 0xff, NULL,               NULL },
        !           609: 
        !           610:        { -1, -1, NULL, NULL }
        !           611: };
        !           612: 
        !           613: /* dcs_interm state table. */
        !           614: static const struct input_transition input_state_dcs_intermediate_table[] = {
        !           615:        INPUT_STATE_ANYWHERE,
        !           616: 
        !           617:        { 0x00, 0x17, NULL,               NULL },
        !           618:        { 0x19, 0x19, NULL,               NULL },
        !           619:        { 0x1c, 0x1f, NULL,               NULL },
        !           620:        { 0x20, 0x2f, input_intermediate, NULL },
        !           621:        { 0x30, 0x3f, NULL,               &input_state_dcs_ignore },
        !           622:        { 0x40, 0x7e, input_input,        &input_state_dcs_handler },
        !           623:        { 0x7f, 0xff, NULL,               NULL },
        !           624: 
        !           625:        { -1, -1, NULL, NULL }
        !           626: };
        !           627: 
        !           628: /* dcs_handler state table. */
        !           629: static const struct input_transition input_state_dcs_handler_table[] = {
        !           630:        /* No INPUT_STATE_ANYWHERE */
        !           631: 
        !           632:        { 0x00, 0x1a, input_input,  NULL },
        !           633:        { 0x1b, 0x1b, NULL,         &input_state_dcs_escape },
        !           634:        { 0x1c, 0xff, input_input,  NULL },
        !           635: 
        !           636:        { -1, -1, NULL, NULL }
        !           637: };
        !           638: 
        !           639: /* dcs_escape state table. */
        !           640: static const struct input_transition input_state_dcs_escape_table[] = {
        !           641:        /* No INPUT_STATE_ANYWHERE */
        !           642: 
        !           643:        { 0x00, 0x5b, input_input,        &input_state_dcs_handler },
        !           644:        { 0x5c, 0x5c, input_dcs_dispatch, &input_state_ground },
        !           645:        { 0x5d, 0xff, input_input,        &input_state_dcs_handler },
        !           646: 
        !           647:        { -1, -1, NULL, NULL }
        !           648: };
        !           649: 
        !           650: /* dcs_ignore state table. */
        !           651: static const struct input_transition input_state_dcs_ignore_table[] = {
        !           652:        INPUT_STATE_ANYWHERE,
        !           653: 
        !           654:        { 0x00, 0x17, NULL,         NULL },
        !           655:        { 0x19, 0x19, NULL,         NULL },
        !           656:        { 0x1c, 0x1f, NULL,         NULL },
        !           657:        { 0x20, 0xff, NULL,         NULL },
        !           658: 
        !           659:        { -1, -1, NULL, NULL }
        !           660: };
        !           661: 
        !           662: /* osc_string state table. */
        !           663: static const struct input_transition input_state_osc_string_table[] = {
        !           664:        INPUT_STATE_ANYWHERE,
        !           665: 
        !           666:        { 0x00, 0x06, NULL,         NULL },
        !           667:        { 0x07, 0x07, NULL,         &input_state_ground },
        !           668:        { 0x08, 0x17, NULL,         NULL },
        !           669:        { 0x19, 0x19, NULL,         NULL },
        !           670:        { 0x1c, 0x1f, NULL,         NULL },
        !           671:        { 0x20, 0xff, input_input,  NULL },
        !           672: 
        !           673:        { -1, -1, NULL, NULL }
        !           674: };
        !           675: 
        !           676: /* apc_string state table. */
        !           677: static const struct input_transition input_state_apc_string_table[] = {
        !           678:        INPUT_STATE_ANYWHERE,
        !           679: 
        !           680:        { 0x00, 0x17, NULL,         NULL },
        !           681:        { 0x19, 0x19, NULL,         NULL },
        !           682:        { 0x1c, 0x1f, NULL,         NULL },
        !           683:        { 0x20, 0xff, input_input,  NULL },
        !           684: 
        !           685:        { -1, -1, NULL, NULL }
        !           686: };
        !           687: 
        !           688: /* rename_string state table. */
        !           689: static const struct input_transition input_state_rename_string_table[] = {
        !           690:        INPUT_STATE_ANYWHERE,
        !           691: 
        !           692:        { 0x00, 0x17, NULL,         NULL },
        !           693:        { 0x19, 0x19, NULL,         NULL },
        !           694:        { 0x1c, 0x1f, NULL,         NULL },
        !           695:        { 0x20, 0xff, input_input,  NULL },
        !           696: 
        !           697:        { -1, -1, NULL, NULL }
        !           698: };
        !           699: 
        !           700: /* consume_st state table. */
        !           701: static const struct input_transition input_state_consume_st_table[] = {
        !           702:        INPUT_STATE_ANYWHERE,
        !           703: 
        !           704:        { 0x00, 0x17, NULL,         NULL },
        !           705:        { 0x19, 0x19, NULL,         NULL },
        !           706:        { 0x1c, 0x1f, NULL,         NULL },
        !           707:        { 0x20, 0xff, NULL,         NULL },
        !           708: 
        !           709:        { -1, -1, NULL, NULL }
        !           710: };
        !           711: 
        !           712: /* utf8_three state table. */
        !           713: static const struct input_transition input_state_utf8_three_table[] = {
        !           714:        /* No INPUT_STATE_ANYWHERE */
        !           715: 
        !           716:        { 0x00, 0x7f, NULL,             &input_state_ground },
        !           717:        { 0x80, 0xbf, input_utf8_add,   &input_state_utf8_two },
        !           718:        { 0xc0, 0xff, NULL,             &input_state_ground },
        !           719: 
        !           720:        { -1, -1, NULL, NULL }
        !           721: };
        !           722: 
        !           723: /* utf8_two state table. */
        !           724: static const struct input_transition input_state_utf8_two_table[] = {
        !           725:        /* No INPUT_STATE_ANYWHERE */
        !           726: 
        !           727:        { 0x00, 0x7f, NULL,           &input_state_ground },
        !           728:        { 0x80, 0xbf, input_utf8_add, &input_state_utf8_one },
        !           729:        { 0xc0, 0xff, NULL,           &input_state_ground },
        !           730: 
        !           731:        { -1, -1, NULL, NULL }
        !           732: };
        !           733: 
        !           734: /* utf8_one state table. */
        !           735: static const struct input_transition input_state_utf8_one_table[] = {
        !           736:        /* No INPUT_STATE_ANYWHERE */
        !           737: 
        !           738:        { 0x00, 0x7f, NULL,             &input_state_ground },
        !           739:        { 0x80, 0xbf, input_utf8_close, &input_state_ground },
        !           740:        { 0xc0, 0xff, NULL,             &input_state_ground },
        !           741: 
        !           742:        { -1, -1, NULL, NULL }
        !           743: };
        !           744: 
        !           745: /* Input table compare. */
        !           746: static int
        !           747: input_table_compare(const void *key, const void *value)
        !           748: {
        !           749:        const struct input_ctx          *ictx = key;
        !           750:        const struct input_table_entry  *entry = value;
        !           751: 
        !           752:        if (ictx->ch != entry->ch)
        !           753:                return (ictx->ch - entry->ch);
        !           754:        return (strcmp(ictx->interm_buf, entry->interm));
        !           755: }
        !           756: 
        !           757: /* Reset cell state to default. */
        !           758: static void
        !           759: input_reset_cell(struct input_ctx *ictx)
        !           760: {
        !           761:        memcpy(&ictx->cell.cell, &grid_default_cell, sizeof ictx->cell.cell);
        !           762:        ictx->cell.set = 0;
        !           763:        ictx->cell.g0set = ictx->cell.g1set = 0;
        !           764: 
        !           765:        memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
        !           766:        ictx->old_cx = 0;
        !           767:        ictx->old_cy = 0;
        !           768: }
        !           769: 
        !           770: /* Initialise input parser. */
        !           771: void
        !           772: input_init(struct window_pane *wp)
        !           773: {
        !           774:        struct input_ctx        *ictx;
        !           775: 
        !           776:        ictx = wp->ictx = xcalloc(1, sizeof *ictx);
        !           777: 
        !           778:        ictx->input_space = INPUT_BUF_START;
        !           779:        ictx->input_buf = xmalloc(INPUT_BUF_START);
        !           780: 
        !           781:        ictx->since_ground = evbuffer_new();
        !           782: 
        !           783:        input_reset(wp, 0);
        !           784: }
        !           785: 
        !           786: /* Destroy input parser. */
        !           787: void
        !           788: input_free(struct window_pane *wp)
        !           789: {
        !           790:        struct input_ctx        *ictx = wp->ictx;
        !           791: 
        !           792:        free(ictx->input_buf);
        !           793:        evbuffer_free(ictx->since_ground);
        !           794: 
        !           795:        free(ictx);
        !           796:        wp->ictx = NULL;
        !           797: }
        !           798: 
        !           799: /* Reset input state and clear screen. */
        !           800: void
        !           801: input_reset(struct window_pane *wp, int clear)
        !           802: {
        !           803:        struct input_ctx        *ictx = wp->ictx;
        !           804: 
        !           805:        input_reset_cell(ictx);
        !           806: 
        !           807:        if (clear) {
        !           808:                if (wp->mode == NULL)
        !           809:                        screen_write_start(&ictx->ctx, wp, &wp->base);
        !           810:                else
        !           811:                        screen_write_start(&ictx->ctx, NULL, &wp->base);
        !           812:                screen_write_reset(&ictx->ctx);
        !           813:                screen_write_stop(&ictx->ctx);
        !           814:        }
        !           815: 
        !           816:        *ictx->interm_buf = '\0';
        !           817:        ictx->interm_len = 0;
        !           818: 
        !           819:        *ictx->param_buf = '\0';
        !           820:        ictx->param_len = 0;
        !           821: 
        !           822:        *ictx->input_buf = '\0';
        !           823:        ictx->input_len = 0;
        !           824: 
        !           825:        ictx->state = &input_state_ground;
        !           826:        ictx->flags = 0;
        !           827: }
        !           828: 
        !           829: /* Return pending data. */
        !           830: struct evbuffer *
        !           831: input_pending(struct window_pane *wp)
        !           832: {
        !           833:        return (wp->ictx->since_ground);
        !           834: }
        !           835: 
        !           836: /* Change input state. */
        !           837: static void
        !           838: input_set_state(struct window_pane *wp, const struct input_transition *itr)
        !           839: {
        !           840:        struct input_ctx        *ictx = wp->ictx;
        !           841: 
        !           842:        if (ictx->state->exit != NULL)
        !           843:                ictx->state->exit(ictx);
        !           844:        ictx->state = itr->state;
        !           845:        if (ictx->state->enter != NULL)
        !           846:                ictx->state->enter(ictx);
        !           847: }
        !           848: 
        !           849: /* Parse input. */
        !           850: void
        !           851: input_parse(struct window_pane *wp)
        !           852: {
        !           853:        struct input_ctx                *ictx = wp->ictx;
        !           854:        const struct input_transition   *itr;
        !           855:        struct evbuffer                 *evb = wp->event->input;
        !           856:        u_char                          *buf;
        !           857:        size_t                           len, off;
        !           858: 
        !           859:        if (EVBUFFER_LENGTH(evb) == 0)
        !           860:                return;
        !           861: 
        !           862:        window_update_activity(wp->window);
        !           863:        wp->flags |= PANE_CHANGED;
        !           864: 
        !           865:        /*
        !           866:         * Open the screen. Use NULL wp if there is a mode set as don't want to
        !           867:         * update the tty.
        !           868:         */
        !           869:        if (wp->mode == NULL)
        !           870:                screen_write_start(&ictx->ctx, wp, &wp->base);
        !           871:        else
        !           872:                screen_write_start(&ictx->ctx, NULL, &wp->base);
        !           873:        ictx->wp = wp;
        !           874: 
        !           875:        buf = EVBUFFER_DATA(evb);
        !           876:        len = EVBUFFER_LENGTH(evb);
        !           877:        off = 0;
        !           878: 
        !           879:        notify_input(wp, evb);
        !           880: 
        !           881:        log_debug("%s: %%%u %s, %zu bytes: %.*s", __func__, wp->id,
        !           882:            ictx->state->name, len, (int)len, buf);
        !           883: 
        !           884:        /* Parse the input. */
        !           885:        while (off < len) {
        !           886:                ictx->ch = buf[off++];
        !           887: 
        !           888:                /* Find the transition. */
        !           889:                itr = ictx->state->transitions;
        !           890:                while (itr->first != -1 && itr->last != -1) {
        !           891:                        if (ictx->ch >= itr->first && ictx->ch <= itr->last)
        !           892:                                break;
        !           893:                        itr++;
        !           894:                }
        !           895:                if (itr->first == -1 || itr->last == -1) {
        !           896:                        /* No transition? Eh? */
        !           897:                        fatalx("no transition from state");
        !           898:                }
        !           899: 
        !           900:                /*
        !           901:                 * Any state except print stops the current collection. This is
        !           902:                 * an optimization to avoid checking if the attributes have
        !           903:                 * changed for every character. It will stop unnecessarily for
        !           904:                 * sequences that don't make a terminal change, but they should
        !           905:                 * be the minority.
        !           906:                 */
        !           907:                if (itr->handler != input_print)
        !           908:                        screen_write_collect_end(&ictx->ctx);
        !           909: 
        !           910:                /*
        !           911:                 * Execute the handler, if any. Don't switch state if it
        !           912:                 * returns non-zero.
        !           913:                 */
        !           914:                if (itr->handler != NULL && itr->handler(ictx) != 0)
        !           915:                        continue;
        !           916: 
        !           917:                /* And switch state, if necessary. */
        !           918:                if (itr->state != NULL)
        !           919:                        input_set_state(wp, itr);
        !           920: 
        !           921:                /* If not in ground state, save input. */
        !           922:                if (ictx->state != &input_state_ground)
        !           923:                        evbuffer_add(ictx->since_ground, &ictx->ch, 1);
        !           924:        }
        !           925: 
        !           926:        /* Close the screen. */
        !           927:        screen_write_stop(&ictx->ctx);
        !           928: 
        !           929:        evbuffer_drain(evb, len);
        !           930: }
        !           931: 
        !           932: /* Split the parameter list (if any). */
        !           933: static int
        !           934: input_split(struct input_ctx *ictx)
        !           935: {
        !           936:        const char      *errstr;
        !           937:        char            *ptr, *out;
        !           938:        int              n;
        !           939: 
        !           940:        ictx->param_list_len = 0;
        !           941:        if (ictx->param_len == 0)
        !           942:                return (0);
        !           943: 
        !           944:        ptr = ictx->param_buf;
        !           945:        while ((out = strsep(&ptr, ";")) != NULL) {
        !           946:                if (*out == '\0')
        !           947:                        n = -1;
        !           948:                else {
        !           949:                        n = strtonum(out, 0, INT_MAX, &errstr);
        !           950:                        if (errstr != NULL)
        !           951:                                return (-1);
        !           952:                }
        !           953: 
        !           954:                ictx->param_list[ictx->param_list_len++] = n;
        !           955:                if (ictx->param_list_len == nitems(ictx->param_list))
        !           956:                        return (-1);
        !           957:        }
        !           958: 
        !           959:        return (0);
        !           960: }
        !           961: 
        !           962: /* Get an argument or return default value. */
        !           963: static int
        !           964: input_get(struct input_ctx *ictx, u_int validx, int minval, int defval)
        !           965: {
        !           966:        int     retval;
        !           967: 
        !           968:        if (validx >= ictx->param_list_len)
        !           969:            return (defval);
        !           970: 
        !           971:        retval = ictx->param_list[validx];
        !           972:        if (retval == -1)
        !           973:                return (defval);
        !           974:        if (retval < minval)
        !           975:                return (minval);
        !           976:        return (retval);
        !           977: }
        !           978: 
        !           979: /* Reply to terminal query. */
        !           980: static void
        !           981: input_reply(struct input_ctx *ictx, const char *fmt, ...)
        !           982: {
        !           983:        va_list ap;
        !           984:        char   *reply;
        !           985: 
        !           986:        va_start(ap, fmt);
        !           987:        xvasprintf(&reply, fmt, ap);
        !           988:        va_end(ap);
        !           989: 
        !           990:        bufferevent_write(ictx->wp->event, reply, strlen(reply));
        !           991:        free(reply);
        !           992: }
        !           993: 
        !           994: /* Clear saved state. */
        !           995: static void
        !           996: input_clear(struct input_ctx *ictx)
        !           997: {
        !           998:        *ictx->interm_buf = '\0';
        !           999:        ictx->interm_len = 0;
        !          1000: 
        !          1001:        *ictx->param_buf = '\0';
        !          1002:        ictx->param_len = 0;
        !          1003: 
        !          1004:        *ictx->input_buf = '\0';
        !          1005:        ictx->input_len = 0;
        !          1006: 
        !          1007:        ictx->flags &= ~INPUT_DISCARD;
        !          1008: }
        !          1009: 
        !          1010: /* Reset for ground state. */
        !          1011: static void
        !          1012: input_ground(struct input_ctx *ictx)
        !          1013: {
        !          1014:        evbuffer_drain(ictx->since_ground, EVBUFFER_LENGTH(ictx->since_ground));
        !          1015: 
        !          1016:        if (ictx->input_space > INPUT_BUF_START) {
        !          1017:                ictx->input_space = INPUT_BUF_START;
        !          1018:                ictx->input_buf = xrealloc(ictx->input_buf, INPUT_BUF_START);
        !          1019:        }
        !          1020: }
        !          1021: 
        !          1022: /* Output this character to the screen. */
        !          1023: static int
        !          1024: input_print(struct input_ctx *ictx)
        !          1025: {
        !          1026:        int     set;
        !          1027: 
        !          1028:        set = ictx->cell.set == 0 ? ictx->cell.g0set : ictx->cell.g1set;
        !          1029:        if (set == 1)
        !          1030:                ictx->cell.cell.attr |= GRID_ATTR_CHARSET;
        !          1031:        else
        !          1032:                ictx->cell.cell.attr &= ~GRID_ATTR_CHARSET;
        !          1033: 
        !          1034:        utf8_set(&ictx->cell.cell.data, ictx->ch);
        !          1035:        screen_write_collect_add(&ictx->ctx, &ictx->cell.cell);
        !          1036: 
        !          1037:        ictx->cell.cell.attr &= ~GRID_ATTR_CHARSET;
        !          1038: 
        !          1039:        return (0);
        !          1040: }
        !          1041: 
        !          1042: /* Collect intermediate string. */
        !          1043: static int
        !          1044: input_intermediate(struct input_ctx *ictx)
        !          1045: {
        !          1046:        if (ictx->interm_len == (sizeof ictx->interm_buf) - 1)
        !          1047:                ictx->flags |= INPUT_DISCARD;
        !          1048:        else {
        !          1049:                ictx->interm_buf[ictx->interm_len++] = ictx->ch;
        !          1050:                ictx->interm_buf[ictx->interm_len] = '\0';
        !          1051:        }
        !          1052: 
        !          1053:        return (0);
        !          1054: }
        !          1055: 
        !          1056: /* Collect parameter string. */
        !          1057: static int
        !          1058: input_parameter(struct input_ctx *ictx)
        !          1059: {
        !          1060:        if (ictx->param_len == (sizeof ictx->param_buf) - 1)
        !          1061:                ictx->flags |= INPUT_DISCARD;
        !          1062:        else {
        !          1063:                ictx->param_buf[ictx->param_len++] = ictx->ch;
        !          1064:                ictx->param_buf[ictx->param_len] = '\0';
        !          1065:        }
        !          1066: 
        !          1067:        return (0);
        !          1068: }
        !          1069: 
        !          1070: /* Collect input string. */
        !          1071: static int
        !          1072: input_input(struct input_ctx *ictx)
        !          1073: {
        !          1074:        size_t available;
        !          1075: 
        !          1076:        available = ictx->input_space;
        !          1077:        while (ictx->input_len + 1 >= available) {
        !          1078:                available *= 2;
        !          1079:                if (available > INPUT_BUF_LIMIT) {
        !          1080:                        ictx->flags |= INPUT_DISCARD;
        !          1081:                        return (0);
        !          1082:                }
        !          1083:                ictx->input_buf = xrealloc(ictx->input_buf, available);
        !          1084:                ictx->input_space = available;
        !          1085:        }
        !          1086:        ictx->input_buf[ictx->input_len++] = ictx->ch;
        !          1087:        ictx->input_buf[ictx->input_len] = '\0';
        !          1088: 
        !          1089:        return (0);
        !          1090: }
        !          1091: 
        !          1092: /* Execute C0 control sequence. */
        !          1093: static int
        !          1094: input_c0_dispatch(struct input_ctx *ictx)
        !          1095: {
        !          1096:        struct screen_write_ctx *sctx = &ictx->ctx;
        !          1097:        struct window_pane      *wp = ictx->wp;
        !          1098:        struct screen           *s = sctx->s;
        !          1099: 
        !          1100:        log_debug("%s: '%c'", __func__, ictx->ch);
        !          1101: 
        !          1102:        switch (ictx->ch) {
        !          1103:        case '\000':    /* NUL */
        !          1104:                break;
        !          1105:        case '\007':    /* BEL */
        !          1106:                alerts_queue(wp->window, WINDOW_BELL);
        !          1107:                break;
        !          1108:        case '\010':    /* BS */
        !          1109:                screen_write_backspace(sctx);
        !          1110:                break;
        !          1111:        case '\011':    /* HT */
        !          1112:                /* Don't tab beyond the end of the line. */
        !          1113:                if (s->cx >= screen_size_x(s) - 1)
        !          1114:                        break;
        !          1115: 
        !          1116:                /* Find the next tab point, or use the last column if none. */
        !          1117:                do {
        !          1118:                        s->cx++;
        !          1119:                        if (bit_test(s->tabs, s->cx))
        !          1120:                                break;
        !          1121:                } while (s->cx < screen_size_x(s) - 1);
        !          1122:                break;
        !          1123:        case '\012':    /* LF */
        !          1124:        case '\013':    /* VT */
        !          1125:        case '\014':    /* FF */
        !          1126:                screen_write_linefeed(sctx, 0);
        !          1127:                break;
        !          1128:        case '\015':    /* CR */
        !          1129:                screen_write_carriagereturn(sctx);
        !          1130:                break;
        !          1131:        case '\016':    /* SO */
        !          1132:                ictx->cell.set = 1;
        !          1133:                break;
        !          1134:        case '\017':    /* SI */
        !          1135:                ictx->cell.set = 0;
        !          1136:                break;
        !          1137:        default:
        !          1138:                log_debug("%s: unknown '%c'", __func__, ictx->ch);
        !          1139:                break;
        !          1140:        }
        !          1141: 
        !          1142:        return (0);
        !          1143: }
        !          1144: 
        !          1145: /* Execute escape sequence. */
        !          1146: static int
        !          1147: input_esc_dispatch(struct input_ctx *ictx)
        !          1148: {
        !          1149:        struct screen_write_ctx         *sctx = &ictx->ctx;
        !          1150:        struct screen                   *s = sctx->s;
        !          1151:        struct input_table_entry        *entry;
        !          1152: 
        !          1153:        if (ictx->flags & INPUT_DISCARD)
        !          1154:                return (0);
        !          1155:        log_debug("%s: '%c', %s", __func__, ictx->ch, ictx->interm_buf);
        !          1156: 
        !          1157:        entry = bsearch(ictx, input_esc_table, nitems(input_esc_table),
        !          1158:            sizeof input_esc_table[0], input_table_compare);
        !          1159:        if (entry == NULL) {
        !          1160:                log_debug("%s: unknown '%c'", __func__, ictx->ch);
        !          1161:                return (0);
        !          1162:        }
        !          1163: 
        !          1164:        switch (entry->type) {
        !          1165:        case INPUT_ESC_RIS:
        !          1166:                window_pane_reset_palette(ictx->wp);
        !          1167:                input_reset_cell(ictx);
        !          1168:                screen_write_reset(sctx);
        !          1169:                break;
        !          1170:        case INPUT_ESC_IND:
        !          1171:                screen_write_linefeed(sctx, 0);
        !          1172:                break;
        !          1173:        case INPUT_ESC_NEL:
        !          1174:                screen_write_carriagereturn(sctx);
        !          1175:                screen_write_linefeed(sctx, 0);
        !          1176:                break;
        !          1177:        case INPUT_ESC_HTS:
        !          1178:                if (s->cx < screen_size_x(s))
        !          1179:                        bit_set(s->tabs, s->cx);
        !          1180:                break;
        !          1181:        case INPUT_ESC_RI:
        !          1182:                screen_write_reverseindex(sctx);
        !          1183:                break;
        !          1184:        case INPUT_ESC_DECKPAM:
        !          1185:                screen_write_mode_set(sctx, MODE_KKEYPAD);
        !          1186:                break;
        !          1187:        case INPUT_ESC_DECKPNM:
        !          1188:                screen_write_mode_clear(sctx, MODE_KKEYPAD);
        !          1189:                break;
        !          1190:        case INPUT_ESC_DECSC:
        !          1191:                memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
        !          1192:                ictx->old_cx = s->cx;
        !          1193:                ictx->old_cy = s->cy;
        !          1194:                break;
        !          1195:        case INPUT_ESC_DECRC:
        !          1196:                memcpy(&ictx->cell, &ictx->old_cell, sizeof ictx->cell);
        !          1197:                screen_write_cursormove(sctx, ictx->old_cx, ictx->old_cy);
        !          1198:                break;
        !          1199:        case INPUT_ESC_DECALN:
        !          1200:                screen_write_alignmenttest(sctx);
        !          1201:                break;
        !          1202:        case INPUT_ESC_SCSG0_ON:
        !          1203:                ictx->cell.g0set = 1;
        !          1204:                break;
        !          1205:        case INPUT_ESC_SCSG0_OFF:
        !          1206:                ictx->cell.g0set = 0;
        !          1207:                break;
        !          1208:        case INPUT_ESC_SCSG1_ON:
        !          1209:                ictx->cell.g1set = 1;
        !          1210:                break;
        !          1211:        case INPUT_ESC_SCSG1_OFF:
        !          1212:                ictx->cell.g1set = 0;
        !          1213:                break;
        !          1214:        case INPUT_ESC_ST:
        !          1215:                /* ST terminates OSC but the state transition already did it. */
        !          1216:                break;
        !          1217:        }
        !          1218: 
        !          1219:        return (0);
        !          1220: }
        !          1221: 
        !          1222: /* Execute control sequence. */
        !          1223: static int
        !          1224: input_csi_dispatch(struct input_ctx *ictx)
        !          1225: {
        !          1226:        struct screen_write_ctx        *sctx = &ictx->ctx;
        !          1227:        struct screen                  *s = sctx->s;
        !          1228:        struct input_table_entry       *entry;
        !          1229:        int                             n, m;
        !          1230:        u_int                           cx;
        !          1231: 
        !          1232:        if (ictx->flags & INPUT_DISCARD)
        !          1233:                return (0);
        !          1234: 
        !          1235:        log_debug("%s: '%c' \"%s\" \"%s\"",
        !          1236:            __func__, ictx->ch, ictx->interm_buf, ictx->param_buf);
        !          1237: 
        !          1238:        if (input_split(ictx) != 0)
        !          1239:                return (0);
        !          1240: 
        !          1241:        entry = bsearch(ictx, input_csi_table, nitems(input_csi_table),
        !          1242:            sizeof input_csi_table[0], input_table_compare);
        !          1243:        if (entry == NULL) {
        !          1244:                log_debug("%s: unknown '%c'", __func__, ictx->ch);
        !          1245:                return (0);
        !          1246:        }
        !          1247: 
        !          1248:        switch (entry->type) {
        !          1249:        case INPUT_CSI_CBT:
        !          1250:                /* Find the previous tab point, n times. */
        !          1251:                cx = s->cx;
        !          1252:                if (cx > screen_size_x(s) - 1)
        !          1253:                        cx = screen_size_x(s) - 1;
        !          1254:                n = input_get(ictx, 0, 1, 1);
        !          1255:                while (cx > 0 && n-- > 0) {
        !          1256:                        do
        !          1257:                                cx--;
        !          1258:                        while (cx > 0 && !bit_test(s->tabs, cx));
        !          1259:                }
        !          1260:                s->cx = cx;
        !          1261:                break;
        !          1262:        case INPUT_CSI_CUB:
        !          1263:                screen_write_cursorleft(sctx, input_get(ictx, 0, 1, 1));
        !          1264:                break;
        !          1265:        case INPUT_CSI_CUD:
        !          1266:                screen_write_cursordown(sctx, input_get(ictx, 0, 1, 1));
        !          1267:                break;
        !          1268:        case INPUT_CSI_CUF:
        !          1269:                screen_write_cursorright(sctx, input_get(ictx, 0, 1, 1));
        !          1270:                break;
        !          1271:        case INPUT_CSI_CUP:
        !          1272:                n = input_get(ictx, 0, 1, 1);
        !          1273:                m = input_get(ictx, 1, 1, 1);
        !          1274:                screen_write_cursormove(sctx, m - 1, n - 1);
        !          1275:                break;
        !          1276:        case INPUT_CSI_WINOPS:
        !          1277:                input_csi_dispatch_winops(ictx);
        !          1278:                break;
        !          1279:        case INPUT_CSI_CUU:
        !          1280:                screen_write_cursorup(sctx, input_get(ictx, 0, 1, 1));
        !          1281:                break;
        !          1282:        case INPUT_CSI_CNL:
        !          1283:                screen_write_carriagereturn(sctx);
        !          1284:                screen_write_cursordown(sctx, input_get(ictx, 0, 1, 1));
        !          1285:                break;
        !          1286:        case INPUT_CSI_CPL:
        !          1287:                screen_write_carriagereturn(sctx);
        !          1288:                screen_write_cursorup(sctx, input_get(ictx, 0, 1, 1));
        !          1289:                break;
        !          1290:        case INPUT_CSI_DA:
        !          1291:                switch (input_get(ictx, 0, 0, 0)) {
        !          1292:                case 0:
        !          1293:                        input_reply(ictx, "\033[?1;2c");
        !          1294:                        break;
        !          1295:                default:
        !          1296:                        log_debug("%s: unknown '%c'", __func__, ictx->ch);
        !          1297:                        break;
        !          1298:                }
        !          1299:                break;
        !          1300:        case INPUT_CSI_DA_TWO:
        !          1301:                switch (input_get(ictx, 0, 0, 0)) {
        !          1302:                case 0:
        !          1303:                        input_reply(ictx, "\033[>84;0;0c");
        !          1304:                        break;
        !          1305:                default:
        !          1306:                        log_debug("%s: unknown '%c'", __func__, ictx->ch);
        !          1307:                        break;
        !          1308:                }
        !          1309:                break;
        !          1310:        case INPUT_CSI_ECH:
        !          1311:                screen_write_clearcharacter(sctx, input_get(ictx, 0, 1, 1));
        !          1312:                break;
        !          1313:        case INPUT_CSI_DCH:
        !          1314:                screen_write_deletecharacter(sctx, input_get(ictx, 0, 1, 1),
        !          1315:                    ictx->cell.cell.bg);
        !          1316:                break;
        !          1317:        case INPUT_CSI_DECSTBM:
        !          1318:                n = input_get(ictx, 0, 1, 1);
        !          1319:                m = input_get(ictx, 1, 1, screen_size_y(s));
        !          1320:                screen_write_scrollregion(sctx, n - 1, m - 1);
        !          1321:                break;
        !          1322:        case INPUT_CSI_DL:
        !          1323:                screen_write_deleteline(sctx, input_get(ictx, 0, 1, 1),
        !          1324:                    ictx->cell.cell.bg);
        !          1325:                break;
        !          1326:        case INPUT_CSI_DSR:
        !          1327:                switch (input_get(ictx, 0, 0, 0)) {
        !          1328:                case 5:
        !          1329:                        input_reply(ictx, "\033[0n");
        !          1330:                        break;
        !          1331:                case 6:
        !          1332:                        input_reply(ictx, "\033[%u;%uR", s->cy + 1, s->cx + 1);
        !          1333:                        break;
        !          1334:                default:
        !          1335:                        log_debug("%s: unknown '%c'", __func__, ictx->ch);
        !          1336:                        break;
        !          1337:                }
        !          1338:                break;
        !          1339:        case INPUT_CSI_ED:
        !          1340:                switch (input_get(ictx, 0, 0, 0)) {
        !          1341:                case 0:
        !          1342:                        screen_write_clearendofscreen(sctx, ictx->cell.cell.bg);
        !          1343:                        break;
        !          1344:                case 1:
        !          1345:                        screen_write_clearstartofscreen(sctx, ictx->cell.cell.bg);
        !          1346:                        break;
        !          1347:                case 2:
        !          1348:                        screen_write_clearscreen(sctx, ictx->cell.cell.bg);
        !          1349:                        break;
        !          1350:                case 3:
        !          1351:                        switch (input_get(ictx, 1, 0, 0)) {
        !          1352:                        case 0:
        !          1353:                                /*
        !          1354:                                 * Linux console extension to clear history
        !          1355:                                 * (for example before locking the screen).
        !          1356:                                 */
        !          1357:                                screen_write_clearhistory(sctx);
        !          1358:                                break;
        !          1359:                        }
        !          1360:                        break;
        !          1361:                default:
        !          1362:                        log_debug("%s: unknown '%c'", __func__, ictx->ch);
        !          1363:                        break;
        !          1364:                }
        !          1365:                break;
        !          1366:        case INPUT_CSI_EL:
        !          1367:                switch (input_get(ictx, 0, 0, 0)) {
        !          1368:                case 0:
        !          1369:                        screen_write_clearendofline(sctx, ictx->cell.cell.bg);
        !          1370:                        break;
        !          1371:                case 1:
        !          1372:                        screen_write_clearstartofline(sctx, ictx->cell.cell.bg);
        !          1373:                        break;
        !          1374:                case 2:
        !          1375:                        screen_write_clearline(sctx, ictx->cell.cell.bg);
        !          1376:                        break;
        !          1377:                default:
        !          1378:                        log_debug("%s: unknown '%c'", __func__, ictx->ch);
        !          1379:                        break;
        !          1380:                }
        !          1381:                break;
        !          1382:        case INPUT_CSI_HPA:
        !          1383:                n = input_get(ictx, 0, 1, 1);
        !          1384:                screen_write_cursormove(sctx, n - 1, s->cy);
        !          1385:                break;
        !          1386:        case INPUT_CSI_ICH:
        !          1387:                screen_write_insertcharacter(sctx, input_get(ictx, 0, 1, 1),
        !          1388:                    ictx->cell.cell.bg);
        !          1389:                break;
        !          1390:        case INPUT_CSI_IL:
        !          1391:                screen_write_insertline(sctx, input_get(ictx, 0, 1, 1),
        !          1392:                    ictx->cell.cell.bg);
        !          1393:                break;
        !          1394:        case INPUT_CSI_RCP:
        !          1395:                memcpy(&ictx->cell, &ictx->old_cell, sizeof ictx->cell);
        !          1396:                screen_write_cursormove(sctx, ictx->old_cx, ictx->old_cy);
        !          1397:                break;
        !          1398:        case INPUT_CSI_RM:
        !          1399:                input_csi_dispatch_rm(ictx);
        !          1400:                break;
        !          1401:        case INPUT_CSI_RM_PRIVATE:
        !          1402:                input_csi_dispatch_rm_private(ictx);
        !          1403:                break;
        !          1404:        case INPUT_CSI_SCP:
        !          1405:                memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
        !          1406:                ictx->old_cx = s->cx;
        !          1407:                ictx->old_cy = s->cy;
        !          1408:                break;
        !          1409:        case INPUT_CSI_SGR:
        !          1410:                input_csi_dispatch_sgr(ictx);
        !          1411:                break;
        !          1412:        case INPUT_CSI_SM:
        !          1413:                input_csi_dispatch_sm(ictx);
        !          1414:                break;
        !          1415:        case INPUT_CSI_SM_PRIVATE:
        !          1416:                input_csi_dispatch_sm_private(ictx);
        !          1417:                break;
        !          1418:        case INPUT_CSI_SU:
        !          1419:                screen_write_scrollup(sctx, input_get(ictx, 0, 1, 1));
        !          1420:                break;
        !          1421:        case INPUT_CSI_TBC:
        !          1422:                switch (input_get(ictx, 0, 0, 0)) {
        !          1423:                case 0:
        !          1424:                        if (s->cx < screen_size_x(s))
        !          1425:                                bit_clear(s->tabs, s->cx);
        !          1426:                        break;
        !          1427:                case 3:
        !          1428:                        bit_nclear(s->tabs, 0, screen_size_x(s) - 1);
        !          1429:                        break;
        !          1430:                default:
        !          1431:                        log_debug("%s: unknown '%c'", __func__, ictx->ch);
        !          1432:                        break;
        !          1433:                }
        !          1434:                break;
        !          1435:        case INPUT_CSI_VPA:
        !          1436:                n = input_get(ictx, 0, 1, 1);
        !          1437:                screen_write_cursormove(sctx, s->cx, n - 1);
        !          1438:                break;
        !          1439:        case INPUT_CSI_DECSCUSR:
        !          1440:                n = input_get(ictx, 0, 0, 0);
        !          1441:                screen_set_cursor_style(s, n);
        !          1442:                break;
        !          1443:        }
        !          1444: 
        !          1445:        return (0);
        !          1446: }
        !          1447: 
        !          1448: /* Handle CSI RM. */
        !          1449: static void
        !          1450: input_csi_dispatch_rm(struct input_ctx *ictx)
        !          1451: {
        !          1452:        u_int   i;
        !          1453: 
        !          1454:        for (i = 0; i < ictx->param_list_len; i++) {
        !          1455:                switch (input_get(ictx, i, 0, -1)) {
        !          1456:                case 4:         /* IRM */
        !          1457:                        screen_write_mode_clear(&ictx->ctx, MODE_INSERT);
        !          1458:                        break;
        !          1459:                case 34:
        !          1460:                        screen_write_mode_set(&ictx->ctx, MODE_BLINKING);
        !          1461:                        break;
        !          1462:                default:
        !          1463:                        log_debug("%s: unknown '%c'", __func__, ictx->ch);
        !          1464:                        break;
        !          1465:                }
        !          1466:        }
        !          1467: }
        !          1468: 
        !          1469: /* Handle CSI private RM. */
        !          1470: static void
        !          1471: input_csi_dispatch_rm_private(struct input_ctx *ictx)
        !          1472: {
        !          1473:        struct window_pane      *wp = ictx->wp;
        !          1474:        u_int                    i;
        !          1475: 
        !          1476:        for (i = 0; i < ictx->param_list_len; i++) {
        !          1477:                switch (input_get(ictx, i, 0, -1)) {
        !          1478:                case 1:         /* DECCKM */
        !          1479:                        screen_write_mode_clear(&ictx->ctx, MODE_KCURSOR);
        !          1480:                        break;
        !          1481:                case 3:         /* DECCOLM */
        !          1482:                        screen_write_cursormove(&ictx->ctx, 0, 0);
        !          1483:                        screen_write_clearscreen(&ictx->ctx,
        !          1484:                            ictx->cell.cell.bg);
        !          1485:                        break;
        !          1486:                case 7:         /* DECAWM */
        !          1487:                        screen_write_mode_clear(&ictx->ctx, MODE_WRAP);
        !          1488:                        break;
        !          1489:                case 12:
        !          1490:                        screen_write_mode_clear(&ictx->ctx, MODE_BLINKING);
        !          1491:                        break;
        !          1492:                case 25:        /* TCEM */
        !          1493:                        screen_write_mode_clear(&ictx->ctx, MODE_CURSOR);
        !          1494:                        break;
        !          1495:                case 1000:
        !          1496:                case 1001:
        !          1497:                case 1002:
        !          1498:                case 1003:
        !          1499:                        screen_write_mode_clear(&ictx->ctx, ALL_MOUSE_MODES);
        !          1500:                        break;
        !          1501:                case 1004:
        !          1502:                        screen_write_mode_clear(&ictx->ctx, MODE_FOCUSON);
        !          1503:                        break;
        !          1504:                case 1005:
        !          1505:                        screen_write_mode_clear(&ictx->ctx, MODE_MOUSE_UTF8);
        !          1506:                        break;
        !          1507:                case 1006:
        !          1508:                        screen_write_mode_clear(&ictx->ctx, MODE_MOUSE_SGR);
        !          1509:                        break;
        !          1510:                case 47:
        !          1511:                case 1047:
        !          1512:                        window_pane_alternate_off(wp, &ictx->cell.cell, 0);
        !          1513:                        break;
        !          1514:                case 1049:
        !          1515:                        window_pane_alternate_off(wp, &ictx->cell.cell, 1);
        !          1516:                        break;
        !          1517:                case 2004:
        !          1518:                        screen_write_mode_clear(&ictx->ctx, MODE_BRACKETPASTE);
        !          1519:                        break;
        !          1520:                default:
        !          1521:                        log_debug("%s: unknown '%c'", __func__, ictx->ch);
        !          1522:                        break;
        !          1523:                }
        !          1524:        }
        !          1525: }
        !          1526: 
        !          1527: /* Handle CSI SM. */
        !          1528: static void
        !          1529: input_csi_dispatch_sm(struct input_ctx *ictx)
        !          1530: {
        !          1531:        u_int   i;
        !          1532: 
        !          1533:        for (i = 0; i < ictx->param_list_len; i++) {
        !          1534:                switch (input_get(ictx, i, 0, -1)) {
        !          1535:                case 4:         /* IRM */
        !          1536:                        screen_write_mode_set(&ictx->ctx, MODE_INSERT);
        !          1537:                        break;
        !          1538:                case 34:
        !          1539:                        screen_write_mode_clear(&ictx->ctx, MODE_BLINKING);
        !          1540:                        break;
        !          1541:                default:
        !          1542:                        log_debug("%s: unknown '%c'", __func__, ictx->ch);
        !          1543:                        break;
        !          1544:                }
        !          1545:        }
        !          1546: }
        !          1547: 
        !          1548: /* Handle CSI private SM. */
        !          1549: static void
        !          1550: input_csi_dispatch_sm_private(struct input_ctx *ictx)
        !          1551: {
        !          1552:        struct window_pane      *wp = ictx->wp;
        !          1553:        u_int                    i;
        !          1554: 
        !          1555:        for (i = 0; i < ictx->param_list_len; i++) {
        !          1556:                switch (input_get(ictx, i, 0, -1)) {
        !          1557:                case 1:         /* DECCKM */
        !          1558:                        screen_write_mode_set(&ictx->ctx, MODE_KCURSOR);
        !          1559:                        break;
        !          1560:                case 3:         /* DECCOLM */
        !          1561:                        screen_write_cursormove(&ictx->ctx, 0, 0);
        !          1562:                        screen_write_clearscreen(&ictx->ctx,
        !          1563:                            ictx->cell.cell.bg);
        !          1564:                        break;
        !          1565:                case 7:         /* DECAWM */
        !          1566:                        screen_write_mode_set(&ictx->ctx, MODE_WRAP);
        !          1567:                        break;
        !          1568:                case 12:
        !          1569:                        screen_write_mode_set(&ictx->ctx, MODE_BLINKING);
        !          1570:                        break;
        !          1571:                case 25:        /* TCEM */
        !          1572:                        screen_write_mode_set(&ictx->ctx, MODE_CURSOR);
        !          1573:                        break;
        !          1574:                case 1000:
        !          1575:                        screen_write_mode_clear(&ictx->ctx, ALL_MOUSE_MODES);
        !          1576:                        screen_write_mode_set(&ictx->ctx, MODE_MOUSE_STANDARD);
        !          1577:                        break;
        !          1578:                case 1002:
        !          1579:                        screen_write_mode_clear(&ictx->ctx, ALL_MOUSE_MODES);
        !          1580:                        screen_write_mode_set(&ictx->ctx, MODE_MOUSE_BUTTON);
        !          1581:                        break;
        !          1582:                case 1003:
        !          1583:                        screen_write_mode_clear(&ictx->ctx, ALL_MOUSE_MODES);
        !          1584:                        screen_write_mode_set(&ictx->ctx, MODE_MOUSE_ALL);
        !          1585:                        break;
        !          1586:                case 1004:
        !          1587:                        if (ictx->ctx.s->mode & MODE_FOCUSON)
        !          1588:                                break;
        !          1589:                        screen_write_mode_set(&ictx->ctx, MODE_FOCUSON);
        !          1590:                        wp->flags |= PANE_FOCUSPUSH; /* force update */
        !          1591:                        break;
        !          1592:                case 1005:
        !          1593:                        screen_write_mode_set(&ictx->ctx, MODE_MOUSE_UTF8);
        !          1594:                        break;
        !          1595:                case 1006:
        !          1596:                        screen_write_mode_set(&ictx->ctx, MODE_MOUSE_SGR);
        !          1597:                        break;
        !          1598:                case 47:
        !          1599:                case 1047:
        !          1600:                        window_pane_alternate_on(wp, &ictx->cell.cell, 0);
        !          1601:                        break;
        !          1602:                case 1049:
        !          1603:                        window_pane_alternate_on(wp, &ictx->cell.cell, 1);
        !          1604:                        break;
        !          1605:                case 2004:
        !          1606:                        screen_write_mode_set(&ictx->ctx, MODE_BRACKETPASTE);
        !          1607:                        break;
        !          1608:                default:
        !          1609:                        log_debug("%s: unknown '%c'", __func__, ictx->ch);
        !          1610:                        break;
        !          1611:                }
        !          1612:        }
        !          1613: }
        !          1614: 
        !          1615: /* Handle CSI window operations. */
        !          1616: static void
        !          1617: input_csi_dispatch_winops(struct input_ctx *ictx)
        !          1618: {
        !          1619:        struct window_pane      *wp = ictx->wp;
        !          1620:        int                      n, m;
        !          1621: 
        !          1622:        m = 0;
        !          1623:        while ((n = input_get(ictx, m, 0, -1)) != -1) {
        !          1624:                switch (n) {
        !          1625:                case 1:
        !          1626:                case 2:
        !          1627:                case 5:
        !          1628:                case 6:
        !          1629:                case 7:
        !          1630:                case 11:
        !          1631:                case 13:
        !          1632:                case 14:
        !          1633:                case 19:
        !          1634:                case 20:
        !          1635:                case 21:
        !          1636:                case 24:
        !          1637:                        break;
        !          1638:                case 3:
        !          1639:                case 4:
        !          1640:                case 8:
        !          1641:                        m++;
        !          1642:                        if (input_get(ictx, m, 0, -1) == -1)
        !          1643:                                return;
        !          1644:                        /* FALLTHROUGH */
        !          1645:                case 9:
        !          1646:                case 10:
        !          1647:                case 22:
        !          1648:                case 23:
        !          1649:                        m++;
        !          1650:                        if (input_get(ictx, m, 0, -1) == -1)
        !          1651:                                return;
        !          1652:                        break;
        !          1653:                case 18:
        !          1654:                        input_reply(ictx, "\033[8;%u;%ut", wp->sy, wp->sx);
        !          1655:                        break;
        !          1656:                default:
        !          1657:                        log_debug("%s: unknown '%c'", __func__, ictx->ch);
        !          1658:                        break;
        !          1659:                }
        !          1660:                m++;
        !          1661:        }
        !          1662: }
        !          1663: 
        !          1664: /* Handle CSI SGR for 256 colours. */
        !          1665: static void
        !          1666: input_csi_dispatch_sgr_256(struct input_ctx *ictx, int fgbg, u_int *i)
        !          1667: {
        !          1668:        struct grid_cell        *gc = &ictx->cell.cell;
        !          1669:        int                      c;
        !          1670: 
        !          1671:        (*i)++;
        !          1672:        c = input_get(ictx, *i, 0, -1);
        !          1673:        if (c == -1) {
        !          1674:                if (fgbg == 38)
        !          1675:                        gc->fg = 8;
        !          1676:                else if (fgbg == 48)
        !          1677:                        gc->bg = 8;
        !          1678:        } else {
        !          1679:                if (fgbg == 38)
        !          1680:                        gc->fg = c | COLOUR_FLAG_256;
        !          1681:                else if (fgbg == 48)
        !          1682:                        gc->bg = c | COLOUR_FLAG_256;
        !          1683:        }
        !          1684: }
        !          1685: 
        !          1686: /* Handle CSI SGR for RGB colours. */
        !          1687: static void
        !          1688: input_csi_dispatch_sgr_rgb(struct input_ctx *ictx, int fgbg, u_int *i)
        !          1689: {
        !          1690:        struct grid_cell        *gc = &ictx->cell.cell;
        !          1691:        int                      r, g, b;
        !          1692: 
        !          1693:        (*i)++;
        !          1694:        r = input_get(ictx, *i, 0, -1);
        !          1695:        if (r == -1 || r > 255)
        !          1696:                return;
        !          1697:        (*i)++;
        !          1698:        g = input_get(ictx, *i, 0, -1);
        !          1699:        if (g == -1 || g > 255)
        !          1700:                return;
        !          1701:        (*i)++;
        !          1702:        b = input_get(ictx, *i, 0, -1);
        !          1703:        if (b == -1 || b > 255)
        !          1704:                return;
        !          1705: 
        !          1706:        if (fgbg == 38)
        !          1707:                gc->fg = colour_join_rgb(r, g, b);
        !          1708:        else if (fgbg == 48)
        !          1709:                gc->bg = colour_join_rgb(r, g, b);
        !          1710: }
        !          1711: 
        !          1712: /* Handle CSI SGR. */
        !          1713: static void
        !          1714: input_csi_dispatch_sgr(struct input_ctx *ictx)
        !          1715: {
        !          1716:        struct grid_cell        *gc = &ictx->cell.cell;
        !          1717:        u_int                    i;
        !          1718:        int                      n;
        !          1719: 
        !          1720:        if (ictx->param_list_len == 0) {
        !          1721:                memcpy(gc, &grid_default_cell, sizeof *gc);
        !          1722:                return;
        !          1723:        }
        !          1724: 
        !          1725:        for (i = 0; i < ictx->param_list_len; i++) {
        !          1726:                n = input_get(ictx, i, 0, 0);
        !          1727: 
        !          1728:                if (n == 38 || n == 48) {
        !          1729:                        i++;
        !          1730:                        switch (input_get(ictx, i, 0, -1)) {
        !          1731:                        case 2:
        !          1732:                                input_csi_dispatch_sgr_rgb(ictx, n, &i);
        !          1733:                                break;
        !          1734:                        case 5:
        !          1735:                                input_csi_dispatch_sgr_256(ictx, n, &i);
        !          1736:                                break;
        !          1737:                        }
        !          1738:                        continue;
        !          1739:                }
        !          1740: 
        !          1741:                switch (n) {
        !          1742:                case 0:
        !          1743:                case 10:
        !          1744:                        memcpy(gc, &grid_default_cell, sizeof *gc);
        !          1745:                        break;
        !          1746:                case 1:
        !          1747:                        gc->attr |= GRID_ATTR_BRIGHT;
        !          1748:                        break;
        !          1749:                case 2:
        !          1750:                        gc->attr |= GRID_ATTR_DIM;
        !          1751:                        break;
        !          1752:                case 3:
        !          1753:                        gc->attr |= GRID_ATTR_ITALICS;
        !          1754:                        break;
        !          1755:                case 4:
        !          1756:                        gc->attr |= GRID_ATTR_UNDERSCORE;
        !          1757:                        break;
        !          1758:                case 5:
        !          1759:                        gc->attr |= GRID_ATTR_BLINK;
        !          1760:                        break;
        !          1761:                case 7:
        !          1762:                        gc->attr |= GRID_ATTR_REVERSE;
        !          1763:                        break;
        !          1764:                case 8:
        !          1765:                        gc->attr |= GRID_ATTR_HIDDEN;
        !          1766:                        break;
        !          1767:                case 9:
        !          1768:                        gc->attr |= GRID_ATTR_STRIKETHROUGH;
        !          1769:                        break;
        !          1770:                case 22:
        !          1771:                        gc->attr &= ~(GRID_ATTR_BRIGHT|GRID_ATTR_DIM);
        !          1772:                        break;
        !          1773:                case 23:
        !          1774:                        gc->attr &= ~GRID_ATTR_ITALICS;
        !          1775:                        break;
        !          1776:                case 24:
        !          1777:                        gc->attr &= ~GRID_ATTR_UNDERSCORE;
        !          1778:                        break;
        !          1779:                case 25:
        !          1780:                        gc->attr &= ~GRID_ATTR_BLINK;
        !          1781:                        break;
        !          1782:                case 27:
        !          1783:                        gc->attr &= ~GRID_ATTR_REVERSE;
        !          1784:                        break;
        !          1785:                case 28:
        !          1786:                        gc->attr &= ~GRID_ATTR_HIDDEN;
        !          1787:                        break;
        !          1788:                case 29:
        !          1789:                        gc->attr &= ~GRID_ATTR_STRIKETHROUGH;
        !          1790:                        break;
        !          1791:                case 30:
        !          1792:                case 31:
        !          1793:                case 32:
        !          1794:                case 33:
        !          1795:                case 34:
        !          1796:                case 35:
        !          1797:                case 36:
        !          1798:                case 37:
        !          1799:                        gc->fg = n - 30;
        !          1800:                        break;
        !          1801:                case 39:
        !          1802:                        gc->fg = 8;
        !          1803:                        break;
        !          1804:                case 40:
        !          1805:                case 41:
        !          1806:                case 42:
        !          1807:                case 43:
        !          1808:                case 44:
        !          1809:                case 45:
        !          1810:                case 46:
        !          1811:                case 47:
        !          1812:                        gc->bg = n - 40;
        !          1813:                        break;
        !          1814:                case 49:
        !          1815:                        gc->bg = 8;
        !          1816:                        break;
        !          1817:                case 90:
        !          1818:                case 91:
        !          1819:                case 92:
        !          1820:                case 93:
        !          1821:                case 94:
        !          1822:                case 95:
        !          1823:                case 96:
        !          1824:                case 97:
        !          1825:                        gc->fg = n;
        !          1826:                        break;
        !          1827:                case 100:
        !          1828:                case 101:
        !          1829:                case 102:
        !          1830:                case 103:
        !          1831:                case 104:
        !          1832:                case 105:
        !          1833:                case 106:
        !          1834:                case 107:
        !          1835:                        gc->bg = n - 10;
        !          1836:                        break;
        !          1837:                }
        !          1838:        }
        !          1839: }
        !          1840: 
        !          1841: /* DCS terminator (ST) received. */
        !          1842: static int
        !          1843: input_dcs_dispatch(struct input_ctx *ictx)
        !          1844: {
        !          1845:        const char      prefix[] = "tmux;";
        !          1846:        const u_int     prefix_len = (sizeof prefix) - 1;
        !          1847: 
        !          1848:        if (ictx->flags & INPUT_DISCARD)
        !          1849:                return (0);
        !          1850: 
        !          1851:        log_debug("%s: \"%s\"", __func__, ictx->input_buf);
        !          1852: 
        !          1853:        /* Check for tmux prefix. */
        !          1854:        if (ictx->input_len >= prefix_len &&
        !          1855:            strncmp(ictx->input_buf, prefix, prefix_len) == 0) {
        !          1856:                screen_write_rawstring(&ictx->ctx,
        !          1857:                    ictx->input_buf + prefix_len, ictx->input_len - prefix_len);
        !          1858:        }
        !          1859: 
        !          1860:        return (0);
        !          1861: }
        !          1862: 
        !          1863: /* OSC string started. */
        !          1864: static void
        !          1865: input_enter_osc(struct input_ctx *ictx)
        !          1866: {
        !          1867:        log_debug("%s", __func__);
        !          1868: 
        !          1869:        input_clear(ictx);
        !          1870: }
        !          1871: 
        !          1872: /* OSC terminator (ST) received. */
        !          1873: static void
        !          1874: input_exit_osc(struct input_ctx *ictx)
        !          1875: {
        !          1876:        u_char  *p = ictx->input_buf;
        !          1877:        u_int    option;
        !          1878: 
        !          1879:        if (ictx->flags & INPUT_DISCARD)
        !          1880:                return;
        !          1881:        if (ictx->input_len < 1 || *p < '0' || *p > '9')
        !          1882:                return;
        !          1883: 
        !          1884:        log_debug("%s: \"%s\"", __func__, p);
        !          1885: 
        !          1886:        option = 0;
        !          1887:        while (*p >= '0' && *p <= '9')
        !          1888:                option = option * 10 + *p++ - '0';
        !          1889:        if (*p == ';')
        !          1890:                p++;
        !          1891: 
        !          1892:        switch (option) {
        !          1893:        case 0:
        !          1894:        case 2:
        !          1895:                screen_set_title(ictx->ctx.s, p);
        !          1896:                server_status_window(ictx->wp->window);
        !          1897:                break;
        !          1898:        case 4:
        !          1899:                input_osc_4(ictx->wp, p);
        !          1900:                break;
        !          1901:        case 52:
        !          1902:                input_osc_52(ictx->wp, p);
        !          1903:                break;
        !          1904:        case 12:
        !          1905:                if (*p != '?') /* ? is colour request */
        !          1906:                        screen_set_cursor_colour(ictx->ctx.s, p);
        !          1907:                break;
        !          1908:        case 104:
        !          1909:                input_osc_104(ictx->wp, p);
        !          1910:                break;
        !          1911:        case 112:
        !          1912:                if (*p == '\0') /* no arguments allowed */
        !          1913:                        screen_set_cursor_colour(ictx->ctx.s, "");
        !          1914:                break;
        !          1915:        default:
        !          1916:                log_debug("%s: unknown '%u'", __func__, option);
        !          1917:                break;
        !          1918:        }
        !          1919: }
        !          1920: 
        !          1921: /* APC string started. */
        !          1922: static void
        !          1923: input_enter_apc(struct input_ctx *ictx)
        !          1924: {
        !          1925:        log_debug("%s", __func__);
        !          1926: 
        !          1927:        input_clear(ictx);
        !          1928: }
        !          1929: 
        !          1930: /* APC terminator (ST) received. */
        !          1931: static void
        !          1932: input_exit_apc(struct input_ctx *ictx)
        !          1933: {
        !          1934:        if (ictx->flags & INPUT_DISCARD)
        !          1935:                return;
        !          1936:        log_debug("%s: \"%s\"", __func__, ictx->input_buf);
        !          1937: 
        !          1938:        screen_set_title(ictx->ctx.s, ictx->input_buf);
        !          1939:        server_status_window(ictx->wp->window);
        !          1940: }
        !          1941: 
        !          1942: /* Rename string started. */
        !          1943: static void
        !          1944: input_enter_rename(struct input_ctx *ictx)
        !          1945: {
        !          1946:        log_debug("%s", __func__);
        !          1947: 
        !          1948:        input_clear(ictx);
        !          1949: }
        !          1950: 
        !          1951: /* Rename terminator (ST) received. */
        !          1952: static void
        !          1953: input_exit_rename(struct input_ctx *ictx)
        !          1954: {
        !          1955:        if (ictx->flags & INPUT_DISCARD)
        !          1956:                return;
        !          1957:        if (!options_get_number(ictx->wp->window->options, "allow-rename"))
        !          1958:                return;
        !          1959:        log_debug("%s: \"%s\"", __func__, ictx->input_buf);
        !          1960: 
        !          1961:        window_set_name(ictx->wp->window, ictx->input_buf);
        !          1962:        options_set_number(ictx->wp->window->options, "automatic-rename", 0);
        !          1963: 
        !          1964:        server_status_window(ictx->wp->window);
        !          1965: }
        !          1966: 
        !          1967: /* Open UTF-8 character. */
        !          1968: static int
        !          1969: input_utf8_open(struct input_ctx *ictx)
        !          1970: {
        !          1971:        struct utf8_data        *ud = &ictx->utf8data;
        !          1972: 
        !          1973:        if (utf8_open(ud, ictx->ch) != UTF8_MORE)
        !          1974:                fatalx("UTF-8 open invalid %#x", ictx->ch);
        !          1975: 
        !          1976:        log_debug("%s %hhu", __func__, ud->size);
        !          1977: 
        !          1978:        return (0);
        !          1979: }
        !          1980: 
        !          1981: /* Append to UTF-8 character. */
        !          1982: static int
        !          1983: input_utf8_add(struct input_ctx *ictx)
        !          1984: {
        !          1985:        struct utf8_data        *ud = &ictx->utf8data;
        !          1986: 
        !          1987:        if (utf8_append(ud, ictx->ch) != UTF8_MORE)
        !          1988:                fatalx("UTF-8 add invalid %#x", ictx->ch);
        !          1989: 
        !          1990:        log_debug("%s", __func__);
        !          1991: 
        !          1992:        return (0);
        !          1993: }
        !          1994: 
        !          1995: /* Close UTF-8 string. */
        !          1996: static int
        !          1997: input_utf8_close(struct input_ctx *ictx)
        !          1998: {
        !          1999:        struct utf8_data        *ud = &ictx->utf8data;
        !          2000: 
        !          2001:        if (utf8_append(ud, ictx->ch) != UTF8_DONE) {
        !          2002:                /*
        !          2003:                 * An error here could be invalid UTF-8 or it could be a
        !          2004:                 * nonprintable character for which we can't get the
        !          2005:                 * width. Drop it.
        !          2006:                 */
        !          2007:                return (0);
        !          2008:        }
        !          2009: 
        !          2010:        log_debug("%s %hhu '%*s' (width %hhu)", __func__, ud->size,
        !          2011:            (int)ud->size, ud->data, ud->width);
        !          2012: 
        !          2013:        utf8_copy(&ictx->cell.cell.data, ud);
        !          2014:        screen_write_cell(&ictx->ctx, &ictx->cell.cell);
        !          2015: 
        !          2016:        return (0);
        !          2017: }
        !          2018: 
        !          2019: /* Handle the OSC 4 sequence for setting (multiple) palette entries. */
        !          2020: static void
        !          2021: input_osc_4(struct window_pane *wp, const char *p)
        !          2022: {
        !          2023:        char    *copy, *s, *next = NULL;
        !          2024:        long     idx;
        !          2025:        u_int    r, g, b;
        !          2026: 
        !          2027:        copy = s = xstrdup(p);
        !          2028:        while (s != NULL && *s != '\0') {
        !          2029:                idx = strtol(s, &next, 10);
        !          2030:                if (*next++ != ';')
        !          2031:                        goto bad;
        !          2032:                if (idx < 0 || idx >= 0x100)
        !          2033:                        goto bad;
        !          2034: 
        !          2035:                s = strsep(&next, ";");
        !          2036:                if (sscanf(s, "rgb:%2x/%2x/%2x", &r, &g, &b) != 3) {
        !          2037:                        s = next;
        !          2038:                        continue;
        !          2039:                }
        !          2040: 
        !          2041:                window_pane_set_palette(wp, idx, colour_join_rgb(r, g, b));
        !          2042:                s = next;
        !          2043:        }
        !          2044: 
        !          2045:        free(copy);
        !          2046:        return;
        !          2047: 
        !          2048: bad:
        !          2049:        log_debug("bad OSC 4: %s", p);
        !          2050:        free(copy);
        !          2051: }
        !          2052: 
        !          2053: /* Handle the OSC 52 sequence for setting the clipboard. */
        !          2054: static void
        !          2055: input_osc_52(struct window_pane *wp, const char *p)
        !          2056: {
        !          2057:        char                    *end;
        !          2058:        size_t                   len;
        !          2059:        u_char                  *out;
        !          2060:        int                      outlen;
        !          2061:        struct screen_write_ctx  ctx;
        !          2062: 
        !          2063:        if ((end = strchr(p, ';')) == NULL)
        !          2064:                return;
        !          2065:        end++;
        !          2066:        if (*end == '\0')
        !          2067:                return;
        !          2068: 
        !          2069:        len = (strlen(end) / 4) * 3;
        !          2070:        if (len == 0)
        !          2071:                return;
        !          2072: 
        !          2073:        out = xmalloc(len);
        !          2074:        if ((outlen = b64_pton(end, out, len)) == -1) {
        !          2075:                free(out);
        !          2076:                return;
        !          2077:        }
        !          2078: 
        !          2079:        if (options_get_number(global_options, "set-clipboard")) {
        !          2080:                screen_write_start(&ctx, wp, NULL);
        !          2081:                screen_write_setselection(&ctx, out, outlen);
        !          2082:                screen_write_stop(&ctx);
        !          2083:        }
        !          2084:        paste_add(out, outlen);
        !          2085: }
        !          2086: 
        !          2087: /* Handle the OSC 104 sequence for unsetting (multiple) palette entries. */
        !          2088: static void
        !          2089: input_osc_104(struct window_pane *wp, const char *p)
        !          2090: {
        !          2091:        char    *copy, *s;
        !          2092:        long    idx;
        !          2093: 
        !          2094:        if (*p == '\0') {
        !          2095:                window_pane_reset_palette(wp);
        !          2096:                return;
        !          2097:        }
        !          2098: 
        !          2099:        copy = s = xstrdup(p);
        !          2100:        while (*s != '\0') {
        !          2101:                idx = strtol(s, &s, 10);
        !          2102:                if (*s != '\0' && *s != ';')
        !          2103:                        goto bad;
        !          2104:                if (idx < 0 || idx >= 0x100)
        !          2105:                        goto bad;
        !          2106: 
        !          2107:                window_pane_unset_palette(wp, idx);
        !          2108:                if (*s == ';')
        !          2109:                        s++;
        !          2110:        }
        !          2111:        free(copy);
        !          2112:        return;
        !          2113: 
        !          2114: bad:
        !          2115:        log_debug("bad OSC 104: %s", p);
        !          2116:        free(copy);
        !          2117: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>