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