Annotation of src/usr.bin/tmux/input.c, Revision 1.175
1.175 ! nicm 1: /* $OpenBSD: input.c,v 1.174 2020/04/30 13:31:22 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.144 nicm 845: screen_write_start(sctx, wp, &wp->base);
1.97 nicm 846: else
1.144 nicm 847: screen_write_start(sctx, NULL, &wp->base);
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))
963: screen_write_start(sctx, wp, &wp->base);
964: else
965: screen_write_start(sctx, NULL, &wp->base);
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
976: input_parse_screen(struct input_ctx *ictx, struct screen *s, u_char *buf,
977: size_t len)
978: {
979: struct screen_write_ctx *sctx = &ictx->ctx;
980:
981: if (len == 0)
982: return;
983:
984: screen_write_start(sctx, NULL, s);
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.69 nicm 1635: struct window_pane *wp = ictx->wp;
1.171 nicm 1636: struct grid_cell *gc = &ictx->cell.cell;
1.69 nicm 1637: u_int i;
1.64 nicm 1638:
1639: for (i = 0; i < ictx->param_list_len; i++) {
1640: switch (input_get(ictx, i, 0, -1)) {
1.131 nicm 1641: case -1:
1642: break;
1.64 nicm 1643: case 1: /* DECCKM */
1.144 nicm 1644: screen_write_mode_clear(sctx, MODE_KCURSOR);
1.1 nicm 1645: break;
1.17 nicm 1646: case 3: /* DECCOLM */
1.146 nicm 1647: screen_write_cursormove(sctx, 0, 0, 1);
1.171 nicm 1648: screen_write_clearscreen(sctx, gc->bg);
1.17 nicm 1649: break;
1.141 nicm 1650: case 6: /* DECOM */
1.144 nicm 1651: screen_write_mode_clear(sctx, MODE_ORIGIN);
1.146 nicm 1652: screen_write_cursormove(sctx, 0, 0, 1);
1.141 nicm 1653: break;
1.61 nicm 1654: case 7: /* DECAWM */
1.144 nicm 1655: screen_write_mode_clear(sctx, MODE_WRAP);
1.61 nicm 1656: break;
1.72 nicm 1657: case 12:
1.144 nicm 1658: screen_write_mode_clear(sctx, MODE_BLINKING);
1.72 nicm 1659: break;
1.1 nicm 1660: case 25: /* TCEM */
1.144 nicm 1661: screen_write_mode_clear(sctx, MODE_CURSOR);
1.1 nicm 1662: break;
1663: case 1000:
1.32 nicm 1664: case 1001:
1665: case 1002:
1.109 nicm 1666: case 1003:
1.144 nicm 1667: screen_write_mode_clear(sctx, ALL_MOUSE_MODES);
1.1 nicm 1668: break;
1.62 nicm 1669: case 1004:
1.144 nicm 1670: screen_write_mode_clear(sctx, MODE_FOCUSON);
1.62 nicm 1671: break;
1.96 nicm 1672: case 1005:
1.144 nicm 1673: screen_write_mode_clear(sctx, MODE_MOUSE_UTF8);
1.96 nicm 1674: break;
1.60 nicm 1675: case 1006:
1.144 nicm 1676: screen_write_mode_clear(sctx, MODE_MOUSE_SGR);
1.60 nicm 1677: break;
1.55 nicm 1678: case 47:
1679: case 1047:
1.171 nicm 1680: if (wp != NULL)
1681: window_pane_alternate_off(wp, gc, 0);
1.173 nicm 1682: else
1683: screen_alternate_off(sctx->s, gc, 0);
1.55 nicm 1684: break;
1.9 nicm 1685: case 1049:
1.171 nicm 1686: if (wp != NULL)
1687: window_pane_alternate_off(wp, gc, 1);
1.173 nicm 1688: else
1689: screen_alternate_off(sctx->s, gc, 1);
1.9 nicm 1690: break;
1.49 nicm 1691: case 2004:
1.144 nicm 1692: screen_write_mode_clear(sctx, MODE_BRACKETPASTE);
1.49 nicm 1693: break;
1.1 nicm 1694: default:
1.28 nicm 1695: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1.1 nicm 1696: break;
1697: }
1.64 nicm 1698: }
1699: }
1700:
1701: /* Handle CSI SM. */
1.104 nicm 1702: static void
1.64 nicm 1703: input_csi_dispatch_sm(struct input_ctx *ictx)
1704: {
1.144 nicm 1705: struct screen_write_ctx *sctx = &ictx->ctx;
1706: u_int i;
1.64 nicm 1707:
1708: for (i = 0; i < ictx->param_list_len; i++) {
1709: switch (input_get(ictx, i, 0, -1)) {
1.131 nicm 1710: case -1:
1711: break;
1.1 nicm 1712: case 4: /* IRM */
1.144 nicm 1713: screen_write_mode_set(sctx, MODE_INSERT);
1.1 nicm 1714: break;
1.72 nicm 1715: case 34:
1.144 nicm 1716: screen_write_mode_clear(sctx, MODE_BLINKING);
1.72 nicm 1717: break;
1.1 nicm 1718: default:
1.28 nicm 1719: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1.1 nicm 1720: break;
1721: }
1.64 nicm 1722: }
1723: }
1724:
1725: /* Handle CSI private SM. */
1.104 nicm 1726: static void
1.64 nicm 1727: input_csi_dispatch_sm_private(struct input_ctx *ictx)
1728: {
1.144 nicm 1729: struct screen_write_ctx *sctx = &ictx->ctx;
1.69 nicm 1730: struct window_pane *wp = ictx->wp;
1.171 nicm 1731: struct grid_cell *gc = &ictx->cell.cell;
1.69 nicm 1732: u_int i;
1.64 nicm 1733:
1734: for (i = 0; i < ictx->param_list_len; i++) {
1735: switch (input_get(ictx, i, 0, -1)) {
1.131 nicm 1736: case -1:
1737: break;
1.64 nicm 1738: case 1: /* DECCKM */
1.144 nicm 1739: screen_write_mode_set(sctx, MODE_KCURSOR);
1.17 nicm 1740: break;
1741: case 3: /* DECCOLM */
1.146 nicm 1742: screen_write_cursormove(sctx, 0, 0, 1);
1.144 nicm 1743: screen_write_clearscreen(sctx, ictx->cell.cell.bg);
1.141 nicm 1744: break;
1745: case 6: /* DECOM */
1.144 nicm 1746: screen_write_mode_set(sctx, MODE_ORIGIN);
1.146 nicm 1747: screen_write_cursormove(sctx, 0, 0, 1);
1.61 nicm 1748: break;
1749: case 7: /* DECAWM */
1.144 nicm 1750: screen_write_mode_set(sctx, MODE_WRAP);
1.72 nicm 1751: break;
1752: case 12:
1.144 nicm 1753: screen_write_mode_set(sctx, MODE_BLINKING);
1.1 nicm 1754: break;
1755: case 25: /* TCEM */
1.144 nicm 1756: screen_write_mode_set(sctx, MODE_CURSOR);
1.1 nicm 1757: break;
1758: case 1000:
1.144 nicm 1759: screen_write_mode_clear(sctx, ALL_MOUSE_MODES);
1760: screen_write_mode_set(sctx, MODE_MOUSE_STANDARD);
1.32 nicm 1761: break;
1762: case 1002:
1.144 nicm 1763: screen_write_mode_clear(sctx, ALL_MOUSE_MODES);
1764: screen_write_mode_set(sctx, MODE_MOUSE_BUTTON);
1.109 nicm 1765: break;
1766: case 1003:
1.144 nicm 1767: screen_write_mode_clear(sctx, ALL_MOUSE_MODES);
1768: screen_write_mode_set(sctx, MODE_MOUSE_ALL);
1.62 nicm 1769: break;
1770: case 1004:
1.144 nicm 1771: if (sctx->s->mode & MODE_FOCUSON)
1.62 nicm 1772: break;
1.144 nicm 1773: screen_write_mode_set(sctx, MODE_FOCUSON);
1.171 nicm 1774: if (wp != NULL)
1775: wp->flags |= PANE_FOCUSPUSH; /* force update */
1.96 nicm 1776: break;
1777: case 1005:
1.144 nicm 1778: screen_write_mode_set(sctx, MODE_MOUSE_UTF8);
1.60 nicm 1779: break;
1780: case 1006:
1.144 nicm 1781: screen_write_mode_set(sctx, MODE_MOUSE_SGR);
1.9 nicm 1782: break;
1.55 nicm 1783: case 47:
1784: case 1047:
1.171 nicm 1785: if (wp != NULL)
1786: window_pane_alternate_on(wp, gc, 0);
1.173 nicm 1787: else
1788: screen_alternate_on(sctx->s, gc, 0);
1.55 nicm 1789: break;
1.9 nicm 1790: case 1049:
1.171 nicm 1791: if (wp != NULL)
1792: window_pane_alternate_on(wp, gc, 1);
1.173 nicm 1793: else
1794: screen_alternate_on(sctx->s, gc, 1);
1.49 nicm 1795: break;
1796: case 2004:
1.144 nicm 1797: screen_write_mode_set(sctx, MODE_BRACKETPASTE);
1.1 nicm 1798: break;
1799: default:
1.28 nicm 1800: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1.1 nicm 1801: break;
1802: }
1.65 nicm 1803: }
1804: }
1805:
1806: /* Handle CSI window operations. */
1.104 nicm 1807: static void
1.65 nicm 1808: input_csi_dispatch_winops(struct input_ctx *ictx)
1809: {
1.144 nicm 1810: struct screen_write_ctx *sctx = &ictx->ctx;
1.172 nicm 1811: struct screen *s = sctx->s;
1.65 nicm 1812: struct window_pane *wp = ictx->wp;
1.172 nicm 1813: u_int x = screen_size_x(s), y = screen_size_y(s);
1.65 nicm 1814: int n, m;
1815:
1816: m = 0;
1817: while ((n = input_get(ictx, m, 0, -1)) != -1) {
1818: switch (n) {
1819: case 1:
1820: case 2:
1821: case 5:
1822: case 6:
1823: case 7:
1824: case 11:
1825: case 13:
1826: case 14:
1827: case 19:
1828: case 20:
1829: case 21:
1830: case 24:
1831: break;
1832: case 3:
1833: case 4:
1834: case 8:
1835: m++;
1836: if (input_get(ictx, m, 0, -1) == -1)
1837: return;
1838: /* FALLTHROUGH */
1839: case 9:
1840: case 10:
1.129 nicm 1841: m++;
1842: if (input_get(ictx, m, 0, -1) == -1)
1843: return;
1844: break;
1.65 nicm 1845: case 22:
1.129 nicm 1846: m++;
1847: switch (input_get(ictx, m, 0, -1)) {
1848: case -1:
1849: return;
1850: case 0:
1851: case 2:
1.144 nicm 1852: screen_push_title(sctx->s);
1.129 nicm 1853: break;
1854: }
1855: break;
1.65 nicm 1856: case 23:
1857: m++;
1.129 nicm 1858: switch (input_get(ictx, m, 0, -1)) {
1859: case -1:
1.65 nicm 1860: return;
1.129 nicm 1861: case 0:
1862: case 2:
1.144 nicm 1863: screen_pop_title(sctx->s);
1.171 nicm 1864: if (wp != NULL)
1865: server_status_window(wp->window);
1.129 nicm 1866: break;
1867: }
1.65 nicm 1868: break;
1869: case 18:
1.172 nicm 1870: input_reply(ictx, "\033[8;%u;%ut", x, y);
1.65 nicm 1871: break;
1872: default:
1873: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1874: break;
1875: }
1876: m++;
1.1 nicm 1877: }
1878: }
1879:
1.131 nicm 1880: /* Helper for 256 colour SGR. */
1881: static int
1882: input_csi_dispatch_sgr_256_do(struct input_ctx *ictx, int fgbg, int c)
1.78 nicm 1883: {
1884: struct grid_cell *gc = &ictx->cell.cell;
1885:
1.131 nicm 1886: if (c == -1 || c > 255) {
1.102 nicm 1887: if (fgbg == 38)
1.78 nicm 1888: gc->fg = 8;
1.102 nicm 1889: else if (fgbg == 48)
1.78 nicm 1890: gc->bg = 8;
1891: } else {
1.102 nicm 1892: if (fgbg == 38)
1893: gc->fg = c | COLOUR_FLAG_256;
1894: else if (fgbg == 48)
1895: gc->bg = c | COLOUR_FLAG_256;
1.158 nicm 1896: else if (fgbg == 58)
1897: gc->us = c | COLOUR_FLAG_256;
1.78 nicm 1898: }
1.131 nicm 1899: return (1);
1.78 nicm 1900: }
1901:
1.131 nicm 1902: /* Handle CSI SGR for 256 colours. */
1.104 nicm 1903: static void
1.131 nicm 1904: input_csi_dispatch_sgr_256(struct input_ctx *ictx, int fgbg, u_int *i)
1905: {
1906: int c;
1907:
1908: c = input_get(ictx, (*i) + 1, 0, -1);
1909: if (input_csi_dispatch_sgr_256_do(ictx, fgbg, c))
1910: (*i)++;
1911: }
1912:
1913: /* Helper for RGB colour SGR. */
1914: static int
1915: input_csi_dispatch_sgr_rgb_do(struct input_ctx *ictx, int fgbg, int r, int g,
1916: int b)
1.78 nicm 1917: {
1918: struct grid_cell *gc = &ictx->cell.cell;
1919:
1920: if (r == -1 || r > 255)
1.131 nicm 1921: return (0);
1.78 nicm 1922: if (g == -1 || g > 255)
1.131 nicm 1923: return (0);
1.78 nicm 1924: if (b == -1 || b > 255)
1.131 nicm 1925: return (0);
1.78 nicm 1926:
1.102 nicm 1927: if (fgbg == 38)
1928: gc->fg = colour_join_rgb(r, g, b);
1929: else if (fgbg == 48)
1930: gc->bg = colour_join_rgb(r, g, b);
1.158 nicm 1931: else if (fgbg == 58)
1932: gc->us = colour_join_rgb(r, g, b);
1.131 nicm 1933: return (1);
1934: }
1935:
1936: /* Handle CSI SGR for RGB colours. */
1937: static void
1938: input_csi_dispatch_sgr_rgb(struct input_ctx *ictx, int fgbg, u_int *i)
1939: {
1940: int r, g, b;
1941:
1942: r = input_get(ictx, (*i) + 1, 0, -1);
1943: g = input_get(ictx, (*i) + 2, 0, -1);
1944: b = input_get(ictx, (*i) + 3, 0, -1);
1945: if (input_csi_dispatch_sgr_rgb_do(ictx, fgbg, r, g, b))
1946: (*i) += 3;
1947: }
1948:
1949: /* Handle CSI SGR with a ISO parameter. */
1950: static void
1951: input_csi_dispatch_sgr_colon(struct input_ctx *ictx, u_int i)
1952: {
1.137 nicm 1953: struct grid_cell *gc = &ictx->cell.cell;
1954: char *s = ictx->param_list[i].str, *copy, *ptr, *out;
1955: int p[8];
1956: u_int n;
1957: const char *errstr;
1.131 nicm 1958:
1959: for (n = 0; n < nitems(p); n++)
1960: p[n] = -1;
1961: n = 0;
1962:
1963: ptr = copy = xstrdup(s);
1964: while ((out = strsep(&ptr, ":")) != NULL) {
1.134 nicm 1965: if (*out != '\0') {
1966: p[n++] = strtonum(out, 0, INT_MAX, &errstr);
1967: if (errstr != NULL || n == nitems(p)) {
1968: free(copy);
1969: return;
1970: }
1.140 nicm 1971: } else
1972: n++;
1.131 nicm 1973: log_debug("%s: %u = %d", __func__, n - 1, p[n - 1]);
1974: }
1975: free(copy);
1976:
1.137 nicm 1977: if (n == 0)
1978: return;
1979: if (p[0] == 4) {
1980: if (n != 2)
1981: return;
1982: switch (p[1]) {
1983: case 0:
1984: gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
1985: break;
1986: case 1:
1987: gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
1988: gc->attr |= GRID_ATTR_UNDERSCORE;
1989: break;
1990: case 2:
1991: gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
1992: gc->attr |= GRID_ATTR_UNDERSCORE_2;
1993: break;
1994: case 3:
1995: gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
1996: gc->attr |= GRID_ATTR_UNDERSCORE_3;
1997: break;
1998: case 4:
1999: gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
2000: gc->attr |= GRID_ATTR_UNDERSCORE_4;
2001: break;
2002: case 5:
2003: gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
2004: gc->attr |= GRID_ATTR_UNDERSCORE_5;
2005: break;
2006: }
2007: return;
2008: }
1.158 nicm 2009: if (n < 2 || (p[0] != 38 && p[0] != 48 && p[0] != 58))
1.131 nicm 2010: return;
1.154 nicm 2011: switch (p[1]) {
1.131 nicm 2012: case 2:
1.154 nicm 2013: if (n < 3)
2014: break;
2015: if (n == 5)
2016: i = 2;
2017: else
2018: i = 3;
2019: if (n < i + 3)
1.131 nicm 2020: break;
1.154 nicm 2021: input_csi_dispatch_sgr_rgb_do(ictx, p[0], p[i], p[i + 1],
2022: p[i + 2]);
1.131 nicm 2023: break;
2024: case 5:
1.154 nicm 2025: if (n < 3)
1.131 nicm 2026: break;
1.154 nicm 2027: input_csi_dispatch_sgr_256_do(ictx, p[0], p[2]);
1.131 nicm 2028: break;
2029: }
1.78 nicm 2030: }
2031:
1.28 nicm 2032: /* Handle CSI SGR. */
1.104 nicm 2033: static void
1.28 nicm 2034: input_csi_dispatch_sgr(struct input_ctx *ictx)
1.1 nicm 2035: {
1.69 nicm 2036: struct grid_cell *gc = &ictx->cell.cell;
1.28 nicm 2037: u_int i;
1.78 nicm 2038: int n;
1.1 nicm 2039:
1.28 nicm 2040: if (ictx->param_list_len == 0) {
1.1 nicm 2041: memcpy(gc, &grid_default_cell, sizeof *gc);
2042: return;
2043: }
2044:
1.28 nicm 2045: for (i = 0; i < ictx->param_list_len; i++) {
1.131 nicm 2046: if (ictx->param_list[i].type == INPUT_STRING) {
2047: input_csi_dispatch_sgr_colon(ictx, i);
2048: continue;
2049: }
1.28 nicm 2050: n = input_get(ictx, i, 0, 0);
1.131 nicm 2051: if (n == -1)
2052: continue;
1.1 nicm 2053:
1.158 nicm 2054: if (n == 38 || n == 48 || n == 58) {
1.1 nicm 2055: i++;
1.78 nicm 2056: switch (input_get(ictx, i, 0, -1)) {
2057: case 2:
2058: input_csi_dispatch_sgr_rgb(ictx, n, &i);
2059: break;
2060: case 5:
2061: input_csi_dispatch_sgr_256(ictx, n, &i);
2062: break;
1.1 nicm 2063: }
2064: continue;
2065: }
2066:
1.28 nicm 2067: switch (n) {
1.1 nicm 2068: case 0:
2069: memcpy(gc, &grid_default_cell, sizeof *gc);
2070: break;
2071: case 1:
2072: gc->attr |= GRID_ATTR_BRIGHT;
2073: break;
2074: case 2:
2075: gc->attr |= GRID_ATTR_DIM;
2076: break;
2077: case 3:
2078: gc->attr |= GRID_ATTR_ITALICS;
2079: break;
2080: case 4:
1.137 nicm 2081: gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
1.1 nicm 2082: gc->attr |= GRID_ATTR_UNDERSCORE;
2083: break;
2084: case 5:
2085: gc->attr |= GRID_ATTR_BLINK;
2086: break;
2087: case 7:
2088: gc->attr |= GRID_ATTR_REVERSE;
2089: break;
2090: case 8:
2091: gc->attr |= GRID_ATTR_HIDDEN;
2092: break;
1.118 nicm 2093: case 9:
2094: gc->attr |= GRID_ATTR_STRIKETHROUGH;
2095: break;
1.1 nicm 2096: case 22:
2097: gc->attr &= ~(GRID_ATTR_BRIGHT|GRID_ATTR_DIM);
2098: break;
2099: case 23:
2100: gc->attr &= ~GRID_ATTR_ITALICS;
2101: break;
2102: case 24:
1.137 nicm 2103: gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
1.1 nicm 2104: break;
2105: case 25:
2106: gc->attr &= ~GRID_ATTR_BLINK;
2107: break;
2108: case 27:
2109: gc->attr &= ~GRID_ATTR_REVERSE;
1.117 nicm 2110: break;
2111: case 28:
2112: gc->attr &= ~GRID_ATTR_HIDDEN;
1.118 nicm 2113: break;
2114: case 29:
2115: gc->attr &= ~GRID_ATTR_STRIKETHROUGH;
1.1 nicm 2116: break;
2117: case 30:
2118: case 31:
2119: case 32:
2120: case 33:
2121: case 34:
2122: case 35:
2123: case 36:
2124: case 37:
1.28 nicm 2125: gc->fg = n - 30;
1.1 nicm 2126: break;
2127: case 39:
2128: gc->fg = 8;
2129: break;
2130: case 40:
2131: case 41:
2132: case 42:
2133: case 43:
2134: case 44:
2135: case 45:
2136: case 46:
2137: case 47:
1.28 nicm 2138: gc->bg = n - 40;
1.1 nicm 2139: break;
2140: case 49:
2141: gc->bg = 8;
1.153 nicm 2142: break;
2143: case 53:
2144: gc->attr |= GRID_ATTR_OVERLINE;
2145: break;
2146: case 55:
2147: gc->attr &= ~GRID_ATTR_OVERLINE;
1.158 nicm 2148: break;
2149: case 59:
2150: gc->us = 0;
1.20 nicm 2151: break;
2152: case 90:
2153: case 91:
2154: case 92:
2155: case 93:
2156: case 94:
2157: case 95:
2158: case 96:
2159: case 97:
1.28 nicm 2160: gc->fg = n;
1.20 nicm 2161: break;
2162: case 100:
2163: case 101:
2164: case 102:
2165: case 103:
2166: case 104:
2167: case 105:
2168: case 106:
2169: case 107:
1.47 nicm 2170: gc->bg = n - 10;
1.1 nicm 2171: break;
2172: }
2173: }
1.28 nicm 2174: }
2175:
1.138 nicm 2176: /* End of input with BEL. */
2177: static int
2178: input_end_bel(struct input_ctx *ictx)
2179: {
2180: log_debug("%s", __func__);
2181:
2182: ictx->input_end = INPUT_END_BEL;
2183:
2184: return (0);
2185: }
2186:
1.125 nicm 2187: /* DCS string started. */
2188: static void
2189: input_enter_dcs(struct input_ctx *ictx)
2190: {
2191: log_debug("%s", __func__);
2192:
2193: input_clear(ictx);
2194: input_start_timer(ictx);
1.127 nicm 2195: ictx->last = -1;
1.125 nicm 2196: }
2197:
1.37 nicm 2198: /* DCS terminator (ST) received. */
1.104 nicm 2199: static int
1.37 nicm 2200: input_dcs_dispatch(struct input_ctx *ictx)
1.28 nicm 2201: {
1.144 nicm 2202: struct screen_write_ctx *sctx = &ictx->ctx;
2203: u_char *buf = ictx->input_buf;
2204: size_t len = ictx->input_len;
2205: const char prefix[] = "tmux;";
2206: const u_int prefixlen = (sizeof prefix) - 1;
1.37 nicm 2207:
2208: if (ictx->flags & INPUT_DISCARD)
2209: return (0);
2210:
1.144 nicm 2211: log_debug("%s: \"%s\"", __func__, buf);
1.28 nicm 2212:
1.144 nicm 2213: if (len >= prefixlen && strncmp(buf, prefix, prefixlen) == 0)
2214: screen_write_rawstring(sctx, buf + prefixlen, len - prefixlen);
1.28 nicm 2215:
1.37 nicm 2216: return (0);
1.28 nicm 2217: }
2218:
2219: /* OSC string started. */
1.104 nicm 2220: static void
1.28 nicm 2221: input_enter_osc(struct input_ctx *ictx)
2222: {
2223: log_debug("%s", __func__);
2224:
1.35 nicm 2225: input_clear(ictx);
1.125 nicm 2226: input_start_timer(ictx);
1.127 nicm 2227: ictx->last = -1;
1.28 nicm 2228: }
2229:
2230: /* OSC terminator (ST) received. */
1.104 nicm 2231: static void
1.28 nicm 2232: input_exit_osc(struct input_ctx *ictx)
2233: {
1.144 nicm 2234: struct screen_write_ctx *sctx = &ictx->ctx;
1.171 nicm 2235: struct window_pane *wp = ictx->wp;
1.144 nicm 2236: u_char *p = ictx->input_buf;
2237: u_int option;
1.38 nicm 2238:
1.28 nicm 2239: if (ictx->flags & INPUT_DISCARD)
2240: return;
1.38 nicm 2241: if (ictx->input_len < 1 || *p < '0' || *p > '9')
2242: return;
1.28 nicm 2243:
1.138 nicm 2244: log_debug("%s: \"%s\" (end %s)", __func__, p,
2245: ictx->input_end == INPUT_END_ST ? "ST" : "BEL");
1.28 nicm 2246:
1.38 nicm 2247: option = 0;
2248: while (*p >= '0' && *p <= '9')
2249: option = option * 10 + *p++ - '0';
2250: if (*p == ';')
2251: p++;
2252:
2253: switch (option) {
2254: case 0:
2255: case 2:
1.171 nicm 2256: if (screen_set_title(sctx->s, p) && wp != NULL)
1.124 nicm 2257: server_status_window(ictx->wp->window);
1.38 nicm 2258: break;
1.107 nicm 2259: case 4:
1.138 nicm 2260: input_osc_4(ictx, p);
1.165 nicm 2261: break;
2262: case 7:
2263: if (utf8_isvalid(p)) {
2264: screen_set_path(sctx->s, p);
1.171 nicm 2265: if (wp != NULL)
2266: server_status_window(wp->window);
1.165 nicm 2267: }
1.107 nicm 2268: break;
1.122 nicm 2269: case 10:
1.138 nicm 2270: input_osc_10(ictx, p);
1.122 nicm 2271: break;
2272: case 11:
1.138 nicm 2273: input_osc_11(ictx, p);
1.108 nicm 2274: break;
1.38 nicm 2275: case 12:
1.124 nicm 2276: if (utf8_isvalid(p) && *p != '?') /* ? is colour request */
1.144 nicm 2277: screen_set_cursor_colour(sctx->s, p);
1.38 nicm 2278: break;
1.122 nicm 2279: case 52:
1.138 nicm 2280: input_osc_52(ictx, p);
1.122 nicm 2281: break;
1.107 nicm 2282: case 104:
1.138 nicm 2283: input_osc_104(ictx, p);
1.107 nicm 2284: break;
1.38 nicm 2285: case 112:
1.57 nicm 2286: if (*p == '\0') /* no arguments allowed */
1.144 nicm 2287: screen_set_cursor_colour(sctx->s, "");
1.38 nicm 2288: break;
2289: default:
2290: log_debug("%s: unknown '%u'", __func__, option);
2291: break;
2292: }
1.28 nicm 2293: }
2294:
2295: /* APC string started. */
1.104 nicm 2296: static void
1.28 nicm 2297: input_enter_apc(struct input_ctx *ictx)
2298: {
2299: log_debug("%s", __func__);
2300:
1.35 nicm 2301: input_clear(ictx);
1.125 nicm 2302: input_start_timer(ictx);
1.127 nicm 2303: ictx->last = -1;
1.28 nicm 2304: }
2305:
2306: /* APC terminator (ST) received. */
1.104 nicm 2307: static void
1.28 nicm 2308: input_exit_apc(struct input_ctx *ictx)
2309: {
1.144 nicm 2310: struct screen_write_ctx *sctx = &ictx->ctx;
1.171 nicm 2311: struct window_pane *wp = ictx->wp;
1.144 nicm 2312:
1.28 nicm 2313: if (ictx->flags & INPUT_DISCARD)
2314: return;
2315: log_debug("%s: \"%s\"", __func__, ictx->input_buf);
2316:
1.171 nicm 2317: if (screen_set_title(sctx->s, ictx->input_buf) && wp != NULL)
2318: server_status_window(wp->window);
1.28 nicm 2319: }
2320:
2321: /* Rename string started. */
1.104 nicm 2322: static void
1.28 nicm 2323: input_enter_rename(struct input_ctx *ictx)
2324: {
2325: log_debug("%s", __func__);
2326:
1.35 nicm 2327: input_clear(ictx);
1.125 nicm 2328: input_start_timer(ictx);
1.127 nicm 2329: ictx->last = -1;
1.28 nicm 2330: }
2331:
2332: /* Rename terminator (ST) received. */
1.104 nicm 2333: static void
1.28 nicm 2334: input_exit_rename(struct input_ctx *ictx)
2335: {
1.162 nicm 2336: struct window_pane *wp = ictx->wp;
2337: struct options_entry *oe;
2338:
1.171 nicm 2339: if (wp == NULL)
2340: return;
1.28 nicm 2341: if (ictx->flags & INPUT_DISCARD)
1.44 nicm 2342: return;
1.157 nicm 2343: if (!options_get_number(ictx->wp->options, "allow-rename"))
1.28 nicm 2344: return;
2345: log_debug("%s: \"%s\"", __func__, ictx->input_buf);
2346:
1.124 nicm 2347: if (!utf8_isvalid(ictx->input_buf))
2348: return;
1.162 nicm 2349:
2350: if (ictx->input_len == 0) {
1.174 nicm 2351: oe = options_get_only(wp->window->options, "automatic-rename");
1.162 nicm 2352: if (oe != NULL)
2353: options_remove(oe);
2354: return;
2355: }
1.171 nicm 2356: window_set_name(wp->window, ictx->input_buf);
2357: options_set_number(wp->window->options, "automatic-rename", 0);
2358: server_status_window(wp->window);
1.28 nicm 2359: }
2360:
2361: /* Open UTF-8 character. */
1.104 nicm 2362: static int
1.130 nicm 2363: input_top_bit_set(struct input_ctx *ictx)
1.28 nicm 2364: {
1.144 nicm 2365: struct screen_write_ctx *sctx = &ictx->ctx;
1.90 nicm 2366: struct utf8_data *ud = &ictx->utf8data;
2367:
1.127 nicm 2368: ictx->last = -1;
1.28 nicm 2369:
1.130 nicm 2370: if (!ictx->utf8started) {
2371: if (utf8_open(ud, ictx->ch) != UTF8_MORE)
2372: return (0);
2373: ictx->utf8started = 1;
2374: return (0);
2375: }
1.28 nicm 2376:
1.130 nicm 2377: switch (utf8_append(ud, ictx->ch)) {
2378: case UTF8_MORE:
2379: return (0);
2380: case UTF8_ERROR:
2381: ictx->utf8started = 0;
1.101 nicm 2382: return (0);
1.130 nicm 2383: case UTF8_DONE:
2384: break;
1.101 nicm 2385: }
1.130 nicm 2386: ictx->utf8started = 0;
1.28 nicm 2387:
1.90 nicm 2388: log_debug("%s %hhu '%*s' (width %hhu)", __func__, ud->size,
2389: (int)ud->size, ud->data, ud->width);
1.28 nicm 2390:
1.90 nicm 2391: utf8_copy(&ictx->cell.cell.data, ud);
1.144 nicm 2392: screen_write_collect_add(sctx, &ictx->cell.cell);
1.28 nicm 2393:
2394: return (0);
1.107 nicm 2395: }
2396:
1.163 nicm 2397: /* Parse colour from OSC. */
2398: static int
2399: input_osc_parse_colour(const char *p, u_int *r, u_int *g, u_int *b)
2400: {
2401: u_int rsize, gsize, bsize;
2402: const char *cp, *s = p;
2403:
2404: if (sscanf(p, "rgb:%x/%x/%x", r, g, b) != 3)
2405: return (0);
2406: p += 4;
2407:
2408: cp = strchr(p, '/');
2409: rsize = cp - p;
2410: if (rsize == 1)
2411: (*r) = (*r) | ((*r) << 4);
2412: else if (rsize == 3)
2413: (*r) >>= 4;
2414: else if (rsize == 4)
2415: (*r) >>= 8;
2416: else if (rsize != 2)
2417: return (0);
2418:
2419: p = cp + 1;
2420: cp = strchr(p, '/');
2421: gsize = cp - p;
2422: if (gsize == 1)
2423: (*g) = (*g) | ((*g) << 4);
2424: else if (gsize == 3)
2425: (*g) >>= 4;
2426: else if (gsize == 4)
2427: (*g) >>= 8;
2428: else if (gsize != 2)
2429: return (0);
2430:
2431: bsize = strlen(cp + 1);
2432: if (bsize == 1)
2433: (*b) = (*b) | ((*b) << 4);
2434: else if (bsize == 3)
2435: (*b) >>= 4;
2436: else if (bsize == 4)
2437: (*b) >>= 8;
2438: else if (bsize != 2)
2439: return (0);
2440:
2441: log_debug("%s: %s = %02x%02x%02x", __func__, s, *r, *g, *b);
2442: return (1);
2443: }
2444:
1.107 nicm 2445: /* Handle the OSC 4 sequence for setting (multiple) palette entries. */
2446: static void
1.138 nicm 2447: input_osc_4(struct input_ctx *ictx, const char *p)
1.107 nicm 2448: {
1.138 nicm 2449: struct window_pane *wp = ictx->wp;
2450: char *copy, *s, *next = NULL;
1.144 nicm 2451: long idx;
1.138 nicm 2452: u_int r, g, b;
1.107 nicm 2453:
1.171 nicm 2454: if (wp == NULL)
2455: return;
2456:
1.107 nicm 2457: copy = s = xstrdup(p);
2458: while (s != NULL && *s != '\0') {
2459: idx = strtol(s, &next, 10);
2460: if (*next++ != ';')
2461: goto bad;
2462: if (idx < 0 || idx >= 0x100)
2463: goto bad;
2464:
2465: s = strsep(&next, ";");
1.163 nicm 2466: if (!input_osc_parse_colour(s, &r, &g, &b)) {
1.107 nicm 2467: s = next;
2468: continue;
2469: }
2470:
2471: window_pane_set_palette(wp, idx, colour_join_rgb(r, g, b));
2472: s = next;
2473: }
2474:
2475: free(copy);
2476: return;
2477:
2478: bad:
2479: log_debug("bad OSC 4: %s", p);
2480: free(copy);
1.122 nicm 2481: }
2482:
1.136 nicm 2483: /* Handle the OSC 10 sequence for setting foreground colour. */
1.122 nicm 2484: static void
1.138 nicm 2485: input_osc_10(struct input_ctx *ictx, const char *p)
1.122 nicm 2486: {
1.138 nicm 2487: struct window_pane *wp = ictx->wp;
2488: u_int r, g, b;
1.156 nicm 2489: char tmp[16];
1.122 nicm 2490:
1.171 nicm 2491: if (wp == NULL)
2492: return;
1.163 nicm 2493: if (strcmp(p, "?") == 0)
2494: return;
2495:
2496: if (!input_osc_parse_colour(p, &r, &g, &b))
2497: goto bad;
1.156 nicm 2498: xsnprintf(tmp, sizeof tmp, "fg=#%02x%02x%02x", r, g, b);
2499: options_set_style(wp->options, "window-style", 1, tmp);
2500: options_set_style(wp->options, "window-active-style", 1, tmp);
2501: wp->flags |= (PANE_REDRAW|PANE_STYLECHANGED);
1.122 nicm 2502:
2503: return;
2504:
2505: bad:
2506: log_debug("bad OSC 10: %s", p);
2507: }
2508:
2509: /* Handle the OSC 11 sequence for setting background colour. */
2510: static void
1.138 nicm 2511: input_osc_11(struct input_ctx *ictx, const char *p)
1.122 nicm 2512: {
1.138 nicm 2513: struct window_pane *wp = ictx->wp;
2514: u_int r, g, b;
1.156 nicm 2515: char tmp[16];
1.122 nicm 2516:
1.171 nicm 2517: if (wp == NULL)
2518: return;
1.163 nicm 2519: if (strcmp(p, "?") == 0)
2520: return;
2521:
2522: if (!input_osc_parse_colour(p, &r, &g, &b))
1.122 nicm 2523: goto bad;
1.156 nicm 2524: xsnprintf(tmp, sizeof tmp, "bg=#%02x%02x%02x", r, g, b);
2525: options_set_style(wp->options, "window-style", 1, tmp);
2526: options_set_style(wp->options, "window-active-style", 1, tmp);
2527: wp->flags |= (PANE_REDRAW|PANE_STYLECHANGED);
1.122 nicm 2528:
2529: return;
2530:
2531: bad:
2532: log_debug("bad OSC 11: %s", p);
1.108 nicm 2533: }
2534:
2535: /* Handle the OSC 52 sequence for setting the clipboard. */
2536: static void
1.138 nicm 2537: input_osc_52(struct input_ctx *ictx, const char *p)
1.108 nicm 2538: {
1.138 nicm 2539: struct window_pane *wp = ictx->wp;
1.108 nicm 2540: char *end;
1.138 nicm 2541: const char *buf;
1.108 nicm 2542: size_t len;
2543: u_char *out;
1.123 nicm 2544: int outlen, state;
1.108 nicm 2545: struct screen_write_ctx ctx;
1.138 nicm 2546: struct paste_buffer *pb;
1.108 nicm 2547:
1.171 nicm 2548: if (wp == NULL)
2549: return;
1.123 nicm 2550: state = options_get_number(global_options, "set-clipboard");
2551: if (state != 2)
2552: return;
2553:
1.108 nicm 2554: if ((end = strchr(p, ';')) == NULL)
2555: return;
2556: end++;
2557: if (*end == '\0')
2558: return;
1.138 nicm 2559: log_debug("%s: %s", __func__, end);
2560:
2561: if (strcmp(end, "?") == 0) {
2562: if ((pb = paste_get_top(NULL)) != NULL) {
2563: buf = paste_buffer_data(pb, &len);
2564: outlen = 4 * ((len + 2) / 3) + 1;
2565: out = xmalloc(outlen);
2566: if ((outlen = b64_ntop(buf, len, out, outlen)) == -1) {
2567: free(out);
2568: return;
2569: }
2570: } else {
2571: outlen = 0;
2572: out = NULL;
2573: }
1.172 nicm 2574: bufferevent_write(ictx->event, "\033]52;;", 6);
1.138 nicm 2575: if (outlen != 0)
1.172 nicm 2576: bufferevent_write(ictx->event, out, outlen);
1.138 nicm 2577: if (ictx->input_end == INPUT_END_BEL)
1.172 nicm 2578: bufferevent_write(ictx->event, "\007", 1);
1.138 nicm 2579: else
1.172 nicm 2580: bufferevent_write(ictx->event, "\033\\", 2);
1.138 nicm 2581: free(out);
2582: return;
2583: }
1.108 nicm 2584:
2585: len = (strlen(end) / 4) * 3;
2586: if (len == 0)
2587: return;
2588:
2589: out = xmalloc(len);
2590: if ((outlen = b64_pton(end, out, len)) == -1) {
2591: free(out);
2592: return;
2593: }
2594:
1.123 nicm 2595: screen_write_start(&ctx, wp, NULL);
2596: screen_write_setselection(&ctx, out, outlen);
2597: screen_write_stop(&ctx);
1.126 nicm 2598: notify_pane("pane-set-clipboard", wp);
1.123 nicm 2599:
1.150 nicm 2600: paste_add(NULL, out, outlen);
1.107 nicm 2601: }
2602:
2603: /* Handle the OSC 104 sequence for unsetting (multiple) palette entries. */
2604: static void
1.138 nicm 2605: input_osc_104(struct input_ctx *ictx, const char *p)
1.107 nicm 2606: {
1.138 nicm 2607: struct window_pane *wp = ictx->wp;
2608: char *copy, *s;
1.144 nicm 2609: long idx;
1.171 nicm 2610:
2611: if (wp == NULL)
2612: return;
1.107 nicm 2613:
2614: if (*p == '\0') {
2615: window_pane_reset_palette(wp);
2616: return;
2617: }
2618:
2619: copy = s = xstrdup(p);
2620: while (*s != '\0') {
2621: idx = strtol(s, &s, 10);
2622: if (*s != '\0' && *s != ';')
2623: goto bad;
2624: if (idx < 0 || idx >= 0x100)
2625: goto bad;
2626:
2627: window_pane_unset_palette(wp, idx);
2628: if (*s == ';')
2629: s++;
2630: }
2631: free(copy);
2632: return;
2633:
2634: bad:
2635: log_debug("bad OSC 104: %s", p);
2636: free(copy);
1.1 nicm 2637: }