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