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