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