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