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