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