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