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