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