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

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

1.28    ! nicm        1: /* $OpenBSD$ */
1.1       nicm        2:
                      3: /*
                      4:  * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
                      5:  *
                      6:  * Permission to use, copy, modify, and distribute this software for any
                      7:  * purpose with or without fee is hereby granted, provided that the above
                      8:  * copyright notice and this permission notice appear in all copies.
                      9:  *
                     10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     12:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     14:  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
                     15:  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
                     16:  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     17:  */
                     18:
                     19: #include <sys/types.h>
                     20:
                     21: #include <stdlib.h>
                     22: #include <string.h>
                     23:
                     24: #include "tmux.h"
                     25:
1.28    ! nicm       26: /*
        !            27:  * Based on the description by Paul Williams at:
        !            28:  *
        !            29:  * http://vt100.net/emu/dec_ansi_parser
        !            30:  *
        !            31:  * With the following changes:
        !            32:  *
        !            33:  * - 7-bit only.
        !            34:  *
        !            35:  * - Support for UTF-8.
        !            36:  *
        !            37:  * - OSC (but not APC) may be terminated by \007 as well as ST.
        !            38:  *
        !            39:  * - A state for APC similar to OSC. Some terminals appear to use this to set
        !            40:  *   the title.
        !            41:  *
        !            42:  * - A state for the screen \033k...\033\\ sequence to rename a window. This is
        !            43:  *   pretty stupid but not supporting it is more trouble than it is worth.
        !            44:  */
        !            45:
        !            46: /* Helper functions. */
        !            47: int    input_split(struct input_ctx *);
        !            48: int    input_get(struct input_ctx *, u_int, int, int);
        !            49: void   input_reply(struct input_ctx *, const char *, ...);
        !            50:
        !            51: /* Transition entry/exit handlers. */
        !            52: void   input_clear(struct input_ctx *);
        !            53: void   input_enter_dcs(struct input_ctx *);
        !            54: void   input_exit_dcs(struct input_ctx *);
        !            55: void   input_enter_osc(struct input_ctx *);
        !            56: void   input_exit_osc(struct input_ctx *);
        !            57: void   input_enter_apc(struct input_ctx *);
        !            58: void   input_exit_apc(struct input_ctx *);
        !            59: void   input_enter_rename(struct input_ctx *);
        !            60: void   input_exit_rename(struct input_ctx *);
        !            61:
        !            62: /* Input state handlers. */
        !            63: int    input_print(struct input_ctx *);
        !            64: int    input_intermediate(struct input_ctx *);
        !            65: int    input_parameter(struct input_ctx *);
        !            66: int    input_input(struct input_ctx *);
        !            67: int    input_c0_dispatch(struct input_ctx *);
        !            68: int    input_esc_dispatch(struct input_ctx *);
        !            69: int    input_csi_dispatch(struct input_ctx *);
        !            70: void   input_csi_dispatch_sgr(struct input_ctx *);
        !            71: int    input_utf8_open(struct input_ctx *);
        !            72: int    input_utf8_add(struct input_ctx *);
        !            73: int    input_utf8_close(struct input_ctx *);
        !            74:
        !            75: /* Command table comparison function. */
        !            76: int    input_table_compare(const void *, const void *);
        !            77:
        !            78: /* Command table entry. */
        !            79: struct input_table_entry {
        !            80:        int             ch;
        !            81:        const char     *interm;
        !            82:        int             type;
1.1       nicm       83: };
                     84:
1.28    ! nicm       85: /* Escape commands. */
        !            86: enum input_esc_type {
        !            87:        INPUT_ESC_DECALN,
        !            88:        INPUT_ESC_DECKPAM,
        !            89:        INPUT_ESC_DECKPNM,
        !            90:        INPUT_ESC_DECRC,
        !            91:        INPUT_ESC_DECSC,
        !            92:        INPUT_ESC_HTS,
        !            93:        INPUT_ESC_IND,
        !            94:        INPUT_ESC_NEL,
        !            95:        INPUT_ESC_RI,
        !            96:        INPUT_ESC_RIS,
        !            97:        INPUT_ESC_SCSOFF_G0,
        !            98:        INPUT_ESC_SCSON_G0,
        !            99: };
1.1       nicm      100:
1.28    ! nicm      101: /* Escape command table. */
        !           102: const struct input_table_entry input_esc_table[] = {
        !           103:        { '0', "(", INPUT_ESC_SCSOFF_G0 },
        !           104:        { '7', "",  INPUT_ESC_DECSC },
        !           105:        { '8', "",  INPUT_ESC_DECRC },
        !           106:        { '8', "#", INPUT_ESC_DECALN },
        !           107:        { '=', "",  INPUT_ESC_DECKPAM },
        !           108:        { '>', "",  INPUT_ESC_DECKPNM },
        !           109:        { 'B', "(", INPUT_ESC_SCSON_G0 },
        !           110:        { 'D', "",  INPUT_ESC_IND },
        !           111:        { 'E', "",  INPUT_ESC_NEL },
        !           112:        { 'H', "",  INPUT_ESC_HTS },
        !           113:        { 'M', "",  INPUT_ESC_RI },
        !           114:        { 'c', "",  INPUT_ESC_RIS },
        !           115: };
1.1       nicm      116:
1.28    ! nicm      117: /* Control (CSI) commands. */
        !           118: enum input_csi_type {
        !           119:        INPUT_CSI_CBT,
        !           120:        INPUT_CSI_CUB,
        !           121:        INPUT_CSI_CUD,
        !           122:        INPUT_CSI_CUF,
        !           123:        INPUT_CSI_CUP,
        !           124:        INPUT_CSI_CUU,
        !           125:        INPUT_CSI_DA,
        !           126:        INPUT_CSI_DCH,
        !           127:        INPUT_CSI_DECSTBM,
        !           128:        INPUT_CSI_DL,
        !           129:        INPUT_CSI_DSR,
        !           130:        INPUT_CSI_ED,
        !           131:        INPUT_CSI_EL,
        !           132:        INPUT_CSI_HPA,
        !           133:        INPUT_CSI_ICH,
        !           134:        INPUT_CSI_IL,
        !           135:        INPUT_CSI_RM,
        !           136:        INPUT_CSI_RM_PRIVATE,
        !           137:        INPUT_CSI_SGR,
        !           138:        INPUT_CSI_SM,
        !           139:        INPUT_CSI_SM_PRIVATE,
        !           140:        INPUT_CSI_TBC,
        !           141:        INPUT_CSI_VPA,
        !           142: };
1.1       nicm      143:
1.28    ! nicm      144: /* Control (CSI) command table. */
        !           145: const struct input_table_entry input_csi_table[] = {
        !           146:        { '@', "",  INPUT_CSI_ICH },
        !           147:        { 'A', "",  INPUT_CSI_CUU },
        !           148:        { 'B', "",  INPUT_CSI_CUD },
        !           149:        { 'C', "",  INPUT_CSI_CUF },
        !           150:        { 'D', "",  INPUT_CSI_CUB },
        !           151:        { 'G', "",  INPUT_CSI_HPA },
        !           152:        { 'H', "",  INPUT_CSI_CUP },
        !           153:        { 'J', "",  INPUT_CSI_ED },
        !           154:        { 'K', "",  INPUT_CSI_EL },
        !           155:        { 'L', "",  INPUT_CSI_IL },
        !           156:        { 'M', "",  INPUT_CSI_DL },
        !           157:        { 'P', "",  INPUT_CSI_DCH },
        !           158:        { 'Z', "",  INPUT_CSI_CBT },
        !           159:        { 'c', "",  INPUT_CSI_DA },
        !           160:        { 'd', "",  INPUT_CSI_VPA },
        !           161:        { 'f', "",  INPUT_CSI_CUP },
        !           162:        { 'g', "",  INPUT_CSI_TBC },
        !           163:        { 'h', "",  INPUT_CSI_SM },
        !           164:        { 'h', "?", INPUT_CSI_SM_PRIVATE },
        !           165:        { 'l', "",  INPUT_CSI_RM },
        !           166:        { 'l', "?", INPUT_CSI_RM_PRIVATE },
        !           167:        { 'm', "",  INPUT_CSI_SGR },
        !           168:        { 'n', "",  INPUT_CSI_DSR },
        !           169:        { 'r', "",  INPUT_CSI_DECSTBM },
        !           170: };
1.1       nicm      171:
1.28    ! nicm      172: /* Input transition. */
        !           173: struct input_transition {
        !           174:        int                             first;
        !           175:        int                             last;
1.1       nicm      176:
1.28    ! nicm      177:        int                             (*handler)(struct input_ctx *);
        !           178:        const struct input_state       *state;
        !           179: };
1.1       nicm      180:
1.28    ! nicm      181: /* Input state. */
        !           182: struct input_state {
        !           183:        const char                      *name;
        !           184:        void                            (*enter)(struct input_ctx *);
        !           185:        void                            (*exit)(struct input_ctx *);
        !           186:        const struct input_transition   *transitions;
        !           187: };
1.1       nicm      188:
1.28    ! nicm      189: /* State transitions available from all states. */
        !           190: #define INPUT_STATE_ANYWHERE \
        !           191:        { 0x18, 0x18, input_c0_dispatch, &input_state_ground }, \
        !           192:        { 0x1a, 0x1a, input_c0_dispatch, &input_state_ground }, \
        !           193:        { 0x1b, 0x1b, NULL,              &input_state_esc_enter }
        !           194:
        !           195: /* Forward declarations of state tables. */
        !           196: const struct input_transition input_state_ground_table[];
        !           197: const struct input_transition input_state_esc_enter_table[];
        !           198: const struct input_transition input_state_esc_intermediate_table[];
        !           199: const struct input_transition input_state_csi_enter_table[];
        !           200: const struct input_transition input_state_csi_parameter_table[];
        !           201: const struct input_transition input_state_csi_intermediate_table[];
        !           202: const struct input_transition input_state_csi_ignore_table[];
        !           203: const struct input_transition input_state_dcs_enter_table[];
        !           204: const struct input_transition input_state_dcs_parameter_table[];
        !           205: const struct input_transition input_state_dcs_intermediate_table[];
        !           206: const struct input_transition input_state_dcs_handler_table[];
        !           207: const struct input_transition input_state_dcs_ignore_table[];
        !           208: const struct input_transition input_state_osc_string_table[];
        !           209: const struct input_transition input_state_apc_string_table[];
        !           210: const struct input_transition input_state_rename_string_table[];
        !           211: const struct input_transition input_state_consume_st_table[];
        !           212: const struct input_transition input_state_utf8_three_table[];
        !           213: const struct input_transition input_state_utf8_two_table[];
        !           214: const struct input_transition input_state_utf8_one_table[];
        !           215:
        !           216: /* ground state definition. */
        !           217: const struct input_state input_state_ground = {
        !           218:        "ground",
        !           219:        NULL, NULL,
        !           220:        input_state_ground_table
        !           221: };
1.1       nicm      222:
1.28    ! nicm      223: /* esc_enter state definition. */
        !           224: const struct input_state input_state_esc_enter = {
        !           225:        "esc_enter",
        !           226:        input_clear, NULL,
        !           227:        input_state_esc_enter_table
        !           228: };
1.1       nicm      229:
1.28    ! nicm      230: /* esc_intermediate state definition. */
        !           231: const struct input_state input_state_esc_intermediate = {
        !           232:        "esc_intermediate",
        !           233:        NULL, NULL,
        !           234:        input_state_esc_intermediate_table
        !           235: };
1.1       nicm      236:
1.28    ! nicm      237: /* csi_enter state definition. */
        !           238: const struct input_state input_state_csi_enter = {
        !           239:        "csi_enter",
        !           240:        input_clear, NULL,
        !           241:        input_state_csi_enter_table
        !           242: };
1.1       nicm      243:
1.28    ! nicm      244: /* csi_parameter state definition. */
        !           245: const struct input_state input_state_csi_parameter = {
        !           246:        "csi_parameter",
        !           247:        NULL, NULL,
        !           248:        input_state_csi_parameter_table
        !           249: };
1.1       nicm      250:
1.28    ! nicm      251: /* csi_intermediate state definition. */
        !           252: const struct input_state input_state_csi_intermediate = {
        !           253:        "csi_intermediate",
        !           254:        NULL, NULL,
        !           255:        input_state_csi_intermediate_table
        !           256: };
1.1       nicm      257:
1.28    ! nicm      258: /* csi_ignore state definition. */
        !           259: const struct input_state input_state_csi_ignore = {
        !           260:        "csi_ignore",
        !           261:        NULL, NULL,
        !           262:        input_state_csi_ignore_table
        !           263: };
1.1       nicm      264:
1.28    ! nicm      265: /* dcs_enter state definition. */
        !           266: const struct input_state input_state_dcs_enter = {
        !           267:        "dcs_enter",
        !           268:        input_clear, NULL,
        !           269:        input_state_dcs_enter_table
        !           270: };
1.1       nicm      271:
1.28    ! nicm      272: /* dcs_parameter state definition. */
        !           273: const struct input_state input_state_dcs_parameter = {
        !           274:        "dcs_parameter",
        !           275:        NULL, NULL,
        !           276:        input_state_dcs_parameter_table
        !           277: };
1.1       nicm      278:
1.28    ! nicm      279: /* dcs_intermediate state definition. */
        !           280: const struct input_state input_state_dcs_intermediate = {
        !           281:        "dcs_intermediate",
        !           282:        NULL, NULL,
        !           283:        input_state_dcs_intermediate_table
        !           284: };
1.1       nicm      285:
1.28    ! nicm      286: /* dcs_handler state definition. */
        !           287: const struct input_state input_state_dcs_handler = {
        !           288:        "dcs_handler",
        !           289:        input_enter_dcs, input_exit_dcs,
        !           290:        input_state_dcs_handler_table
        !           291: };
1.1       nicm      292:
1.28    ! nicm      293: /* dcs_ignore state definition. */
        !           294: const struct input_state input_state_dcs_ignore = {
        !           295:        "dcs_ignore",
        !           296:        NULL, NULL,
        !           297:        input_state_dcs_ignore_table
        !           298: };
1.1       nicm      299:
1.28    ! nicm      300: /* osc_string state definition. */
        !           301: const struct input_state input_state_osc_string = {
        !           302:        "osc_string",
        !           303:        input_enter_osc, input_exit_osc,
        !           304:        input_state_osc_string_table
        !           305: };
1.1       nicm      306:
1.28    ! nicm      307: /* apc_string state definition. */
        !           308: const struct input_state input_state_apc_string = {
        !           309:        "apc_string",
        !           310:        input_enter_apc, input_exit_apc,
        !           311:        input_state_apc_string_table
        !           312: };
1.1       nicm      313:
1.28    ! nicm      314: /* rename_string state definition. */
        !           315: const struct input_state input_state_rename_string = {
        !           316:        "rename_string",
        !           317:        input_enter_rename, input_exit_rename,
        !           318:        input_state_rename_string_table
        !           319: };
1.1       nicm      320:
1.28    ! nicm      321: /* consume_st state definition. */
        !           322: const struct input_state input_state_consume_st = {
        !           323:        "consume_st",
        !           324:        NULL, NULL,
        !           325:        input_state_consume_st_table
        !           326: };
1.1       nicm      327:
1.28    ! nicm      328: /* utf8_three state definition. */
        !           329: const struct input_state input_state_utf8_three = {
        !           330:        "utf8_three",
        !           331:        NULL, NULL,
        !           332:        input_state_utf8_three_table
        !           333: };
1.1       nicm      334:
1.28    ! nicm      335: /* utf8_two state definition. */
        !           336: const struct input_state input_state_utf8_two = {
        !           337:        "utf8_two",
        !           338:        NULL, NULL,
        !           339:        input_state_utf8_two_table
        !           340: };
1.1       nicm      341:
1.28    ! nicm      342: /* utf8_one state definition. */
        !           343: const struct input_state input_state_utf8_one = {
        !           344:        "utf8_one",
        !           345:        NULL, NULL,
        !           346:        input_state_utf8_one_table
        !           347: };
1.1       nicm      348:
1.28    ! nicm      349: /* ground state table. */
        !           350: const struct input_transition input_state_ground_table[] = {
        !           351:        INPUT_STATE_ANYWHERE,
        !           352:
        !           353:        { 0x00, 0x17, input_c0_dispatch, NULL },
        !           354:        { 0x19, 0x19, input_c0_dispatch, NULL },
        !           355:        { 0x1c, 0x1f, input_c0_dispatch, NULL },
        !           356:        { 0x20, 0x7e, input_print,       NULL },
        !           357:        { 0x7f, 0x7f, NULL,              NULL },
        !           358:        { 0x80, 0xc1, input_print,       NULL },
        !           359:        { 0xc2, 0xdf, input_utf8_open,   &input_state_utf8_one },
        !           360:        { 0xe0, 0xef, input_utf8_open,   &input_state_utf8_two },
        !           361:        { 0xf0, 0xf4, input_utf8_open,   &input_state_utf8_three },
        !           362:        { 0xf5, 0xff, input_print,       NULL },
1.1       nicm      363:
1.28    ! nicm      364:        { -1, -1, NULL, NULL }
        !           365: };
1.13      nicm      366:
1.28    ! nicm      367: /* esc_enter state table. */
        !           368: const struct input_transition input_state_esc_enter_table[] = {
        !           369:        INPUT_STATE_ANYWHERE,
        !           370:
        !           371:        { 0x00, 0x17, input_c0_dispatch,  NULL },
        !           372:        { 0x19, 0x19, input_c0_dispatch,  NULL },
        !           373:        { 0x1c, 0x1f, input_c0_dispatch,  NULL },
        !           374:        { 0x20, 0x2f, input_intermediate, &input_state_esc_intermediate },
        !           375:        { 0x30, 0x4f, input_esc_dispatch, &input_state_ground },
        !           376:        { 0x50, 0x50, NULL,               &input_state_dcs_enter },
        !           377:        { 0x51, 0x57, input_esc_dispatch, &input_state_ground },
        !           378:        { 0x58, 0x58, NULL,               &input_state_consume_st },
        !           379:        { 0x59, 0x59, input_esc_dispatch, &input_state_ground },
        !           380:        { 0x5a, 0x5a, input_esc_dispatch, &input_state_ground },
        !           381:        { 0x5b, 0x5b, NULL,               &input_state_csi_enter },
        !           382:        { 0x5c, 0x5c, input_esc_dispatch, &input_state_ground },
        !           383:        { 0x5d, 0x5d, NULL,               &input_state_osc_string },
        !           384:        { 0x5e, 0x5e, NULL,               &input_state_consume_st },
        !           385:        { 0x5f, 0x5f, NULL,               &input_state_apc_string },
        !           386:        { 0x60, 0x6a, input_esc_dispatch, &input_state_ground },
        !           387:        { 0x6b, 0x6b, NULL,               &input_state_rename_string },
        !           388:        { 0x6c, 0x7c, input_esc_dispatch, &input_state_ground },
        !           389:        { 0x7f, 0xff, NULL,               NULL },
1.1       nicm      390:
1.28    ! nicm      391:        { -1, -1, NULL, NULL }
        !           392: };
1.1       nicm      393:
1.28    ! nicm      394: /* esc_interm state table. */
        !           395: const struct input_transition input_state_esc_intermediate_table[] = {
        !           396:        INPUT_STATE_ANYWHERE,
        !           397:
        !           398:        { 0x00, 0x17, input_c0_dispatch,  NULL },
        !           399:        { 0x19, 0x19, input_c0_dispatch,  NULL },
        !           400:        { 0x1c, 0x1f, input_c0_dispatch,  NULL },
        !           401:        { 0x20, 0x2f, input_intermediate, NULL },
        !           402:        { 0x30, 0x7e, input_esc_dispatch, &input_state_ground },
        !           403:        { 0x7f, 0xff, NULL,               NULL },
1.1       nicm      404:
1.28    ! nicm      405:        { -1, -1, NULL, NULL }
        !           406: };
1.1       nicm      407:
1.28    ! nicm      408: /* csi_enter state table. */
        !           409: const struct input_transition input_state_csi_enter_table[] = {
        !           410:        INPUT_STATE_ANYWHERE,
        !           411:
        !           412:        { 0x00, 0x17, input_c0_dispatch,  NULL },
        !           413:        { 0x19, 0x19, input_c0_dispatch,  NULL },
        !           414:        { 0x1c, 0x1f, input_c0_dispatch,  NULL },
        !           415:        { 0x20, 0x2f, input_intermediate, &input_state_csi_intermediate },
        !           416:        { 0x30, 0x39, input_parameter,    &input_state_csi_parameter },
        !           417:        { 0x3a, 0x3a, NULL,               &input_state_csi_ignore },
        !           418:        { 0x3b, 0x3b, input_parameter,    &input_state_csi_parameter },
        !           419:        { 0x3c, 0x3f, input_intermediate, &input_state_csi_parameter },
        !           420:        { 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
        !           421:        { 0x7f, 0xff, NULL,               NULL },
1.1       nicm      422:
1.28    ! nicm      423:        { -1, -1, NULL, NULL }
        !           424: };
1.1       nicm      425:
1.28    ! nicm      426: /* csi_parameter state table. */
        !           427: const struct input_transition input_state_csi_parameter_table[] = {
        !           428:        INPUT_STATE_ANYWHERE,
        !           429:
        !           430:        { 0x00, 0x17, input_c0_dispatch,  NULL },
        !           431:        { 0x19, 0x19, input_c0_dispatch,  NULL },
        !           432:        { 0x1c, 0x1f, input_c0_dispatch,  NULL },
        !           433:        { 0x20, 0x2f, input_intermediate, &input_state_csi_intermediate },
        !           434:        { 0x30, 0x39, input_parameter,    NULL },
        !           435:        { 0x3a, 0x3a, NULL,               &input_state_csi_ignore },
        !           436:        { 0x3b, 0x3b, input_parameter,    NULL },
        !           437:        { 0x3c, 0x3f, NULL,               &input_state_csi_ignore },
        !           438:        { 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
        !           439:        { 0x7f, 0xff, NULL,               NULL },
1.1       nicm      440:
1.28    ! nicm      441:        { -1, -1, NULL, NULL }
        !           442: };
1.1       nicm      443:
1.28    ! nicm      444: /* csi_intermediate state table. */
        !           445: const struct input_transition input_state_csi_intermediate_table[] = {
        !           446:        INPUT_STATE_ANYWHERE,
        !           447:
        !           448:        { 0x00, 0x17, input_c0_dispatch,  NULL },
        !           449:        { 0x19, 0x19, input_c0_dispatch,  NULL },
        !           450:        { 0x1c, 0x1f, input_c0_dispatch,  NULL },
        !           451:        { 0x20, 0x2f, input_intermediate, NULL },
        !           452:        { 0x30, 0x3f, NULL,               &input_state_csi_ignore },
        !           453:        { 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
        !           454:        { 0x7f, 0xff, NULL,               NULL },
1.1       nicm      455:
1.28    ! nicm      456:        { -1, -1, NULL, NULL }
        !           457: };
1.1       nicm      458:
1.28    ! nicm      459: /* csi_ignore state table. */
        !           460: const struct input_transition input_state_csi_ignore_table[] = {
        !           461:        INPUT_STATE_ANYWHERE,
        !           462:
        !           463:        { 0x00, 0x17, input_c0_dispatch, NULL },
        !           464:        { 0x19, 0x19, input_c0_dispatch, NULL },
        !           465:        { 0x1c, 0x1f, input_c0_dispatch, NULL },
        !           466:        { 0x20, 0x3f, NULL,              NULL },
        !           467:        { 0x40, 0x7e, NULL,              &input_state_ground },
        !           468:        { 0x7f, 0xff, NULL,              NULL },
1.1       nicm      469:
1.28    ! nicm      470:        { -1, -1, NULL, NULL }
        !           471: };
1.1       nicm      472:
1.28    ! nicm      473: /* dcs_enter state table. */
        !           474: const struct input_transition input_state_dcs_enter_table[] = {
        !           475:        INPUT_STATE_ANYWHERE,
        !           476:
        !           477:        { 0x00, 0x17, NULL,               NULL },
        !           478:        { 0x19, 0x19, NULL,               NULL },
        !           479:        { 0x1c, 0x1f, NULL,               NULL },
        !           480:        { 0x20, 0x2f, input_intermediate, &input_state_dcs_intermediate },
        !           481:        { 0x30, 0x39, input_parameter,    &input_state_dcs_parameter },
        !           482:        { 0x3a, 0x3a, NULL,               &input_state_dcs_ignore },
        !           483:        { 0x3b, 0x3b, input_parameter,    &input_state_dcs_parameter },
        !           484:        { 0x3c, 0x3f, input_intermediate, &input_state_dcs_parameter },
        !           485:        { 0x40, 0x7e, NULL,               &input_state_dcs_handler },
        !           486:        { 0x7f, 0xff, NULL,               NULL },
1.1       nicm      487:
1.28    ! nicm      488:        { -1, -1, NULL, NULL }
        !           489: };
1.1       nicm      490:
1.28    ! nicm      491: /* dcs_parameter state table. */
        !           492: const struct input_transition input_state_dcs_parameter_table[] = {
        !           493:        INPUT_STATE_ANYWHERE,
        !           494:
        !           495:        { 0x00, 0x17, NULL,               NULL },
        !           496:        { 0x19, 0x19, NULL,               NULL },
        !           497:        { 0x1c, 0x1f, NULL,               NULL },
        !           498:        { 0x20, 0x2f, input_intermediate, &input_state_dcs_intermediate },
        !           499:        { 0x30, 0x39, input_parameter,    NULL },
        !           500:        { 0x3a, 0x3a, NULL,               &input_state_dcs_ignore },
        !           501:        { 0x3b, 0x3b, input_parameter,    NULL },
        !           502:        { 0x3c, 0x3f, NULL,               &input_state_dcs_ignore },
        !           503:        { 0x40, 0x7e, NULL,               &input_state_dcs_handler },
        !           504:        { 0x7f, 0xff, NULL,               NULL },
1.1       nicm      505:
1.28    ! nicm      506:        { -1, -1, NULL, NULL }
        !           507: };
1.1       nicm      508:
1.28    ! nicm      509: /* dcs_interm state table. */
        !           510: const struct input_transition input_state_dcs_intermediate_table[] = {
        !           511:        INPUT_STATE_ANYWHERE,
        !           512:
        !           513:        { 0x00, 0x17, NULL,               NULL },
        !           514:        { 0x19, 0x19, NULL,               NULL },
        !           515:        { 0x1c, 0x1f, NULL,               NULL },
        !           516:        { 0x20, 0x2f, input_intermediate, NULL },
        !           517:        { 0x30, 0x3f, NULL,               &input_state_dcs_ignore },
        !           518:        { 0x40, 0x7e, NULL,               &input_state_dcs_handler },
        !           519:        { 0x7f, 0xff, NULL,               NULL },
1.1       nicm      520:
1.28    ! nicm      521:        { -1, -1, NULL, NULL }
        !           522: };
1.1       nicm      523:
1.28    ! nicm      524: /* dcs_handler state table. */
        !           525: const struct input_transition input_state_dcs_handler_table[] = {
        !           526:        INPUT_STATE_ANYWHERE,
        !           527:
        !           528:        { 0x00, 0x17, NULL,         NULL },
        !           529:        { 0x19, 0x19, input_input,  NULL },
        !           530:        { 0x1c, 0x1f, input_input,  NULL },
        !           531:        { 0x20, 0x7e, input_input,  NULL },
        !           532:        { 0x7f, 0xff, NULL,         NULL },
1.1       nicm      533:
1.28    ! nicm      534:        { -1, -1, NULL, NULL }
        !           535: };
1.1       nicm      536:
1.28    ! nicm      537: /* device_ignore state table. */
        !           538: const struct input_transition input_state_dcs_ignore_table[] = {
        !           539:        INPUT_STATE_ANYWHERE,
        !           540:
        !           541:        { 0x00, 0x17, NULL,         NULL },
        !           542:        { 0x19, 0x19, NULL,         NULL },
        !           543:        { 0x1c, 0x1f, NULL,         NULL },
        !           544:        { 0x20, 0xff, NULL,         NULL },
1.1       nicm      545:
1.28    ! nicm      546:        { -1, -1, NULL, NULL }
        !           547: };
1.1       nicm      548:
1.28    ! nicm      549: /* osc_string state table. */
        !           550: const struct input_transition input_state_osc_string_table[] = {
        !           551:        INPUT_STATE_ANYWHERE,
        !           552:
        !           553:        { 0x00, 0x06, NULL,         NULL },
        !           554:        { 0x07, 0x07, NULL,         &input_state_ground },
        !           555:        { 0x08, 0x17, NULL,         NULL },
        !           556:        { 0x19, 0x19, NULL,         NULL },
        !           557:        { 0x1c, 0x1f, NULL,         NULL },
        !           558:        { 0x20, 0xff, input_input,  NULL },
1.1       nicm      559:
1.28    ! nicm      560:        { -1, -1, NULL, NULL }
        !           561: };
1.1       nicm      562:
1.28    ! nicm      563: /* apc_string state table. */
        !           564: const struct input_transition input_state_apc_string_table[] = {
        !           565:        INPUT_STATE_ANYWHERE,
        !           566:
        !           567:        { 0x00, 0x17, NULL,         NULL },
        !           568:        { 0x19, 0x19, NULL,         NULL },
        !           569:        { 0x1c, 0x1f, NULL,         NULL },
        !           570:        { 0x20, 0xff, input_input,  NULL },
1.1       nicm      571:
1.28    ! nicm      572:        { -1, -1, NULL, NULL }
        !           573: };
1.1       nicm      574:
1.28    ! nicm      575: /* rename_string state table. */
        !           576: const struct input_transition input_state_rename_string_table[] = {
        !           577:        INPUT_STATE_ANYWHERE,
        !           578:
        !           579:        { 0x00, 0x17, NULL,         NULL },
        !           580:        { 0x19, 0x19, NULL,         NULL },
        !           581:        { 0x1c, 0x1f, NULL,         NULL },
        !           582:        { 0x20, 0xff, input_input,  NULL },
1.1       nicm      583:
1.28    ! nicm      584:        { -1, -1, NULL, NULL }
        !           585: };
1.1       nicm      586:
1.28    ! nicm      587: /* consume_st state table. */
        !           588: const struct input_transition input_state_consume_st_table[] = {
        !           589:        INPUT_STATE_ANYWHERE,
        !           590:
        !           591:        { 0x00, 0x17, NULL,         NULL },
        !           592:        { 0x19, 0x19, NULL,         NULL },
        !           593:        { 0x1c, 0x1f, NULL,         NULL },
        !           594:        { 0x20, 0xff, NULL,         NULL },
1.6       nicm      595:
1.28    ! nicm      596:        { -1, -1, NULL, NULL }
        !           597: };
1.6       nicm      598:
1.28    ! nicm      599: /* utf8_three state table. */
        !           600: const struct input_transition input_state_utf8_three_table[] = {
        !           601:        /* No INPUT_STATE_ANYWHERE */
        !           602:
        !           603:        { 0x00, 0x7f, NULL,             &input_state_ground },
        !           604:        { 0x80, 0xbf, input_utf8_add,   &input_state_utf8_two },
        !           605:        { 0xc0, 0xff, NULL,             &input_state_ground },
1.4       nicm      606:
1.28    ! nicm      607:        { -1, -1, NULL, NULL }
        !           608: };
1.1       nicm      609:
1.28    ! nicm      610: /* utf8_two state table. */
        !           611: const struct input_transition input_state_utf8_two_table[] = {
        !           612:        /* No INPUT_STATE_ANYWHERE */
        !           613:
        !           614:        { 0x00, 0x7f, NULL,           &input_state_ground },
        !           615:        { 0x80, 0xbf, input_utf8_add, &input_state_utf8_one },
        !           616:        { 0xc0, 0xff, NULL,           &input_state_ground },
1.1       nicm      617:
1.28    ! nicm      618:        { -1, -1, NULL, NULL }
        !           619: };
1.1       nicm      620:
1.28    ! nicm      621: /* utf8_one state table. */
        !           622: const struct input_transition input_state_utf8_one_table[] = {
        !           623:        /* No INPUT_STATE_ANYWHERE */
        !           624:
        !           625:        { 0x00, 0x7f, NULL,             &input_state_ground },
        !           626:        { 0x80, 0xbf, input_utf8_close, &input_state_ground },
        !           627:        { 0xc0, 0xff, NULL,             &input_state_ground },
1.1       nicm      628:
1.28    ! nicm      629:        { -1, -1, NULL, NULL }
        !           630: };
1.1       nicm      631:
1.28    ! nicm      632: /* Input table compare. */
        !           633: int
        !           634: input_table_compare(const void *key, const void *value)
1.1       nicm      635: {
1.28    ! nicm      636:        const struct input_ctx          *ictx = key;
        !           637:        const struct input_table_entry  *entry = value;
1.1       nicm      638:
1.28    ! nicm      639:        if (ictx->ch != entry->ch)
        !           640:                return (ictx->ch - entry->ch);
        !           641:        return (strcmp(ictx->interm_buf, entry->interm));
1.1       nicm      642: }
                    643:
1.28    ! nicm      644: /* Initialise input parser. */
1.1       nicm      645: void
1.28    ! nicm      646: input_init(struct window_pane *wp)
1.1       nicm      647: {
1.28    ! nicm      648:        struct input_ctx        *ictx = &wp->ictx;
1.1       nicm      649:
1.28    ! nicm      650:        memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell);
1.1       nicm      651:
1.28    ! nicm      652:        memcpy(&ictx->old_cell, &grid_default_cell, sizeof ictx->old_cell);
        !           653:        ictx->old_cx = 0;
        !           654:        ictx->old_cy = 0;
1.1       nicm      655:
1.28    ! nicm      656:        *ictx->interm_buf = '\0';
        !           657:        ictx->interm_len = 0;
1.1       nicm      658:
1.28    ! nicm      659:        *ictx->param_buf = '\0';
        !           660:        ictx->param_len = 0;
1.1       nicm      661:
1.28    ! nicm      662:        ictx->state = &input_state_ground;
        !           663:        ictx->flags = 0;
1.1       nicm      664: }
                    665:
1.28    ! nicm      666: /* Destroy input parser. */
1.1       nicm      667: void
1.28    ! nicm      668: input_free(unused struct window_pane *wp)
1.1       nicm      669: {
                    670: }
                    671:
1.28    ! nicm      672: /* Parse input. */
1.1       nicm      673: void
1.28    ! nicm      674: input_parse(struct window_pane *wp)
1.1       nicm      675: {
1.28    ! nicm      676:        struct input_ctx                *ictx = &wp->ictx;
        !           677:        const struct input_transition   *itr;
        !           678:        struct evbuffer                 *evb = wp->event->input;
        !           679:        u_char                          *buf;
        !           680:        size_t                           len, off;
1.1       nicm      681:
1.28    ! nicm      682:        if (EVBUFFER_LENGTH(evb) == 0)
        !           683:                return;
        !           684:        wp->window->flags |= WINDOW_ACTIVITY;
1.1       nicm      685:
1.28    ! nicm      686:        /*
        !           687:         * Open the screen. Use NULL wp if there is a mode set as don't want to
        !           688:         * update the tty.
        !           689:         */
        !           690:        if (wp->mode == NULL)
        !           691:                screen_write_start(&ictx->ctx, wp, &wp->base);
        !           692:        else
        !           693:                screen_write_start(&ictx->ctx, NULL, &wp->base);
        !           694:        ictx->wp = wp;
1.7       nicm      695:
1.28    ! nicm      696:        buf = EVBUFFER_DATA(evb);
        !           697:        len = EVBUFFER_LENGTH(evb);
        !           698:        off = 0;
        !           699:
        !           700:        /* Parse the input. */
        !           701:        while (off < len) {
        !           702:                ictx->ch = buf[off++];
        !           703:                log_debug("%s: '%c' %s", __func__, ictx->ch, ictx->state->name);
        !           704:
        !           705:                /* Find the transition. */
        !           706:                itr = ictx->state->transitions;
        !           707:                while (itr->first != -1 && itr->last != -1) {
        !           708:                        if (ictx->ch >= itr->first && ictx->ch <= itr->last)
1.7       nicm      709:                                break;
1.28    ! nicm      710:                        itr++;
1.1       nicm      711:                }
1.28    ! nicm      712:                if (itr->first == -1 || itr->last == -1) {
        !           713:                        /* No transition? Eh? */
        !           714:                        fatalx("No transition from state!");
1.3       nicm      715:                }
1.1       nicm      716:
                    717:                /*
1.28    ! nicm      718:                 * Execute the handler, if any. Don't switch state if it
        !           719:                 * returns non-zero.
1.1       nicm      720:                 */
1.28    ! nicm      721:                if (itr->handler && itr->handler(ictx) != 0)
        !           722:                        continue;
        !           723:
        !           724:                /* And switch state, if necessary. */
        !           725:                if (itr->state) {
        !           726:                        if (ictx->state->exit != NULL)
        !           727:                                ictx->state->exit(ictx);
        !           728:                        ictx->state = itr->state;
        !           729:                        if (ictx->state->enter != NULL)
        !           730:                                ictx->state->enter(ictx);
1.1       nicm      731:                }
                    732:        }
                    733:
1.28    ! nicm      734:        /* Close the screen. */
        !           735:        screen_write_stop(&ictx->ctx);
1.1       nicm      736:
1.28    ! nicm      737:        evbuffer_drain(evb, len);
1.1       nicm      738: }
                    739:
1.28    ! nicm      740: /* Split the parameter list (if any). */
        !           741: int
        !           742: input_split(struct input_ctx *ictx)
1.1       nicm      743:
                    744: {
1.28    ! nicm      745:        const char      *errstr;
        !           746:        char            *ptr, *out;
        !           747:        int              n;
1.1       nicm      748:
1.28    ! nicm      749:        ictx->param_list_len = 0;
        !           750:        if (ictx->param_len == 0)
        !           751:                return (0);
1.1       nicm      752:
1.28    ! nicm      753:        ptr = ictx->param_buf;
        !           754:        while ((out = strsep(&ptr, ";")) != NULL) {
        !           755:                if (*out == '\0')
        !           756:                        n = -1;
        !           757:                else {
        !           758:                        n = strtonum(out, 0, INT_MAX, &errstr);
        !           759:                        if (errstr != NULL)
        !           760:                                return (-1);
        !           761:                }
1.1       nicm      762:
1.28    ! nicm      763:                ictx->param_list[ictx->param_list_len++] = n;
        !           764:                if (ictx->param_list_len == nitems(ictx->param_list))
        !           765:                        return (-1);
        !           766:        }
1.1       nicm      767:
1.28    ! nicm      768:        return (0);
1.1       nicm      769: }
                    770:
1.28    ! nicm      771: /* Get an argument or return default value..*/
        !           772: int
        !           773: input_get(struct input_ctx *ictx, u_int validx, int minval, int defval)
1.1       nicm      774: {
1.28    ! nicm      775:        int     retval;
1.1       nicm      776:
1.28    ! nicm      777:        if (validx >= ictx->param_list_len)
        !           778:            return (defval);
1.1       nicm      779:
1.28    ! nicm      780:        retval = ictx->param_list[validx];
        !           781:        if (retval == -1)
        !           782:                return (defval);
        !           783:        if (retval < minval)
        !           784:                return (minval);
        !           785:        return (retval);
1.1       nicm      786: }
                    787:
1.28    ! nicm      788: /* Reply to terminal query. */
1.1       nicm      789: void
1.28    ! nicm      790: input_reply(struct input_ctx *ictx, const char *fmt, ...)
1.1       nicm      791: {
1.28    ! nicm      792:        va_list ap;
        !           793:        char   *reply;
1.1       nicm      794:
1.28    ! nicm      795:        va_start(ap, fmt);
        !           796:        vasprintf(&reply, fmt, ap);
        !           797:        va_end(ap);
1.1       nicm      798:
1.28    ! nicm      799:        bufferevent_write(ictx->wp->event, reply, strlen(reply));
        !           800:        xfree(reply);
1.8       nicm      801: }
                    802:
1.28    ! nicm      803: /* Clear saved state. */
1.8       nicm      804: void
1.28    ! nicm      805: input_clear(struct input_ctx *ictx)
1.8       nicm      806: {
1.28    ! nicm      807:        *ictx->interm_buf = '\0';
        !           808:        ictx->interm_len = 0;
1.8       nicm      809:
1.28    ! nicm      810:        *ictx->param_buf = '\0';
        !           811:        ictx->param_len = 0;
1.8       nicm      812:
1.28    ! nicm      813:        ictx->flags &= ~INPUT_DISCARD;
1.14      nicm      814: }
                    815:
1.28    ! nicm      816: /* Output this character to the screen. */
        !           817: int
        !           818: input_print(struct input_ctx *ictx)
1.14      nicm      819: {
1.28    ! nicm      820:        ictx->cell.data = ictx->ch;
        !           821:        screen_write_cell(&ictx->ctx, &ictx->cell, NULL);
1.14      nicm      822:
1.28    ! nicm      823:        return (0);
1.1       nicm      824: }
                    825:
1.28    ! nicm      826: /* Collect intermediate string. */
        !           827: int
        !           828: input_intermediate(struct input_ctx *ictx)
1.1       nicm      829: {
1.28    ! nicm      830:        if (ictx->interm_len == (sizeof ictx->interm_buf) - 1)
        !           831:                ictx->flags |= INPUT_DISCARD;
        !           832:        else {
        !           833:                ictx->interm_buf[ictx->interm_len++] = ictx->ch;
        !           834:                ictx->interm_buf[ictx->interm_len] = '\0';
        !           835:        }
1.1       nicm      836:
1.28    ! nicm      837:        return (0);
1.1       nicm      838: }
                    839:
1.28    ! nicm      840: /* Collect parameter string. */
        !           841: int
        !           842: input_parameter(struct input_ctx *ictx)
1.1       nicm      843: {
1.28    ! nicm      844:        if (ictx->param_len == (sizeof ictx->param_buf) - 1)
        !           845:                ictx->flags |= INPUT_DISCARD;
        !           846:        else {
        !           847:                ictx->param_buf[ictx->param_len++] = ictx->ch;
        !           848:                ictx->param_buf[ictx->param_len] = '\0';
        !           849:        }
1.1       nicm      850:
1.28    ! nicm      851:        return (0);
1.1       nicm      852: }
                    853:
1.28    ! nicm      854: /* Collect input string. */
        !           855: int
        !           856: input_input(struct input_ctx *ictx)
1.1       nicm      857: {
1.28    ! nicm      858:        if (ictx->input_len == (sizeof ictx->input_buf) - 1)
        !           859:                ictx->flags |= INPUT_DISCARD;
        !           860:        else {
        !           861:                ictx->input_buf[ictx->input_len++] = ictx->ch;
        !           862:                ictx->input_buf[ictx->input_len] = '\0';
        !           863:        }
1.1       nicm      864:
1.28    ! nicm      865:        return (0);
1.1       nicm      866: }
                    867:
1.28    ! nicm      868: /* Execute C0 control sequence. */
        !           869: int
        !           870: input_c0_dispatch(struct input_ctx *ictx)
1.1       nicm      871: {
1.28    ! nicm      872:        struct screen_write_ctx *sctx = &ictx->ctx;
        !           873:        struct window_pane      *wp = ictx->wp;
        !           874:        struct screen           *s = sctx->s;
1.1       nicm      875:
1.28    ! nicm      876:        log_debug("%s: '%c", __func__, ictx->ch);
1.1       nicm      877:
1.28    ! nicm      878:        switch (ictx->ch) {
        !           879:        case '\000':    /* NUL */
        !           880:                break;
        !           881:        case '\007':    /* BEL */
        !           882:                wp->window->flags |= WINDOW_BELL;
        !           883:                break;
        !           884:        case '\010':    /* BS */
        !           885:                screen_write_backspace(sctx);
        !           886:                break;
        !           887:        case '\011':    /* HT */
        !           888:                /* Don't tab beyond the end of the line. */
        !           889:                if (s->cx >= screen_size_x(s) - 1)
        !           890:                        break;
1.1       nicm      891:
1.28    ! nicm      892:                /* Find the next tab point, or use the last column if none. */
        !           893:                do {
        !           894:                        s->cx++;
        !           895:                        if (bit_test(s->tabs, s->cx))
        !           896:                                break;
        !           897:                } while (s->cx < screen_size_x(s) - 1);
        !           898:                break;
        !           899:        case '\012':    /* LF */
        !           900:        case '\013':    /* VT */
        !           901:        case '\014':    /* FF */
        !           902:                screen_write_linefeed(sctx, 0);
        !           903:                break;
        !           904:        case '\015':    /* CR */
        !           905:                screen_write_carriagereturn(sctx);
        !           906:                break;
        !           907:        case '\016':    /* SO */
        !           908:                ictx->cell.attr |= GRID_ATTR_CHARSET;
        !           909:                break;
        !           910:        case '\017':    /* SI */
        !           911:                ictx->cell.attr &= ~GRID_ATTR_CHARSET;
        !           912:                break;
        !           913:        default:
        !           914:                log_debug("%s: unknown '%c'", __func__, ictx->ch);
        !           915:                break;
        !           916:        }
1.1       nicm      917:
1.28    ! nicm      918:        return (0);
1.7       nicm      919: }
                    920:
1.28    ! nicm      921: /* Execute escape sequence. */
        !           922: int
        !           923: input_esc_dispatch(struct input_ctx *ictx)
1.7       nicm      924: {
1.28    ! nicm      925:        struct screen_write_ctx *sctx = &ictx->ctx;
        !           926:        struct screen           *s = sctx->s;
        !           927:        struct input_table_entry       *entry;
1.7       nicm      928:
1.28    ! nicm      929:        if (ictx->flags & INPUT_DISCARD)
        !           930:                return (0);
        !           931:        log_debug("%s: '%c', %s", __func__, ictx->ch, ictx->interm_buf);
1.7       nicm      932:
1.28    ! nicm      933:        entry = bsearch(ictx, input_esc_table, nitems(input_esc_table),
        !           934:            sizeof input_esc_table[0], input_table_compare);
        !           935:        if (entry == NULL) {
        !           936:                log_debug("%s: unknown '%c'", __func__, ictx->ch);
        !           937:                return (0);
        !           938:        }
1.7       nicm      939:
1.28    ! nicm      940:        switch (entry->type) {
        !           941:        case INPUT_ESC_RIS:
        !           942:                memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell);
        !           943:                memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
        !           944:                ictx->old_cx = 0;
        !           945:                ictx->old_cy = 0;
1.1       nicm      946:
1.28    ! nicm      947:                screen_reset_tabs(sctx->s);
1.1       nicm      948:
1.28    ! nicm      949:                screen_write_scrollregion(sctx, 0, screen_size_y(sctx->s) - 1);
1.1       nicm      950:
1.28    ! nicm      951:                screen_write_insertmode(sctx, 0);
        !           952:                screen_write_kcursormode(sctx, 0);
        !           953:                screen_write_kkeypadmode(sctx, 0);
        !           954:                screen_write_mousemode(sctx, 0);
1.1       nicm      955:
1.28    ! nicm      956:                screen_write_clearscreen(sctx);
        !           957:                screen_write_cursormove(sctx, 0, 0);
        !           958:                break;
        !           959:        case INPUT_ESC_IND:
        !           960:                screen_write_linefeed(sctx, 0);
        !           961:                break;
        !           962:        case INPUT_ESC_NEL:
        !           963:                screen_write_carriagereturn(sctx);
        !           964:                screen_write_linefeed(sctx, 0);
        !           965:                break;
        !           966:        case INPUT_ESC_HTS:
        !           967:                if (s->cx < screen_size_x(s))
        !           968:                        bit_set(s->tabs, s->cx);
        !           969:                break;
        !           970:        case INPUT_ESC_RI:
        !           971:                screen_write_reverseindex(sctx);
        !           972:                break;
        !           973:        case INPUT_ESC_DECKPAM:
        !           974:                screen_write_kkeypadmode(sctx, 1);
        !           975:                break;
        !           976:        case INPUT_ESC_DECKPNM:
        !           977:                screen_write_kkeypadmode(sctx, 0);
1.1       nicm      978:                break;
1.28    ! nicm      979:        case INPUT_ESC_DECSC:
        !           980:                memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
        !           981:                ictx->old_cx = s->cx;
        !           982:                ictx->old_cy = s->cy;
        !           983:                break;
        !           984:        case INPUT_ESC_DECRC:
        !           985:                memcpy(&ictx->cell, &ictx->old_cell, sizeof ictx->cell);
        !           986:                screen_write_cursormove(sctx, ictx->old_cx, ictx->old_cy);
        !           987:                break;
        !           988:        case INPUT_ESC_DECALN:
        !           989:                screen_write_alignmenttest(sctx);
        !           990:                break;
        !           991:        case INPUT_ESC_SCSON_G0:
        !           992:                /*
        !           993:                 * Not really supported, but fake it up enough for those that
        !           994:                 * use it to switch character sets (by redefining G0 to
        !           995:                 * graphics set, rather than switching to G1).
        !           996:                 */
        !           997:                ictx->cell.attr &= ~GRID_ATTR_CHARSET;
1.1       nicm      998:                break;
1.28    ! nicm      999:        case INPUT_ESC_SCSOFF_G0:
        !          1000:                ictx->cell.attr |= GRID_ATTR_CHARSET;
1.1       nicm     1001:                break;
                   1002:        }
1.28    ! nicm     1003:
        !          1004:        return (0);
1.1       nicm     1005: }
                   1006:
1.28    ! nicm     1007: /* Execute control sequence. */
        !          1008: int
        !          1009: input_csi_dispatch(struct input_ctx *ictx)
1.1       nicm     1010: {
1.28    ! nicm     1011:        struct screen_write_ctx        *sctx = &ictx->ctx;
        !          1012:        struct window_pane             *wp = ictx->wp;
        !          1013:        struct screen                  *s = sctx->s;
        !          1014:        struct input_table_entry       *entry;
        !          1015:        int                             n, m;
1.1       nicm     1016:
1.28    ! nicm     1017:        if (ictx->flags & INPUT_DISCARD)
        !          1018:                return (0);
        !          1019:        if (input_split(ictx) != 0)
        !          1020:                return (0);
        !          1021:        log_debug("%s: '%c' \"%s\" \"%s\"",
        !          1022:            __func__, ictx->ch, ictx->interm_buf, ictx->param_buf);
1.1       nicm     1023:
1.28    ! nicm     1024:        entry = bsearch(ictx, input_csi_table, nitems(input_csi_table),
        !          1025:            sizeof input_csi_table[0], input_table_compare);
        !          1026:        if (entry == NULL) {
        !          1027:                log_debug("%s: unknown '%c'", __func__, ictx->ch);
        !          1028:                return (0);
        !          1029:        }
1.1       nicm     1030:
1.28    ! nicm     1031:        switch (entry->type) {
        !          1032:        case INPUT_CSI_CBT:
        !          1033:                /* Find the previous tab point, n times. */
        !          1034:                n = input_get(ictx, 0, 1, 1);
        !          1035:                while (s->cx > 0 && n-- > 0) {
        !          1036:                        do
        !          1037:                                s->cx--;
        !          1038:                        while (s->cx > 0 && !bit_test(s->tabs, s->cx));
        !          1039:                }
        !          1040:                break;
        !          1041:        case INPUT_CSI_CUB:
        !          1042:                screen_write_cursorleft(sctx, input_get(ictx, 0, 1, 1));
        !          1043:                break;
        !          1044:        case INPUT_CSI_CUD:
        !          1045:                screen_write_cursordown(sctx, input_get(ictx, 0, 1, 1));
        !          1046:                break;
        !          1047:        case INPUT_CSI_CUF:
        !          1048:                screen_write_cursorright(sctx, input_get(ictx, 0, 1, 1));
        !          1049:                break;
        !          1050:        case INPUT_CSI_CUP:
        !          1051:                n = input_get(ictx, 0, 1, 1);
        !          1052:                m = input_get(ictx, 1, 1, 1);
        !          1053:                screen_write_cursormove(sctx, m - 1, n - 1);
        !          1054:                break;
        !          1055:        case INPUT_CSI_CUU:
        !          1056:                screen_write_cursorup(sctx, input_get(ictx, 0, 1, 1));
        !          1057:                break;
        !          1058:        case INPUT_CSI_DA:
        !          1059:                switch (input_get(ictx, 0, 0, 0)) {
        !          1060:                case 0:
        !          1061:                        input_reply(ictx, "\033[?1;2c");
        !          1062:                        break;
        !          1063:                default:
        !          1064:                        log_debug("%s: unknown '%c'", __func__, ictx->ch);
        !          1065:                        break;
        !          1066:                }
        !          1067:                break;
        !          1068:        case INPUT_CSI_DCH:
        !          1069:                screen_write_deletecharacter(sctx, input_get(ictx, 0, 1, 1));
        !          1070:                break;
        !          1071:        case INPUT_CSI_DECSTBM:
        !          1072:                n = input_get(ictx, 0, 1, 1);
        !          1073:                m = input_get(ictx, 1, 1, screen_size_y(s));
        !          1074:                screen_write_scrollregion(sctx, n - 1, m - 1);
1.1       nicm     1075:                break;
1.28    ! nicm     1076:        case INPUT_CSI_DL:
        !          1077:                screen_write_deleteline(sctx, input_get(ictx, 0, 1, 1));
1.1       nicm     1078:                break;
1.28    ! nicm     1079:        case INPUT_CSI_DSR:
        !          1080:                switch (input_get(ictx, 0, 0, 0)) {
        !          1081:                case 5:
        !          1082:                        input_reply(ictx, "\033[0n");
        !          1083:                        break;
        !          1084:                case 6:
        !          1085:                        input_reply(ictx, "\033[%u;%uR", s->cy + 1, s->cx + 1);
        !          1086:                        break;
        !          1087:                default:
        !          1088:                        log_debug("%s: unknown '%c'", __func__, ictx->ch);
        !          1089:                        break;
        !          1090:                }
        !          1091:                break;
        !          1092:        case INPUT_CSI_ED:
        !          1093:                switch (input_get(ictx, 0, 0, 0)) {
        !          1094:                case 0:
        !          1095:                        screen_write_clearendofscreen(sctx);
        !          1096:                        break;
        !          1097:                case 1:
        !          1098:                        screen_write_clearstartofscreen(sctx);
        !          1099:                        break;
        !          1100:                case 2:
        !          1101:                        screen_write_clearscreen(sctx);
        !          1102:                        break;
        !          1103:                default:
        !          1104:                        log_debug("%s: unknown '%c'", __func__, ictx->ch);
        !          1105:                        break;
        !          1106:                }
        !          1107:                break;
        !          1108:        case INPUT_CSI_EL:
        !          1109:                switch (input_get(ictx, 0, 0, 0)) {
        !          1110:                case 0:
        !          1111:                        screen_write_clearendofline(sctx);
        !          1112:                        break;
        !          1113:                case 1:
        !          1114:                        screen_write_clearstartofline(sctx);
        !          1115:                        break;
        !          1116:                case 2:
        !          1117:                        screen_write_clearline(sctx);
        !          1118:                        break;
        !          1119:                default:
        !          1120:                        log_debug("%s: unknown '%c'", __func__, ictx->ch);
        !          1121:                        break;
        !          1122:                }
        !          1123:                break;
        !          1124:        case INPUT_CSI_HPA:
        !          1125:                n = input_get(ictx, 0, 1, 1);
        !          1126:                screen_write_cursormove(sctx, n - 1, s->cy);
        !          1127:                break;
        !          1128:        case INPUT_CSI_ICH:
        !          1129:                screen_write_insertcharacter(sctx, input_get(ictx, 0, 1, 1));
        !          1130:                break;
        !          1131:        case INPUT_CSI_IL:
        !          1132:                screen_write_insertline(sctx, input_get(ictx, 0, 1, 1));
        !          1133:                break;
        !          1134:        case INPUT_CSI_RM:
        !          1135:                switch (input_get(ictx, 0, 0, -1)) {
        !          1136:                case 4:         /* IRM */
        !          1137:                        screen_write_insertmode(&ictx->ctx, 0);
        !          1138:                        break;
        !          1139:                default:
        !          1140:                        log_debug("%s: unknown '%c'", __func__, ictx->ch);
        !          1141:                        break;
        !          1142:                }
1.1       nicm     1143:                break;
1.28    ! nicm     1144:        case INPUT_CSI_RM_PRIVATE:
        !          1145:                switch (input_get(ictx, 0, 0, -1)) {
1.1       nicm     1146:                case 1:         /* GATM */
1.28    ! nicm     1147:                        screen_write_kcursormode(&ictx->ctx, 0);
1.1       nicm     1148:                        break;
1.17      nicm     1149:                case 3:         /* DECCOLM */
1.24      nicm     1150:                        screen_write_cursormove(&ictx->ctx, 0, 0);
1.17      nicm     1151:                        screen_write_clearscreen(&ictx->ctx);
                   1152:                        break;
1.1       nicm     1153:                case 25:        /* TCEM */
1.28    ! nicm     1154:                        screen_write_cursormode(&ictx->ctx, 0);
1.1       nicm     1155:                        break;
                   1156:                case 1000:
1.28    ! nicm     1157:                        screen_write_mousemode(&ictx->ctx, 0);
1.1       nicm     1158:                        break;
1.9       nicm     1159:                case 1049:
1.28    ! nicm     1160:                        window_pane_alternate_off(wp, &ictx->cell);
1.9       nicm     1161:                        break;
1.1       nicm     1162:                default:
1.28    ! nicm     1163:                        log_debug("%s: unknown '%c'", __func__, ictx->ch);
1.1       nicm     1164:                        break;
                   1165:                }
1.28    ! nicm     1166:                break;
        !          1167:        case INPUT_CSI_SGR:
        !          1168:                input_csi_dispatch_sgr(ictx);
        !          1169:                break;
        !          1170:        case INPUT_CSI_SM:
        !          1171:                switch (input_get(ictx, 0, 0, -1)) {
1.1       nicm     1172:                case 4:         /* IRM */
                   1173:                        screen_write_insertmode(&ictx->ctx, 1);
                   1174:                        break;
                   1175:                default:
1.28    ! nicm     1176:                        log_debug("%s: unknown '%c'", __func__, ictx->ch);
1.1       nicm     1177:                        break;
                   1178:                }
1.28    ! nicm     1179:                break;
        !          1180:        case INPUT_CSI_SM_PRIVATE:
        !          1181:                switch (input_get(ictx, 0, 0, -1)) {
1.1       nicm     1182:                case 1:         /* GATM */
1.28    ! nicm     1183:                        screen_write_kcursormode(&ictx->ctx, 1);
1.17      nicm     1184:                        break;
                   1185:                case 3:         /* DECCOLM */
1.24      nicm     1186:                        screen_write_cursormove(&ictx->ctx, 0, 0);
1.17      nicm     1187:                        screen_write_clearscreen(&ictx->ctx);
1.1       nicm     1188:                        break;
                   1189:                case 25:        /* TCEM */
1.28    ! nicm     1190:                        screen_write_cursormode(&ictx->ctx, 1);
1.1       nicm     1191:                        break;
                   1192:                case 1000:
1.28    ! nicm     1193:                        screen_write_mousemode(&ictx->ctx, 1);
1.9       nicm     1194:                        break;
                   1195:                case 1049:
1.28    ! nicm     1196:                        window_pane_alternate_on(wp, &ictx->cell);
1.1       nicm     1197:                        break;
                   1198:                default:
1.28    ! nicm     1199:                        log_debug("%s: unknown '%c'", __func__, ictx->ch);
1.1       nicm     1200:                        break;
                   1201:                }
1.28    ! nicm     1202:                break;
        !          1203:        case INPUT_CSI_TBC:
        !          1204:                switch (input_get(ictx, 0, 0, 0)) {
        !          1205:                case 0:
        !          1206:                        if (s->cx < screen_size_x(s))
        !          1207:                                bit_clear(s->tabs, s->cx);
1.1       nicm     1208:                        break;
1.28    ! nicm     1209:                case 3:
        !          1210:                        bit_nclear(s->tabs, 0, screen_size_x(s) - 1);
1.1       nicm     1211:                        break;
                   1212:                default:
1.28    ! nicm     1213:                        log_debug("%s: unknown '%c'", __func__, ictx->ch);
1.1       nicm     1214:                        break;
                   1215:                }
1.28    ! nicm     1216:                break;
        !          1217:        case INPUT_CSI_VPA:
        !          1218:                n = input_get(ictx, 0, 1, 1);
        !          1219:                screen_write_cursormove(sctx, s->cx, n - 1);
        !          1220:                break;
1.1       nicm     1221:        }
                   1222:
1.28    ! nicm     1223:        return (0);
1.1       nicm     1224: }
                   1225:
1.28    ! nicm     1226: /* Handle CSI SGR. */
1.1       nicm     1227: void
1.28    ! nicm     1228: input_csi_dispatch_sgr(struct input_ctx *ictx)
1.1       nicm     1229: {
1.28    ! nicm     1230:        struct grid_cell        *gc = &ictx->cell;
        !          1231:        u_int                    i;
        !          1232:        int                      n, m;
        !          1233:        u_char                   attr;
1.1       nicm     1234:
1.28    ! nicm     1235:        if (ictx->param_list_len == 0) {
1.1       nicm     1236:                attr = gc->attr;
                   1237:                memcpy(gc, &grid_default_cell, sizeof *gc);
1.24      nicm     1238:                gc->attr |= (attr & GRID_ATTR_CHARSET);
1.1       nicm     1239:                return;
                   1240:        }
                   1241:
1.28    ! nicm     1242:        for (i = 0; i < ictx->param_list_len; i++) {
        !          1243:                n = input_get(ictx, i, 0, 0);
1.1       nicm     1244:
1.28    ! nicm     1245:                if (n == 38 || n == 48) {
1.1       nicm     1246:                        i++;
1.28    ! nicm     1247:                        if (input_get(ictx, i, 0, -1) != 5)
1.1       nicm     1248:                                continue;
                   1249:
                   1250:                        i++;
1.28    ! nicm     1251:                        m = input_get(ictx, i, 0, -1);
        !          1252:                        if (m == -1) {
        !          1253:                                if (n == 38) {
        !          1254:                                        gc->flags &= ~GRID_FLAG_FG256;
        !          1255:                                        gc->fg = 8;
        !          1256:                                } else if (n == 48) {
        !          1257:                                        gc->flags &= ~GRID_FLAG_BG256;
        !          1258:                                        gc->fg = 8;
        !          1259:                                }
        !          1260:
        !          1261:                        } else {
        !          1262:                                if (n == 38) {
        !          1263:                                        gc->flags |= GRID_FLAG_FG256;
        !          1264:                                        gc->fg = m;
        !          1265:                                } else if (n == 48) {
        !          1266:                                        gc->flags |= GRID_FLAG_BG256;
        !          1267:                                        gc->bg = m;
        !          1268:                                }
1.1       nicm     1269:                        }
                   1270:                        continue;
                   1271:                }
                   1272:
1.28    ! nicm     1273:                switch (n) {
1.1       nicm     1274:                case 0:
                   1275:                case 10:
                   1276:                        attr = gc->attr;
                   1277:                        memcpy(gc, &grid_default_cell, sizeof *gc);
                   1278:                        gc->attr |= (attr & GRID_ATTR_CHARSET);
                   1279:                        break;
                   1280:                case 1:
                   1281:                        gc->attr |= GRID_ATTR_BRIGHT;
                   1282:                        break;
                   1283:                case 2:
                   1284:                        gc->attr |= GRID_ATTR_DIM;
                   1285:                        break;
                   1286:                case 3:
                   1287:                        gc->attr |= GRID_ATTR_ITALICS;
                   1288:                        break;
                   1289:                case 4:
                   1290:                        gc->attr |= GRID_ATTR_UNDERSCORE;
                   1291:                        break;
                   1292:                case 5:
                   1293:                        gc->attr |= GRID_ATTR_BLINK;
                   1294:                        break;
                   1295:                case 7:
                   1296:                        gc->attr |= GRID_ATTR_REVERSE;
                   1297:                        break;
                   1298:                case 8:
                   1299:                        gc->attr |= GRID_ATTR_HIDDEN;
                   1300:                        break;
                   1301:                case 22:
                   1302:                        gc->attr &= ~(GRID_ATTR_BRIGHT|GRID_ATTR_DIM);
                   1303:                        break;
                   1304:                case 23:
                   1305:                        gc->attr &= ~GRID_ATTR_ITALICS;
                   1306:                        break;
                   1307:                case 24:
                   1308:                        gc->attr &= ~GRID_ATTR_UNDERSCORE;
                   1309:                        break;
                   1310:                case 25:
                   1311:                        gc->attr &= ~GRID_ATTR_BLINK;
                   1312:                        break;
                   1313:                case 27:
                   1314:                        gc->attr &= ~GRID_ATTR_REVERSE;
                   1315:                        break;
                   1316:                case 30:
                   1317:                case 31:
                   1318:                case 32:
                   1319:                case 33:
                   1320:                case 34:
                   1321:                case 35:
                   1322:                case 36:
                   1323:                case 37:
                   1324:                        gc->flags &= ~GRID_FLAG_FG256;
1.28    ! nicm     1325:                        gc->fg = n - 30;
1.1       nicm     1326:                        break;
                   1327:                case 39:
                   1328:                        gc->flags &= ~GRID_FLAG_FG256;
                   1329:                        gc->fg = 8;
                   1330:                        break;
                   1331:                case 40:
                   1332:                case 41:
                   1333:                case 42:
                   1334:                case 43:
                   1335:                case 44:
                   1336:                case 45:
                   1337:                case 46:
                   1338:                case 47:
                   1339:                        gc->flags &= ~GRID_FLAG_BG256;
1.28    ! nicm     1340:                        gc->bg = n - 40;
1.1       nicm     1341:                        break;
                   1342:                case 49:
                   1343:                        gc->flags &= ~GRID_FLAG_BG256;
                   1344:                        gc->bg = 8;
1.20      nicm     1345:                        break;
                   1346:                case 90:
                   1347:                case 91:
                   1348:                case 92:
                   1349:                case 93:
                   1350:                case 94:
                   1351:                case 95:
                   1352:                case 96:
                   1353:                case 97:
1.26      nicm     1354:                        gc->flags &= ~GRID_FLAG_FG256;
1.28    ! nicm     1355:                        gc->fg = n;
1.20      nicm     1356:                        break;
                   1357:                case 100:
                   1358:                case 101:
                   1359:                case 102:
                   1360:                case 103:
                   1361:                case 104:
                   1362:                case 105:
                   1363:                case 106:
                   1364:                case 107:
1.26      nicm     1365:                        gc->flags &= ~GRID_FLAG_BG256;
1.28    ! nicm     1366:                        gc->bg = n;
1.1       nicm     1367:                        break;
                   1368:                }
                   1369:        }
1.28    ! nicm     1370: }
        !          1371:
        !          1372: /* DCS string started. */
        !          1373: void
        !          1374: input_enter_dcs(struct input_ctx *ictx)
        !          1375: {
        !          1376:        log_debug("%s", __func__);
        !          1377:
        !          1378:        ictx->input_len = 0;
        !          1379: }
        !          1380:
        !          1381: /* DCS terminator (ST) received. */
        !          1382: void
        !          1383: input_exit_dcs(unused struct input_ctx *ictx)
        !          1384: {
        !          1385:        log_debug("%s", __func__);
        !          1386: }
        !          1387:
        !          1388: /* OSC string started. */
        !          1389: void
        !          1390: input_enter_osc(struct input_ctx *ictx)
        !          1391: {
        !          1392:        log_debug("%s", __func__);
        !          1393:
        !          1394:        ictx->input_len = 0;
        !          1395: }
        !          1396:
        !          1397: /* OSC terminator (ST) received. */
        !          1398: void
        !          1399: input_exit_osc(struct input_ctx *ictx)
        !          1400: {
        !          1401:        if (ictx->flags & INPUT_DISCARD)
        !          1402:                return;
        !          1403:        log_debug("%s: \"%s\"", __func__, ictx->input_buf);
        !          1404:
        !          1405:        if (ictx->input_len < 2 || ictx->input_buf[1] != ';')
        !          1406:                return;
        !          1407:        if (ictx->input_buf[0] != '0' && ictx->input_buf[0] != '2')
        !          1408:                return;
        !          1409:
        !          1410:        screen_set_title(ictx->ctx.s, ictx->input_buf + 2);
        !          1411:        server_status_window(ictx->wp->window);
        !          1412: }
        !          1413:
        !          1414: /* APC string started. */
        !          1415: void
        !          1416: input_enter_apc(struct input_ctx *ictx)
        !          1417: {
        !          1418:        log_debug("%s", __func__);
        !          1419:
        !          1420:        ictx->input_len = 0;
        !          1421: }
        !          1422:
        !          1423: /* APC terminator (ST) received. */
        !          1424: void
        !          1425: input_exit_apc(struct input_ctx *ictx)
        !          1426: {
        !          1427:        if (ictx->flags & INPUT_DISCARD)
        !          1428:                return;
        !          1429:        log_debug("%s: \"%s\"", __func__, ictx->input_buf);
        !          1430:
        !          1431:        screen_set_title(ictx->ctx.s, ictx->input_buf);
        !          1432:        server_status_window(ictx->wp->window);
        !          1433: }
        !          1434:
        !          1435: /* Rename string started. */
        !          1436: void
        !          1437: input_enter_rename(struct input_ctx *ictx)
        !          1438: {
        !          1439:        log_debug("%s", __func__);
        !          1440:
        !          1441:        ictx->input_len = 0;
        !          1442: }
        !          1443:
        !          1444: /* Rename terminator (ST) received. */
        !          1445: void
        !          1446: input_exit_rename(struct input_ctx *ictx)
        !          1447: {
        !          1448:        if (ictx->flags & INPUT_DISCARD)
        !          1449:                return;
        !          1450:        log_debug("%s: \"%s\"", __func__, ictx->input_buf);
        !          1451:
        !          1452:        xfree(ictx->wp->window->name);
        !          1453:        ictx->wp->window->name = xstrdup(ictx->input_buf);
        !          1454:        options_set_number(&ictx->wp->window->options, "automatic-rename", 0);
        !          1455:
        !          1456:        server_status_window(ictx->wp->window);
        !          1457: }
        !          1458:
        !          1459: /* Open UTF-8 character. */
        !          1460: int
        !          1461: input_utf8_open(struct input_ctx *ictx)
        !          1462: {
        !          1463:        if (!options_get_number(&ictx->wp->window->options, "utf8")) {
        !          1464:                /* Print, and do not switch state. */
        !          1465:                input_print(ictx);
        !          1466:                return (-1);
        !          1467:        }
        !          1468:        log_debug("%s", __func__);
        !          1469:
        !          1470:        utf8_open(&ictx->utf8data, ictx->ch);
        !          1471:        return (0);
        !          1472: }
        !          1473:
        !          1474: /* Append to UTF-8 character. */
        !          1475: int
        !          1476: input_utf8_add(struct input_ctx *ictx)
        !          1477: {
        !          1478:        log_debug("%s", __func__);
        !          1479:
        !          1480:        utf8_append(&ictx->utf8data, ictx->ch);
        !          1481:        return (0);
        !          1482: }
        !          1483:
        !          1484: /* Close UTF-8 string. */
        !          1485: int
        !          1486: input_utf8_close(struct input_ctx *ictx)
        !          1487: {
        !          1488:        log_debug("%s", __func__);
        !          1489:
        !          1490:        utf8_append(&ictx->utf8data, ictx->ch);
        !          1491:
        !          1492:        ictx->cell.flags |= GRID_FLAG_UTF8;
        !          1493:        screen_write_cell(&ictx->ctx, &ictx->cell, &ictx->utf8data);
        !          1494:        ictx->cell.flags &= ~GRID_FLAG_UTF8;
        !          1495:
        !          1496:        return (0);
1.1       nicm     1497: }