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