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