Annotation of src/usr.bin/tmux/input.c, Revision 1.164
1.164 ! nicm 1: /* $OpenBSD: input.c,v 1.163 2019/11/01 09:09:53 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.164 ! nicm 879: struct evbuffer *evb = wp->event->input;
1.152 nicm 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) {
1.161 nicm 926: if (ictx->ch >= itr->first &&
927: ictx->ch <= itr->last)
1.160 nicm 928: break;
929: itr++;
930: }
931: if (itr->first == -1 || itr->last == -1) {
932: /* No transition? Eh? */
933: fatalx("no transition from state");
934: }
1.3 nicm 935: }
1.160 nicm 936: state = ictx->state;
1.1 nicm 937:
938: /*
1.114 nicm 939: * Any state except print stops the current collection. This is
940: * an optimization to avoid checking if the attributes have
941: * changed for every character. It will stop unnecessarily for
942: * sequences that don't make a terminal change, but they should
943: * be the minority.
944: */
945: if (itr->handler != input_print)
1.144 nicm 946: screen_write_collect_end(sctx);
1.114 nicm 947:
948: /*
1.28 nicm 949: * Execute the handler, if any. Don't switch state if it
950: * returns non-zero.
1.1 nicm 951: */
1.31 nicm 952: if (itr->handler != NULL && itr->handler(ictx) != 0)
1.28 nicm 953: continue;
954:
955: /* And switch state, if necessary. */
1.52 nicm 956: if (itr->state != NULL)
957: input_set_state(wp, itr);
958:
959: /* If not in ground state, save input. */
960: if (ictx->state != &input_state_ground)
961: evbuffer_add(ictx->since_ground, &ictx->ch, 1);
1.1 nicm 962: }
963:
1.28 nicm 964: /* Close the screen. */
1.144 nicm 965: screen_write_stop(sctx);
1.1 nicm 966: }
967:
1.28 nicm 968: /* Split the parameter list (if any). */
1.104 nicm 969: static int
1.28 nicm 970: input_split(struct input_ctx *ictx)
1.1 nicm 971: {
1.131 nicm 972: const char *errstr;
973: char *ptr, *out;
974: struct input_param *ip;
975: u_int i;
1.1 nicm 976:
1.131 nicm 977: for (i = 0; i < ictx->param_list_len; i++) {
978: if (ictx->param_list[i].type == INPUT_STRING)
979: free(ictx->param_list[i].str);
980: }
1.28 nicm 981: ictx->param_list_len = 0;
1.131 nicm 982:
1.28 nicm 983: if (ictx->param_len == 0)
984: return (0);
1.131 nicm 985: ip = &ictx->param_list[0];
1.1 nicm 986:
1.28 nicm 987: ptr = ictx->param_buf;
988: while ((out = strsep(&ptr, ";")) != NULL) {
989: if (*out == '\0')
1.131 nicm 990: ip->type = INPUT_MISSING;
1.28 nicm 991: else {
1.131 nicm 992: if (strchr(out, ':') != NULL) {
993: ip->type = INPUT_STRING;
994: ip->str = xstrdup(out);
995: } else {
996: ip->type = INPUT_NUMBER;
997: ip->num = strtonum(out, 0, INT_MAX, &errstr);
998: if (errstr != NULL)
999: return (-1);
1000: }
1.28 nicm 1001: }
1.131 nicm 1002: ip = &ictx->param_list[++ictx->param_list_len];
1.28 nicm 1003: if (ictx->param_list_len == nitems(ictx->param_list))
1004: return (-1);
1005: }
1.1 nicm 1006:
1.131 nicm 1007: for (i = 0; i < ictx->param_list_len; i++) {
1008: ip = &ictx->param_list[i];
1009: if (ip->type == INPUT_MISSING)
1010: log_debug("parameter %u: missing", i);
1011: else if (ip->type == INPUT_STRING)
1012: log_debug("parameter %u: string %s", i, ip->str);
1013: else if (ip->type == INPUT_NUMBER)
1014: log_debug("parameter %u: number %d", i, ip->num);
1015: }
1016:
1.28 nicm 1017: return (0);
1.1 nicm 1018: }
1019:
1.40 nicm 1020: /* Get an argument or return default value. */
1.104 nicm 1021: static int
1.28 nicm 1022: input_get(struct input_ctx *ictx, u_int validx, int minval, int defval)
1.1 nicm 1023: {
1.131 nicm 1024: struct input_param *ip;
1025: int retval;
1.1 nicm 1026:
1.28 nicm 1027: if (validx >= ictx->param_list_len)
1028: return (defval);
1.131 nicm 1029: ip = &ictx->param_list[validx];
1030: if (ip->type == INPUT_MISSING)
1.28 nicm 1031: return (defval);
1.131 nicm 1032: if (ip->type == INPUT_STRING)
1033: return (-1);
1034: retval = ip->num;
1.28 nicm 1035: if (retval < minval)
1036: return (minval);
1037: return (retval);
1.1 nicm 1038: }
1039:
1.28 nicm 1040: /* Reply to terminal query. */
1.104 nicm 1041: static void
1.28 nicm 1042: input_reply(struct input_ctx *ictx, const char *fmt, ...)
1.1 nicm 1043: {
1.138 nicm 1044: va_list ap;
1045: char *reply;
1.1 nicm 1046:
1.28 nicm 1047: va_start(ap, fmt);
1.103 nicm 1048: xvasprintf(&reply, fmt, ap);
1.28 nicm 1049: va_end(ap);
1.1 nicm 1050:
1.28 nicm 1051: bufferevent_write(ictx->wp->event, reply, strlen(reply));
1.53 nicm 1052: free(reply);
1.8 nicm 1053: }
1054:
1.28 nicm 1055: /* Clear saved state. */
1.104 nicm 1056: static void
1.28 nicm 1057: input_clear(struct input_ctx *ictx)
1.8 nicm 1058: {
1.125 nicm 1059: event_del(&ictx->timer);
1060:
1.28 nicm 1061: *ictx->interm_buf = '\0';
1062: ictx->interm_len = 0;
1.8 nicm 1063:
1.28 nicm 1064: *ictx->param_buf = '\0';
1065: ictx->param_len = 0;
1.8 nicm 1066:
1.35 nicm 1067: *ictx->input_buf = '\0';
1068: ictx->input_len = 0;
1069:
1.138 nicm 1070: ictx->input_end = INPUT_END_ST;
1071:
1.28 nicm 1072: ictx->flags &= ~INPUT_DISCARD;
1.14 nicm 1073: }
1074:
1.67 nicm 1075: /* Reset for ground state. */
1.104 nicm 1076: static void
1.67 nicm 1077: input_ground(struct input_ctx *ictx)
1078: {
1.125 nicm 1079: event_del(&ictx->timer);
1.67 nicm 1080: evbuffer_drain(ictx->since_ground, EVBUFFER_LENGTH(ictx->since_ground));
1081:
1082: if (ictx->input_space > INPUT_BUF_START) {
1083: ictx->input_space = INPUT_BUF_START;
1.71 nicm 1084: ictx->input_buf = xrealloc(ictx->input_buf, INPUT_BUF_START);
1.67 nicm 1085: }
1086: }
1087:
1.28 nicm 1088: /* Output this character to the screen. */
1.104 nicm 1089: static int
1.28 nicm 1090: input_print(struct input_ctx *ictx)
1.14 nicm 1091: {
1.144 nicm 1092: struct screen_write_ctx *sctx = &ictx->ctx;
1093: int set;
1.69 nicm 1094:
1.130 nicm 1095: ictx->utf8started = 0; /* can't be valid UTF-8 */
1096:
1.69 nicm 1097: set = ictx->cell.set == 0 ? ictx->cell.g0set : ictx->cell.g1set;
1098: if (set == 1)
1099: ictx->cell.cell.attr |= GRID_ATTR_CHARSET;
1100: else
1101: ictx->cell.cell.attr &= ~GRID_ATTR_CHARSET;
1102:
1.89 nicm 1103: utf8_set(&ictx->cell.cell.data, ictx->ch);
1.144 nicm 1104: screen_write_collect_add(sctx, &ictx->cell.cell);
1.127 nicm 1105: ictx->last = ictx->ch;
1.69 nicm 1106:
1107: ictx->cell.cell.attr &= ~GRID_ATTR_CHARSET;
1.14 nicm 1108:
1.28 nicm 1109: return (0);
1.1 nicm 1110: }
1111:
1.28 nicm 1112: /* Collect intermediate string. */
1.104 nicm 1113: static int
1.28 nicm 1114: input_intermediate(struct input_ctx *ictx)
1.1 nicm 1115: {
1.28 nicm 1116: if (ictx->interm_len == (sizeof ictx->interm_buf) - 1)
1117: ictx->flags |= INPUT_DISCARD;
1118: else {
1119: ictx->interm_buf[ictx->interm_len++] = ictx->ch;
1120: ictx->interm_buf[ictx->interm_len] = '\0';
1121: }
1.1 nicm 1122:
1.28 nicm 1123: return (0);
1.1 nicm 1124: }
1125:
1.28 nicm 1126: /* Collect parameter string. */
1.104 nicm 1127: static int
1.28 nicm 1128: input_parameter(struct input_ctx *ictx)
1.1 nicm 1129: {
1.28 nicm 1130: if (ictx->param_len == (sizeof ictx->param_buf) - 1)
1131: ictx->flags |= INPUT_DISCARD;
1132: else {
1133: ictx->param_buf[ictx->param_len++] = ictx->ch;
1134: ictx->param_buf[ictx->param_len] = '\0';
1135: }
1.1 nicm 1136:
1.28 nicm 1137: return (0);
1.1 nicm 1138: }
1139:
1.28 nicm 1140: /* Collect input string. */
1.104 nicm 1141: static int
1.28 nicm 1142: input_input(struct input_ctx *ictx)
1.1 nicm 1143: {
1.67 nicm 1144: size_t available;
1145:
1146: available = ictx->input_space;
1147: while (ictx->input_len + 1 >= available) {
1148: available *= 2;
1149: if (available > INPUT_BUF_LIMIT) {
1150: ictx->flags |= INPUT_DISCARD;
1151: return (0);
1152: }
1.71 nicm 1153: ictx->input_buf = xrealloc(ictx->input_buf, available);
1.67 nicm 1154: ictx->input_space = available;
1.28 nicm 1155: }
1.67 nicm 1156: ictx->input_buf[ictx->input_len++] = ictx->ch;
1157: ictx->input_buf[ictx->input_len] = '\0';
1.1 nicm 1158:
1.28 nicm 1159: return (0);
1.1 nicm 1160: }
1161:
1.28 nicm 1162: /* Execute C0 control sequence. */
1.104 nicm 1163: static int
1.28 nicm 1164: input_c0_dispatch(struct input_ctx *ictx)
1.1 nicm 1165: {
1.28 nicm 1166: struct screen_write_ctx *sctx = &ictx->ctx;
1167: struct window_pane *wp = ictx->wp;
1168: struct screen *s = sctx->s;
1.1 nicm 1169:
1.130 nicm 1170: ictx->utf8started = 0; /* can't be valid UTF-8 */
1171:
1.84 nicm 1172: log_debug("%s: '%c'", __func__, ictx->ch);
1.1 nicm 1173:
1.28 nicm 1174: switch (ictx->ch) {
1175: case '\000': /* NUL */
1176: break;
1177: case '\007': /* BEL */
1.83 nicm 1178: alerts_queue(wp->window, WINDOW_BELL);
1.28 nicm 1179: break;
1180: case '\010': /* BS */
1181: screen_write_backspace(sctx);
1.75 nicm 1182: break;
1.28 nicm 1183: case '\011': /* HT */
1184: /* Don't tab beyond the end of the line. */
1185: if (s->cx >= screen_size_x(s) - 1)
1186: break;
1.1 nicm 1187:
1.28 nicm 1188: /* Find the next tab point, or use the last column if none. */
1189: do {
1190: s->cx++;
1191: if (bit_test(s->tabs, s->cx))
1192: break;
1193: } while (s->cx < screen_size_x(s) - 1);
1194: break;
1195: case '\012': /* LF */
1196: case '\013': /* VT */
1197: case '\014': /* FF */
1.121 nicm 1198: screen_write_linefeed(sctx, 0, ictx->cell.cell.bg);
1.151 nicm 1199: if (s->mode & MODE_CRLF)
1200: screen_write_carriagereturn(sctx);
1.75 nicm 1201: break;
1.28 nicm 1202: case '\015': /* CR */
1203: screen_write_carriagereturn(sctx);
1.75 nicm 1204: break;
1.28 nicm 1205: case '\016': /* SO */
1.69 nicm 1206: ictx->cell.set = 1;
1.28 nicm 1207: break;
1208: case '\017': /* SI */
1.69 nicm 1209: ictx->cell.set = 0;
1.28 nicm 1210: break;
1211: default:
1212: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1213: break;
1214: }
1.1 nicm 1215:
1.127 nicm 1216: ictx->last = -1;
1.28 nicm 1217: return (0);
1.7 nicm 1218: }
1219:
1.28 nicm 1220: /* Execute escape sequence. */
1.104 nicm 1221: static int
1.28 nicm 1222: input_esc_dispatch(struct input_ctx *ictx)
1.7 nicm 1223: {
1.31 nicm 1224: struct screen_write_ctx *sctx = &ictx->ctx;
1225: struct screen *s = sctx->s;
1226: struct input_table_entry *entry;
1.7 nicm 1227:
1.28 nicm 1228: if (ictx->flags & INPUT_DISCARD)
1229: return (0);
1230: log_debug("%s: '%c', %s", __func__, ictx->ch, ictx->interm_buf);
1.7 nicm 1231:
1.28 nicm 1232: entry = bsearch(ictx, input_esc_table, nitems(input_esc_table),
1233: sizeof input_esc_table[0], input_table_compare);
1234: if (entry == NULL) {
1235: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1236: return (0);
1237: }
1.7 nicm 1238:
1.28 nicm 1239: switch (entry->type) {
1240: case INPUT_ESC_RIS:
1.107 nicm 1241: window_pane_reset_palette(ictx->wp);
1.69 nicm 1242: input_reset_cell(ictx);
1.46 nicm 1243: screen_write_reset(sctx);
1.28 nicm 1244: break;
1245: case INPUT_ESC_IND:
1.121 nicm 1246: screen_write_linefeed(sctx, 0, ictx->cell.cell.bg);
1.28 nicm 1247: break;
1248: case INPUT_ESC_NEL:
1249: screen_write_carriagereturn(sctx);
1.121 nicm 1250: screen_write_linefeed(sctx, 0, ictx->cell.cell.bg);
1.28 nicm 1251: break;
1252: case INPUT_ESC_HTS:
1253: if (s->cx < screen_size_x(s))
1254: bit_set(s->tabs, s->cx);
1255: break;
1256: case INPUT_ESC_RI:
1.121 nicm 1257: screen_write_reverseindex(sctx, ictx->cell.cell.bg);
1.28 nicm 1258: break;
1259: case INPUT_ESC_DECKPAM:
1.59 nicm 1260: screen_write_mode_set(sctx, MODE_KKEYPAD);
1.28 nicm 1261: break;
1262: case INPUT_ESC_DECKPNM:
1.59 nicm 1263: screen_write_mode_clear(sctx, MODE_KKEYPAD);
1.1 nicm 1264: break;
1.28 nicm 1265: case INPUT_ESC_DECSC:
1.146 nicm 1266: input_save_state(ictx);
1.28 nicm 1267: break;
1268: case INPUT_ESC_DECRC:
1.146 nicm 1269: input_restore_state(ictx);
1.28 nicm 1270: break;
1271: case INPUT_ESC_DECALN:
1272: screen_write_alignmenttest(sctx);
1273: break;
1.69 nicm 1274: case INPUT_ESC_SCSG0_ON:
1275: ictx->cell.g0set = 1;
1276: break;
1277: case INPUT_ESC_SCSG0_OFF:
1278: ictx->cell.g0set = 0;
1279: break;
1280: case INPUT_ESC_SCSG1_ON:
1281: ictx->cell.g1set = 1;
1.1 nicm 1282: break;
1.69 nicm 1283: case INPUT_ESC_SCSG1_OFF:
1284: ictx->cell.g1set = 0;
1.1 nicm 1285: break;
1.107 nicm 1286: case INPUT_ESC_ST:
1287: /* ST terminates OSC but the state transition already did it. */
1288: break;
1.1 nicm 1289: }
1.28 nicm 1290:
1.127 nicm 1291: ictx->last = -1;
1.28 nicm 1292: return (0);
1.1 nicm 1293: }
1294:
1.28 nicm 1295: /* Execute control sequence. */
1.104 nicm 1296: static int
1.28 nicm 1297: input_csi_dispatch(struct input_ctx *ictx)
1.1 nicm 1298: {
1.28 nicm 1299: struct screen_write_ctx *sctx = &ictx->ctx;
1300: struct screen *s = sctx->s;
1301: struct input_table_entry *entry;
1.127 nicm 1302: int i, n, m;
1.131 nicm 1303: u_int cx, bg = ictx->cell.cell.bg;
1.1 nicm 1304:
1.28 nicm 1305: if (ictx->flags & INPUT_DISCARD)
1306: return (0);
1.110 nicm 1307:
1308: log_debug("%s: '%c' \"%s\" \"%s\"",
1309: __func__, ictx->ch, ictx->interm_buf, ictx->param_buf);
1310:
1.28 nicm 1311: if (input_split(ictx) != 0)
1312: return (0);
1.1 nicm 1313:
1.28 nicm 1314: entry = bsearch(ictx, input_csi_table, nitems(input_csi_table),
1315: sizeof input_csi_table[0], input_table_compare);
1316: if (entry == NULL) {
1317: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1318: return (0);
1319: }
1.1 nicm 1320:
1.28 nicm 1321: switch (entry->type) {
1322: case INPUT_CSI_CBT:
1323: /* Find the previous tab point, n times. */
1.81 nicm 1324: cx = s->cx;
1325: if (cx > screen_size_x(s) - 1)
1326: cx = screen_size_x(s) - 1;
1.28 nicm 1327: n = input_get(ictx, 0, 1, 1);
1.131 nicm 1328: if (n == -1)
1329: break;
1.81 nicm 1330: while (cx > 0 && n-- > 0) {
1.28 nicm 1331: do
1.81 nicm 1332: cx--;
1333: while (cx > 0 && !bit_test(s->tabs, cx));
1.28 nicm 1334: }
1.81 nicm 1335: s->cx = cx;
1.28 nicm 1336: break;
1337: case INPUT_CSI_CUB:
1.131 nicm 1338: n = input_get(ictx, 0, 1, 1);
1339: if (n != -1)
1340: screen_write_cursorleft(sctx, n);
1.28 nicm 1341: break;
1342: case INPUT_CSI_CUD:
1.131 nicm 1343: n = input_get(ictx, 0, 1, 1);
1344: if (n != -1)
1345: screen_write_cursordown(sctx, n);
1.28 nicm 1346: break;
1347: case INPUT_CSI_CUF:
1.131 nicm 1348: n = input_get(ictx, 0, 1, 1);
1349: if (n != -1)
1350: screen_write_cursorright(sctx, n);
1.28 nicm 1351: break;
1352: case INPUT_CSI_CUP:
1353: n = input_get(ictx, 0, 1, 1);
1354: m = input_get(ictx, 1, 1, 1);
1.131 nicm 1355: if (n != -1 && m != -1)
1.146 nicm 1356: screen_write_cursormove(sctx, m - 1, n - 1, 1);
1.28 nicm 1357: break;
1.65 nicm 1358: case INPUT_CSI_WINOPS:
1359: input_csi_dispatch_winops(ictx);
1360: break;
1.28 nicm 1361: case INPUT_CSI_CUU:
1.131 nicm 1362: n = input_get(ictx, 0, 1, 1);
1363: if (n != -1)
1364: screen_write_cursorup(sctx, n);
1.43 nicm 1365: break;
1366: case INPUT_CSI_CNL:
1.131 nicm 1367: n = input_get(ictx, 0, 1, 1);
1368: if (n != -1) {
1369: screen_write_carriagereturn(sctx);
1370: screen_write_cursordown(sctx, n);
1371: }
1.43 nicm 1372: break;
1373: case INPUT_CSI_CPL:
1.131 nicm 1374: n = input_get(ictx, 0, 1, 1);
1375: if (n != -1) {
1376: screen_write_carriagereturn(sctx);
1377: screen_write_cursorup(sctx, n);
1378: }
1.28 nicm 1379: break;
1380: case INPUT_CSI_DA:
1381: switch (input_get(ictx, 0, 0, 0)) {
1.131 nicm 1382: case -1:
1383: break;
1.28 nicm 1384: case 0:
1385: input_reply(ictx, "\033[?1;2c");
1.50 nicm 1386: break;
1387: default:
1388: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1389: break;
1390: }
1391: break;
1392: case INPUT_CSI_DA_TWO:
1393: switch (input_get(ictx, 0, 0, 0)) {
1.131 nicm 1394: case -1:
1395: break;
1.50 nicm 1396: case 0:
1.66 nicm 1397: input_reply(ictx, "\033[>84;0;0c");
1.28 nicm 1398: break;
1399: default:
1400: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1401: break;
1402: }
1.56 nicm 1403: break;
1404: case INPUT_CSI_ECH:
1.131 nicm 1405: n = input_get(ictx, 0, 1, 1);
1406: if (n != -1)
1407: screen_write_clearcharacter(sctx, n, bg);
1.28 nicm 1408: break;
1409: case INPUT_CSI_DCH:
1.131 nicm 1410: n = input_get(ictx, 0, 1, 1);
1411: if (n != -1)
1412: screen_write_deletecharacter(sctx, n, bg);
1.28 nicm 1413: break;
1414: case INPUT_CSI_DECSTBM:
1415: n = input_get(ictx, 0, 1, 1);
1416: m = input_get(ictx, 1, 1, screen_size_y(s));
1.131 nicm 1417: if (n != -1 && m != -1)
1418: screen_write_scrollregion(sctx, n - 1, m - 1);
1.1 nicm 1419: break;
1.28 nicm 1420: case INPUT_CSI_DL:
1.131 nicm 1421: n = input_get(ictx, 0, 1, 1);
1422: if (n != -1)
1423: screen_write_deleteline(sctx, n, bg);
1.1 nicm 1424: break;
1.28 nicm 1425: case INPUT_CSI_DSR:
1426: switch (input_get(ictx, 0, 0, 0)) {
1.131 nicm 1427: case -1:
1428: break;
1.28 nicm 1429: case 5:
1430: input_reply(ictx, "\033[0n");
1431: break;
1432: case 6:
1433: input_reply(ictx, "\033[%u;%uR", s->cy + 1, s->cx + 1);
1434: break;
1435: default:
1436: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1437: break;
1438: }
1439: break;
1440: case INPUT_CSI_ED:
1441: switch (input_get(ictx, 0, 0, 0)) {
1.131 nicm 1442: case -1:
1443: break;
1.28 nicm 1444: case 0:
1.131 nicm 1445: screen_write_clearendofscreen(sctx, bg);
1.28 nicm 1446: break;
1447: case 1:
1.131 nicm 1448: screen_write_clearstartofscreen(sctx, bg);
1.28 nicm 1449: break;
1450: case 2:
1.131 nicm 1451: screen_write_clearscreen(sctx, bg);
1.41 nicm 1452: break;
1453: case 3:
1.131 nicm 1454: if (input_get(ictx, 1, 0, 0) == 0) {
1.41 nicm 1455: /*
1456: * Linux console extension to clear history
1457: * (for example before locking the screen).
1458: */
1459: screen_write_clearhistory(sctx);
1460: }
1.28 nicm 1461: break;
1462: default:
1463: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1464: break;
1465: }
1466: break;
1467: case INPUT_CSI_EL:
1468: switch (input_get(ictx, 0, 0, 0)) {
1.131 nicm 1469: case -1:
1470: break;
1.28 nicm 1471: case 0:
1.131 nicm 1472: screen_write_clearendofline(sctx, bg);
1.28 nicm 1473: break;
1474: case 1:
1.131 nicm 1475: screen_write_clearstartofline(sctx, bg);
1.28 nicm 1476: break;
1477: case 2:
1.131 nicm 1478: screen_write_clearline(sctx, bg);
1.28 nicm 1479: break;
1480: default:
1481: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1482: break;
1483: }
1484: break;
1485: case INPUT_CSI_HPA:
1486: n = input_get(ictx, 0, 1, 1);
1.131 nicm 1487: if (n != -1)
1.148 nicm 1488: screen_write_cursormove(sctx, n - 1, -1, 1);
1.28 nicm 1489: break;
1490: case INPUT_CSI_ICH:
1.131 nicm 1491: n = input_get(ictx, 0, 1, 1);
1492: if (n != -1)
1493: screen_write_insertcharacter(sctx, n, bg);
1.28 nicm 1494: break;
1495: case INPUT_CSI_IL:
1.131 nicm 1496: n = input_get(ictx, 0, 1, 1);
1497: if (n != -1)
1498: screen_write_insertline(sctx, n, bg);
1.28 nicm 1499: break;
1.127 nicm 1500: case INPUT_CSI_REP:
1.131 nicm 1501: n = input_get(ictx, 0, 1, 1);
1502: if (n == -1)
1503: break;
1504:
1.127 nicm 1505: if (ictx->last == -1)
1506: break;
1507: ictx->ch = ictx->last;
1508:
1509: for (i = 0; i < n; i++)
1510: input_print(ictx);
1511: break;
1.42 nicm 1512: case INPUT_CSI_RCP:
1.146 nicm 1513: input_restore_state(ictx);
1.42 nicm 1514: break;
1.28 nicm 1515: case INPUT_CSI_RM:
1.64 nicm 1516: input_csi_dispatch_rm(ictx);
1517: break;
1518: case INPUT_CSI_RM_PRIVATE:
1519: input_csi_dispatch_rm_private(ictx);
1520: break;
1521: case INPUT_CSI_SCP:
1.146 nicm 1522: input_save_state(ictx);
1.64 nicm 1523: break;
1524: case INPUT_CSI_SGR:
1525: input_csi_dispatch_sgr(ictx);
1526: break;
1527: case INPUT_CSI_SM:
1528: input_csi_dispatch_sm(ictx);
1529: break;
1530: case INPUT_CSI_SM_PRIVATE:
1531: input_csi_dispatch_sm_private(ictx);
1.115 nicm 1532: break;
1533: case INPUT_CSI_SU:
1.131 nicm 1534: n = input_get(ictx, 0, 1, 1);
1535: if (n != -1)
1536: screen_write_scrollup(sctx, n, bg);
1.159 nicm 1537: break;
1538: case INPUT_CSI_SD:
1539: n = input_get(ictx, 0, 1, 1);
1540: if (n != -1)
1541: screen_write_scrolldown(sctx, n, bg);
1.64 nicm 1542: break;
1543: case INPUT_CSI_TBC:
1544: switch (input_get(ictx, 0, 0, 0)) {
1.131 nicm 1545: case -1:
1546: break;
1.64 nicm 1547: case 0:
1548: if (s->cx < screen_size_x(s))
1549: bit_clear(s->tabs, s->cx);
1550: break;
1551: case 3:
1552: bit_nclear(s->tabs, 0, screen_size_x(s) - 1);
1553: break;
1554: default:
1555: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1556: break;
1557: }
1558: break;
1559: case INPUT_CSI_VPA:
1560: n = input_get(ictx, 0, 1, 1);
1.131 nicm 1561: if (n != -1)
1.148 nicm 1562: screen_write_cursormove(sctx, -1, n - 1, 1);
1.64 nicm 1563: break;
1564: case INPUT_CSI_DECSCUSR:
1565: n = input_get(ictx, 0, 0, 0);
1.131 nicm 1566: if (n != -1)
1567: screen_set_cursor_style(s, n);
1.64 nicm 1568: break;
1569: }
1570:
1.127 nicm 1571: ictx->last = -1;
1.64 nicm 1572: return (0);
1573: }
1574:
1575: /* Handle CSI RM. */
1.104 nicm 1576: static void
1.64 nicm 1577: input_csi_dispatch_rm(struct input_ctx *ictx)
1578: {
1.144 nicm 1579: struct screen_write_ctx *sctx = &ictx->ctx;
1580: u_int i;
1.64 nicm 1581:
1582: for (i = 0; i < ictx->param_list_len; i++) {
1583: switch (input_get(ictx, i, 0, -1)) {
1.131 nicm 1584: case -1:
1585: break;
1.28 nicm 1586: case 4: /* IRM */
1.144 nicm 1587: screen_write_mode_clear(sctx, MODE_INSERT);
1.28 nicm 1588: break;
1.72 nicm 1589: case 34:
1.144 nicm 1590: screen_write_mode_set(sctx, MODE_BLINKING);
1.72 nicm 1591: break;
1.28 nicm 1592: default:
1593: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1594: break;
1595: }
1.64 nicm 1596: }
1597: }
1598:
1599: /* Handle CSI private RM. */
1.104 nicm 1600: static void
1.64 nicm 1601: input_csi_dispatch_rm_private(struct input_ctx *ictx)
1602: {
1.144 nicm 1603: struct screen_write_ctx *sctx = &ictx->ctx;
1.69 nicm 1604: struct window_pane *wp = ictx->wp;
1605: u_int i;
1.64 nicm 1606:
1607: for (i = 0; i < ictx->param_list_len; i++) {
1608: switch (input_get(ictx, i, 0, -1)) {
1.131 nicm 1609: case -1:
1610: break;
1.64 nicm 1611: case 1: /* DECCKM */
1.144 nicm 1612: screen_write_mode_clear(sctx, MODE_KCURSOR);
1.1 nicm 1613: break;
1.17 nicm 1614: case 3: /* DECCOLM */
1.146 nicm 1615: screen_write_cursormove(sctx, 0, 0, 1);
1.144 nicm 1616: screen_write_clearscreen(sctx, ictx->cell.cell.bg);
1.17 nicm 1617: break;
1.141 nicm 1618: case 6: /* DECOM */
1.144 nicm 1619: screen_write_mode_clear(sctx, MODE_ORIGIN);
1.146 nicm 1620: screen_write_cursormove(sctx, 0, 0, 1);
1.141 nicm 1621: break;
1.61 nicm 1622: case 7: /* DECAWM */
1.144 nicm 1623: screen_write_mode_clear(sctx, MODE_WRAP);
1.61 nicm 1624: break;
1.72 nicm 1625: case 12:
1.144 nicm 1626: screen_write_mode_clear(sctx, MODE_BLINKING);
1.72 nicm 1627: break;
1.1 nicm 1628: case 25: /* TCEM */
1.144 nicm 1629: screen_write_mode_clear(sctx, MODE_CURSOR);
1.1 nicm 1630: break;
1631: case 1000:
1.32 nicm 1632: case 1001:
1633: case 1002:
1.109 nicm 1634: case 1003:
1.144 nicm 1635: screen_write_mode_clear(sctx, ALL_MOUSE_MODES);
1.1 nicm 1636: break;
1.62 nicm 1637: case 1004:
1.144 nicm 1638: screen_write_mode_clear(sctx, MODE_FOCUSON);
1.62 nicm 1639: break;
1.96 nicm 1640: case 1005:
1.144 nicm 1641: screen_write_mode_clear(sctx, MODE_MOUSE_UTF8);
1.96 nicm 1642: break;
1.60 nicm 1643: case 1006:
1.144 nicm 1644: screen_write_mode_clear(sctx, MODE_MOUSE_SGR);
1.60 nicm 1645: break;
1.55 nicm 1646: case 47:
1647: case 1047:
1.69 nicm 1648: window_pane_alternate_off(wp, &ictx->cell.cell, 0);
1.55 nicm 1649: break;
1.9 nicm 1650: case 1049:
1.69 nicm 1651: window_pane_alternate_off(wp, &ictx->cell.cell, 1);
1.9 nicm 1652: break;
1.49 nicm 1653: case 2004:
1.144 nicm 1654: screen_write_mode_clear(sctx, MODE_BRACKETPASTE);
1.49 nicm 1655: break;
1.1 nicm 1656: default:
1.28 nicm 1657: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1.1 nicm 1658: break;
1659: }
1.64 nicm 1660: }
1661: }
1662:
1663: /* Handle CSI SM. */
1.104 nicm 1664: static void
1.64 nicm 1665: input_csi_dispatch_sm(struct input_ctx *ictx)
1666: {
1.144 nicm 1667: struct screen_write_ctx *sctx = &ictx->ctx;
1668: u_int i;
1.64 nicm 1669:
1670: for (i = 0; i < ictx->param_list_len; i++) {
1671: switch (input_get(ictx, i, 0, -1)) {
1.131 nicm 1672: case -1:
1673: break;
1.1 nicm 1674: case 4: /* IRM */
1.144 nicm 1675: screen_write_mode_set(sctx, MODE_INSERT);
1.1 nicm 1676: break;
1.72 nicm 1677: case 34:
1.144 nicm 1678: screen_write_mode_clear(sctx, MODE_BLINKING);
1.72 nicm 1679: break;
1.1 nicm 1680: default:
1.28 nicm 1681: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1.1 nicm 1682: break;
1683: }
1.64 nicm 1684: }
1685: }
1686:
1687: /* Handle CSI private SM. */
1.104 nicm 1688: static void
1.64 nicm 1689: input_csi_dispatch_sm_private(struct input_ctx *ictx)
1690: {
1.144 nicm 1691: struct screen_write_ctx *sctx = &ictx->ctx;
1.69 nicm 1692: struct window_pane *wp = ictx->wp;
1693: u_int i;
1.64 nicm 1694:
1695: for (i = 0; i < ictx->param_list_len; i++) {
1696: switch (input_get(ictx, i, 0, -1)) {
1.131 nicm 1697: case -1:
1698: break;
1.64 nicm 1699: case 1: /* DECCKM */
1.144 nicm 1700: screen_write_mode_set(sctx, MODE_KCURSOR);
1.17 nicm 1701: break;
1702: case 3: /* DECCOLM */
1.146 nicm 1703: screen_write_cursormove(sctx, 0, 0, 1);
1.144 nicm 1704: screen_write_clearscreen(sctx, ictx->cell.cell.bg);
1.141 nicm 1705: break;
1706: case 6: /* DECOM */
1.144 nicm 1707: screen_write_mode_set(sctx, MODE_ORIGIN);
1.146 nicm 1708: screen_write_cursormove(sctx, 0, 0, 1);
1.61 nicm 1709: break;
1710: case 7: /* DECAWM */
1.144 nicm 1711: screen_write_mode_set(sctx, MODE_WRAP);
1.72 nicm 1712: break;
1713: case 12:
1.144 nicm 1714: screen_write_mode_set(sctx, MODE_BLINKING);
1.1 nicm 1715: break;
1716: case 25: /* TCEM */
1.144 nicm 1717: screen_write_mode_set(sctx, MODE_CURSOR);
1.1 nicm 1718: break;
1719: case 1000:
1.144 nicm 1720: screen_write_mode_clear(sctx, ALL_MOUSE_MODES);
1721: screen_write_mode_set(sctx, MODE_MOUSE_STANDARD);
1.32 nicm 1722: break;
1723: case 1002:
1.144 nicm 1724: screen_write_mode_clear(sctx, ALL_MOUSE_MODES);
1725: screen_write_mode_set(sctx, MODE_MOUSE_BUTTON);
1.109 nicm 1726: break;
1727: case 1003:
1.144 nicm 1728: screen_write_mode_clear(sctx, ALL_MOUSE_MODES);
1729: screen_write_mode_set(sctx, MODE_MOUSE_ALL);
1.62 nicm 1730: break;
1731: case 1004:
1.144 nicm 1732: if (sctx->s->mode & MODE_FOCUSON)
1.62 nicm 1733: break;
1.144 nicm 1734: screen_write_mode_set(sctx, MODE_FOCUSON);
1.69 nicm 1735: wp->flags |= PANE_FOCUSPUSH; /* force update */
1.96 nicm 1736: break;
1737: case 1005:
1.144 nicm 1738: screen_write_mode_set(sctx, MODE_MOUSE_UTF8);
1.60 nicm 1739: break;
1740: case 1006:
1.144 nicm 1741: screen_write_mode_set(sctx, MODE_MOUSE_SGR);
1.9 nicm 1742: break;
1.55 nicm 1743: case 47:
1744: case 1047:
1.69 nicm 1745: window_pane_alternate_on(wp, &ictx->cell.cell, 0);
1.55 nicm 1746: break;
1.9 nicm 1747: case 1049:
1.69 nicm 1748: window_pane_alternate_on(wp, &ictx->cell.cell, 1);
1.49 nicm 1749: break;
1750: case 2004:
1.144 nicm 1751: screen_write_mode_set(sctx, MODE_BRACKETPASTE);
1.1 nicm 1752: break;
1753: default:
1.28 nicm 1754: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1.1 nicm 1755: break;
1756: }
1.65 nicm 1757: }
1758: }
1759:
1760: /* Handle CSI window operations. */
1.104 nicm 1761: static void
1.65 nicm 1762: input_csi_dispatch_winops(struct input_ctx *ictx)
1763: {
1.144 nicm 1764: struct screen_write_ctx *sctx = &ictx->ctx;
1.65 nicm 1765: struct window_pane *wp = ictx->wp;
1766: int n, m;
1767:
1768: m = 0;
1769: while ((n = input_get(ictx, m, 0, -1)) != -1) {
1770: switch (n) {
1771: case 1:
1772: case 2:
1773: case 5:
1774: case 6:
1775: case 7:
1776: case 11:
1777: case 13:
1778: case 14:
1779: case 19:
1780: case 20:
1781: case 21:
1782: case 24:
1783: break;
1784: case 3:
1785: case 4:
1786: case 8:
1787: m++;
1788: if (input_get(ictx, m, 0, -1) == -1)
1789: return;
1790: /* FALLTHROUGH */
1791: case 9:
1792: case 10:
1.129 nicm 1793: m++;
1794: if (input_get(ictx, m, 0, -1) == -1)
1795: return;
1796: break;
1.65 nicm 1797: case 22:
1.129 nicm 1798: m++;
1799: switch (input_get(ictx, m, 0, -1)) {
1800: case -1:
1801: return;
1802: case 0:
1803: case 2:
1.144 nicm 1804: screen_push_title(sctx->s);
1.129 nicm 1805: break;
1806: }
1807: break;
1.65 nicm 1808: case 23:
1809: m++;
1.129 nicm 1810: switch (input_get(ictx, m, 0, -1)) {
1811: case -1:
1.65 nicm 1812: return;
1.129 nicm 1813: case 0:
1814: case 2:
1.144 nicm 1815: screen_pop_title(sctx->s);
1.129 nicm 1816: server_status_window(ictx->wp->window);
1817: break;
1818: }
1.65 nicm 1819: break;
1820: case 18:
1.76 nicm 1821: input_reply(ictx, "\033[8;%u;%ut", wp->sy, wp->sx);
1.65 nicm 1822: break;
1823: default:
1824: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1825: break;
1826: }
1827: m++;
1.1 nicm 1828: }
1829: }
1830:
1.131 nicm 1831: /* Helper for 256 colour SGR. */
1832: static int
1833: input_csi_dispatch_sgr_256_do(struct input_ctx *ictx, int fgbg, int c)
1.78 nicm 1834: {
1835: struct grid_cell *gc = &ictx->cell.cell;
1836:
1.131 nicm 1837: if (c == -1 || c > 255) {
1.102 nicm 1838: if (fgbg == 38)
1.78 nicm 1839: gc->fg = 8;
1.102 nicm 1840: else if (fgbg == 48)
1.78 nicm 1841: gc->bg = 8;
1842: } else {
1.102 nicm 1843: if (fgbg == 38)
1844: gc->fg = c | COLOUR_FLAG_256;
1845: else if (fgbg == 48)
1846: gc->bg = c | COLOUR_FLAG_256;
1.158 nicm 1847: else if (fgbg == 58)
1848: gc->us = c | COLOUR_FLAG_256;
1.78 nicm 1849: }
1.131 nicm 1850: return (1);
1.78 nicm 1851: }
1852:
1.131 nicm 1853: /* Handle CSI SGR for 256 colours. */
1.104 nicm 1854: static void
1.131 nicm 1855: input_csi_dispatch_sgr_256(struct input_ctx *ictx, int fgbg, u_int *i)
1856: {
1857: int c;
1858:
1859: c = input_get(ictx, (*i) + 1, 0, -1);
1860: if (input_csi_dispatch_sgr_256_do(ictx, fgbg, c))
1861: (*i)++;
1862: }
1863:
1864: /* Helper for RGB colour SGR. */
1865: static int
1866: input_csi_dispatch_sgr_rgb_do(struct input_ctx *ictx, int fgbg, int r, int g,
1867: int b)
1.78 nicm 1868: {
1869: struct grid_cell *gc = &ictx->cell.cell;
1870:
1871: if (r == -1 || r > 255)
1.131 nicm 1872: return (0);
1.78 nicm 1873: if (g == -1 || g > 255)
1.131 nicm 1874: return (0);
1.78 nicm 1875: if (b == -1 || b > 255)
1.131 nicm 1876: return (0);
1.78 nicm 1877:
1.102 nicm 1878: if (fgbg == 38)
1879: gc->fg = colour_join_rgb(r, g, b);
1880: else if (fgbg == 48)
1881: gc->bg = colour_join_rgb(r, g, b);
1.158 nicm 1882: else if (fgbg == 58)
1883: gc->us = colour_join_rgb(r, g, b);
1.131 nicm 1884: return (1);
1885: }
1886:
1887: /* Handle CSI SGR for RGB colours. */
1888: static void
1889: input_csi_dispatch_sgr_rgb(struct input_ctx *ictx, int fgbg, u_int *i)
1890: {
1891: int r, g, b;
1892:
1893: r = input_get(ictx, (*i) + 1, 0, -1);
1894: g = input_get(ictx, (*i) + 2, 0, -1);
1895: b = input_get(ictx, (*i) + 3, 0, -1);
1896: if (input_csi_dispatch_sgr_rgb_do(ictx, fgbg, r, g, b))
1897: (*i) += 3;
1898: }
1899:
1900: /* Handle CSI SGR with a ISO parameter. */
1901: static void
1902: input_csi_dispatch_sgr_colon(struct input_ctx *ictx, u_int i)
1903: {
1.137 nicm 1904: struct grid_cell *gc = &ictx->cell.cell;
1905: char *s = ictx->param_list[i].str, *copy, *ptr, *out;
1906: int p[8];
1907: u_int n;
1908: const char *errstr;
1.131 nicm 1909:
1910: for (n = 0; n < nitems(p); n++)
1911: p[n] = -1;
1912: n = 0;
1913:
1914: ptr = copy = xstrdup(s);
1915: while ((out = strsep(&ptr, ":")) != NULL) {
1.134 nicm 1916: if (*out != '\0') {
1917: p[n++] = strtonum(out, 0, INT_MAX, &errstr);
1918: if (errstr != NULL || n == nitems(p)) {
1919: free(copy);
1920: return;
1921: }
1.140 nicm 1922: } else
1923: n++;
1.131 nicm 1924: log_debug("%s: %u = %d", __func__, n - 1, p[n - 1]);
1925: }
1926: free(copy);
1927:
1.137 nicm 1928: if (n == 0)
1929: return;
1930: if (p[0] == 4) {
1931: if (n != 2)
1932: return;
1933: switch (p[1]) {
1934: case 0:
1935: gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
1936: break;
1937: case 1:
1938: gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
1939: gc->attr |= GRID_ATTR_UNDERSCORE;
1940: break;
1941: case 2:
1942: gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
1943: gc->attr |= GRID_ATTR_UNDERSCORE_2;
1944: break;
1945: case 3:
1946: gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
1947: gc->attr |= GRID_ATTR_UNDERSCORE_3;
1948: break;
1949: case 4:
1950: gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
1951: gc->attr |= GRID_ATTR_UNDERSCORE_4;
1952: break;
1953: case 5:
1954: gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
1955: gc->attr |= GRID_ATTR_UNDERSCORE_5;
1956: break;
1957: }
1958: return;
1959: }
1.158 nicm 1960: if (n < 2 || (p[0] != 38 && p[0] != 48 && p[0] != 58))
1.131 nicm 1961: return;
1.154 nicm 1962: switch (p[1]) {
1.131 nicm 1963: case 2:
1.154 nicm 1964: if (n < 3)
1965: break;
1966: if (n == 5)
1967: i = 2;
1968: else
1969: i = 3;
1970: if (n < i + 3)
1.131 nicm 1971: break;
1.154 nicm 1972: input_csi_dispatch_sgr_rgb_do(ictx, p[0], p[i], p[i + 1],
1973: p[i + 2]);
1.131 nicm 1974: break;
1975: case 5:
1.154 nicm 1976: if (n < 3)
1.131 nicm 1977: break;
1.154 nicm 1978: input_csi_dispatch_sgr_256_do(ictx, p[0], p[2]);
1.131 nicm 1979: break;
1980: }
1.78 nicm 1981: }
1982:
1.28 nicm 1983: /* Handle CSI SGR. */
1.104 nicm 1984: static void
1.28 nicm 1985: input_csi_dispatch_sgr(struct input_ctx *ictx)
1.1 nicm 1986: {
1.69 nicm 1987: struct grid_cell *gc = &ictx->cell.cell;
1.28 nicm 1988: u_int i;
1.78 nicm 1989: int n;
1.1 nicm 1990:
1.28 nicm 1991: if (ictx->param_list_len == 0) {
1.1 nicm 1992: memcpy(gc, &grid_default_cell, sizeof *gc);
1993: return;
1994: }
1995:
1.28 nicm 1996: for (i = 0; i < ictx->param_list_len; i++) {
1.131 nicm 1997: if (ictx->param_list[i].type == INPUT_STRING) {
1998: input_csi_dispatch_sgr_colon(ictx, i);
1999: continue;
2000: }
1.28 nicm 2001: n = input_get(ictx, i, 0, 0);
1.131 nicm 2002: if (n == -1)
2003: continue;
1.1 nicm 2004:
1.158 nicm 2005: if (n == 38 || n == 48 || n == 58) {
1.1 nicm 2006: i++;
1.78 nicm 2007: switch (input_get(ictx, i, 0, -1)) {
2008: case 2:
2009: input_csi_dispatch_sgr_rgb(ictx, n, &i);
2010: break;
2011: case 5:
2012: input_csi_dispatch_sgr_256(ictx, n, &i);
2013: break;
1.1 nicm 2014: }
2015: continue;
2016: }
2017:
1.28 nicm 2018: switch (n) {
1.1 nicm 2019: case 0:
2020: memcpy(gc, &grid_default_cell, sizeof *gc);
2021: break;
2022: case 1:
2023: gc->attr |= GRID_ATTR_BRIGHT;
2024: break;
2025: case 2:
2026: gc->attr |= GRID_ATTR_DIM;
2027: break;
2028: case 3:
2029: gc->attr |= GRID_ATTR_ITALICS;
2030: break;
2031: case 4:
1.137 nicm 2032: gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
1.1 nicm 2033: gc->attr |= GRID_ATTR_UNDERSCORE;
2034: break;
2035: case 5:
2036: gc->attr |= GRID_ATTR_BLINK;
2037: break;
2038: case 7:
2039: gc->attr |= GRID_ATTR_REVERSE;
2040: break;
2041: case 8:
2042: gc->attr |= GRID_ATTR_HIDDEN;
2043: break;
1.118 nicm 2044: case 9:
2045: gc->attr |= GRID_ATTR_STRIKETHROUGH;
2046: break;
1.1 nicm 2047: case 22:
2048: gc->attr &= ~(GRID_ATTR_BRIGHT|GRID_ATTR_DIM);
2049: break;
2050: case 23:
2051: gc->attr &= ~GRID_ATTR_ITALICS;
2052: break;
2053: case 24:
1.137 nicm 2054: gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
1.1 nicm 2055: break;
2056: case 25:
2057: gc->attr &= ~GRID_ATTR_BLINK;
2058: break;
2059: case 27:
2060: gc->attr &= ~GRID_ATTR_REVERSE;
1.117 nicm 2061: break;
2062: case 28:
2063: gc->attr &= ~GRID_ATTR_HIDDEN;
1.118 nicm 2064: break;
2065: case 29:
2066: gc->attr &= ~GRID_ATTR_STRIKETHROUGH;
1.1 nicm 2067: break;
2068: case 30:
2069: case 31:
2070: case 32:
2071: case 33:
2072: case 34:
2073: case 35:
2074: case 36:
2075: case 37:
1.28 nicm 2076: gc->fg = n - 30;
1.1 nicm 2077: break;
2078: case 39:
2079: gc->fg = 8;
2080: break;
2081: case 40:
2082: case 41:
2083: case 42:
2084: case 43:
2085: case 44:
2086: case 45:
2087: case 46:
2088: case 47:
1.28 nicm 2089: gc->bg = n - 40;
1.1 nicm 2090: break;
2091: case 49:
2092: gc->bg = 8;
1.153 nicm 2093: break;
2094: case 53:
2095: gc->attr |= GRID_ATTR_OVERLINE;
2096: break;
2097: case 55:
2098: gc->attr &= ~GRID_ATTR_OVERLINE;
1.158 nicm 2099: break;
2100: case 59:
2101: gc->us = 0;
1.20 nicm 2102: break;
2103: case 90:
2104: case 91:
2105: case 92:
2106: case 93:
2107: case 94:
2108: case 95:
2109: case 96:
2110: case 97:
1.28 nicm 2111: gc->fg = n;
1.20 nicm 2112: break;
2113: case 100:
2114: case 101:
2115: case 102:
2116: case 103:
2117: case 104:
2118: case 105:
2119: case 106:
2120: case 107:
1.47 nicm 2121: gc->bg = n - 10;
1.1 nicm 2122: break;
2123: }
2124: }
1.28 nicm 2125: }
2126:
1.138 nicm 2127: /* End of input with BEL. */
2128: static int
2129: input_end_bel(struct input_ctx *ictx)
2130: {
2131: log_debug("%s", __func__);
2132:
2133: ictx->input_end = INPUT_END_BEL;
2134:
2135: return (0);
2136: }
2137:
1.125 nicm 2138: /* DCS string started. */
2139: static void
2140: input_enter_dcs(struct input_ctx *ictx)
2141: {
2142: log_debug("%s", __func__);
2143:
2144: input_clear(ictx);
2145: input_start_timer(ictx);
1.127 nicm 2146: ictx->last = -1;
1.125 nicm 2147: }
2148:
1.37 nicm 2149: /* DCS terminator (ST) received. */
1.104 nicm 2150: static int
1.37 nicm 2151: input_dcs_dispatch(struct input_ctx *ictx)
1.28 nicm 2152: {
1.144 nicm 2153: struct screen_write_ctx *sctx = &ictx->ctx;
2154: u_char *buf = ictx->input_buf;
2155: size_t len = ictx->input_len;
2156: const char prefix[] = "tmux;";
2157: const u_int prefixlen = (sizeof prefix) - 1;
1.37 nicm 2158:
2159: if (ictx->flags & INPUT_DISCARD)
2160: return (0);
2161:
1.144 nicm 2162: log_debug("%s: \"%s\"", __func__, buf);
1.28 nicm 2163:
1.144 nicm 2164: if (len >= prefixlen && strncmp(buf, prefix, prefixlen) == 0)
2165: screen_write_rawstring(sctx, buf + prefixlen, len - prefixlen);
1.28 nicm 2166:
1.37 nicm 2167: return (0);
1.28 nicm 2168: }
2169:
2170: /* OSC string started. */
1.104 nicm 2171: static void
1.28 nicm 2172: input_enter_osc(struct input_ctx *ictx)
2173: {
2174: log_debug("%s", __func__);
2175:
1.35 nicm 2176: input_clear(ictx);
1.125 nicm 2177: input_start_timer(ictx);
1.127 nicm 2178: ictx->last = -1;
1.28 nicm 2179: }
2180:
2181: /* OSC terminator (ST) received. */
1.104 nicm 2182: static void
1.28 nicm 2183: input_exit_osc(struct input_ctx *ictx)
2184: {
1.144 nicm 2185: struct screen_write_ctx *sctx = &ictx->ctx;
2186: u_char *p = ictx->input_buf;
2187: u_int option;
1.38 nicm 2188:
1.28 nicm 2189: if (ictx->flags & INPUT_DISCARD)
2190: return;
1.38 nicm 2191: if (ictx->input_len < 1 || *p < '0' || *p > '9')
2192: return;
1.28 nicm 2193:
1.138 nicm 2194: log_debug("%s: \"%s\" (end %s)", __func__, p,
2195: ictx->input_end == INPUT_END_ST ? "ST" : "BEL");
1.28 nicm 2196:
1.38 nicm 2197: option = 0;
2198: while (*p >= '0' && *p <= '9')
2199: option = option * 10 + *p++ - '0';
2200: if (*p == ';')
2201: p++;
2202:
2203: switch (option) {
2204: case 0:
2205: case 2:
1.124 nicm 2206: if (utf8_isvalid(p)) {
1.144 nicm 2207: screen_set_title(sctx->s, p);
1.124 nicm 2208: server_status_window(ictx->wp->window);
2209: }
1.38 nicm 2210: break;
1.107 nicm 2211: case 4:
1.138 nicm 2212: input_osc_4(ictx, p);
1.107 nicm 2213: break;
1.122 nicm 2214: case 10:
1.138 nicm 2215: input_osc_10(ictx, p);
1.122 nicm 2216: break;
2217: case 11:
1.138 nicm 2218: input_osc_11(ictx, p);
1.108 nicm 2219: break;
1.38 nicm 2220: case 12:
1.124 nicm 2221: if (utf8_isvalid(p) && *p != '?') /* ? is colour request */
1.144 nicm 2222: screen_set_cursor_colour(sctx->s, p);
1.38 nicm 2223: break;
1.122 nicm 2224: case 52:
1.138 nicm 2225: input_osc_52(ictx, p);
1.122 nicm 2226: break;
1.107 nicm 2227: case 104:
1.138 nicm 2228: input_osc_104(ictx, p);
1.107 nicm 2229: break;
1.38 nicm 2230: case 112:
1.57 nicm 2231: if (*p == '\0') /* no arguments allowed */
1.144 nicm 2232: screen_set_cursor_colour(sctx->s, "");
1.38 nicm 2233: break;
2234: default:
2235: log_debug("%s: unknown '%u'", __func__, option);
2236: break;
2237: }
1.28 nicm 2238: }
2239:
2240: /* APC string started. */
1.104 nicm 2241: static void
1.28 nicm 2242: input_enter_apc(struct input_ctx *ictx)
2243: {
2244: log_debug("%s", __func__);
2245:
1.35 nicm 2246: input_clear(ictx);
1.125 nicm 2247: input_start_timer(ictx);
1.127 nicm 2248: ictx->last = -1;
1.28 nicm 2249: }
2250:
2251: /* APC terminator (ST) received. */
1.104 nicm 2252: static void
1.28 nicm 2253: input_exit_apc(struct input_ctx *ictx)
2254: {
1.144 nicm 2255: struct screen_write_ctx *sctx = &ictx->ctx;
2256:
1.28 nicm 2257: if (ictx->flags & INPUT_DISCARD)
2258: return;
2259: log_debug("%s: \"%s\"", __func__, ictx->input_buf);
2260:
1.124 nicm 2261: if (!utf8_isvalid(ictx->input_buf))
2262: return;
1.144 nicm 2263: screen_set_title(sctx->s, ictx->input_buf);
1.28 nicm 2264: server_status_window(ictx->wp->window);
2265: }
2266:
2267: /* Rename string started. */
1.104 nicm 2268: static void
1.28 nicm 2269: input_enter_rename(struct input_ctx *ictx)
2270: {
2271: log_debug("%s", __func__);
2272:
1.35 nicm 2273: input_clear(ictx);
1.125 nicm 2274: input_start_timer(ictx);
1.127 nicm 2275: ictx->last = -1;
1.28 nicm 2276: }
2277:
2278: /* Rename terminator (ST) received. */
1.104 nicm 2279: static void
1.28 nicm 2280: input_exit_rename(struct input_ctx *ictx)
2281: {
1.162 nicm 2282: struct window_pane *wp = ictx->wp;
2283: struct options_entry *oe;
2284:
1.28 nicm 2285: if (ictx->flags & INPUT_DISCARD)
1.44 nicm 2286: return;
1.157 nicm 2287: if (!options_get_number(ictx->wp->options, "allow-rename"))
1.28 nicm 2288: return;
2289: log_debug("%s: \"%s\"", __func__, ictx->input_buf);
2290:
1.124 nicm 2291: if (!utf8_isvalid(ictx->input_buf))
2292: return;
1.162 nicm 2293:
2294: if (ictx->input_len == 0) {
2295: oe = options_get(wp->window->options, "automatic-rename");
2296: if (oe != NULL)
2297: options_remove(oe);
2298: return;
2299: }
1.48 nicm 2300: window_set_name(ictx->wp->window, ictx->input_buf);
1.87 nicm 2301: options_set_number(ictx->wp->window->options, "automatic-rename", 0);
1.28 nicm 2302: server_status_window(ictx->wp->window);
2303: }
2304:
2305: /* Open UTF-8 character. */
1.104 nicm 2306: static int
1.130 nicm 2307: input_top_bit_set(struct input_ctx *ictx)
1.28 nicm 2308: {
1.144 nicm 2309: struct screen_write_ctx *sctx = &ictx->ctx;
1.90 nicm 2310: struct utf8_data *ud = &ictx->utf8data;
2311:
1.127 nicm 2312: ictx->last = -1;
1.28 nicm 2313:
1.130 nicm 2314: if (!ictx->utf8started) {
2315: if (utf8_open(ud, ictx->ch) != UTF8_MORE)
2316: return (0);
2317: ictx->utf8started = 1;
2318: return (0);
2319: }
1.28 nicm 2320:
1.130 nicm 2321: switch (utf8_append(ud, ictx->ch)) {
2322: case UTF8_MORE:
2323: return (0);
2324: case UTF8_ERROR:
2325: ictx->utf8started = 0;
1.101 nicm 2326: return (0);
1.130 nicm 2327: case UTF8_DONE:
2328: break;
1.101 nicm 2329: }
1.130 nicm 2330: ictx->utf8started = 0;
1.28 nicm 2331:
1.90 nicm 2332: log_debug("%s %hhu '%*s' (width %hhu)", __func__, ud->size,
2333: (int)ud->size, ud->data, ud->width);
1.28 nicm 2334:
1.90 nicm 2335: utf8_copy(&ictx->cell.cell.data, ud);
1.144 nicm 2336: screen_write_collect_add(sctx, &ictx->cell.cell);
1.28 nicm 2337:
2338: return (0);
1.107 nicm 2339: }
2340:
1.163 nicm 2341: /* Parse colour from OSC. */
2342: static int
2343: input_osc_parse_colour(const char *p, u_int *r, u_int *g, u_int *b)
2344: {
2345: u_int rsize, gsize, bsize;
2346: const char *cp, *s = p;
2347:
2348: if (sscanf(p, "rgb:%x/%x/%x", r, g, b) != 3)
2349: return (0);
2350: p += 4;
2351:
2352: cp = strchr(p, '/');
2353: rsize = cp - p;
2354: if (rsize == 1)
2355: (*r) = (*r) | ((*r) << 4);
2356: else if (rsize == 3)
2357: (*r) >>= 4;
2358: else if (rsize == 4)
2359: (*r) >>= 8;
2360: else if (rsize != 2)
2361: return (0);
2362:
2363: p = cp + 1;
2364: cp = strchr(p, '/');
2365: gsize = cp - p;
2366: if (gsize == 1)
2367: (*g) = (*g) | ((*g) << 4);
2368: else if (gsize == 3)
2369: (*g) >>= 4;
2370: else if (gsize == 4)
2371: (*g) >>= 8;
2372: else if (gsize != 2)
2373: return (0);
2374:
2375: bsize = strlen(cp + 1);
2376: if (bsize == 1)
2377: (*b) = (*b) | ((*b) << 4);
2378: else if (bsize == 3)
2379: (*b) >>= 4;
2380: else if (bsize == 4)
2381: (*b) >>= 8;
2382: else if (bsize != 2)
2383: return (0);
2384:
2385: log_debug("%s: %s = %02x%02x%02x", __func__, s, *r, *g, *b);
2386: return (1);
2387: }
2388:
1.107 nicm 2389: /* Handle the OSC 4 sequence for setting (multiple) palette entries. */
2390: static void
1.138 nicm 2391: input_osc_4(struct input_ctx *ictx, const char *p)
1.107 nicm 2392: {
1.138 nicm 2393: struct window_pane *wp = ictx->wp;
2394: char *copy, *s, *next = NULL;
1.144 nicm 2395: long idx;
1.138 nicm 2396: u_int r, g, b;
1.107 nicm 2397:
2398: copy = s = xstrdup(p);
2399: while (s != NULL && *s != '\0') {
2400: idx = strtol(s, &next, 10);
2401: if (*next++ != ';')
2402: goto bad;
2403: if (idx < 0 || idx >= 0x100)
2404: goto bad;
2405:
2406: s = strsep(&next, ";");
1.163 nicm 2407: if (!input_osc_parse_colour(s, &r, &g, &b)) {
1.107 nicm 2408: s = next;
2409: continue;
2410: }
2411:
2412: window_pane_set_palette(wp, idx, colour_join_rgb(r, g, b));
2413: s = next;
2414: }
2415:
2416: free(copy);
2417: return;
2418:
2419: bad:
2420: log_debug("bad OSC 4: %s", p);
2421: free(copy);
1.122 nicm 2422: }
2423:
1.136 nicm 2424: /* Handle the OSC 10 sequence for setting foreground colour. */
1.122 nicm 2425: static void
1.138 nicm 2426: input_osc_10(struct input_ctx *ictx, const char *p)
1.122 nicm 2427: {
1.138 nicm 2428: struct window_pane *wp = ictx->wp;
2429: u_int r, g, b;
1.156 nicm 2430: char tmp[16];
1.122 nicm 2431:
1.163 nicm 2432: if (strcmp(p, "?") == 0)
2433: return;
2434:
2435: if (!input_osc_parse_colour(p, &r, &g, &b))
2436: goto bad;
1.156 nicm 2437: xsnprintf(tmp, sizeof tmp, "fg=#%02x%02x%02x", r, g, b);
2438: options_set_style(wp->options, "window-style", 1, tmp);
2439: options_set_style(wp->options, "window-active-style", 1, tmp);
2440: wp->flags |= (PANE_REDRAW|PANE_STYLECHANGED);
1.122 nicm 2441:
2442: return;
2443:
2444: bad:
2445: log_debug("bad OSC 10: %s", p);
2446: }
2447:
2448: /* Handle the OSC 11 sequence for setting background colour. */
2449: static void
1.138 nicm 2450: input_osc_11(struct input_ctx *ictx, const char *p)
1.122 nicm 2451: {
1.138 nicm 2452: struct window_pane *wp = ictx->wp;
2453: u_int r, g, b;
1.156 nicm 2454: char tmp[16];
1.122 nicm 2455:
1.163 nicm 2456: if (strcmp(p, "?") == 0)
2457: return;
2458:
2459: if (!input_osc_parse_colour(p, &r, &g, &b))
1.122 nicm 2460: goto bad;
1.156 nicm 2461: xsnprintf(tmp, sizeof tmp, "bg=#%02x%02x%02x", r, g, b);
2462: options_set_style(wp->options, "window-style", 1, tmp);
2463: options_set_style(wp->options, "window-active-style", 1, tmp);
2464: wp->flags |= (PANE_REDRAW|PANE_STYLECHANGED);
1.122 nicm 2465:
2466: return;
2467:
2468: bad:
2469: log_debug("bad OSC 11: %s", p);
1.108 nicm 2470: }
2471:
2472: /* Handle the OSC 52 sequence for setting the clipboard. */
2473: static void
1.138 nicm 2474: input_osc_52(struct input_ctx *ictx, const char *p)
1.108 nicm 2475: {
1.138 nicm 2476: struct window_pane *wp = ictx->wp;
1.108 nicm 2477: char *end;
1.138 nicm 2478: const char *buf;
1.108 nicm 2479: size_t len;
2480: u_char *out;
1.123 nicm 2481: int outlen, state;
1.108 nicm 2482: struct screen_write_ctx ctx;
1.138 nicm 2483: struct paste_buffer *pb;
1.108 nicm 2484:
1.123 nicm 2485: state = options_get_number(global_options, "set-clipboard");
2486: if (state != 2)
2487: return;
2488:
1.108 nicm 2489: if ((end = strchr(p, ';')) == NULL)
2490: return;
2491: end++;
2492: if (*end == '\0')
2493: return;
1.138 nicm 2494: log_debug("%s: %s", __func__, end);
2495:
2496: if (strcmp(end, "?") == 0) {
2497: if ((pb = paste_get_top(NULL)) != NULL) {
2498: buf = paste_buffer_data(pb, &len);
2499: outlen = 4 * ((len + 2) / 3) + 1;
2500: out = xmalloc(outlen);
2501: if ((outlen = b64_ntop(buf, len, out, outlen)) == -1) {
2502: free(out);
2503: return;
2504: }
2505: } else {
2506: outlen = 0;
2507: out = NULL;
2508: }
2509: bufferevent_write(wp->event, "\033]52;;", 6);
2510: if (outlen != 0)
2511: bufferevent_write(wp->event, out, outlen);
2512: if (ictx->input_end == INPUT_END_BEL)
2513: bufferevent_write(wp->event, "\007", 1);
2514: else
2515: bufferevent_write(wp->event, "\033\\", 2);
2516: free(out);
2517: return;
2518: }
1.108 nicm 2519:
2520: len = (strlen(end) / 4) * 3;
2521: if (len == 0)
2522: return;
2523:
2524: out = xmalloc(len);
2525: if ((outlen = b64_pton(end, out, len)) == -1) {
2526: free(out);
2527: return;
2528: }
2529:
1.123 nicm 2530: screen_write_start(&ctx, wp, NULL);
2531: screen_write_setselection(&ctx, out, outlen);
2532: screen_write_stop(&ctx);
1.126 nicm 2533: notify_pane("pane-set-clipboard", wp);
1.123 nicm 2534:
1.150 nicm 2535: paste_add(NULL, out, outlen);
1.107 nicm 2536: }
2537:
2538: /* Handle the OSC 104 sequence for unsetting (multiple) palette entries. */
2539: static void
1.138 nicm 2540: input_osc_104(struct input_ctx *ictx, const char *p)
1.107 nicm 2541: {
1.138 nicm 2542: struct window_pane *wp = ictx->wp;
2543: char *copy, *s;
1.144 nicm 2544: long idx;
1.107 nicm 2545:
2546: if (*p == '\0') {
2547: window_pane_reset_palette(wp);
2548: return;
2549: }
2550:
2551: copy = s = xstrdup(p);
2552: while (*s != '\0') {
2553: idx = strtol(s, &s, 10);
2554: if (*s != '\0' && *s != ';')
2555: goto bad;
2556: if (idx < 0 || idx >= 0x100)
2557: goto bad;
2558:
2559: window_pane_unset_palette(wp, idx);
2560: if (*s == ';')
2561: s++;
2562: }
2563: free(copy);
2564: return;
2565:
2566: bad:
2567: log_debug("bad OSC 104: %s", p);
2568: free(copy);
1.1 nicm 2569: }