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