File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / tmux / input.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 14 12:22:44 2017 UTC (7 years ago) by misho
Branches: tmux, MAIN
CVS tags: v2_4p0, v2_4, HEAD
tmux 2.4

    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>