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