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