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