Annotation of src/usr.bin/tmux/input.c, Revision 1.189
1.189 ! nicm 1: /* $OpenBSD: input.c,v 1.188 2021/02/18 13:30:24 nicm Exp $ */
1.1 nicm 2:
3: /*
1.99 nicm 4: * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
1.1 nicm 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:
1.108 nicm 21: #include <netinet/in.h>
22:
1.168 nicm 23: #include <ctype.h>
1.108 nicm 24: #include <resolv.h>
1.1 nicm 25: #include <stdlib.h>
26: #include <string.h>
1.79 nicm 27: #include <time.h>
1.1 nicm 28:
29: #include "tmux.h"
30:
1.28 nicm 31: /*
32: * Based on the description by Paul Williams at:
33: *
1.133 nicm 34: * https://vt100.net/emu/dec_ansi_parser
1.28 nicm 35: *
36: * With the following changes:
37: *
38: * - 7-bit only.
39: *
40: * - Support for UTF-8.
41: *
42: * - OSC (but not APC) may be terminated by \007 as well as ST.
43: *
44: * - A state for APC similar to OSC. Some terminals appear to use this to set
45: * the title.
46: *
47: * - A state for the screen \033k...\033\\ sequence to rename a window. This is
48: * pretty stupid but not supporting it is more trouble than it is worth.
1.37 nicm 49: *
50: * - Special handling for ESC inside a DCS to allow arbitrary byte sequences to
1.77 nicm 51: * be passed to the underlying terminals.
1.28 nicm 52: */
53:
1.74 nicm 54: /* Input parser cell. */
55: struct input_cell {
56: struct grid_cell cell;
57: int set;
58: int g0set; /* 1 if ACS */
59: int g1set; /* 1 if ACS */
60: };
61:
1.131 nicm 62: /* Input parser argument. */
63: struct input_param {
64: enum {
65: INPUT_MISSING,
66: INPUT_NUMBER,
67: INPUT_STRING
1.183 nicm 68: } type;
1.131 nicm 69: union {
70: int num;
71: char *str;
72: };
73: };
74:
1.74 nicm 75: /* Input parser context. */
76: struct input_ctx {
77: struct window_pane *wp;
1.172 nicm 78: struct bufferevent *event;
1.74 nicm 79: struct screen_write_ctx ctx;
80:
81: struct input_cell cell;
82:
83: struct input_cell old_cell;
1.183 nicm 84: u_int old_cx;
1.74 nicm 85: u_int old_cy;
1.146 nicm 86: int old_mode;
1.74 nicm 87:
88: u_char interm_buf[4];
89: size_t interm_len;
90:
91: u_char param_buf[64];
92: size_t param_len;
93:
94: #define INPUT_BUF_START 32
95: #define INPUT_BUF_LIMIT 1048576
96: u_char *input_buf;
97: size_t input_len;
98: size_t input_space;
1.138 nicm 99: enum {
100: INPUT_END_ST,
101: INPUT_END_BEL
102: } input_end;
1.74 nicm 103:
1.131 nicm 104: struct input_param param_list[24];
1.74 nicm 105: u_int param_list_len;
106:
107: struct utf8_data utf8data;
1.130 nicm 108: int utf8started;
1.74 nicm 109:
110: int ch;
1.127 nicm 111: int last;
1.112 nicm 112:
1.74 nicm 113: int flags;
114: #define INPUT_DISCARD 0x1
115:
116: const struct input_state *state;
117:
1.125 nicm 118: struct event timer;
119:
1.74 nicm 120: /*
121: * All input received since we were last in the ground state. Sent to
122: * control clients on connection.
123: */
1.183 nicm 124: struct evbuffer *since_ground;
1.74 nicm 125: };
126:
1.28 nicm 127: /* Helper functions. */
1.52 nicm 128: struct input_transition;
1.104 nicm 129: static int input_split(struct input_ctx *);
130: static int input_get(struct input_ctx *, u_int, int, int);
131: static void printflike(2, 3) input_reply(struct input_ctx *, const char *, ...);
1.171 nicm 132: static void input_set_state(struct input_ctx *,
1.104 nicm 133: const struct input_transition *);
134: static void input_reset_cell(struct input_ctx *);
1.28 nicm 135:
1.138 nicm 136: static void input_osc_4(struct input_ctx *, const char *);
137: static void input_osc_10(struct input_ctx *, const char *);
138: static void input_osc_11(struct input_ctx *, const char *);
139: static void input_osc_52(struct input_ctx *, const char *);
140: static void input_osc_104(struct input_ctx *, const char *);
1.186 nicm 141: static void input_osc_110(struct input_ctx *, const char *);
142: static void input_osc_111(struct input_ctx *, const char *);
1.107 nicm 143:
1.28 nicm 144: /* Transition entry/exit handlers. */
1.104 nicm 145: static void input_clear(struct input_ctx *);
146: static void input_ground(struct input_ctx *);
1.125 nicm 147: static void input_enter_dcs(struct input_ctx *);
1.104 nicm 148: static void input_enter_osc(struct input_ctx *);
149: static void input_exit_osc(struct input_ctx *);
150: static void input_enter_apc(struct input_ctx *);
151: static void input_exit_apc(struct input_ctx *);
152: static void input_enter_rename(struct input_ctx *);
153: static void input_exit_rename(struct input_ctx *);
1.28 nicm 154:
155: /* Input state handlers. */
1.104 nicm 156: static int input_print(struct input_ctx *);
157: static int input_intermediate(struct input_ctx *);
158: static int input_parameter(struct input_ctx *);
159: static int input_input(struct input_ctx *);
160: static int input_c0_dispatch(struct input_ctx *);
161: static int input_esc_dispatch(struct input_ctx *);
162: static int input_csi_dispatch(struct input_ctx *);
163: static void input_csi_dispatch_rm(struct input_ctx *);
164: static void input_csi_dispatch_rm_private(struct input_ctx *);
165: static void input_csi_dispatch_sm(struct input_ctx *);
166: static void input_csi_dispatch_sm_private(struct input_ctx *);
167: static void input_csi_dispatch_winops(struct input_ctx *);
168: static void input_csi_dispatch_sgr_256(struct input_ctx *, int, u_int *);
169: static void input_csi_dispatch_sgr_rgb(struct input_ctx *, int, u_int *);
170: static void input_csi_dispatch_sgr(struct input_ctx *);
171: static int input_dcs_dispatch(struct input_ctx *);
1.130 nicm 172: static int input_top_bit_set(struct input_ctx *);
1.138 nicm 173: static int input_end_bel(struct input_ctx *);
1.28 nicm 174:
175: /* Command table comparison function. */
1.104 nicm 176: static int input_table_compare(const void *, const void *);
1.28 nicm 177:
178: /* Command table entry. */
179: struct input_table_entry {
180: int ch;
181: const char *interm;
182: int type;
1.1 nicm 183: };
184:
1.28 nicm 185: /* Escape commands. */
186: enum input_esc_type {
187: INPUT_ESC_DECALN,
188: INPUT_ESC_DECKPAM,
189: INPUT_ESC_DECKPNM,
190: INPUT_ESC_DECRC,
191: INPUT_ESC_DECSC,
192: INPUT_ESC_HTS,
193: INPUT_ESC_IND,
194: INPUT_ESC_NEL,
195: INPUT_ESC_RI,
196: INPUT_ESC_RIS,
1.69 nicm 197: INPUT_ESC_SCSG0_OFF,
198: INPUT_ESC_SCSG0_ON,
199: INPUT_ESC_SCSG1_OFF,
200: INPUT_ESC_SCSG1_ON,
1.107 nicm 201: INPUT_ESC_ST,
1.28 nicm 202: };
1.1 nicm 203:
1.28 nicm 204: /* Escape command table. */
1.104 nicm 205: static const struct input_table_entry input_esc_table[] = {
1.69 nicm 206: { '0', "(", INPUT_ESC_SCSG0_ON },
207: { '0', ")", INPUT_ESC_SCSG1_ON },
1.28 nicm 208: { '7', "", INPUT_ESC_DECSC },
209: { '8', "", INPUT_ESC_DECRC },
210: { '8', "#", INPUT_ESC_DECALN },
211: { '=', "", INPUT_ESC_DECKPAM },
212: { '>', "", INPUT_ESC_DECKPNM },
1.69 nicm 213: { 'B', "(", INPUT_ESC_SCSG0_OFF },
214: { 'B', ")", INPUT_ESC_SCSG1_OFF },
1.28 nicm 215: { 'D', "", INPUT_ESC_IND },
216: { 'E', "", INPUT_ESC_NEL },
217: { 'H', "", INPUT_ESC_HTS },
218: { 'M', "", INPUT_ESC_RI },
1.107 nicm 219: { '\\', "", INPUT_ESC_ST },
1.28 nicm 220: { 'c', "", INPUT_ESC_RIS },
221: };
1.1 nicm 222:
1.28 nicm 223: /* Control (CSI) commands. */
224: enum input_csi_type {
225: INPUT_CSI_CBT,
1.43 nicm 226: INPUT_CSI_CNL,
227: INPUT_CSI_CPL,
1.28 nicm 228: INPUT_CSI_CUB,
229: INPUT_CSI_CUD,
230: INPUT_CSI_CUF,
231: INPUT_CSI_CUP,
232: INPUT_CSI_CUU,
233: INPUT_CSI_DA,
1.50 nicm 234: INPUT_CSI_DA_TWO,
1.28 nicm 235: INPUT_CSI_DCH,
1.39 nicm 236: INPUT_CSI_DECSCUSR,
1.28 nicm 237: INPUT_CSI_DECSTBM,
238: INPUT_CSI_DL,
239: INPUT_CSI_DSR,
1.56 nicm 240: INPUT_CSI_ECH,
1.28 nicm 241: INPUT_CSI_ED,
242: INPUT_CSI_EL,
243: INPUT_CSI_HPA,
244: INPUT_CSI_ICH,
245: INPUT_CSI_IL,
1.178 nicm 246: INPUT_CSI_MODOFF,
247: INPUT_CSI_MODSET,
1.42 nicm 248: INPUT_CSI_RCP,
1.127 nicm 249: INPUT_CSI_REP,
1.28 nicm 250: INPUT_CSI_RM,
251: INPUT_CSI_RM_PRIVATE,
1.42 nicm 252: INPUT_CSI_SCP,
1.159 nicm 253: INPUT_CSI_SD,
1.28 nicm 254: INPUT_CSI_SGR,
255: INPUT_CSI_SM,
256: INPUT_CSI_SM_PRIVATE,
1.115 nicm 257: INPUT_CSI_SU,
1.28 nicm 258: INPUT_CSI_TBC,
259: INPUT_CSI_VPA,
1.65 nicm 260: INPUT_CSI_WINOPS,
1.175 nicm 261: INPUT_CSI_XDA,
1.28 nicm 262: };
1.1 nicm 263:
1.28 nicm 264: /* Control (CSI) command table. */
1.104 nicm 265: static const struct input_table_entry input_csi_table[] = {
1.28 nicm 266: { '@', "", INPUT_CSI_ICH },
267: { 'A', "", INPUT_CSI_CUU },
268: { 'B', "", INPUT_CSI_CUD },
269: { 'C', "", INPUT_CSI_CUF },
270: { 'D', "", INPUT_CSI_CUB },
1.43 nicm 271: { 'E', "", INPUT_CSI_CNL },
272: { 'F', "", INPUT_CSI_CPL },
1.28 nicm 273: { 'G', "", INPUT_CSI_HPA },
274: { 'H', "", INPUT_CSI_CUP },
275: { 'J', "", INPUT_CSI_ED },
276: { 'K', "", INPUT_CSI_EL },
277: { 'L', "", INPUT_CSI_IL },
278: { 'M', "", INPUT_CSI_DL },
279: { 'P', "", INPUT_CSI_DCH },
1.115 nicm 280: { 'S', "", INPUT_CSI_SU },
1.159 nicm 281: { 'T', "", INPUT_CSI_SD },
1.56 nicm 282: { 'X', "", INPUT_CSI_ECH },
1.28 nicm 283: { 'Z', "", INPUT_CSI_CBT },
1.148 nicm 284: { '`', "", INPUT_CSI_HPA },
1.127 nicm 285: { 'b', "", INPUT_CSI_REP },
1.28 nicm 286: { 'c', "", INPUT_CSI_DA },
1.50 nicm 287: { 'c', ">", INPUT_CSI_DA_TWO },
1.28 nicm 288: { 'd', "", INPUT_CSI_VPA },
289: { 'f', "", INPUT_CSI_CUP },
290: { 'g', "", INPUT_CSI_TBC },
291: { 'h', "", INPUT_CSI_SM },
292: { 'h', "?", INPUT_CSI_SM_PRIVATE },
293: { 'l', "", INPUT_CSI_RM },
294: { 'l', "?", INPUT_CSI_RM_PRIVATE },
295: { 'm', "", INPUT_CSI_SGR },
1.178 nicm 296: { 'm', ">", INPUT_CSI_MODSET },
1.28 nicm 297: { 'n', "", INPUT_CSI_DSR },
1.178 nicm 298: { 'n', ">", INPUT_CSI_MODOFF },
1.39 nicm 299: { 'q', " ", INPUT_CSI_DECSCUSR },
1.175 nicm 300: { 'q', ">", INPUT_CSI_XDA },
1.28 nicm 301: { 'r', "", INPUT_CSI_DECSTBM },
1.42 nicm 302: { 's', "", INPUT_CSI_SCP },
1.65 nicm 303: { 't', "", INPUT_CSI_WINOPS },
1.42 nicm 304: { 'u', "", INPUT_CSI_RCP },
1.28 nicm 305: };
1.1 nicm 306:
1.28 nicm 307: /* Input transition. */
308: struct input_transition {
309: int first;
310: int last;
1.1 nicm 311:
1.28 nicm 312: int (*handler)(struct input_ctx *);
313: const struct input_state *state;
314: };
1.1 nicm 315:
1.28 nicm 316: /* Input state. */
317: struct input_state {
318: const char *name;
319: void (*enter)(struct input_ctx *);
320: void (*exit)(struct input_ctx *);
321: const struct input_transition *transitions;
322: };
1.1 nicm 323:
1.28 nicm 324: /* State transitions available from all states. */
325: #define INPUT_STATE_ANYWHERE \
326: { 0x18, 0x18, input_c0_dispatch, &input_state_ground }, \
327: { 0x1a, 0x1a, input_c0_dispatch, &input_state_ground }, \
328: { 0x1b, 0x1b, NULL, &input_state_esc_enter }
329:
330: /* Forward declarations of state tables. */
1.104 nicm 331: static const struct input_transition input_state_ground_table[];
332: static const struct input_transition input_state_esc_enter_table[];
333: static const struct input_transition input_state_esc_intermediate_table[];
334: static const struct input_transition input_state_csi_enter_table[];
335: static const struct input_transition input_state_csi_parameter_table[];
336: static const struct input_transition input_state_csi_intermediate_table[];
337: static const struct input_transition input_state_csi_ignore_table[];
338: static const struct input_transition input_state_dcs_enter_table[];
339: static const struct input_transition input_state_dcs_parameter_table[];
340: static const struct input_transition input_state_dcs_intermediate_table[];
341: static const struct input_transition input_state_dcs_handler_table[];
342: static const struct input_transition input_state_dcs_escape_table[];
343: static const struct input_transition input_state_dcs_ignore_table[];
344: static const struct input_transition input_state_osc_string_table[];
345: static const struct input_transition input_state_apc_string_table[];
346: static const struct input_transition input_state_rename_string_table[];
347: static const struct input_transition input_state_consume_st_table[];
1.28 nicm 348:
349: /* ground state definition. */
1.104 nicm 350: static const struct input_state input_state_ground = {
1.28 nicm 351: "ground",
1.67 nicm 352: input_ground, NULL,
1.28 nicm 353: input_state_ground_table
354: };
1.1 nicm 355:
1.28 nicm 356: /* esc_enter state definition. */
1.104 nicm 357: static const struct input_state input_state_esc_enter = {
1.28 nicm 358: "esc_enter",
359: input_clear, NULL,
360: input_state_esc_enter_table
361: };
1.1 nicm 362:
1.28 nicm 363: /* esc_intermediate state definition. */
1.104 nicm 364: static const struct input_state input_state_esc_intermediate = {
1.28 nicm 365: "esc_intermediate",
366: NULL, NULL,
367: input_state_esc_intermediate_table
368: };
1.1 nicm 369:
1.28 nicm 370: /* csi_enter state definition. */
1.104 nicm 371: static const struct input_state input_state_csi_enter = {
1.28 nicm 372: "csi_enter",
373: input_clear, NULL,
374: input_state_csi_enter_table
375: };
1.1 nicm 376:
1.28 nicm 377: /* csi_parameter state definition. */
1.104 nicm 378: static const struct input_state input_state_csi_parameter = {
1.28 nicm 379: "csi_parameter",
380: NULL, NULL,
381: input_state_csi_parameter_table
382: };
1.1 nicm 383:
1.28 nicm 384: /* csi_intermediate state definition. */
1.104 nicm 385: static const struct input_state input_state_csi_intermediate = {
1.28 nicm 386: "csi_intermediate",
387: NULL, NULL,
388: input_state_csi_intermediate_table
389: };
1.1 nicm 390:
1.28 nicm 391: /* csi_ignore state definition. */
1.104 nicm 392: static const struct input_state input_state_csi_ignore = {
1.28 nicm 393: "csi_ignore",
394: NULL, NULL,
395: input_state_csi_ignore_table
396: };
1.1 nicm 397:
1.28 nicm 398: /* dcs_enter state definition. */
1.104 nicm 399: static const struct input_state input_state_dcs_enter = {
1.28 nicm 400: "dcs_enter",
1.125 nicm 401: input_enter_dcs, NULL,
1.28 nicm 402: input_state_dcs_enter_table
403: };
1.1 nicm 404:
1.28 nicm 405: /* dcs_parameter state definition. */
1.104 nicm 406: static const struct input_state input_state_dcs_parameter = {
1.28 nicm 407: "dcs_parameter",
408: NULL, NULL,
409: input_state_dcs_parameter_table
410: };
1.1 nicm 411:
1.28 nicm 412: /* dcs_intermediate state definition. */
1.104 nicm 413: static const struct input_state input_state_dcs_intermediate = {
1.28 nicm 414: "dcs_intermediate",
415: NULL, NULL,
416: input_state_dcs_intermediate_table
417: };
1.1 nicm 418:
1.28 nicm 419: /* dcs_handler state definition. */
1.104 nicm 420: static const struct input_state input_state_dcs_handler = {
1.28 nicm 421: "dcs_handler",
1.37 nicm 422: NULL, NULL,
1.28 nicm 423: input_state_dcs_handler_table
424: };
1.1 nicm 425:
1.37 nicm 426: /* dcs_escape state definition. */
1.104 nicm 427: static const struct input_state input_state_dcs_escape = {
1.37 nicm 428: "dcs_escape",
429: NULL, NULL,
430: input_state_dcs_escape_table
431: };
432:
1.28 nicm 433: /* dcs_ignore state definition. */
1.104 nicm 434: static const struct input_state input_state_dcs_ignore = {
1.28 nicm 435: "dcs_ignore",
436: NULL, NULL,
437: input_state_dcs_ignore_table
438: };
1.1 nicm 439:
1.28 nicm 440: /* osc_string state definition. */
1.104 nicm 441: static const struct input_state input_state_osc_string = {
1.28 nicm 442: "osc_string",
443: input_enter_osc, input_exit_osc,
444: input_state_osc_string_table
445: };
1.1 nicm 446:
1.28 nicm 447: /* apc_string state definition. */
1.104 nicm 448: static const struct input_state input_state_apc_string = {
1.28 nicm 449: "apc_string",
450: input_enter_apc, input_exit_apc,
451: input_state_apc_string_table
452: };
1.1 nicm 453:
1.28 nicm 454: /* rename_string state definition. */
1.104 nicm 455: static const struct input_state input_state_rename_string = {
1.28 nicm 456: "rename_string",
457: input_enter_rename, input_exit_rename,
458: input_state_rename_string_table
459: };
1.1 nicm 460:
1.28 nicm 461: /* consume_st state definition. */
1.104 nicm 462: static const struct input_state input_state_consume_st = {
1.28 nicm 463: "consume_st",
1.128 nicm 464: input_enter_rename, NULL, /* rename also waits for ST */
1.28 nicm 465: input_state_consume_st_table
466: };
1.1 nicm 467:
1.28 nicm 468: /* ground state table. */
1.104 nicm 469: static const struct input_transition input_state_ground_table[] = {
1.28 nicm 470: INPUT_STATE_ANYWHERE,
471:
472: { 0x00, 0x17, input_c0_dispatch, NULL },
473: { 0x19, 0x19, input_c0_dispatch, NULL },
474: { 0x1c, 0x1f, input_c0_dispatch, NULL },
475: { 0x20, 0x7e, input_print, NULL },
476: { 0x7f, 0x7f, NULL, NULL },
1.130 nicm 477: { 0x80, 0xff, input_top_bit_set, NULL },
1.1 nicm 478:
1.28 nicm 479: { -1, -1, NULL, NULL }
480: };
1.13 nicm 481:
1.28 nicm 482: /* esc_enter state table. */
1.104 nicm 483: static const struct input_transition input_state_esc_enter_table[] = {
1.28 nicm 484: INPUT_STATE_ANYWHERE,
485:
486: { 0x00, 0x17, input_c0_dispatch, NULL },
487: { 0x19, 0x19, input_c0_dispatch, NULL },
488: { 0x1c, 0x1f, input_c0_dispatch, NULL },
489: { 0x20, 0x2f, input_intermediate, &input_state_esc_intermediate },
490: { 0x30, 0x4f, input_esc_dispatch, &input_state_ground },
491: { 0x50, 0x50, NULL, &input_state_dcs_enter },
492: { 0x51, 0x57, input_esc_dispatch, &input_state_ground },
493: { 0x58, 0x58, NULL, &input_state_consume_st },
494: { 0x59, 0x59, input_esc_dispatch, &input_state_ground },
495: { 0x5a, 0x5a, input_esc_dispatch, &input_state_ground },
496: { 0x5b, 0x5b, NULL, &input_state_csi_enter },
497: { 0x5c, 0x5c, input_esc_dispatch, &input_state_ground },
498: { 0x5d, 0x5d, NULL, &input_state_osc_string },
499: { 0x5e, 0x5e, NULL, &input_state_consume_st },
500: { 0x5f, 0x5f, NULL, &input_state_apc_string },
501: { 0x60, 0x6a, input_esc_dispatch, &input_state_ground },
502: { 0x6b, 0x6b, NULL, &input_state_rename_string },
1.29 nicm 503: { 0x6c, 0x7e, input_esc_dispatch, &input_state_ground },
1.28 nicm 504: { 0x7f, 0xff, NULL, NULL },
1.1 nicm 505:
1.28 nicm 506: { -1, -1, NULL, NULL }
507: };
1.1 nicm 508:
1.138 nicm 509: /* esc_intermediate state table. */
1.104 nicm 510: static const struct input_transition input_state_esc_intermediate_table[] = {
1.28 nicm 511: INPUT_STATE_ANYWHERE,
512:
513: { 0x00, 0x17, input_c0_dispatch, NULL },
514: { 0x19, 0x19, input_c0_dispatch, NULL },
515: { 0x1c, 0x1f, input_c0_dispatch, NULL },
516: { 0x20, 0x2f, input_intermediate, NULL },
517: { 0x30, 0x7e, input_esc_dispatch, &input_state_ground },
518: { 0x7f, 0xff, NULL, NULL },
1.1 nicm 519:
1.28 nicm 520: { -1, -1, NULL, NULL }
521: };
1.1 nicm 522:
1.28 nicm 523: /* csi_enter state table. */
1.104 nicm 524: static const struct input_transition input_state_csi_enter_table[] = {
1.28 nicm 525: INPUT_STATE_ANYWHERE,
526:
527: { 0x00, 0x17, input_c0_dispatch, NULL },
528: { 0x19, 0x19, input_c0_dispatch, NULL },
529: { 0x1c, 0x1f, input_c0_dispatch, NULL },
530: { 0x20, 0x2f, input_intermediate, &input_state_csi_intermediate },
531: { 0x30, 0x39, input_parameter, &input_state_csi_parameter },
1.131 nicm 532: { 0x3a, 0x3a, input_parameter, &input_state_csi_parameter },
1.28 nicm 533: { 0x3b, 0x3b, input_parameter, &input_state_csi_parameter },
534: { 0x3c, 0x3f, input_intermediate, &input_state_csi_parameter },
535: { 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
536: { 0x7f, 0xff, NULL, NULL },
1.1 nicm 537:
1.28 nicm 538: { -1, -1, NULL, NULL }
539: };
1.1 nicm 540:
1.28 nicm 541: /* csi_parameter state table. */
1.104 nicm 542: static const struct input_transition input_state_csi_parameter_table[] = {
1.28 nicm 543: INPUT_STATE_ANYWHERE,
544:
545: { 0x00, 0x17, input_c0_dispatch, NULL },
546: { 0x19, 0x19, input_c0_dispatch, NULL },
547: { 0x1c, 0x1f, input_c0_dispatch, NULL },
548: { 0x20, 0x2f, input_intermediate, &input_state_csi_intermediate },
549: { 0x30, 0x39, input_parameter, NULL },
1.131 nicm 550: { 0x3a, 0x3a, input_parameter, NULL },
1.28 nicm 551: { 0x3b, 0x3b, input_parameter, NULL },
552: { 0x3c, 0x3f, NULL, &input_state_csi_ignore },
553: { 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
554: { 0x7f, 0xff, NULL, NULL },
1.1 nicm 555:
1.28 nicm 556: { -1, -1, NULL, NULL }
557: };
1.1 nicm 558:
1.28 nicm 559: /* csi_intermediate state table. */
1.104 nicm 560: static const struct input_transition input_state_csi_intermediate_table[] = {
1.28 nicm 561: INPUT_STATE_ANYWHERE,
562:
563: { 0x00, 0x17, input_c0_dispatch, NULL },
564: { 0x19, 0x19, input_c0_dispatch, NULL },
565: { 0x1c, 0x1f, input_c0_dispatch, NULL },
566: { 0x20, 0x2f, input_intermediate, NULL },
567: { 0x30, 0x3f, NULL, &input_state_csi_ignore },
568: { 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
569: { 0x7f, 0xff, NULL, NULL },
1.1 nicm 570:
1.28 nicm 571: { -1, -1, NULL, NULL }
572: };
1.1 nicm 573:
1.28 nicm 574: /* csi_ignore state table. */
1.104 nicm 575: static const struct input_transition input_state_csi_ignore_table[] = {
1.28 nicm 576: INPUT_STATE_ANYWHERE,
577:
578: { 0x00, 0x17, input_c0_dispatch, NULL },
579: { 0x19, 0x19, input_c0_dispatch, NULL },
580: { 0x1c, 0x1f, input_c0_dispatch, NULL },
581: { 0x20, 0x3f, NULL, NULL },
582: { 0x40, 0x7e, NULL, &input_state_ground },
583: { 0x7f, 0xff, NULL, NULL },
1.1 nicm 584:
1.28 nicm 585: { -1, -1, NULL, NULL }
586: };
1.1 nicm 587:
1.28 nicm 588: /* dcs_enter state table. */
1.104 nicm 589: static const struct input_transition input_state_dcs_enter_table[] = {
1.28 nicm 590: INPUT_STATE_ANYWHERE,
591:
592: { 0x00, 0x17, NULL, NULL },
593: { 0x19, 0x19, NULL, NULL },
594: { 0x1c, 0x1f, NULL, NULL },
595: { 0x20, 0x2f, input_intermediate, &input_state_dcs_intermediate },
596: { 0x30, 0x39, input_parameter, &input_state_dcs_parameter },
597: { 0x3a, 0x3a, NULL, &input_state_dcs_ignore },
598: { 0x3b, 0x3b, input_parameter, &input_state_dcs_parameter },
599: { 0x3c, 0x3f, input_intermediate, &input_state_dcs_parameter },
1.37 nicm 600: { 0x40, 0x7e, input_input, &input_state_dcs_handler },
1.28 nicm 601: { 0x7f, 0xff, NULL, NULL },
1.1 nicm 602:
1.28 nicm 603: { -1, -1, NULL, NULL }
604: };
1.1 nicm 605:
1.28 nicm 606: /* dcs_parameter state table. */
1.104 nicm 607: static const struct input_transition input_state_dcs_parameter_table[] = {
1.28 nicm 608: INPUT_STATE_ANYWHERE,
609:
610: { 0x00, 0x17, NULL, NULL },
611: { 0x19, 0x19, NULL, NULL },
612: { 0x1c, 0x1f, NULL, NULL },
613: { 0x20, 0x2f, input_intermediate, &input_state_dcs_intermediate },
614: { 0x30, 0x39, input_parameter, NULL },
615: { 0x3a, 0x3a, NULL, &input_state_dcs_ignore },
616: { 0x3b, 0x3b, input_parameter, NULL },
617: { 0x3c, 0x3f, NULL, &input_state_dcs_ignore },
1.37 nicm 618: { 0x40, 0x7e, input_input, &input_state_dcs_handler },
1.28 nicm 619: { 0x7f, 0xff, NULL, NULL },
1.1 nicm 620:
1.28 nicm 621: { -1, -1, NULL, NULL }
622: };
1.1 nicm 623:
1.138 nicm 624: /* dcs_intermediate state table. */
1.104 nicm 625: static const struct input_transition input_state_dcs_intermediate_table[] = {
1.28 nicm 626: INPUT_STATE_ANYWHERE,
627:
628: { 0x00, 0x17, NULL, NULL },
629: { 0x19, 0x19, NULL, NULL },
630: { 0x1c, 0x1f, NULL, NULL },
631: { 0x20, 0x2f, input_intermediate, NULL },
632: { 0x30, 0x3f, NULL, &input_state_dcs_ignore },
1.37 nicm 633: { 0x40, 0x7e, input_input, &input_state_dcs_handler },
1.28 nicm 634: { 0x7f, 0xff, NULL, NULL },
1.1 nicm 635:
1.28 nicm 636: { -1, -1, NULL, NULL }
637: };
1.1 nicm 638:
1.28 nicm 639: /* dcs_handler state table. */
1.104 nicm 640: static const struct input_transition input_state_dcs_handler_table[] = {
1.37 nicm 641: /* No INPUT_STATE_ANYWHERE */
642:
643: { 0x00, 0x1a, input_input, NULL },
644: { 0x1b, 0x1b, NULL, &input_state_dcs_escape },
645: { 0x1c, 0xff, input_input, NULL },
646:
647: { -1, -1, NULL, NULL }
648: };
649:
650: /* dcs_escape state table. */
1.104 nicm 651: static const struct input_transition input_state_dcs_escape_table[] = {
1.37 nicm 652: /* No INPUT_STATE_ANYWHERE */
1.28 nicm 653:
1.37 nicm 654: { 0x00, 0x5b, input_input, &input_state_dcs_handler },
655: { 0x5c, 0x5c, input_dcs_dispatch, &input_state_ground },
656: { 0x5d, 0xff, input_input, &input_state_dcs_handler },
1.1 nicm 657:
1.28 nicm 658: { -1, -1, NULL, NULL }
659: };
1.1 nicm 660:
1.40 nicm 661: /* dcs_ignore state table. */
1.104 nicm 662: static const struct input_transition input_state_dcs_ignore_table[] = {
1.28 nicm 663: INPUT_STATE_ANYWHERE,
664:
665: { 0x00, 0x17, NULL, NULL },
666: { 0x19, 0x19, NULL, NULL },
667: { 0x1c, 0x1f, NULL, NULL },
668: { 0x20, 0xff, NULL, NULL },
1.1 nicm 669:
1.28 nicm 670: { -1, -1, NULL, NULL }
671: };
1.1 nicm 672:
1.28 nicm 673: /* osc_string state table. */
1.104 nicm 674: static const struct input_transition input_state_osc_string_table[] = {
1.28 nicm 675: INPUT_STATE_ANYWHERE,
676:
1.138 nicm 677: { 0x00, 0x06, NULL, NULL },
678: { 0x07, 0x07, input_end_bel, &input_state_ground },
679: { 0x08, 0x17, NULL, NULL },
680: { 0x19, 0x19, NULL, NULL },
681: { 0x1c, 0x1f, NULL, NULL },
682: { 0x20, 0xff, input_input, NULL },
1.1 nicm 683:
1.28 nicm 684: { -1, -1, NULL, NULL }
685: };
1.1 nicm 686:
1.28 nicm 687: /* apc_string state table. */
1.104 nicm 688: static const struct input_transition input_state_apc_string_table[] = {
1.28 nicm 689: INPUT_STATE_ANYWHERE,
690:
691: { 0x00, 0x17, NULL, NULL },
692: { 0x19, 0x19, NULL, NULL },
693: { 0x1c, 0x1f, NULL, NULL },
694: { 0x20, 0xff, input_input, NULL },
1.1 nicm 695:
1.28 nicm 696: { -1, -1, NULL, NULL }
697: };
1.1 nicm 698:
1.28 nicm 699: /* rename_string state table. */
1.104 nicm 700: static const struct input_transition input_state_rename_string_table[] = {
1.28 nicm 701: INPUT_STATE_ANYWHERE,
702:
703: { 0x00, 0x17, NULL, NULL },
704: { 0x19, 0x19, NULL, NULL },
705: { 0x1c, 0x1f, NULL, NULL },
706: { 0x20, 0xff, input_input, NULL },
1.1 nicm 707:
1.28 nicm 708: { -1, -1, NULL, NULL }
709: };
1.1 nicm 710:
1.28 nicm 711: /* consume_st state table. */
1.104 nicm 712: static const struct input_transition input_state_consume_st_table[] = {
1.28 nicm 713: INPUT_STATE_ANYWHERE,
714:
715: { 0x00, 0x17, NULL, NULL },
716: { 0x19, 0x19, NULL, NULL },
717: { 0x1c, 0x1f, NULL, NULL },
718: { 0x20, 0xff, NULL, NULL },
1.6 nicm 719:
1.28 nicm 720: { -1, -1, NULL, NULL }
721: };
1.6 nicm 722:
1.28 nicm 723: /* Input table compare. */
1.104 nicm 724: static int
1.28 nicm 725: input_table_compare(const void *key, const void *value)
1.1 nicm 726: {
1.28 nicm 727: const struct input_ctx *ictx = key;
728: const struct input_table_entry *entry = value;
1.1 nicm 729:
1.28 nicm 730: if (ictx->ch != entry->ch)
731: return (ictx->ch - entry->ch);
732: return (strcmp(ictx->interm_buf, entry->interm));
1.1 nicm 733: }
734:
1.125 nicm 735: /*
736: * Timer - if this expires then have been waiting for a terminator for too
737: * long, so reset to ground.
738: */
739: static void
740: input_timer_callback(__unused int fd, __unused short events, void *arg)
741: {
742: struct input_ctx *ictx = arg;
743:
1.171 nicm 744: log_debug("%s: %s expired" , __func__, ictx->state->name);
745: input_reset(ictx, 0);
1.125 nicm 746: }
747:
748: /* Start the timer. */
749: static void
750: input_start_timer(struct input_ctx *ictx)
751: {
1.167 nicm 752: struct timeval tv = { .tv_sec = 5, .tv_usec = 0 };
1.125 nicm 753:
754: event_del(&ictx->timer);
755: event_add(&ictx->timer, &tv);
756: }
757:
1.69 nicm 758: /* Reset cell state to default. */
1.104 nicm 759: static void
1.69 nicm 760: input_reset_cell(struct input_ctx *ictx)
761: {
762: memcpy(&ictx->cell.cell, &grid_default_cell, sizeof ictx->cell.cell);
763: ictx->cell.set = 0;
764: ictx->cell.g0set = ictx->cell.g1set = 0;
765:
766: memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
767: ictx->old_cx = 0;
768: ictx->old_cy = 0;
769: }
770:
1.146 nicm 771: /* Save screen state. */
772: static void
773: input_save_state(struct input_ctx *ictx)
774: {
775: struct screen_write_ctx *sctx = &ictx->ctx;
776: struct screen *s = sctx->s;
777:
778: memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
779: ictx->old_cx = s->cx;
780: ictx->old_cy = s->cy;
781: ictx->old_mode = s->mode;
782: }
783:
1.169 nicm 784: /* Restore screen state. */
1.146 nicm 785: static void
786: input_restore_state(struct input_ctx *ictx)
787: {
788: struct screen_write_ctx *sctx = &ictx->ctx;
789:
790: memcpy(&ictx->cell, &ictx->old_cell, sizeof ictx->cell);
791: if (ictx->old_mode & MODE_ORIGIN)
792: screen_write_mode_set(sctx, MODE_ORIGIN);
793: else
794: screen_write_mode_clear(sctx, MODE_ORIGIN);
795: screen_write_cursormove(sctx, ictx->old_cx, ictx->old_cy, 0);
796: }
797:
1.28 nicm 798: /* Initialise input parser. */
1.171 nicm 799: struct input_ctx *
1.172 nicm 800: input_init(struct window_pane *wp, struct bufferevent *bev)
1.1 nicm 801: {
1.74 nicm 802: struct input_ctx *ictx;
803:
1.171 nicm 804: ictx = xcalloc(1, sizeof *ictx);
805: ictx->wp = wp;
1.172 nicm 806: ictx->event = bev;
1.1 nicm 807:
1.67 nicm 808: ictx->input_space = INPUT_BUF_START;
809: ictx->input_buf = xmalloc(INPUT_BUF_START);
810:
1.97 nicm 811: ictx->since_ground = evbuffer_new();
1.139 nicm 812: if (ictx->since_ground == NULL)
813: fatalx("out of memory");
1.52 nicm 814:
1.125 nicm 815: evtimer_set(&ictx->timer, input_timer_callback, ictx);
816:
1.171 nicm 817: input_reset(ictx, 0);
818: return (ictx);
1.1 nicm 819: }
820:
1.28 nicm 821: /* Destroy input parser. */
1.1 nicm 822: void
1.171 nicm 823: input_free(struct input_ctx *ictx)
1.1 nicm 824: {
1.171 nicm 825: u_int i;
1.131 nicm 826:
827: for (i = 0; i < ictx->param_list_len; i++) {
828: if (ictx->param_list[i].type == INPUT_STRING)
829: free(ictx->param_list[i].str);
830: }
1.74 nicm 831:
1.125 nicm 832: event_del(&ictx->timer);
833:
1.74 nicm 834: free(ictx->input_buf);
835: evbuffer_free(ictx->since_ground);
836:
1.106 nicm 837: free(ictx);
1.74 nicm 838: }
839:
840: /* Reset input state and clear screen. */
841: void
1.171 nicm 842: input_reset(struct input_ctx *ictx, int clear)
1.74 nicm 843: {
1.144 nicm 844: struct screen_write_ctx *sctx = &ictx->ctx;
1.171 nicm 845: struct window_pane *wp = ictx->wp;
1.67 nicm 846:
1.80 nicm 847: input_reset_cell(ictx);
1.74 nicm 848:
1.171 nicm 849: if (clear && wp != NULL) {
1.142 nicm 850: if (TAILQ_EMPTY(&wp->modes))
1.177 nicm 851: screen_write_start_pane(sctx, wp, &wp->base);
1.97 nicm 852: else
1.177 nicm 853: screen_write_start(sctx, &wp->base);
1.144 nicm 854: screen_write_reset(sctx);
855: screen_write_stop(sctx);
1.97 nicm 856: }
857:
1.125 nicm 858: input_clear(ictx);
1.97 nicm 859:
1.127 nicm 860: ictx->last = -1;
861:
1.97 nicm 862: ictx->state = &input_state_ground;
863: ictx->flags = 0;
1.74 nicm 864: }
865:
866: /* Return pending data. */
867: struct evbuffer *
1.171 nicm 868: input_pending(struct input_ctx *ictx)
1.74 nicm 869: {
1.171 nicm 870: return (ictx->since_ground);
1.52 nicm 871: }
872:
873: /* Change input state. */
1.104 nicm 874: static void
1.171 nicm 875: input_set_state(struct input_ctx *ictx, const struct input_transition *itr)
1.52 nicm 876: {
877: if (ictx->state->exit != NULL)
878: ictx->state->exit(ictx);
879: ictx->state = itr->state;
880: if (ictx->state->enter != NULL)
881: ictx->state->enter(ictx);
1.1 nicm 882: }
883:
1.171 nicm 884: /* Parse data. */
885: static void
886: input_parse(struct input_ctx *ictx, u_char *buf, size_t len)
1.1 nicm 887: {
1.144 nicm 888: struct screen_write_ctx *sctx = &ictx->ctx;
1.160 nicm 889: const struct input_state *state = NULL;
890: const struct input_transition *itr = NULL;
1.152 nicm 891: size_t off = 0;
1.1 nicm 892:
1.28 nicm 893: /* Parse the input. */
894: while (off < len) {
895: ictx->ch = buf[off++];
896:
897: /* Find the transition. */
1.160 nicm 898: if (ictx->state != state ||
899: itr == NULL ||
900: ictx->ch < itr->first ||
901: ictx->ch > itr->last) {
902: itr = ictx->state->transitions;
903: while (itr->first != -1 && itr->last != -1) {
1.161 nicm 904: if (ictx->ch >= itr->first &&
905: ictx->ch <= itr->last)
1.160 nicm 906: break;
907: itr++;
908: }
909: if (itr->first == -1 || itr->last == -1) {
910: /* No transition? Eh? */
911: fatalx("no transition from state");
912: }
1.3 nicm 913: }
1.160 nicm 914: state = ictx->state;
1.1 nicm 915:
916: /*
1.114 nicm 917: * Any state except print stops the current collection. This is
918: * an optimization to avoid checking if the attributes have
919: * changed for every character. It will stop unnecessarily for
920: * sequences that don't make a terminal change, but they should
921: * be the minority.
922: */
923: if (itr->handler != input_print)
1.144 nicm 924: screen_write_collect_end(sctx);
1.114 nicm 925:
926: /*
1.28 nicm 927: * Execute the handler, if any. Don't switch state if it
928: * returns non-zero.
1.1 nicm 929: */
1.31 nicm 930: if (itr->handler != NULL && itr->handler(ictx) != 0)
1.28 nicm 931: continue;
932:
933: /* And switch state, if necessary. */
1.52 nicm 934: if (itr->state != NULL)
1.171 nicm 935: input_set_state(ictx, itr);
1.52 nicm 936:
937: /* If not in ground state, save input. */
938: if (ictx->state != &input_state_ground)
939: evbuffer_add(ictx->since_ground, &ictx->ch, 1);
1.1 nicm 940: }
1.171 nicm 941: }
942:
943: /* Parse input from pane. */
944: void
945: input_parse_pane(struct window_pane *wp)
946: {
1.179 nicm 947: void *new_data;
948: size_t new_size;
1.171 nicm 949:
1.179 nicm 950: new_data = window_pane_get_new_data(wp, &wp->offset, &new_size);
951: input_parse_buffer(wp, new_data, new_size);
1.180 nicm 952: window_pane_update_used_data(wp, &wp->offset, new_size);
1.171 nicm 953: }
954:
955: /* Parse given input. */
956: void
957: input_parse_buffer(struct window_pane *wp, u_char *buf, size_t len)
958: {
959: struct input_ctx *ictx = wp->ictx;
960: struct screen_write_ctx *sctx = &ictx->ctx;
961:
962: if (len == 0)
963: return;
964:
965: window_update_activity(wp->window);
966: wp->flags |= PANE_CHANGED;
1.1 nicm 967:
1.171 nicm 968: /* NULL wp if there is a mode set as don't want to update the tty. */
969: if (TAILQ_EMPTY(&wp->modes))
1.177 nicm 970: screen_write_start_pane(sctx, wp, &wp->base);
1.171 nicm 971: else
1.177 nicm 972: screen_write_start(sctx, &wp->base);
1.171 nicm 973:
974: log_debug("%s: %%%u %s, %zu bytes: %.*s", __func__, wp->id,
975: ictx->state->name, len, (int)len, buf);
976:
977: input_parse(ictx, buf, len);
978: screen_write_stop(sctx);
979: }
980:
981: /* Parse given input for screen. */
982: void
1.177 nicm 983: input_parse_screen(struct input_ctx *ictx, struct screen *s,
984: screen_write_init_ctx_cb cb, void *arg, u_char *buf, size_t len)
1.171 nicm 985: {
986: struct screen_write_ctx *sctx = &ictx->ctx;
987:
988: if (len == 0)
989: return;
990:
1.177 nicm 991: screen_write_start_callback(sctx, s, cb, arg);
1.171 nicm 992: input_parse(ictx, buf, len);
1.144 nicm 993: screen_write_stop(sctx);
1.1 nicm 994: }
995:
1.28 nicm 996: /* Split the parameter list (if any). */
1.104 nicm 997: static int
1.28 nicm 998: input_split(struct input_ctx *ictx)
1.1 nicm 999: {
1.131 nicm 1000: const char *errstr;
1001: char *ptr, *out;
1002: struct input_param *ip;
1003: u_int i;
1.1 nicm 1004:
1.131 nicm 1005: for (i = 0; i < ictx->param_list_len; i++) {
1006: if (ictx->param_list[i].type == INPUT_STRING)
1007: free(ictx->param_list[i].str);
1008: }
1.28 nicm 1009: ictx->param_list_len = 0;
1.131 nicm 1010:
1.28 nicm 1011: if (ictx->param_len == 0)
1012: return (0);
1.131 nicm 1013: ip = &ictx->param_list[0];
1.1 nicm 1014:
1.28 nicm 1015: ptr = ictx->param_buf;
1016: while ((out = strsep(&ptr, ";")) != NULL) {
1017: if (*out == '\0')
1.131 nicm 1018: ip->type = INPUT_MISSING;
1.28 nicm 1019: else {
1.131 nicm 1020: if (strchr(out, ':') != NULL) {
1021: ip->type = INPUT_STRING;
1022: ip->str = xstrdup(out);
1023: } else {
1024: ip->type = INPUT_NUMBER;
1025: ip->num = strtonum(out, 0, INT_MAX, &errstr);
1026: if (errstr != NULL)
1027: return (-1);
1028: }
1.28 nicm 1029: }
1.131 nicm 1030: ip = &ictx->param_list[++ictx->param_list_len];
1.28 nicm 1031: if (ictx->param_list_len == nitems(ictx->param_list))
1032: return (-1);
1033: }
1.1 nicm 1034:
1.131 nicm 1035: for (i = 0; i < ictx->param_list_len; i++) {
1036: ip = &ictx->param_list[i];
1037: if (ip->type == INPUT_MISSING)
1038: log_debug("parameter %u: missing", i);
1039: else if (ip->type == INPUT_STRING)
1040: log_debug("parameter %u: string %s", i, ip->str);
1041: else if (ip->type == INPUT_NUMBER)
1042: log_debug("parameter %u: number %d", i, ip->num);
1043: }
1044:
1.28 nicm 1045: return (0);
1.1 nicm 1046: }
1047:
1.40 nicm 1048: /* Get an argument or return default value. */
1.104 nicm 1049: static int
1.28 nicm 1050: input_get(struct input_ctx *ictx, u_int validx, int minval, int defval)
1.1 nicm 1051: {
1.131 nicm 1052: struct input_param *ip;
1053: int retval;
1.1 nicm 1054:
1.28 nicm 1055: if (validx >= ictx->param_list_len)
1056: return (defval);
1.131 nicm 1057: ip = &ictx->param_list[validx];
1058: if (ip->type == INPUT_MISSING)
1.28 nicm 1059: return (defval);
1.131 nicm 1060: if (ip->type == INPUT_STRING)
1061: return (-1);
1062: retval = ip->num;
1.28 nicm 1063: if (retval < minval)
1064: return (minval);
1065: return (retval);
1.1 nicm 1066: }
1067:
1.28 nicm 1068: /* Reply to terminal query. */
1.104 nicm 1069: static void
1.28 nicm 1070: input_reply(struct input_ctx *ictx, const char *fmt, ...)
1.1 nicm 1071: {
1.172 nicm 1072: struct bufferevent *bev = ictx->event;
1.171 nicm 1073: va_list ap;
1074: char *reply;
1075:
1.28 nicm 1076: va_start(ap, fmt);
1.103 nicm 1077: xvasprintf(&reply, fmt, ap);
1.28 nicm 1078: va_end(ap);
1.1 nicm 1079:
1.172 nicm 1080: bufferevent_write(bev, reply, strlen(reply));
1.53 nicm 1081: free(reply);
1.8 nicm 1082: }
1083:
1.28 nicm 1084: /* Clear saved state. */
1.104 nicm 1085: static void
1.28 nicm 1086: input_clear(struct input_ctx *ictx)
1.8 nicm 1087: {
1.125 nicm 1088: event_del(&ictx->timer);
1089:
1.28 nicm 1090: *ictx->interm_buf = '\0';
1091: ictx->interm_len = 0;
1.8 nicm 1092:
1.28 nicm 1093: *ictx->param_buf = '\0';
1094: ictx->param_len = 0;
1.8 nicm 1095:
1.35 nicm 1096: *ictx->input_buf = '\0';
1097: ictx->input_len = 0;
1098:
1.138 nicm 1099: ictx->input_end = INPUT_END_ST;
1100:
1.28 nicm 1101: ictx->flags &= ~INPUT_DISCARD;
1.14 nicm 1102: }
1103:
1.67 nicm 1104: /* Reset for ground state. */
1.104 nicm 1105: static void
1.67 nicm 1106: input_ground(struct input_ctx *ictx)
1107: {
1.125 nicm 1108: event_del(&ictx->timer);
1.67 nicm 1109: evbuffer_drain(ictx->since_ground, EVBUFFER_LENGTH(ictx->since_ground));
1110:
1111: if (ictx->input_space > INPUT_BUF_START) {
1112: ictx->input_space = INPUT_BUF_START;
1.71 nicm 1113: ictx->input_buf = xrealloc(ictx->input_buf, INPUT_BUF_START);
1.67 nicm 1114: }
1115: }
1116:
1.28 nicm 1117: /* Output this character to the screen. */
1.104 nicm 1118: static int
1.28 nicm 1119: input_print(struct input_ctx *ictx)
1.14 nicm 1120: {
1.144 nicm 1121: struct screen_write_ctx *sctx = &ictx->ctx;
1122: int set;
1.69 nicm 1123:
1.130 nicm 1124: ictx->utf8started = 0; /* can't be valid UTF-8 */
1125:
1.69 nicm 1126: set = ictx->cell.set == 0 ? ictx->cell.g0set : ictx->cell.g1set;
1127: if (set == 1)
1128: ictx->cell.cell.attr |= GRID_ATTR_CHARSET;
1129: else
1130: ictx->cell.cell.attr &= ~GRID_ATTR_CHARSET;
1131:
1.89 nicm 1132: utf8_set(&ictx->cell.cell.data, ictx->ch);
1.144 nicm 1133: screen_write_collect_add(sctx, &ictx->cell.cell);
1.127 nicm 1134: ictx->last = ictx->ch;
1.69 nicm 1135:
1136: ictx->cell.cell.attr &= ~GRID_ATTR_CHARSET;
1.14 nicm 1137:
1.28 nicm 1138: return (0);
1.1 nicm 1139: }
1140:
1.28 nicm 1141: /* Collect intermediate string. */
1.104 nicm 1142: static int
1.28 nicm 1143: input_intermediate(struct input_ctx *ictx)
1.1 nicm 1144: {
1.28 nicm 1145: if (ictx->interm_len == (sizeof ictx->interm_buf) - 1)
1146: ictx->flags |= INPUT_DISCARD;
1147: else {
1148: ictx->interm_buf[ictx->interm_len++] = ictx->ch;
1149: ictx->interm_buf[ictx->interm_len] = '\0';
1150: }
1.1 nicm 1151:
1.28 nicm 1152: return (0);
1.1 nicm 1153: }
1154:
1.28 nicm 1155: /* Collect parameter string. */
1.104 nicm 1156: static int
1.28 nicm 1157: input_parameter(struct input_ctx *ictx)
1.1 nicm 1158: {
1.28 nicm 1159: if (ictx->param_len == (sizeof ictx->param_buf) - 1)
1160: ictx->flags |= INPUT_DISCARD;
1161: else {
1162: ictx->param_buf[ictx->param_len++] = ictx->ch;
1163: ictx->param_buf[ictx->param_len] = '\0';
1164: }
1.1 nicm 1165:
1.28 nicm 1166: return (0);
1.1 nicm 1167: }
1168:
1.28 nicm 1169: /* Collect input string. */
1.104 nicm 1170: static int
1.28 nicm 1171: input_input(struct input_ctx *ictx)
1.1 nicm 1172: {
1.67 nicm 1173: size_t available;
1174:
1175: available = ictx->input_space;
1176: while (ictx->input_len + 1 >= available) {
1177: available *= 2;
1178: if (available > INPUT_BUF_LIMIT) {
1179: ictx->flags |= INPUT_DISCARD;
1180: return (0);
1181: }
1.71 nicm 1182: ictx->input_buf = xrealloc(ictx->input_buf, available);
1.67 nicm 1183: ictx->input_space = available;
1.28 nicm 1184: }
1.67 nicm 1185: ictx->input_buf[ictx->input_len++] = ictx->ch;
1186: ictx->input_buf[ictx->input_len] = '\0';
1.1 nicm 1187:
1.28 nicm 1188: return (0);
1.1 nicm 1189: }
1190:
1.28 nicm 1191: /* Execute C0 control sequence. */
1.104 nicm 1192: static int
1.28 nicm 1193: input_c0_dispatch(struct input_ctx *ictx)
1.1 nicm 1194: {
1.28 nicm 1195: struct screen_write_ctx *sctx = &ictx->ctx;
1196: struct window_pane *wp = ictx->wp;
1197: struct screen *s = sctx->s;
1.1 nicm 1198:
1.130 nicm 1199: ictx->utf8started = 0; /* can't be valid UTF-8 */
1200:
1.84 nicm 1201: log_debug("%s: '%c'", __func__, ictx->ch);
1.1 nicm 1202:
1.28 nicm 1203: switch (ictx->ch) {
1204: case '\000': /* NUL */
1205: break;
1206: case '\007': /* BEL */
1.171 nicm 1207: if (wp != NULL)
1208: alerts_queue(wp->window, WINDOW_BELL);
1.28 nicm 1209: break;
1210: case '\010': /* BS */
1211: screen_write_backspace(sctx);
1.75 nicm 1212: break;
1.28 nicm 1213: case '\011': /* HT */
1214: /* Don't tab beyond the end of the line. */
1215: if (s->cx >= screen_size_x(s) - 1)
1216: break;
1.1 nicm 1217:
1.28 nicm 1218: /* Find the next tab point, or use the last column if none. */
1219: do {
1220: s->cx++;
1221: if (bit_test(s->tabs, s->cx))
1222: break;
1223: } while (s->cx < screen_size_x(s) - 1);
1224: break;
1225: case '\012': /* LF */
1226: case '\013': /* VT */
1227: case '\014': /* FF */
1.121 nicm 1228: screen_write_linefeed(sctx, 0, ictx->cell.cell.bg);
1.151 nicm 1229: if (s->mode & MODE_CRLF)
1230: screen_write_carriagereturn(sctx);
1.75 nicm 1231: break;
1.28 nicm 1232: case '\015': /* CR */
1233: screen_write_carriagereturn(sctx);
1.75 nicm 1234: break;
1.28 nicm 1235: case '\016': /* SO */
1.69 nicm 1236: ictx->cell.set = 1;
1.28 nicm 1237: break;
1238: case '\017': /* SI */
1.69 nicm 1239: ictx->cell.set = 0;
1.28 nicm 1240: break;
1241: default:
1242: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1243: break;
1244: }
1.1 nicm 1245:
1.127 nicm 1246: ictx->last = -1;
1.28 nicm 1247: return (0);
1.7 nicm 1248: }
1249:
1.28 nicm 1250: /* Execute escape sequence. */
1.104 nicm 1251: static int
1.28 nicm 1252: input_esc_dispatch(struct input_ctx *ictx)
1.7 nicm 1253: {
1.31 nicm 1254: struct screen_write_ctx *sctx = &ictx->ctx;
1.171 nicm 1255: struct window_pane *wp = ictx->wp;
1.31 nicm 1256: struct screen *s = sctx->s;
1257: struct input_table_entry *entry;
1.7 nicm 1258:
1.28 nicm 1259: if (ictx->flags & INPUT_DISCARD)
1260: return (0);
1261: log_debug("%s: '%c', %s", __func__, ictx->ch, ictx->interm_buf);
1.7 nicm 1262:
1.28 nicm 1263: entry = bsearch(ictx, input_esc_table, nitems(input_esc_table),
1264: sizeof input_esc_table[0], input_table_compare);
1265: if (entry == NULL) {
1266: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1267: return (0);
1268: }
1.7 nicm 1269:
1.28 nicm 1270: switch (entry->type) {
1271: case INPUT_ESC_RIS:
1.171 nicm 1272: if (wp != NULL)
1273: window_pane_reset_palette(wp);
1.69 nicm 1274: input_reset_cell(ictx);
1.46 nicm 1275: screen_write_reset(sctx);
1.28 nicm 1276: break;
1277: case INPUT_ESC_IND:
1.121 nicm 1278: screen_write_linefeed(sctx, 0, ictx->cell.cell.bg);
1.28 nicm 1279: break;
1280: case INPUT_ESC_NEL:
1281: screen_write_carriagereturn(sctx);
1.121 nicm 1282: screen_write_linefeed(sctx, 0, ictx->cell.cell.bg);
1.28 nicm 1283: break;
1284: case INPUT_ESC_HTS:
1285: if (s->cx < screen_size_x(s))
1286: bit_set(s->tabs, s->cx);
1287: break;
1288: case INPUT_ESC_RI:
1.121 nicm 1289: screen_write_reverseindex(sctx, ictx->cell.cell.bg);
1.28 nicm 1290: break;
1291: case INPUT_ESC_DECKPAM:
1.59 nicm 1292: screen_write_mode_set(sctx, MODE_KKEYPAD);
1.28 nicm 1293: break;
1294: case INPUT_ESC_DECKPNM:
1.59 nicm 1295: screen_write_mode_clear(sctx, MODE_KKEYPAD);
1.1 nicm 1296: break;
1.28 nicm 1297: case INPUT_ESC_DECSC:
1.146 nicm 1298: input_save_state(ictx);
1.28 nicm 1299: break;
1300: case INPUT_ESC_DECRC:
1.146 nicm 1301: input_restore_state(ictx);
1.28 nicm 1302: break;
1303: case INPUT_ESC_DECALN:
1304: screen_write_alignmenttest(sctx);
1305: break;
1.69 nicm 1306: case INPUT_ESC_SCSG0_ON:
1307: ictx->cell.g0set = 1;
1308: break;
1309: case INPUT_ESC_SCSG0_OFF:
1310: ictx->cell.g0set = 0;
1311: break;
1312: case INPUT_ESC_SCSG1_ON:
1313: ictx->cell.g1set = 1;
1.1 nicm 1314: break;
1.69 nicm 1315: case INPUT_ESC_SCSG1_OFF:
1316: ictx->cell.g1set = 0;
1.1 nicm 1317: break;
1.107 nicm 1318: case INPUT_ESC_ST:
1319: /* ST terminates OSC but the state transition already did it. */
1320: break;
1.1 nicm 1321: }
1.28 nicm 1322:
1.127 nicm 1323: ictx->last = -1;
1.28 nicm 1324: return (0);
1.1 nicm 1325: }
1326:
1.28 nicm 1327: /* Execute control sequence. */
1.104 nicm 1328: static int
1.28 nicm 1329: input_csi_dispatch(struct input_ctx *ictx)
1.1 nicm 1330: {
1.28 nicm 1331: struct screen_write_ctx *sctx = &ictx->ctx;
1332: struct screen *s = sctx->s;
1333: struct input_table_entry *entry;
1.127 nicm 1334: int i, n, m;
1.131 nicm 1335: u_int cx, bg = ictx->cell.cell.bg;
1.1 nicm 1336:
1.28 nicm 1337: if (ictx->flags & INPUT_DISCARD)
1338: return (0);
1.110 nicm 1339:
1340: log_debug("%s: '%c' \"%s\" \"%s\"",
1341: __func__, ictx->ch, ictx->interm_buf, ictx->param_buf);
1342:
1.28 nicm 1343: if (input_split(ictx) != 0)
1344: return (0);
1.1 nicm 1345:
1.28 nicm 1346: entry = bsearch(ictx, input_csi_table, nitems(input_csi_table),
1347: sizeof input_csi_table[0], input_table_compare);
1348: if (entry == NULL) {
1349: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1350: return (0);
1351: }
1.1 nicm 1352:
1.28 nicm 1353: switch (entry->type) {
1354: case INPUT_CSI_CBT:
1355: /* Find the previous tab point, n times. */
1.81 nicm 1356: cx = s->cx;
1357: if (cx > screen_size_x(s) - 1)
1358: cx = screen_size_x(s) - 1;
1.28 nicm 1359: n = input_get(ictx, 0, 1, 1);
1.131 nicm 1360: if (n == -1)
1361: break;
1.81 nicm 1362: while (cx > 0 && n-- > 0) {
1.28 nicm 1363: do
1.81 nicm 1364: cx--;
1365: while (cx > 0 && !bit_test(s->tabs, cx));
1.28 nicm 1366: }
1.81 nicm 1367: s->cx = cx;
1.28 nicm 1368: break;
1369: case INPUT_CSI_CUB:
1.131 nicm 1370: n = input_get(ictx, 0, 1, 1);
1371: if (n != -1)
1372: screen_write_cursorleft(sctx, n);
1.28 nicm 1373: break;
1374: case INPUT_CSI_CUD:
1.131 nicm 1375: n = input_get(ictx, 0, 1, 1);
1376: if (n != -1)
1377: screen_write_cursordown(sctx, n);
1.28 nicm 1378: break;
1379: case INPUT_CSI_CUF:
1.131 nicm 1380: n = input_get(ictx, 0, 1, 1);
1381: if (n != -1)
1382: screen_write_cursorright(sctx, n);
1.28 nicm 1383: break;
1384: case INPUT_CSI_CUP:
1385: n = input_get(ictx, 0, 1, 1);
1386: m = input_get(ictx, 1, 1, 1);
1.131 nicm 1387: if (n != -1 && m != -1)
1.146 nicm 1388: screen_write_cursormove(sctx, m - 1, n - 1, 1);
1.28 nicm 1389: break;
1.178 nicm 1390: case INPUT_CSI_MODSET:
1391: n = input_get(ictx, 0, 0, 0);
1392: m = input_get(ictx, 1, 0, 0);
1.189 ! nicm 1393: if (options_get_number(global_options, "extended-keys") == 2)
! 1394: break;
1.178 nicm 1395: if (n == 0 || (n == 4 && m == 0))
1396: screen_write_mode_clear(sctx, MODE_KEXTENDED);
1397: else if (n == 4 && (m == 1 || m == 2))
1398: screen_write_mode_set(sctx, MODE_KEXTENDED);
1399: break;
1400: case INPUT_CSI_MODOFF:
1401: n = input_get(ictx, 0, 0, 0);
1402: if (n == 4)
1403: screen_write_mode_clear(sctx, MODE_KEXTENDED);
1404: break;
1.65 nicm 1405: case INPUT_CSI_WINOPS:
1406: input_csi_dispatch_winops(ictx);
1407: break;
1.28 nicm 1408: case INPUT_CSI_CUU:
1.131 nicm 1409: n = input_get(ictx, 0, 1, 1);
1410: if (n != -1)
1411: screen_write_cursorup(sctx, n);
1.43 nicm 1412: break;
1413: case INPUT_CSI_CNL:
1.131 nicm 1414: n = input_get(ictx, 0, 1, 1);
1415: if (n != -1) {
1416: screen_write_carriagereturn(sctx);
1417: screen_write_cursordown(sctx, n);
1418: }
1.43 nicm 1419: break;
1420: case INPUT_CSI_CPL:
1.131 nicm 1421: n = input_get(ictx, 0, 1, 1);
1422: if (n != -1) {
1423: screen_write_carriagereturn(sctx);
1424: screen_write_cursorup(sctx, n);
1425: }
1.28 nicm 1426: break;
1427: case INPUT_CSI_DA:
1428: switch (input_get(ictx, 0, 0, 0)) {
1.131 nicm 1429: case -1:
1430: break;
1.28 nicm 1431: case 0:
1432: input_reply(ictx, "\033[?1;2c");
1.50 nicm 1433: break;
1434: default:
1435: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1436: break;
1437: }
1438: break;
1439: case INPUT_CSI_DA_TWO:
1440: switch (input_get(ictx, 0, 0, 0)) {
1.131 nicm 1441: case -1:
1442: break;
1.50 nicm 1443: case 0:
1.66 nicm 1444: input_reply(ictx, "\033[>84;0;0c");
1.28 nicm 1445: break;
1446: default:
1447: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1448: break;
1449: }
1.56 nicm 1450: break;
1451: case INPUT_CSI_ECH:
1.131 nicm 1452: n = input_get(ictx, 0, 1, 1);
1453: if (n != -1)
1454: screen_write_clearcharacter(sctx, n, bg);
1.28 nicm 1455: break;
1456: case INPUT_CSI_DCH:
1.131 nicm 1457: n = input_get(ictx, 0, 1, 1);
1458: if (n != -1)
1459: screen_write_deletecharacter(sctx, n, bg);
1.28 nicm 1460: break;
1461: case INPUT_CSI_DECSTBM:
1462: n = input_get(ictx, 0, 1, 1);
1463: m = input_get(ictx, 1, 1, screen_size_y(s));
1.131 nicm 1464: if (n != -1 && m != -1)
1465: screen_write_scrollregion(sctx, n - 1, m - 1);
1.1 nicm 1466: break;
1.28 nicm 1467: case INPUT_CSI_DL:
1.131 nicm 1468: n = input_get(ictx, 0, 1, 1);
1469: if (n != -1)
1470: screen_write_deleteline(sctx, n, bg);
1.1 nicm 1471: break;
1.28 nicm 1472: case INPUT_CSI_DSR:
1473: switch (input_get(ictx, 0, 0, 0)) {
1.131 nicm 1474: case -1:
1475: break;
1.28 nicm 1476: case 5:
1477: input_reply(ictx, "\033[0n");
1478: break;
1479: case 6:
1480: input_reply(ictx, "\033[%u;%uR", s->cy + 1, s->cx + 1);
1.168 nicm 1481: break;
1.28 nicm 1482: default:
1483: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1484: break;
1485: }
1486: break;
1487: case INPUT_CSI_ED:
1488: switch (input_get(ictx, 0, 0, 0)) {
1.131 nicm 1489: case -1:
1490: break;
1.28 nicm 1491: case 0:
1.131 nicm 1492: screen_write_clearendofscreen(sctx, bg);
1.28 nicm 1493: break;
1494: case 1:
1.131 nicm 1495: screen_write_clearstartofscreen(sctx, bg);
1.28 nicm 1496: break;
1497: case 2:
1.131 nicm 1498: screen_write_clearscreen(sctx, bg);
1.41 nicm 1499: break;
1500: case 3:
1.131 nicm 1501: if (input_get(ictx, 1, 0, 0) == 0) {
1.41 nicm 1502: /*
1503: * Linux console extension to clear history
1504: * (for example before locking the screen).
1505: */
1506: screen_write_clearhistory(sctx);
1507: }
1.28 nicm 1508: break;
1509: default:
1510: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1511: break;
1512: }
1513: break;
1514: case INPUT_CSI_EL:
1515: switch (input_get(ictx, 0, 0, 0)) {
1.131 nicm 1516: case -1:
1517: break;
1.28 nicm 1518: case 0:
1.131 nicm 1519: screen_write_clearendofline(sctx, bg);
1.28 nicm 1520: break;
1521: case 1:
1.131 nicm 1522: screen_write_clearstartofline(sctx, bg);
1.28 nicm 1523: break;
1524: case 2:
1.131 nicm 1525: screen_write_clearline(sctx, bg);
1.28 nicm 1526: break;
1527: default:
1528: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1529: break;
1530: }
1531: break;
1532: case INPUT_CSI_HPA:
1533: n = input_get(ictx, 0, 1, 1);
1.131 nicm 1534: if (n != -1)
1.148 nicm 1535: screen_write_cursormove(sctx, n - 1, -1, 1);
1.28 nicm 1536: break;
1537: case INPUT_CSI_ICH:
1.131 nicm 1538: n = input_get(ictx, 0, 1, 1);
1539: if (n != -1)
1540: screen_write_insertcharacter(sctx, n, bg);
1.28 nicm 1541: break;
1542: case INPUT_CSI_IL:
1.131 nicm 1543: n = input_get(ictx, 0, 1, 1);
1544: if (n != -1)
1545: screen_write_insertline(sctx, n, bg);
1.28 nicm 1546: break;
1.127 nicm 1547: case INPUT_CSI_REP:
1.131 nicm 1548: n = input_get(ictx, 0, 1, 1);
1549: if (n == -1)
1550: break;
1.185 nicm 1551:
1552: m = screen_size_x(s) - s->cx;
1553: if (n > m)
1554: n = m;
1.131 nicm 1555:
1.127 nicm 1556: if (ictx->last == -1)
1557: break;
1558: ictx->ch = ictx->last;
1559:
1560: for (i = 0; i < n; i++)
1561: input_print(ictx);
1562: break;
1.42 nicm 1563: case INPUT_CSI_RCP:
1.146 nicm 1564: input_restore_state(ictx);
1.42 nicm 1565: break;
1.28 nicm 1566: case INPUT_CSI_RM:
1.64 nicm 1567: input_csi_dispatch_rm(ictx);
1568: break;
1569: case INPUT_CSI_RM_PRIVATE:
1570: input_csi_dispatch_rm_private(ictx);
1571: break;
1572: case INPUT_CSI_SCP:
1.146 nicm 1573: input_save_state(ictx);
1.64 nicm 1574: break;
1575: case INPUT_CSI_SGR:
1576: input_csi_dispatch_sgr(ictx);
1577: break;
1578: case INPUT_CSI_SM:
1579: input_csi_dispatch_sm(ictx);
1580: break;
1581: case INPUT_CSI_SM_PRIVATE:
1582: input_csi_dispatch_sm_private(ictx);
1.115 nicm 1583: break;
1584: case INPUT_CSI_SU:
1.131 nicm 1585: n = input_get(ictx, 0, 1, 1);
1586: if (n != -1)
1587: screen_write_scrollup(sctx, n, bg);
1.159 nicm 1588: break;
1589: case INPUT_CSI_SD:
1590: n = input_get(ictx, 0, 1, 1);
1591: if (n != -1)
1592: screen_write_scrolldown(sctx, n, bg);
1.64 nicm 1593: break;
1594: case INPUT_CSI_TBC:
1595: switch (input_get(ictx, 0, 0, 0)) {
1.131 nicm 1596: case -1:
1597: break;
1.64 nicm 1598: case 0:
1599: if (s->cx < screen_size_x(s))
1600: bit_clear(s->tabs, s->cx);
1601: break;
1602: case 3:
1603: bit_nclear(s->tabs, 0, screen_size_x(s) - 1);
1604: break;
1605: default:
1606: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1607: break;
1608: }
1609: break;
1610: case INPUT_CSI_VPA:
1611: n = input_get(ictx, 0, 1, 1);
1.131 nicm 1612: if (n != -1)
1.148 nicm 1613: screen_write_cursormove(sctx, -1, n - 1, 1);
1.64 nicm 1614: break;
1615: case INPUT_CSI_DECSCUSR:
1616: n = input_get(ictx, 0, 0, 0);
1.131 nicm 1617: if (n != -1)
1618: screen_set_cursor_style(s, n);
1.64 nicm 1619: break;
1.175 nicm 1620: case INPUT_CSI_XDA:
1621: n = input_get(ictx, 0, 0, 0);
1.178 nicm 1622: if (n == 0)
1.175 nicm 1623: input_reply(ictx, "\033P>|tmux %s\033\\", getversion());
1624: break;
1625:
1.64 nicm 1626: }
1627:
1.127 nicm 1628: ictx->last = -1;
1.64 nicm 1629: return (0);
1630: }
1631:
1632: /* Handle CSI RM. */
1.104 nicm 1633: static void
1.64 nicm 1634: input_csi_dispatch_rm(struct input_ctx *ictx)
1635: {
1.144 nicm 1636: struct screen_write_ctx *sctx = &ictx->ctx;
1637: u_int i;
1.64 nicm 1638:
1639: for (i = 0; i < ictx->param_list_len; i++) {
1640: switch (input_get(ictx, i, 0, -1)) {
1.131 nicm 1641: case -1:
1642: break;
1.28 nicm 1643: case 4: /* IRM */
1.144 nicm 1644: screen_write_mode_clear(sctx, MODE_INSERT);
1.28 nicm 1645: break;
1.72 nicm 1646: case 34:
1.144 nicm 1647: screen_write_mode_set(sctx, MODE_BLINKING);
1.72 nicm 1648: break;
1.28 nicm 1649: default:
1650: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1651: break;
1652: }
1.64 nicm 1653: }
1654: }
1655:
1656: /* Handle CSI private RM. */
1.104 nicm 1657: static void
1.64 nicm 1658: input_csi_dispatch_rm_private(struct input_ctx *ictx)
1659: {
1.144 nicm 1660: struct screen_write_ctx *sctx = &ictx->ctx;
1.171 nicm 1661: struct grid_cell *gc = &ictx->cell.cell;
1.69 nicm 1662: u_int i;
1.64 nicm 1663:
1664: for (i = 0; i < ictx->param_list_len; i++) {
1665: switch (input_get(ictx, i, 0, -1)) {
1.131 nicm 1666: case -1:
1667: break;
1.64 nicm 1668: case 1: /* DECCKM */
1.144 nicm 1669: screen_write_mode_clear(sctx, MODE_KCURSOR);
1.1 nicm 1670: break;
1.17 nicm 1671: case 3: /* DECCOLM */
1.146 nicm 1672: screen_write_cursormove(sctx, 0, 0, 1);
1.171 nicm 1673: screen_write_clearscreen(sctx, gc->bg);
1.17 nicm 1674: break;
1.141 nicm 1675: case 6: /* DECOM */
1.144 nicm 1676: screen_write_mode_clear(sctx, MODE_ORIGIN);
1.146 nicm 1677: screen_write_cursormove(sctx, 0, 0, 1);
1.141 nicm 1678: break;
1.61 nicm 1679: case 7: /* DECAWM */
1.144 nicm 1680: screen_write_mode_clear(sctx, MODE_WRAP);
1.61 nicm 1681: break;
1.72 nicm 1682: case 12:
1.144 nicm 1683: screen_write_mode_clear(sctx, MODE_BLINKING);
1.72 nicm 1684: break;
1.1 nicm 1685: case 25: /* TCEM */
1.144 nicm 1686: screen_write_mode_clear(sctx, MODE_CURSOR);
1.1 nicm 1687: break;
1688: case 1000:
1.32 nicm 1689: case 1001:
1690: case 1002:
1.109 nicm 1691: case 1003:
1.144 nicm 1692: screen_write_mode_clear(sctx, ALL_MOUSE_MODES);
1.1 nicm 1693: break;
1.62 nicm 1694: case 1004:
1.144 nicm 1695: screen_write_mode_clear(sctx, MODE_FOCUSON);
1.62 nicm 1696: break;
1.96 nicm 1697: case 1005:
1.144 nicm 1698: screen_write_mode_clear(sctx, MODE_MOUSE_UTF8);
1.96 nicm 1699: break;
1.60 nicm 1700: case 1006:
1.144 nicm 1701: screen_write_mode_clear(sctx, MODE_MOUSE_SGR);
1.60 nicm 1702: break;
1.55 nicm 1703: case 47:
1704: case 1047:
1.177 nicm 1705: screen_write_alternateoff(sctx, gc, 0);
1.55 nicm 1706: break;
1.9 nicm 1707: case 1049:
1.177 nicm 1708: screen_write_alternateoff(sctx, gc, 1);
1.9 nicm 1709: break;
1.49 nicm 1710: case 2004:
1.144 nicm 1711: screen_write_mode_clear(sctx, MODE_BRACKETPASTE);
1.49 nicm 1712: break;
1.1 nicm 1713: default:
1.28 nicm 1714: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1.1 nicm 1715: break;
1716: }
1.64 nicm 1717: }
1718: }
1719:
1720: /* Handle CSI SM. */
1.104 nicm 1721: static void
1.64 nicm 1722: input_csi_dispatch_sm(struct input_ctx *ictx)
1723: {
1.144 nicm 1724: struct screen_write_ctx *sctx = &ictx->ctx;
1725: u_int i;
1.64 nicm 1726:
1727: for (i = 0; i < ictx->param_list_len; i++) {
1728: switch (input_get(ictx, i, 0, -1)) {
1.131 nicm 1729: case -1:
1730: break;
1.1 nicm 1731: case 4: /* IRM */
1.144 nicm 1732: screen_write_mode_set(sctx, MODE_INSERT);
1.1 nicm 1733: break;
1.72 nicm 1734: case 34:
1.144 nicm 1735: screen_write_mode_clear(sctx, MODE_BLINKING);
1.72 nicm 1736: break;
1.1 nicm 1737: default:
1.28 nicm 1738: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1.1 nicm 1739: break;
1740: }
1.64 nicm 1741: }
1742: }
1743:
1744: /* Handle CSI private SM. */
1.104 nicm 1745: static void
1.64 nicm 1746: input_csi_dispatch_sm_private(struct input_ctx *ictx)
1747: {
1.144 nicm 1748: struct screen_write_ctx *sctx = &ictx->ctx;
1.69 nicm 1749: struct window_pane *wp = ictx->wp;
1.171 nicm 1750: struct grid_cell *gc = &ictx->cell.cell;
1.69 nicm 1751: u_int i;
1.64 nicm 1752:
1753: for (i = 0; i < ictx->param_list_len; i++) {
1754: switch (input_get(ictx, i, 0, -1)) {
1.131 nicm 1755: case -1:
1756: break;
1.64 nicm 1757: case 1: /* DECCKM */
1.144 nicm 1758: screen_write_mode_set(sctx, MODE_KCURSOR);
1.17 nicm 1759: break;
1760: case 3: /* DECCOLM */
1.146 nicm 1761: screen_write_cursormove(sctx, 0, 0, 1);
1.144 nicm 1762: screen_write_clearscreen(sctx, ictx->cell.cell.bg);
1.141 nicm 1763: break;
1764: case 6: /* DECOM */
1.144 nicm 1765: screen_write_mode_set(sctx, MODE_ORIGIN);
1.146 nicm 1766: screen_write_cursormove(sctx, 0, 0, 1);
1.61 nicm 1767: break;
1768: case 7: /* DECAWM */
1.144 nicm 1769: screen_write_mode_set(sctx, MODE_WRAP);
1.72 nicm 1770: break;
1771: case 12:
1.144 nicm 1772: screen_write_mode_set(sctx, MODE_BLINKING);
1.1 nicm 1773: break;
1774: case 25: /* TCEM */
1.144 nicm 1775: screen_write_mode_set(sctx, MODE_CURSOR);
1.1 nicm 1776: break;
1777: case 1000:
1.144 nicm 1778: screen_write_mode_clear(sctx, ALL_MOUSE_MODES);
1779: screen_write_mode_set(sctx, MODE_MOUSE_STANDARD);
1.32 nicm 1780: break;
1781: case 1002:
1.144 nicm 1782: screen_write_mode_clear(sctx, ALL_MOUSE_MODES);
1783: screen_write_mode_set(sctx, MODE_MOUSE_BUTTON);
1.109 nicm 1784: break;
1785: case 1003:
1.144 nicm 1786: screen_write_mode_clear(sctx, ALL_MOUSE_MODES);
1787: screen_write_mode_set(sctx, MODE_MOUSE_ALL);
1.62 nicm 1788: break;
1789: case 1004:
1.144 nicm 1790: if (sctx->s->mode & MODE_FOCUSON)
1.62 nicm 1791: break;
1.144 nicm 1792: screen_write_mode_set(sctx, MODE_FOCUSON);
1.171 nicm 1793: if (wp != NULL)
1794: wp->flags |= PANE_FOCUSPUSH; /* force update */
1.96 nicm 1795: break;
1796: case 1005:
1.144 nicm 1797: screen_write_mode_set(sctx, MODE_MOUSE_UTF8);
1.60 nicm 1798: break;
1799: case 1006:
1.144 nicm 1800: screen_write_mode_set(sctx, MODE_MOUSE_SGR);
1.9 nicm 1801: break;
1.55 nicm 1802: case 47:
1803: case 1047:
1.177 nicm 1804: screen_write_alternateon(sctx, gc, 0);
1.55 nicm 1805: break;
1.9 nicm 1806: case 1049:
1.177 nicm 1807: screen_write_alternateon(sctx, gc, 1);
1.49 nicm 1808: break;
1809: case 2004:
1.144 nicm 1810: screen_write_mode_set(sctx, MODE_BRACKETPASTE);
1.1 nicm 1811: break;
1812: default:
1.28 nicm 1813: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1.1 nicm 1814: break;
1815: }
1.65 nicm 1816: }
1817: }
1818:
1819: /* Handle CSI window operations. */
1.104 nicm 1820: static void
1.65 nicm 1821: input_csi_dispatch_winops(struct input_ctx *ictx)
1822: {
1.144 nicm 1823: struct screen_write_ctx *sctx = &ictx->ctx;
1.172 nicm 1824: struct screen *s = sctx->s;
1.65 nicm 1825: struct window_pane *wp = ictx->wp;
1.172 nicm 1826: u_int x = screen_size_x(s), y = screen_size_y(s);
1.65 nicm 1827: int n, m;
1828:
1829: m = 0;
1830: while ((n = input_get(ictx, m, 0, -1)) != -1) {
1831: switch (n) {
1832: case 1:
1833: case 2:
1834: case 5:
1835: case 6:
1836: case 7:
1837: case 11:
1838: case 13:
1839: case 14:
1840: case 19:
1841: case 20:
1842: case 21:
1843: case 24:
1844: break;
1845: case 3:
1846: case 4:
1847: case 8:
1848: m++;
1849: if (input_get(ictx, m, 0, -1) == -1)
1850: return;
1851: /* FALLTHROUGH */
1852: case 9:
1853: case 10:
1.129 nicm 1854: m++;
1855: if (input_get(ictx, m, 0, -1) == -1)
1856: return;
1857: break;
1.65 nicm 1858: case 22:
1.129 nicm 1859: m++;
1860: switch (input_get(ictx, m, 0, -1)) {
1861: case -1:
1862: return;
1863: case 0:
1864: case 2:
1.144 nicm 1865: screen_push_title(sctx->s);
1.129 nicm 1866: break;
1867: }
1868: break;
1.65 nicm 1869: case 23:
1870: m++;
1.129 nicm 1871: switch (input_get(ictx, m, 0, -1)) {
1872: case -1:
1.65 nicm 1873: return;
1.129 nicm 1874: case 0:
1875: case 2:
1.144 nicm 1876: screen_pop_title(sctx->s);
1.176 nicm 1877: if (wp != NULL) {
1.182 nicm 1878: notify_pane("pane-title-changed", wp);
1.176 nicm 1879: server_redraw_window_borders(wp->window);
1.171 nicm 1880: server_status_window(wp->window);
1.176 nicm 1881: }
1.129 nicm 1882: break;
1883: }
1.65 nicm 1884: break;
1885: case 18:
1.172 nicm 1886: input_reply(ictx, "\033[8;%u;%ut", x, y);
1.65 nicm 1887: break;
1888: default:
1889: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1890: break;
1891: }
1892: m++;
1.1 nicm 1893: }
1894: }
1895:
1.131 nicm 1896: /* Helper for 256 colour SGR. */
1897: static int
1898: input_csi_dispatch_sgr_256_do(struct input_ctx *ictx, int fgbg, int c)
1.78 nicm 1899: {
1900: struct grid_cell *gc = &ictx->cell.cell;
1901:
1.131 nicm 1902: if (c == -1 || c > 255) {
1.102 nicm 1903: if (fgbg == 38)
1.78 nicm 1904: gc->fg = 8;
1.102 nicm 1905: else if (fgbg == 48)
1.78 nicm 1906: gc->bg = 8;
1907: } else {
1.102 nicm 1908: if (fgbg == 38)
1909: gc->fg = c | COLOUR_FLAG_256;
1910: else if (fgbg == 48)
1911: gc->bg = c | COLOUR_FLAG_256;
1.158 nicm 1912: else if (fgbg == 58)
1913: gc->us = c | COLOUR_FLAG_256;
1.78 nicm 1914: }
1.131 nicm 1915: return (1);
1.78 nicm 1916: }
1917:
1.131 nicm 1918: /* Handle CSI SGR for 256 colours. */
1.104 nicm 1919: static void
1.131 nicm 1920: input_csi_dispatch_sgr_256(struct input_ctx *ictx, int fgbg, u_int *i)
1921: {
1922: int c;
1923:
1924: c = input_get(ictx, (*i) + 1, 0, -1);
1925: if (input_csi_dispatch_sgr_256_do(ictx, fgbg, c))
1926: (*i)++;
1927: }
1928:
1929: /* Helper for RGB colour SGR. */
1930: static int
1931: input_csi_dispatch_sgr_rgb_do(struct input_ctx *ictx, int fgbg, int r, int g,
1932: int b)
1.78 nicm 1933: {
1934: struct grid_cell *gc = &ictx->cell.cell;
1935:
1936: if (r == -1 || r > 255)
1.131 nicm 1937: return (0);
1.78 nicm 1938: if (g == -1 || g > 255)
1.131 nicm 1939: return (0);
1.78 nicm 1940: if (b == -1 || b > 255)
1.131 nicm 1941: return (0);
1.78 nicm 1942:
1.102 nicm 1943: if (fgbg == 38)
1944: gc->fg = colour_join_rgb(r, g, b);
1945: else if (fgbg == 48)
1946: gc->bg = colour_join_rgb(r, g, b);
1.158 nicm 1947: else if (fgbg == 58)
1948: gc->us = colour_join_rgb(r, g, b);
1.131 nicm 1949: return (1);
1950: }
1951:
1952: /* Handle CSI SGR for RGB colours. */
1953: static void
1954: input_csi_dispatch_sgr_rgb(struct input_ctx *ictx, int fgbg, u_int *i)
1955: {
1956: int r, g, b;
1957:
1958: r = input_get(ictx, (*i) + 1, 0, -1);
1959: g = input_get(ictx, (*i) + 2, 0, -1);
1960: b = input_get(ictx, (*i) + 3, 0, -1);
1961: if (input_csi_dispatch_sgr_rgb_do(ictx, fgbg, r, g, b))
1962: (*i) += 3;
1963: }
1964:
1965: /* Handle CSI SGR with a ISO parameter. */
1966: static void
1967: input_csi_dispatch_sgr_colon(struct input_ctx *ictx, u_int i)
1968: {
1.137 nicm 1969: struct grid_cell *gc = &ictx->cell.cell;
1970: char *s = ictx->param_list[i].str, *copy, *ptr, *out;
1971: int p[8];
1972: u_int n;
1973: const char *errstr;
1.131 nicm 1974:
1975: for (n = 0; n < nitems(p); n++)
1976: p[n] = -1;
1977: n = 0;
1978:
1979: ptr = copy = xstrdup(s);
1980: while ((out = strsep(&ptr, ":")) != NULL) {
1.134 nicm 1981: if (*out != '\0') {
1982: p[n++] = strtonum(out, 0, INT_MAX, &errstr);
1983: if (errstr != NULL || n == nitems(p)) {
1984: free(copy);
1985: return;
1986: }
1.184 nicm 1987: } else {
1.140 nicm 1988: n++;
1.184 nicm 1989: if (n == nitems(p)) {
1990: free(copy);
1991: return;
1992: }
1993: }
1.131 nicm 1994: log_debug("%s: %u = %d", __func__, n - 1, p[n - 1]);
1995: }
1996: free(copy);
1997:
1.137 nicm 1998: if (n == 0)
1999: return;
2000: if (p[0] == 4) {
2001: if (n != 2)
2002: return;
2003: switch (p[1]) {
2004: case 0:
2005: gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
2006: break;
2007: case 1:
2008: gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
2009: gc->attr |= GRID_ATTR_UNDERSCORE;
2010: break;
2011: case 2:
2012: gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
2013: gc->attr |= GRID_ATTR_UNDERSCORE_2;
2014: break;
2015: case 3:
2016: gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
2017: gc->attr |= GRID_ATTR_UNDERSCORE_3;
2018: break;
2019: case 4:
2020: gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
2021: gc->attr |= GRID_ATTR_UNDERSCORE_4;
2022: break;
2023: case 5:
2024: gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
2025: gc->attr |= GRID_ATTR_UNDERSCORE_5;
2026: break;
2027: }
2028: return;
2029: }
1.158 nicm 2030: if (n < 2 || (p[0] != 38 && p[0] != 48 && p[0] != 58))
1.131 nicm 2031: return;
1.154 nicm 2032: switch (p[1]) {
1.131 nicm 2033: case 2:
1.154 nicm 2034: if (n < 3)
2035: break;
2036: if (n == 5)
2037: i = 2;
2038: else
2039: i = 3;
2040: if (n < i + 3)
1.131 nicm 2041: break;
1.154 nicm 2042: input_csi_dispatch_sgr_rgb_do(ictx, p[0], p[i], p[i + 1],
2043: p[i + 2]);
1.131 nicm 2044: break;
2045: case 5:
1.154 nicm 2046: if (n < 3)
1.131 nicm 2047: break;
1.154 nicm 2048: input_csi_dispatch_sgr_256_do(ictx, p[0], p[2]);
1.131 nicm 2049: break;
2050: }
1.78 nicm 2051: }
2052:
1.28 nicm 2053: /* Handle CSI SGR. */
1.104 nicm 2054: static void
1.28 nicm 2055: input_csi_dispatch_sgr(struct input_ctx *ictx)
1.1 nicm 2056: {
1.69 nicm 2057: struct grid_cell *gc = &ictx->cell.cell;
1.28 nicm 2058: u_int i;
1.78 nicm 2059: int n;
1.1 nicm 2060:
1.28 nicm 2061: if (ictx->param_list_len == 0) {
1.1 nicm 2062: memcpy(gc, &grid_default_cell, sizeof *gc);
2063: return;
2064: }
2065:
1.28 nicm 2066: for (i = 0; i < ictx->param_list_len; i++) {
1.131 nicm 2067: if (ictx->param_list[i].type == INPUT_STRING) {
2068: input_csi_dispatch_sgr_colon(ictx, i);
2069: continue;
2070: }
1.28 nicm 2071: n = input_get(ictx, i, 0, 0);
1.131 nicm 2072: if (n == -1)
2073: continue;
1.1 nicm 2074:
1.158 nicm 2075: if (n == 38 || n == 48 || n == 58) {
1.1 nicm 2076: i++;
1.78 nicm 2077: switch (input_get(ictx, i, 0, -1)) {
2078: case 2:
2079: input_csi_dispatch_sgr_rgb(ictx, n, &i);
2080: break;
2081: case 5:
2082: input_csi_dispatch_sgr_256(ictx, n, &i);
2083: break;
1.1 nicm 2084: }
2085: continue;
2086: }
2087:
1.28 nicm 2088: switch (n) {
1.1 nicm 2089: case 0:
2090: memcpy(gc, &grid_default_cell, sizeof *gc);
2091: break;
2092: case 1:
2093: gc->attr |= GRID_ATTR_BRIGHT;
2094: break;
2095: case 2:
2096: gc->attr |= GRID_ATTR_DIM;
2097: break;
2098: case 3:
2099: gc->attr |= GRID_ATTR_ITALICS;
2100: break;
2101: case 4:
1.137 nicm 2102: gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
1.1 nicm 2103: gc->attr |= GRID_ATTR_UNDERSCORE;
2104: break;
2105: case 5:
1.187 nicm 2106: case 6:
1.1 nicm 2107: gc->attr |= GRID_ATTR_BLINK;
2108: break;
2109: case 7:
2110: gc->attr |= GRID_ATTR_REVERSE;
2111: break;
2112: case 8:
2113: gc->attr |= GRID_ATTR_HIDDEN;
2114: break;
1.118 nicm 2115: case 9:
2116: gc->attr |= GRID_ATTR_STRIKETHROUGH;
1.187 nicm 2117: break;
2118: case 21:
2119: gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
2120: gc->attr |= GRID_ATTR_UNDERSCORE_2;
1.118 nicm 2121: break;
1.1 nicm 2122: case 22:
2123: gc->attr &= ~(GRID_ATTR_BRIGHT|GRID_ATTR_DIM);
2124: break;
2125: case 23:
2126: gc->attr &= ~GRID_ATTR_ITALICS;
2127: break;
2128: case 24:
1.137 nicm 2129: gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
1.1 nicm 2130: break;
2131: case 25:
2132: gc->attr &= ~GRID_ATTR_BLINK;
2133: break;
2134: case 27:
2135: gc->attr &= ~GRID_ATTR_REVERSE;
1.117 nicm 2136: break;
2137: case 28:
2138: gc->attr &= ~GRID_ATTR_HIDDEN;
1.118 nicm 2139: break;
2140: case 29:
2141: gc->attr &= ~GRID_ATTR_STRIKETHROUGH;
1.1 nicm 2142: break;
2143: case 30:
2144: case 31:
2145: case 32:
2146: case 33:
2147: case 34:
2148: case 35:
2149: case 36:
2150: case 37:
1.28 nicm 2151: gc->fg = n - 30;
1.1 nicm 2152: break;
2153: case 39:
2154: gc->fg = 8;
2155: break;
2156: case 40:
2157: case 41:
2158: case 42:
2159: case 43:
2160: case 44:
2161: case 45:
2162: case 46:
2163: case 47:
1.28 nicm 2164: gc->bg = n - 40;
1.1 nicm 2165: break;
2166: case 49:
2167: gc->bg = 8;
1.153 nicm 2168: break;
2169: case 53:
2170: gc->attr |= GRID_ATTR_OVERLINE;
2171: break;
2172: case 55:
2173: gc->attr &= ~GRID_ATTR_OVERLINE;
1.158 nicm 2174: break;
2175: case 59:
2176: gc->us = 0;
1.20 nicm 2177: break;
2178: case 90:
2179: case 91:
2180: case 92:
2181: case 93:
2182: case 94:
2183: case 95:
2184: case 96:
2185: case 97:
1.28 nicm 2186: gc->fg = n;
1.20 nicm 2187: break;
2188: case 100:
2189: case 101:
2190: case 102:
2191: case 103:
2192: case 104:
2193: case 105:
2194: case 106:
2195: case 107:
1.47 nicm 2196: gc->bg = n - 10;
1.1 nicm 2197: break;
2198: }
2199: }
1.28 nicm 2200: }
2201:
1.138 nicm 2202: /* End of input with BEL. */
2203: static int
2204: input_end_bel(struct input_ctx *ictx)
2205: {
2206: log_debug("%s", __func__);
2207:
2208: ictx->input_end = INPUT_END_BEL;
2209:
2210: return (0);
2211: }
2212:
1.125 nicm 2213: /* DCS string started. */
2214: static void
2215: input_enter_dcs(struct input_ctx *ictx)
2216: {
2217: log_debug("%s", __func__);
2218:
2219: input_clear(ictx);
2220: input_start_timer(ictx);
1.127 nicm 2221: ictx->last = -1;
1.125 nicm 2222: }
2223:
1.37 nicm 2224: /* DCS terminator (ST) received. */
1.104 nicm 2225: static int
1.37 nicm 2226: input_dcs_dispatch(struct input_ctx *ictx)
1.28 nicm 2227: {
1.144 nicm 2228: struct screen_write_ctx *sctx = &ictx->ctx;
2229: u_char *buf = ictx->input_buf;
2230: size_t len = ictx->input_len;
2231: const char prefix[] = "tmux;";
2232: const u_int prefixlen = (sizeof prefix) - 1;
1.37 nicm 2233:
2234: if (ictx->flags & INPUT_DISCARD)
2235: return (0);
2236:
1.144 nicm 2237: log_debug("%s: \"%s\"", __func__, buf);
1.28 nicm 2238:
1.144 nicm 2239: if (len >= prefixlen && strncmp(buf, prefix, prefixlen) == 0)
2240: screen_write_rawstring(sctx, buf + prefixlen, len - prefixlen);
1.28 nicm 2241:
1.37 nicm 2242: return (0);
1.28 nicm 2243: }
2244:
2245: /* OSC string started. */
1.104 nicm 2246: static void
1.28 nicm 2247: input_enter_osc(struct input_ctx *ictx)
2248: {
2249: log_debug("%s", __func__);
2250:
1.35 nicm 2251: input_clear(ictx);
1.125 nicm 2252: input_start_timer(ictx);
1.127 nicm 2253: ictx->last = -1;
1.28 nicm 2254: }
2255:
2256: /* OSC terminator (ST) received. */
1.104 nicm 2257: static void
1.28 nicm 2258: input_exit_osc(struct input_ctx *ictx)
2259: {
1.144 nicm 2260: struct screen_write_ctx *sctx = &ictx->ctx;
1.171 nicm 2261: struct window_pane *wp = ictx->wp;
1.144 nicm 2262: u_char *p = ictx->input_buf;
2263: u_int option;
1.38 nicm 2264:
1.28 nicm 2265: if (ictx->flags & INPUT_DISCARD)
2266: return;
1.38 nicm 2267: if (ictx->input_len < 1 || *p < '0' || *p > '9')
2268: return;
1.28 nicm 2269:
1.138 nicm 2270: log_debug("%s: \"%s\" (end %s)", __func__, p,
2271: ictx->input_end == INPUT_END_ST ? "ST" : "BEL");
1.28 nicm 2272:
1.38 nicm 2273: option = 0;
2274: while (*p >= '0' && *p <= '9')
2275: option = option * 10 + *p++ - '0';
2276: if (*p == ';')
2277: p++;
2278:
2279: switch (option) {
2280: case 0:
2281: case 2:
1.176 nicm 2282: if (screen_set_title(sctx->s, p) && wp != NULL) {
1.182 nicm 2283: notify_pane("pane-title-changed", wp);
1.176 nicm 2284: server_redraw_window_borders(wp->window);
2285: server_status_window(wp->window);
2286: }
1.38 nicm 2287: break;
1.107 nicm 2288: case 4:
1.138 nicm 2289: input_osc_4(ictx, p);
1.165 nicm 2290: break;
2291: case 7:
2292: if (utf8_isvalid(p)) {
2293: screen_set_path(sctx->s, p);
1.176 nicm 2294: if (wp != NULL) {
2295: server_redraw_window_borders(wp->window);
1.171 nicm 2296: server_status_window(wp->window);
1.176 nicm 2297: }
1.165 nicm 2298: }
1.107 nicm 2299: break;
1.122 nicm 2300: case 10:
1.138 nicm 2301: input_osc_10(ictx, p);
1.122 nicm 2302: break;
2303: case 11:
1.138 nicm 2304: input_osc_11(ictx, p);
1.108 nicm 2305: break;
1.38 nicm 2306: case 12:
1.124 nicm 2307: if (utf8_isvalid(p) && *p != '?') /* ? is colour request */
1.144 nicm 2308: screen_set_cursor_colour(sctx->s, p);
1.38 nicm 2309: break;
1.122 nicm 2310: case 52:
1.138 nicm 2311: input_osc_52(ictx, p);
1.122 nicm 2312: break;
1.107 nicm 2313: case 104:
1.138 nicm 2314: input_osc_104(ictx, p);
1.107 nicm 2315: break;
1.186 nicm 2316: case 110:
2317: input_osc_110(ictx, p);
2318: break;
2319: case 111:
2320: input_osc_111(ictx, p);
2321: break;
1.38 nicm 2322: case 112:
1.57 nicm 2323: if (*p == '\0') /* no arguments allowed */
1.144 nicm 2324: screen_set_cursor_colour(sctx->s, "");
1.38 nicm 2325: break;
2326: default:
2327: log_debug("%s: unknown '%u'", __func__, option);
2328: break;
2329: }
1.28 nicm 2330: }
2331:
2332: /* APC string started. */
1.104 nicm 2333: static void
1.28 nicm 2334: input_enter_apc(struct input_ctx *ictx)
2335: {
2336: log_debug("%s", __func__);
2337:
1.35 nicm 2338: input_clear(ictx);
1.125 nicm 2339: input_start_timer(ictx);
1.127 nicm 2340: ictx->last = -1;
1.28 nicm 2341: }
2342:
2343: /* APC terminator (ST) received. */
1.104 nicm 2344: static void
1.28 nicm 2345: input_exit_apc(struct input_ctx *ictx)
2346: {
1.144 nicm 2347: struct screen_write_ctx *sctx = &ictx->ctx;
1.171 nicm 2348: struct window_pane *wp = ictx->wp;
1.144 nicm 2349:
1.28 nicm 2350: if (ictx->flags & INPUT_DISCARD)
2351: return;
2352: log_debug("%s: \"%s\"", __func__, ictx->input_buf);
2353:
1.176 nicm 2354: if (screen_set_title(sctx->s, ictx->input_buf) && wp != NULL) {
1.182 nicm 2355: notify_pane("pane-title-changed", wp);
1.176 nicm 2356: server_redraw_window_borders(wp->window);
1.171 nicm 2357: server_status_window(wp->window);
1.176 nicm 2358: }
1.28 nicm 2359: }
2360:
2361: /* Rename string started. */
1.104 nicm 2362: static void
1.28 nicm 2363: input_enter_rename(struct input_ctx *ictx)
2364: {
2365: log_debug("%s", __func__);
2366:
1.35 nicm 2367: input_clear(ictx);
1.125 nicm 2368: input_start_timer(ictx);
1.127 nicm 2369: ictx->last = -1;
1.28 nicm 2370: }
2371:
2372: /* Rename terminator (ST) received. */
1.104 nicm 2373: static void
1.28 nicm 2374: input_exit_rename(struct input_ctx *ictx)
2375: {
1.162 nicm 2376: struct window_pane *wp = ictx->wp;
1.181 nicm 2377: struct options_entry *o;
1.162 nicm 2378:
1.171 nicm 2379: if (wp == NULL)
2380: return;
1.28 nicm 2381: if (ictx->flags & INPUT_DISCARD)
1.44 nicm 2382: return;
1.157 nicm 2383: if (!options_get_number(ictx->wp->options, "allow-rename"))
1.28 nicm 2384: return;
2385: log_debug("%s: \"%s\"", __func__, ictx->input_buf);
2386:
1.124 nicm 2387: if (!utf8_isvalid(ictx->input_buf))
2388: return;
1.162 nicm 2389:
2390: if (ictx->input_len == 0) {
1.181 nicm 2391: o = options_get_only(wp->window->options, "automatic-rename");
2392: if (o != NULL)
2393: options_remove_or_default(o, -1, NULL);
1.162 nicm 2394: return;
2395: }
1.171 nicm 2396: window_set_name(wp->window, ictx->input_buf);
2397: options_set_number(wp->window->options, "automatic-rename", 0);
1.176 nicm 2398: server_redraw_window_borders(wp->window);
1.171 nicm 2399: server_status_window(wp->window);
1.28 nicm 2400: }
2401:
2402: /* Open UTF-8 character. */
1.104 nicm 2403: static int
1.130 nicm 2404: input_top_bit_set(struct input_ctx *ictx)
1.28 nicm 2405: {
1.144 nicm 2406: struct screen_write_ctx *sctx = &ictx->ctx;
1.90 nicm 2407: struct utf8_data *ud = &ictx->utf8data;
2408:
1.127 nicm 2409: ictx->last = -1;
1.28 nicm 2410:
1.130 nicm 2411: if (!ictx->utf8started) {
2412: if (utf8_open(ud, ictx->ch) != UTF8_MORE)
2413: return (0);
2414: ictx->utf8started = 1;
2415: return (0);
2416: }
1.28 nicm 2417:
1.130 nicm 2418: switch (utf8_append(ud, ictx->ch)) {
2419: case UTF8_MORE:
2420: return (0);
2421: case UTF8_ERROR:
2422: ictx->utf8started = 0;
1.101 nicm 2423: return (0);
1.130 nicm 2424: case UTF8_DONE:
2425: break;
1.101 nicm 2426: }
1.130 nicm 2427: ictx->utf8started = 0;
1.28 nicm 2428:
1.90 nicm 2429: log_debug("%s %hhu '%*s' (width %hhu)", __func__, ud->size,
2430: (int)ud->size, ud->data, ud->width);
1.28 nicm 2431:
1.90 nicm 2432: utf8_copy(&ictx->cell.cell.data, ud);
1.144 nicm 2433: screen_write_collect_add(sctx, &ictx->cell.cell);
1.28 nicm 2434:
2435: return (0);
1.107 nicm 2436: }
2437:
1.163 nicm 2438: /* Parse colour from OSC. */
2439: static int
1.186 nicm 2440: input_osc_parse_colour(const char *p)
1.163 nicm 2441: {
1.186 nicm 2442: double c, m, y, k = 0;
2443: u_int r, g, b;
2444: size_t len = strlen(p);
2445: int colour = -1;
2446: char *copy;
2447:
2448: if ((len == 12 && sscanf(p, "rgb:%02x/%02x/%02x", &r, &g, &b) == 3) ||
2449: (len == 7 && sscanf(p, "#%02x%02x%02x", &r, &g, &b) == 3) ||
2450: sscanf(p, "%d,%d,%d", &r, &g, &b) == 3)
2451: colour = colour_join_rgb(r, g, b);
2452: else if ((len == 18 &&
2453: sscanf(p, "rgb:%04x/%04x/%04x", &r, &g, &b) == 3) ||
2454: (len == 13 && sscanf(p, "#%04x%04x%04x", &r, &g, &b) == 3))
2455: colour = colour_join_rgb(r >> 8, g >> 8, b >> 8);
2456: else if ((sscanf(p, "cmyk:%lf/%lf/%lf/%lf", &c, &m, &y, &k) == 4 ||
2457: sscanf(p, "cmy:%lf/%lf/%lf", &c, &m, &y) == 3) &&
2458: c >= 0 && c <= 1 && m >= 0 && m <= 1 &&
2459: y >= 0 && y <= 1 && k >= 0 && k <= 1) {
2460: colour = colour_join_rgb(
2461: (1 - c) * (1 - k) * 255,
2462: (1 - m) * (1 - k) * 255,
2463: (1 - y) * (1 - k) * 255);
2464: } else {
1.188 nicm 2465: while (len != 0 && *p == ' ') {
1.186 nicm 2466: p++;
1.188 nicm 2467: len--;
2468: }
1.186 nicm 2469: while (len != 0 && p[len - 1] == ' ')
2470: len--;
2471: copy = xstrndup(p, len);
2472: colour = colour_byname(copy);
2473: free(copy);
2474: }
2475: log_debug("%s: %s = %s", __func__, p, colour_tostring(colour));
2476: return (colour);
1.163 nicm 2477: }
2478:
1.183 nicm 2479: /* Reply to a colour request. */
2480: static void
2481: input_osc_colour_reply(struct input_ctx *ictx, u_int n, int c)
2482: {
2483: u_char r, g, b;
2484: const char *end;
2485:
2486: if (c == 8 || (~c & COLOUR_FLAG_RGB))
2487: return;
2488: colour_split_rgb(c, &r, &g, &b);
2489:
2490: if (ictx->input_end == INPUT_END_BEL)
2491: end = "\007";
2492: else
2493: end = "\033\\";
2494: input_reply(ictx, "\033]%u;rgb:%02hhx/%02hhx/%02hhx%s", n, r, g, b, end);
2495: }
2496:
1.107 nicm 2497: /* Handle the OSC 4 sequence for setting (multiple) palette entries. */
2498: static void
1.138 nicm 2499: input_osc_4(struct input_ctx *ictx, const char *p)
1.107 nicm 2500: {
1.138 nicm 2501: struct window_pane *wp = ictx->wp;
2502: char *copy, *s, *next = NULL;
1.183 nicm 2503: long idx;
1.186 nicm 2504: int c;
1.107 nicm 2505:
1.171 nicm 2506: if (wp == NULL)
2507: return;
2508:
1.107 nicm 2509: copy = s = xstrdup(p);
2510: while (s != NULL && *s != '\0') {
2511: idx = strtol(s, &next, 10);
2512: if (*next++ != ';')
2513: goto bad;
2514: if (idx < 0 || idx >= 0x100)
2515: goto bad;
2516:
2517: s = strsep(&next, ";");
1.186 nicm 2518: if ((c = input_osc_parse_colour(s)) == -1) {
1.107 nicm 2519: s = next;
2520: continue;
2521: }
2522:
1.186 nicm 2523: window_pane_set_palette(wp, idx, c);
1.107 nicm 2524: s = next;
2525: }
2526:
2527: free(copy);
2528: return;
2529:
2530: bad:
2531: log_debug("bad OSC 4: %s", p);
2532: free(copy);
1.122 nicm 2533: }
2534:
1.183 nicm 2535: /* Handle the OSC 10 sequence for setting and querying foreground colour. */
1.122 nicm 2536: static void
1.138 nicm 2537: input_osc_10(struct input_ctx *ictx, const char *p)
1.122 nicm 2538: {
1.138 nicm 2539: struct window_pane *wp = ictx->wp;
1.183 nicm 2540: struct grid_cell defaults;
1.186 nicm 2541: int c;
1.122 nicm 2542:
1.171 nicm 2543: if (wp == NULL)
2544: return;
1.183 nicm 2545:
2546: if (strcmp(p, "?") == 0) {
2547: tty_default_colours(&defaults, wp);
2548: input_osc_colour_reply(ictx, 10, defaults.fg);
1.163 nicm 2549: return;
1.183 nicm 2550: }
1.163 nicm 2551:
1.186 nicm 2552: if ((c = input_osc_parse_colour(p)) == -1)
1.163 nicm 2553: goto bad;
1.186 nicm 2554: wp->fg = c;
1.156 nicm 2555: wp->flags |= (PANE_REDRAW|PANE_STYLECHANGED);
1.122 nicm 2556:
2557: return;
2558:
2559: bad:
2560: log_debug("bad OSC 10: %s", p);
2561: }
2562:
1.186 nicm 2563: /* Handle the OSC 110 sequence for resetting background colour. */
2564: static void
2565: input_osc_110(struct input_ctx *ictx, const char *p)
2566: {
2567: struct window_pane *wp = ictx->wp;
2568:
2569: if (wp == NULL)
2570: return;
2571:
2572: if (*p != '\0')
2573: return;
2574:
2575: wp->fg = 8;
2576: wp->flags |= (PANE_REDRAW|PANE_STYLECHANGED);
2577: }
2578:
1.183 nicm 2579: /* Handle the OSC 11 sequence for setting and querying background colour. */
1.122 nicm 2580: static void
1.138 nicm 2581: input_osc_11(struct input_ctx *ictx, const char *p)
1.122 nicm 2582: {
1.138 nicm 2583: struct window_pane *wp = ictx->wp;
1.183 nicm 2584: struct grid_cell defaults;
1.186 nicm 2585: int c;
1.122 nicm 2586:
1.171 nicm 2587: if (wp == NULL)
2588: return;
1.183 nicm 2589:
2590: if (strcmp(p, "?") == 0) {
2591: tty_default_colours(&defaults, wp);
2592: input_osc_colour_reply(ictx, 11, defaults.bg);
1.163 nicm 2593: return;
1.183 nicm 2594: }
1.163 nicm 2595:
1.186 nicm 2596: if ((c = input_osc_parse_colour(p)) == -1)
2597: goto bad;
2598: wp->bg = c;
1.156 nicm 2599: wp->flags |= (PANE_REDRAW|PANE_STYLECHANGED);
1.122 nicm 2600:
2601: return;
2602:
2603: bad:
2604: log_debug("bad OSC 11: %s", p);
1.186 nicm 2605: }
2606:
2607: /* Handle the OSC 111 sequence for resetting background colour. */
2608: static void
2609: input_osc_111(struct input_ctx *ictx, const char *p)
2610: {
2611: struct window_pane *wp = ictx->wp;
2612:
2613: if (wp == NULL)
2614: return;
2615:
2616: if (*p != '\0')
2617: return;
2618:
2619: wp->bg = 8;
2620: wp->flags |= (PANE_REDRAW|PANE_STYLECHANGED);
1.108 nicm 2621: }
2622:
2623: /* Handle the OSC 52 sequence for setting the clipboard. */
2624: static void
1.138 nicm 2625: input_osc_52(struct input_ctx *ictx, const char *p)
1.108 nicm 2626: {
1.138 nicm 2627: struct window_pane *wp = ictx->wp;
1.108 nicm 2628: char *end;
1.138 nicm 2629: const char *buf;
1.108 nicm 2630: size_t len;
2631: u_char *out;
1.123 nicm 2632: int outlen, state;
1.108 nicm 2633: struct screen_write_ctx ctx;
1.138 nicm 2634: struct paste_buffer *pb;
1.108 nicm 2635:
1.171 nicm 2636: if (wp == NULL)
2637: return;
1.123 nicm 2638: state = options_get_number(global_options, "set-clipboard");
2639: if (state != 2)
2640: return;
2641:
1.108 nicm 2642: if ((end = strchr(p, ';')) == NULL)
2643: return;
2644: end++;
2645: if (*end == '\0')
2646: return;
1.138 nicm 2647: log_debug("%s: %s", __func__, end);
2648:
2649: if (strcmp(end, "?") == 0) {
2650: if ((pb = paste_get_top(NULL)) != NULL) {
2651: buf = paste_buffer_data(pb, &len);
2652: outlen = 4 * ((len + 2) / 3) + 1;
2653: out = xmalloc(outlen);
2654: if ((outlen = b64_ntop(buf, len, out, outlen)) == -1) {
2655: free(out);
2656: return;
2657: }
2658: } else {
2659: outlen = 0;
2660: out = NULL;
2661: }
1.172 nicm 2662: bufferevent_write(ictx->event, "\033]52;;", 6);
1.138 nicm 2663: if (outlen != 0)
1.172 nicm 2664: bufferevent_write(ictx->event, out, outlen);
1.138 nicm 2665: if (ictx->input_end == INPUT_END_BEL)
1.172 nicm 2666: bufferevent_write(ictx->event, "\007", 1);
1.138 nicm 2667: else
1.172 nicm 2668: bufferevent_write(ictx->event, "\033\\", 2);
1.138 nicm 2669: free(out);
2670: return;
2671: }
1.108 nicm 2672:
2673: len = (strlen(end) / 4) * 3;
2674: if (len == 0)
2675: return;
2676:
2677: out = xmalloc(len);
2678: if ((outlen = b64_pton(end, out, len)) == -1) {
2679: free(out);
2680: return;
2681: }
2682:
1.177 nicm 2683: screen_write_start_pane(&ctx, wp, NULL);
1.123 nicm 2684: screen_write_setselection(&ctx, out, outlen);
2685: screen_write_stop(&ctx);
1.126 nicm 2686: notify_pane("pane-set-clipboard", wp);
1.123 nicm 2687:
1.150 nicm 2688: paste_add(NULL, out, outlen);
1.107 nicm 2689: }
2690:
2691: /* Handle the OSC 104 sequence for unsetting (multiple) palette entries. */
2692: static void
1.138 nicm 2693: input_osc_104(struct input_ctx *ictx, const char *p)
1.107 nicm 2694: {
1.138 nicm 2695: struct window_pane *wp = ictx->wp;
2696: char *copy, *s;
1.144 nicm 2697: long idx;
1.171 nicm 2698:
2699: if (wp == NULL)
2700: return;
1.107 nicm 2701:
2702: if (*p == '\0') {
2703: window_pane_reset_palette(wp);
2704: return;
2705: }
2706:
2707: copy = s = xstrdup(p);
2708: while (*s != '\0') {
2709: idx = strtol(s, &s, 10);
2710: if (*s != '\0' && *s != ';')
2711: goto bad;
2712: if (idx < 0 || idx >= 0x100)
2713: goto bad;
2714:
2715: window_pane_unset_palette(wp, idx);
2716: if (*s == ';')
2717: s++;
2718: }
2719: free(copy);
2720: return;
2721:
2722: bad:
2723: log_debug("bad OSC 104: %s", p);
2724: free(copy);
1.1 nicm 2725: }