Annotation of src/usr.bin/tmux/input.c, Revision 1.168
1.168 ! nicm 1: /* $OpenBSD: input.c,v 1.167 2019/11/28 09:50:09 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 *, ...);
131: static void input_set_state(struct window_pane *,
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: struct window_pane *wp = ictx->wp;
735:
736: log_debug("%s: %%%u %s expired" , __func__, wp->id, ictx->state->name);
737: input_reset(wp, 0);
738: }
739:
740: /* Start the timer. */
741: static void
742: input_start_timer(struct input_ctx *ictx)
743: {
1.167 nicm 744: struct timeval tv = { .tv_sec = 5, .tv_usec = 0 };
1.125 nicm 745:
746: event_del(&ictx->timer);
747: event_add(&ictx->timer, &tv);
748: }
749:
1.69 nicm 750: /* Reset cell state to default. */
1.104 nicm 751: static void
1.69 nicm 752: input_reset_cell(struct input_ctx *ictx)
753: {
754: memcpy(&ictx->cell.cell, &grid_default_cell, sizeof ictx->cell.cell);
755: ictx->cell.set = 0;
756: ictx->cell.g0set = ictx->cell.g1set = 0;
757:
758: memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
759: ictx->old_cx = 0;
760: ictx->old_cy = 0;
761: }
762:
1.146 nicm 763: /* Save screen state. */
764: static void
765: input_save_state(struct input_ctx *ictx)
766: {
767: struct screen_write_ctx *sctx = &ictx->ctx;
768: struct screen *s = sctx->s;
769:
770: memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
771: ictx->old_cx = s->cx;
772: ictx->old_cy = s->cy;
773: ictx->old_mode = s->mode;
774: }
775:
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.1 nicm 790: void
1.28 nicm 791: input_init(struct window_pane *wp)
1.1 nicm 792: {
1.74 nicm 793: struct input_ctx *ictx;
794:
795: ictx = wp->ictx = xcalloc(1, sizeof *ictx);
1.1 nicm 796:
1.67 nicm 797: ictx->input_space = INPUT_BUF_START;
798: ictx->input_buf = xmalloc(INPUT_BUF_START);
799:
1.97 nicm 800: ictx->since_ground = evbuffer_new();
1.139 nicm 801: if (ictx->since_ground == NULL)
802: fatalx("out of memory");
1.52 nicm 803:
1.125 nicm 804: evtimer_set(&ictx->timer, input_timer_callback, ictx);
805:
1.97 nicm 806: input_reset(wp, 0);
1.1 nicm 807: }
808:
1.28 nicm 809: /* Destroy input parser. */
1.1 nicm 810: void
1.52 nicm 811: input_free(struct window_pane *wp)
1.1 nicm 812: {
1.74 nicm 813: struct input_ctx *ictx = wp->ictx;
1.131 nicm 814: u_int i;
815:
816: for (i = 0; i < ictx->param_list_len; i++) {
817: if (ictx->param_list[i].type == INPUT_STRING)
818: free(ictx->param_list[i].str);
819: }
1.74 nicm 820:
1.125 nicm 821: event_del(&ictx->timer);
822:
1.74 nicm 823: free(ictx->input_buf);
824: evbuffer_free(ictx->since_ground);
825:
1.106 nicm 826: free(ictx);
1.74 nicm 827: wp->ictx = NULL;
828: }
829:
830: /* Reset input state and clear screen. */
831: void
1.97 nicm 832: input_reset(struct window_pane *wp, int clear)
1.74 nicm 833: {
834: struct input_ctx *ictx = wp->ictx;
1.144 nicm 835: struct screen_write_ctx *sctx = &ictx->ctx;
1.67 nicm 836:
1.80 nicm 837: input_reset_cell(ictx);
1.74 nicm 838:
1.97 nicm 839: if (clear) {
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 *
858: input_pending(struct window_pane *wp)
859: {
860: return (wp->ictx->since_ground);
1.52 nicm 861: }
862:
863: /* Change input state. */
1.104 nicm 864: static void
1.52 nicm 865: input_set_state(struct window_pane *wp, const struct input_transition *itr)
866: {
1.74 nicm 867: struct input_ctx *ictx = wp->ictx;
1.52 nicm 868:
869: if (ictx->state->exit != NULL)
870: ictx->state->exit(ictx);
871: ictx->state = itr->state;
872: if (ictx->state->enter != NULL)
873: ictx->state->enter(ictx);
1.1 nicm 874: }
875:
1.28 nicm 876: /* Parse input. */
1.1 nicm 877: void
1.28 nicm 878: input_parse(struct window_pane *wp)
1.1 nicm 879: {
1.164 nicm 880: struct evbuffer *evb = wp->event->input;
1.152 nicm 881:
882: input_parse_buffer(wp, EVBUFFER_DATA(evb), EVBUFFER_LENGTH(evb));
883: evbuffer_drain(evb, EVBUFFER_LENGTH(evb));
884: }
885:
886: /* Parse given input. */
887: void
888: input_parse_buffer(struct window_pane *wp, u_char *buf, size_t len)
889: {
1.74 nicm 890: struct input_ctx *ictx = wp->ictx;
1.144 nicm 891: struct screen_write_ctx *sctx = &ictx->ctx;
1.160 nicm 892: const struct input_state *state = NULL;
893: const struct input_transition *itr = NULL;
1.152 nicm 894: size_t off = 0;
1.1 nicm 895:
1.152 nicm 896: if (len == 0)
1.28 nicm 897: return;
1.82 nicm 898:
1.83 nicm 899: window_update_activity(wp->window);
1.82 nicm 900: wp->flags |= PANE_CHANGED;
1.152 nicm 901: notify_input(wp, buf, len);
1.30 nicm 902:
1.28 nicm 903: /*
904: * Open the screen. Use NULL wp if there is a mode set as don't want to
905: * update the tty.
906: */
1.142 nicm 907: if (TAILQ_EMPTY(&wp->modes))
1.144 nicm 908: screen_write_start(sctx, wp, &wp->base);
1.28 nicm 909: else
1.144 nicm 910: screen_write_start(sctx, NULL, &wp->base);
1.28 nicm 911: ictx->wp = wp;
1.7 nicm 912:
1.86 nicm 913: log_debug("%s: %%%u %s, %zu bytes: %.*s", __func__, wp->id,
914: ictx->state->name, len, (int)len, buf);
1.84 nicm 915:
1.28 nicm 916: /* Parse the input. */
917: while (off < len) {
918: ictx->ch = buf[off++];
919:
920: /* Find the transition. */
1.160 nicm 921: if (ictx->state != state ||
922: itr == NULL ||
923: ictx->ch < itr->first ||
924: ictx->ch > itr->last) {
925: itr = ictx->state->transitions;
926: while (itr->first != -1 && itr->last != -1) {
1.161 nicm 927: if (ictx->ch >= itr->first &&
928: ictx->ch <= itr->last)
1.160 nicm 929: break;
930: itr++;
931: }
932: if (itr->first == -1 || itr->last == -1) {
933: /* No transition? Eh? */
934: fatalx("no transition from state");
935: }
1.3 nicm 936: }
1.160 nicm 937: state = ictx->state;
1.1 nicm 938:
939: /*
1.114 nicm 940: * Any state except print stops the current collection. This is
941: * an optimization to avoid checking if the attributes have
942: * changed for every character. It will stop unnecessarily for
943: * sequences that don't make a terminal change, but they should
944: * be the minority.
945: */
946: if (itr->handler != input_print)
1.144 nicm 947: screen_write_collect_end(sctx);
1.114 nicm 948:
949: /*
1.28 nicm 950: * Execute the handler, if any. Don't switch state if it
951: * returns non-zero.
1.1 nicm 952: */
1.31 nicm 953: if (itr->handler != NULL && itr->handler(ictx) != 0)
1.28 nicm 954: continue;
955:
956: /* And switch state, if necessary. */
1.52 nicm 957: if (itr->state != NULL)
958: input_set_state(wp, itr);
959:
960: /* If not in ground state, save input. */
961: if (ictx->state != &input_state_ground)
962: evbuffer_add(ictx->since_ground, &ictx->ch, 1);
1.1 nicm 963: }
964:
1.28 nicm 965: /* Close the screen. */
1.144 nicm 966: screen_write_stop(sctx);
1.1 nicm 967: }
968:
1.28 nicm 969: /* Split the parameter list (if any). */
1.104 nicm 970: static int
1.28 nicm 971: input_split(struct input_ctx *ictx)
1.1 nicm 972: {
1.131 nicm 973: const char *errstr;
974: char *ptr, *out;
975: struct input_param *ip;
976: u_int i;
1.1 nicm 977:
1.131 nicm 978: for (i = 0; i < ictx->param_list_len; i++) {
979: if (ictx->param_list[i].type == INPUT_STRING)
980: free(ictx->param_list[i].str);
981: }
1.28 nicm 982: ictx->param_list_len = 0;
1.131 nicm 983:
1.28 nicm 984: if (ictx->param_len == 0)
985: return (0);
1.131 nicm 986: ip = &ictx->param_list[0];
1.1 nicm 987:
1.28 nicm 988: ptr = ictx->param_buf;
989: while ((out = strsep(&ptr, ";")) != NULL) {
990: if (*out == '\0')
1.131 nicm 991: ip->type = INPUT_MISSING;
1.28 nicm 992: else {
1.131 nicm 993: if (strchr(out, ':') != NULL) {
994: ip->type = INPUT_STRING;
995: ip->str = xstrdup(out);
996: } else {
997: ip->type = INPUT_NUMBER;
998: ip->num = strtonum(out, 0, INT_MAX, &errstr);
999: if (errstr != NULL)
1000: return (-1);
1001: }
1.28 nicm 1002: }
1.131 nicm 1003: ip = &ictx->param_list[++ictx->param_list_len];
1.28 nicm 1004: if (ictx->param_list_len == nitems(ictx->param_list))
1005: return (-1);
1006: }
1.1 nicm 1007:
1.131 nicm 1008: for (i = 0; i < ictx->param_list_len; i++) {
1009: ip = &ictx->param_list[i];
1010: if (ip->type == INPUT_MISSING)
1011: log_debug("parameter %u: missing", i);
1012: else if (ip->type == INPUT_STRING)
1013: log_debug("parameter %u: string %s", i, ip->str);
1014: else if (ip->type == INPUT_NUMBER)
1015: log_debug("parameter %u: number %d", i, ip->num);
1016: }
1017:
1.28 nicm 1018: return (0);
1.1 nicm 1019: }
1020:
1.40 nicm 1021: /* Get an argument or return default value. */
1.104 nicm 1022: static int
1.28 nicm 1023: input_get(struct input_ctx *ictx, u_int validx, int minval, int defval)
1.1 nicm 1024: {
1.131 nicm 1025: struct input_param *ip;
1026: int retval;
1.1 nicm 1027:
1.28 nicm 1028: if (validx >= ictx->param_list_len)
1029: return (defval);
1.131 nicm 1030: ip = &ictx->param_list[validx];
1031: if (ip->type == INPUT_MISSING)
1.28 nicm 1032: return (defval);
1.131 nicm 1033: if (ip->type == INPUT_STRING)
1034: return (-1);
1035: retval = ip->num;
1.28 nicm 1036: if (retval < minval)
1037: return (minval);
1038: return (retval);
1.1 nicm 1039: }
1040:
1.28 nicm 1041: /* Reply to terminal query. */
1.104 nicm 1042: static void
1.28 nicm 1043: input_reply(struct input_ctx *ictx, const char *fmt, ...)
1.1 nicm 1044: {
1.138 nicm 1045: va_list ap;
1046: char *reply;
1.1 nicm 1047:
1.28 nicm 1048: va_start(ap, fmt);
1.103 nicm 1049: xvasprintf(&reply, fmt, ap);
1.28 nicm 1050: va_end(ap);
1.1 nicm 1051:
1.28 nicm 1052: bufferevent_write(ictx->wp->event, reply, strlen(reply));
1.53 nicm 1053: free(reply);
1.8 nicm 1054: }
1055:
1.28 nicm 1056: /* Clear saved state. */
1.104 nicm 1057: static void
1.28 nicm 1058: input_clear(struct input_ctx *ictx)
1.8 nicm 1059: {
1.125 nicm 1060: event_del(&ictx->timer);
1061:
1.28 nicm 1062: *ictx->interm_buf = '\0';
1063: ictx->interm_len = 0;
1.8 nicm 1064:
1.28 nicm 1065: *ictx->param_buf = '\0';
1066: ictx->param_len = 0;
1.8 nicm 1067:
1.35 nicm 1068: *ictx->input_buf = '\0';
1069: ictx->input_len = 0;
1070:
1.138 nicm 1071: ictx->input_end = INPUT_END_ST;
1072:
1.28 nicm 1073: ictx->flags &= ~INPUT_DISCARD;
1.14 nicm 1074: }
1075:
1.67 nicm 1076: /* Reset for ground state. */
1.104 nicm 1077: static void
1.67 nicm 1078: input_ground(struct input_ctx *ictx)
1079: {
1.125 nicm 1080: event_del(&ictx->timer);
1.67 nicm 1081: evbuffer_drain(ictx->since_ground, EVBUFFER_LENGTH(ictx->since_ground));
1082:
1083: if (ictx->input_space > INPUT_BUF_START) {
1084: ictx->input_space = INPUT_BUF_START;
1.71 nicm 1085: ictx->input_buf = xrealloc(ictx->input_buf, INPUT_BUF_START);
1.67 nicm 1086: }
1087: }
1088:
1.28 nicm 1089: /* Output this character to the screen. */
1.104 nicm 1090: static int
1.28 nicm 1091: input_print(struct input_ctx *ictx)
1.14 nicm 1092: {
1.144 nicm 1093: struct screen_write_ctx *sctx = &ictx->ctx;
1094: int set;
1.69 nicm 1095:
1.130 nicm 1096: ictx->utf8started = 0; /* can't be valid UTF-8 */
1097:
1.69 nicm 1098: set = ictx->cell.set == 0 ? ictx->cell.g0set : ictx->cell.g1set;
1099: if (set == 1)
1100: ictx->cell.cell.attr |= GRID_ATTR_CHARSET;
1101: else
1102: ictx->cell.cell.attr &= ~GRID_ATTR_CHARSET;
1103:
1.89 nicm 1104: utf8_set(&ictx->cell.cell.data, ictx->ch);
1.144 nicm 1105: screen_write_collect_add(sctx, &ictx->cell.cell);
1.127 nicm 1106: ictx->last = ictx->ch;
1.69 nicm 1107:
1108: ictx->cell.cell.attr &= ~GRID_ATTR_CHARSET;
1.14 nicm 1109:
1.28 nicm 1110: return (0);
1.1 nicm 1111: }
1112:
1.28 nicm 1113: /* Collect intermediate string. */
1.104 nicm 1114: static int
1.28 nicm 1115: input_intermediate(struct input_ctx *ictx)
1.1 nicm 1116: {
1.28 nicm 1117: if (ictx->interm_len == (sizeof ictx->interm_buf) - 1)
1118: ictx->flags |= INPUT_DISCARD;
1119: else {
1120: ictx->interm_buf[ictx->interm_len++] = ictx->ch;
1121: ictx->interm_buf[ictx->interm_len] = '\0';
1122: }
1.1 nicm 1123:
1.28 nicm 1124: return (0);
1.1 nicm 1125: }
1126:
1.28 nicm 1127: /* Collect parameter string. */
1.104 nicm 1128: static int
1.28 nicm 1129: input_parameter(struct input_ctx *ictx)
1.1 nicm 1130: {
1.28 nicm 1131: if (ictx->param_len == (sizeof ictx->param_buf) - 1)
1132: ictx->flags |= INPUT_DISCARD;
1133: else {
1134: ictx->param_buf[ictx->param_len++] = ictx->ch;
1135: ictx->param_buf[ictx->param_len] = '\0';
1136: }
1.1 nicm 1137:
1.28 nicm 1138: return (0);
1.1 nicm 1139: }
1140:
1.28 nicm 1141: /* Collect input string. */
1.104 nicm 1142: static int
1.28 nicm 1143: input_input(struct input_ctx *ictx)
1.1 nicm 1144: {
1.67 nicm 1145: size_t available;
1146:
1147: available = ictx->input_space;
1148: while (ictx->input_len + 1 >= available) {
1149: available *= 2;
1150: if (available > INPUT_BUF_LIMIT) {
1151: ictx->flags |= INPUT_DISCARD;
1152: return (0);
1153: }
1.71 nicm 1154: ictx->input_buf = xrealloc(ictx->input_buf, available);
1.67 nicm 1155: ictx->input_space = available;
1.28 nicm 1156: }
1.67 nicm 1157: ictx->input_buf[ictx->input_len++] = ictx->ch;
1158: ictx->input_buf[ictx->input_len] = '\0';
1.1 nicm 1159:
1.28 nicm 1160: return (0);
1.1 nicm 1161: }
1162:
1.28 nicm 1163: /* Execute C0 control sequence. */
1.104 nicm 1164: static int
1.28 nicm 1165: input_c0_dispatch(struct input_ctx *ictx)
1.1 nicm 1166: {
1.28 nicm 1167: struct screen_write_ctx *sctx = &ictx->ctx;
1168: struct window_pane *wp = ictx->wp;
1169: struct screen *s = sctx->s;
1.1 nicm 1170:
1.130 nicm 1171: ictx->utf8started = 0; /* can't be valid UTF-8 */
1172:
1.84 nicm 1173: log_debug("%s: '%c'", __func__, ictx->ch);
1.1 nicm 1174:
1.28 nicm 1175: switch (ictx->ch) {
1176: case '\000': /* NUL */
1177: break;
1178: case '\007': /* BEL */
1.83 nicm 1179: alerts_queue(wp->window, WINDOW_BELL);
1.28 nicm 1180: break;
1181: case '\010': /* BS */
1182: screen_write_backspace(sctx);
1.75 nicm 1183: break;
1.28 nicm 1184: case '\011': /* HT */
1185: /* Don't tab beyond the end of the line. */
1186: if (s->cx >= screen_size_x(s) - 1)
1187: break;
1.1 nicm 1188:
1.28 nicm 1189: /* Find the next tab point, or use the last column if none. */
1190: do {
1191: s->cx++;
1192: if (bit_test(s->tabs, s->cx))
1193: break;
1194: } while (s->cx < screen_size_x(s) - 1);
1195: break;
1196: case '\012': /* LF */
1197: case '\013': /* VT */
1198: case '\014': /* FF */
1.121 nicm 1199: screen_write_linefeed(sctx, 0, ictx->cell.cell.bg);
1.151 nicm 1200: if (s->mode & MODE_CRLF)
1201: screen_write_carriagereturn(sctx);
1.75 nicm 1202: break;
1.28 nicm 1203: case '\015': /* CR */
1204: screen_write_carriagereturn(sctx);
1.75 nicm 1205: break;
1.28 nicm 1206: case '\016': /* SO */
1.69 nicm 1207: ictx->cell.set = 1;
1.28 nicm 1208: break;
1209: case '\017': /* SI */
1.69 nicm 1210: ictx->cell.set = 0;
1.28 nicm 1211: break;
1212: default:
1213: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1214: break;
1215: }
1.1 nicm 1216:
1.127 nicm 1217: ictx->last = -1;
1.28 nicm 1218: return (0);
1.7 nicm 1219: }
1220:
1.28 nicm 1221: /* Execute escape sequence. */
1.104 nicm 1222: static int
1.28 nicm 1223: input_esc_dispatch(struct input_ctx *ictx)
1.7 nicm 1224: {
1.31 nicm 1225: struct screen_write_ctx *sctx = &ictx->ctx;
1226: struct screen *s = sctx->s;
1227: struct input_table_entry *entry;
1.7 nicm 1228:
1.28 nicm 1229: if (ictx->flags & INPUT_DISCARD)
1230: return (0);
1231: log_debug("%s: '%c', %s", __func__, ictx->ch, ictx->interm_buf);
1.7 nicm 1232:
1.28 nicm 1233: entry = bsearch(ictx, input_esc_table, nitems(input_esc_table),
1234: sizeof input_esc_table[0], input_table_compare);
1235: if (entry == NULL) {
1236: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1237: return (0);
1238: }
1.7 nicm 1239:
1.28 nicm 1240: switch (entry->type) {
1241: case INPUT_ESC_RIS:
1.107 nicm 1242: window_pane_reset_palette(ictx->wp);
1.69 nicm 1243: input_reset_cell(ictx);
1.46 nicm 1244: screen_write_reset(sctx);
1.28 nicm 1245: break;
1246: case INPUT_ESC_IND:
1.121 nicm 1247: screen_write_linefeed(sctx, 0, ictx->cell.cell.bg);
1.28 nicm 1248: break;
1249: case INPUT_ESC_NEL:
1250: screen_write_carriagereturn(sctx);
1.121 nicm 1251: screen_write_linefeed(sctx, 0, ictx->cell.cell.bg);
1.28 nicm 1252: break;
1253: case INPUT_ESC_HTS:
1254: if (s->cx < screen_size_x(s))
1255: bit_set(s->tabs, s->cx);
1256: break;
1257: case INPUT_ESC_RI:
1.121 nicm 1258: screen_write_reverseindex(sctx, ictx->cell.cell.bg);
1.28 nicm 1259: break;
1260: case INPUT_ESC_DECKPAM:
1.59 nicm 1261: screen_write_mode_set(sctx, MODE_KKEYPAD);
1.28 nicm 1262: break;
1263: case INPUT_ESC_DECKPNM:
1.59 nicm 1264: screen_write_mode_clear(sctx, MODE_KKEYPAD);
1.1 nicm 1265: break;
1.28 nicm 1266: case INPUT_ESC_DECSC:
1.146 nicm 1267: input_save_state(ictx);
1.28 nicm 1268: break;
1269: case INPUT_ESC_DECRC:
1.146 nicm 1270: input_restore_state(ictx);
1.28 nicm 1271: break;
1272: case INPUT_ESC_DECALN:
1273: screen_write_alignmenttest(sctx);
1274: break;
1.69 nicm 1275: case INPUT_ESC_SCSG0_ON:
1276: ictx->cell.g0set = 1;
1277: break;
1278: case INPUT_ESC_SCSG0_OFF:
1279: ictx->cell.g0set = 0;
1280: break;
1281: case INPUT_ESC_SCSG1_ON:
1282: ictx->cell.g1set = 1;
1.1 nicm 1283: break;
1.69 nicm 1284: case INPUT_ESC_SCSG1_OFF:
1285: ictx->cell.g1set = 0;
1.1 nicm 1286: break;
1.107 nicm 1287: case INPUT_ESC_ST:
1288: /* ST terminates OSC but the state transition already did it. */
1289: break;
1.1 nicm 1290: }
1.28 nicm 1291:
1.127 nicm 1292: ictx->last = -1;
1.28 nicm 1293: return (0);
1.1 nicm 1294: }
1295:
1.28 nicm 1296: /* Execute control sequence. */
1.104 nicm 1297: static int
1.28 nicm 1298: input_csi_dispatch(struct input_ctx *ictx)
1.1 nicm 1299: {
1.28 nicm 1300: struct screen_write_ctx *sctx = &ictx->ctx;
1301: struct screen *s = sctx->s;
1302: struct input_table_entry *entry;
1.127 nicm 1303: int i, n, m;
1.131 nicm 1304: u_int cx, bg = ictx->cell.cell.bg;
1.168 ! nicm 1305: char *copy, *cp;
1.1 nicm 1306:
1.28 nicm 1307: if (ictx->flags & INPUT_DISCARD)
1308: return (0);
1.110 nicm 1309:
1310: log_debug("%s: '%c' \"%s\" \"%s\"",
1311: __func__, ictx->ch, ictx->interm_buf, ictx->param_buf);
1312:
1.28 nicm 1313: if (input_split(ictx) != 0)
1314: return (0);
1.1 nicm 1315:
1.28 nicm 1316: entry = bsearch(ictx, input_csi_table, nitems(input_csi_table),
1317: sizeof input_csi_table[0], input_table_compare);
1318: if (entry == NULL) {
1319: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1320: return (0);
1321: }
1.1 nicm 1322:
1.28 nicm 1323: switch (entry->type) {
1324: case INPUT_CSI_CBT:
1325: /* Find the previous tab point, n times. */
1.81 nicm 1326: cx = s->cx;
1327: if (cx > screen_size_x(s) - 1)
1328: cx = screen_size_x(s) - 1;
1.28 nicm 1329: n = input_get(ictx, 0, 1, 1);
1.131 nicm 1330: if (n == -1)
1331: break;
1.81 nicm 1332: while (cx > 0 && n-- > 0) {
1.28 nicm 1333: do
1.81 nicm 1334: cx--;
1335: while (cx > 0 && !bit_test(s->tabs, cx));
1.28 nicm 1336: }
1.81 nicm 1337: s->cx = cx;
1.28 nicm 1338: break;
1339: case INPUT_CSI_CUB:
1.131 nicm 1340: n = input_get(ictx, 0, 1, 1);
1341: if (n != -1)
1342: screen_write_cursorleft(sctx, n);
1.28 nicm 1343: break;
1344: case INPUT_CSI_CUD:
1.131 nicm 1345: n = input_get(ictx, 0, 1, 1);
1346: if (n != -1)
1347: screen_write_cursordown(sctx, n);
1.28 nicm 1348: break;
1349: case INPUT_CSI_CUF:
1.131 nicm 1350: n = input_get(ictx, 0, 1, 1);
1351: if (n != -1)
1352: screen_write_cursorright(sctx, n);
1.28 nicm 1353: break;
1354: case INPUT_CSI_CUP:
1355: n = input_get(ictx, 0, 1, 1);
1356: m = input_get(ictx, 1, 1, 1);
1.131 nicm 1357: if (n != -1 && m != -1)
1.146 nicm 1358: screen_write_cursormove(sctx, m - 1, n - 1, 1);
1.28 nicm 1359: break;
1.65 nicm 1360: case INPUT_CSI_WINOPS:
1361: input_csi_dispatch_winops(ictx);
1362: break;
1.28 nicm 1363: case INPUT_CSI_CUU:
1.131 nicm 1364: n = input_get(ictx, 0, 1, 1);
1365: if (n != -1)
1366: screen_write_cursorup(sctx, n);
1.43 nicm 1367: break;
1368: case INPUT_CSI_CNL:
1.131 nicm 1369: n = input_get(ictx, 0, 1, 1);
1370: if (n != -1) {
1371: screen_write_carriagereturn(sctx);
1372: screen_write_cursordown(sctx, n);
1373: }
1.43 nicm 1374: break;
1375: case INPUT_CSI_CPL:
1.131 nicm 1376: n = input_get(ictx, 0, 1, 1);
1377: if (n != -1) {
1378: screen_write_carriagereturn(sctx);
1379: screen_write_cursorup(sctx, n);
1380: }
1.28 nicm 1381: break;
1382: case INPUT_CSI_DA:
1383: switch (input_get(ictx, 0, 0, 0)) {
1.131 nicm 1384: case -1:
1385: break;
1.28 nicm 1386: case 0:
1387: input_reply(ictx, "\033[?1;2c");
1.50 nicm 1388: break;
1389: default:
1390: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1391: break;
1392: }
1393: break;
1394: case INPUT_CSI_DA_TWO:
1395: switch (input_get(ictx, 0, 0, 0)) {
1.131 nicm 1396: case -1:
1397: break;
1.50 nicm 1398: case 0:
1.66 nicm 1399: input_reply(ictx, "\033[>84;0;0c");
1.28 nicm 1400: break;
1401: default:
1402: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1403: break;
1404: }
1.56 nicm 1405: break;
1406: case INPUT_CSI_ECH:
1.131 nicm 1407: n = input_get(ictx, 0, 1, 1);
1408: if (n != -1)
1409: screen_write_clearcharacter(sctx, n, bg);
1.28 nicm 1410: break;
1411: case INPUT_CSI_DCH:
1.131 nicm 1412: n = input_get(ictx, 0, 1, 1);
1413: if (n != -1)
1414: screen_write_deletecharacter(sctx, n, bg);
1.28 nicm 1415: break;
1416: case INPUT_CSI_DECSTBM:
1417: n = input_get(ictx, 0, 1, 1);
1418: m = input_get(ictx, 1, 1, screen_size_y(s));
1.131 nicm 1419: if (n != -1 && m != -1)
1420: screen_write_scrollregion(sctx, n - 1, m - 1);
1.1 nicm 1421: break;
1.28 nicm 1422: case INPUT_CSI_DL:
1.131 nicm 1423: n = input_get(ictx, 0, 1, 1);
1424: if (n != -1)
1425: screen_write_deleteline(sctx, n, bg);
1.1 nicm 1426: break;
1.28 nicm 1427: case INPUT_CSI_DSR:
1428: switch (input_get(ictx, 0, 0, 0)) {
1.131 nicm 1429: case -1:
1430: break;
1.28 nicm 1431: case 5:
1432: input_reply(ictx, "\033[0n");
1433: break;
1434: case 6:
1435: input_reply(ictx, "\033[%u;%uR", s->cy + 1, s->cx + 1);
1.168 ! nicm 1436: break;
! 1437: case 1337: /* Terminal version, from iTerm2. */
! 1438: copy = xstrdup(getversion());
! 1439: for (cp = copy; *cp != '\0'; cp++)
! 1440: *cp = toupper((u_char)*cp);
! 1441: input_reply(ictx, "\033[TMUX %sn", copy);
! 1442: free(copy);
1.28 nicm 1443: break;
1444: default:
1445: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1446: break;
1447: }
1448: break;
1449: case INPUT_CSI_ED:
1450: switch (input_get(ictx, 0, 0, 0)) {
1.131 nicm 1451: case -1:
1452: break;
1.28 nicm 1453: case 0:
1.131 nicm 1454: screen_write_clearendofscreen(sctx, bg);
1.28 nicm 1455: break;
1456: case 1:
1.131 nicm 1457: screen_write_clearstartofscreen(sctx, bg);
1.28 nicm 1458: break;
1459: case 2:
1.131 nicm 1460: screen_write_clearscreen(sctx, bg);
1.41 nicm 1461: break;
1462: case 3:
1.131 nicm 1463: if (input_get(ictx, 1, 0, 0) == 0) {
1.41 nicm 1464: /*
1465: * Linux console extension to clear history
1466: * (for example before locking the screen).
1467: */
1468: screen_write_clearhistory(sctx);
1469: }
1.28 nicm 1470: break;
1471: default:
1472: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1473: break;
1474: }
1475: break;
1476: case INPUT_CSI_EL:
1477: switch (input_get(ictx, 0, 0, 0)) {
1.131 nicm 1478: case -1:
1479: break;
1.28 nicm 1480: case 0:
1.131 nicm 1481: screen_write_clearendofline(sctx, bg);
1.28 nicm 1482: break;
1483: case 1:
1.131 nicm 1484: screen_write_clearstartofline(sctx, bg);
1.28 nicm 1485: break;
1486: case 2:
1.131 nicm 1487: screen_write_clearline(sctx, bg);
1.28 nicm 1488: break;
1489: default:
1490: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1491: break;
1492: }
1493: break;
1494: case INPUT_CSI_HPA:
1495: n = input_get(ictx, 0, 1, 1);
1.131 nicm 1496: if (n != -1)
1.148 nicm 1497: screen_write_cursormove(sctx, n - 1, -1, 1);
1.28 nicm 1498: break;
1499: case INPUT_CSI_ICH:
1.131 nicm 1500: n = input_get(ictx, 0, 1, 1);
1501: if (n != -1)
1502: screen_write_insertcharacter(sctx, n, bg);
1.28 nicm 1503: break;
1504: case INPUT_CSI_IL:
1.131 nicm 1505: n = input_get(ictx, 0, 1, 1);
1506: if (n != -1)
1507: screen_write_insertline(sctx, n, bg);
1.28 nicm 1508: break;
1.127 nicm 1509: case INPUT_CSI_REP:
1.131 nicm 1510: n = input_get(ictx, 0, 1, 1);
1511: if (n == -1)
1512: break;
1513:
1.127 nicm 1514: if (ictx->last == -1)
1515: break;
1516: ictx->ch = ictx->last;
1517:
1518: for (i = 0; i < n; i++)
1519: input_print(ictx);
1520: break;
1.42 nicm 1521: case INPUT_CSI_RCP:
1.146 nicm 1522: input_restore_state(ictx);
1.42 nicm 1523: break;
1.28 nicm 1524: case INPUT_CSI_RM:
1.64 nicm 1525: input_csi_dispatch_rm(ictx);
1526: break;
1527: case INPUT_CSI_RM_PRIVATE:
1528: input_csi_dispatch_rm_private(ictx);
1529: break;
1530: case INPUT_CSI_SCP:
1.146 nicm 1531: input_save_state(ictx);
1.64 nicm 1532: break;
1533: case INPUT_CSI_SGR:
1534: input_csi_dispatch_sgr(ictx);
1535: break;
1536: case INPUT_CSI_SM:
1537: input_csi_dispatch_sm(ictx);
1538: break;
1539: case INPUT_CSI_SM_PRIVATE:
1540: input_csi_dispatch_sm_private(ictx);
1.115 nicm 1541: break;
1542: case INPUT_CSI_SU:
1.131 nicm 1543: n = input_get(ictx, 0, 1, 1);
1544: if (n != -1)
1545: screen_write_scrollup(sctx, n, bg);
1.159 nicm 1546: break;
1547: case INPUT_CSI_SD:
1548: n = input_get(ictx, 0, 1, 1);
1549: if (n != -1)
1550: screen_write_scrolldown(sctx, n, bg);
1.64 nicm 1551: break;
1552: case INPUT_CSI_TBC:
1553: switch (input_get(ictx, 0, 0, 0)) {
1.131 nicm 1554: case -1:
1555: break;
1.64 nicm 1556: case 0:
1557: if (s->cx < screen_size_x(s))
1558: bit_clear(s->tabs, s->cx);
1559: break;
1560: case 3:
1561: bit_nclear(s->tabs, 0, screen_size_x(s) - 1);
1562: break;
1563: default:
1564: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1565: break;
1566: }
1567: break;
1568: case INPUT_CSI_VPA:
1569: n = input_get(ictx, 0, 1, 1);
1.131 nicm 1570: if (n != -1)
1.148 nicm 1571: screen_write_cursormove(sctx, -1, n - 1, 1);
1.64 nicm 1572: break;
1573: case INPUT_CSI_DECSCUSR:
1574: n = input_get(ictx, 0, 0, 0);
1.131 nicm 1575: if (n != -1)
1576: screen_set_cursor_style(s, n);
1.64 nicm 1577: break;
1578: }
1579:
1.127 nicm 1580: ictx->last = -1;
1.64 nicm 1581: return (0);
1582: }
1583:
1584: /* Handle CSI RM. */
1.104 nicm 1585: static void
1.64 nicm 1586: input_csi_dispatch_rm(struct input_ctx *ictx)
1587: {
1.144 nicm 1588: struct screen_write_ctx *sctx = &ictx->ctx;
1589: u_int i;
1.64 nicm 1590:
1591: for (i = 0; i < ictx->param_list_len; i++) {
1592: switch (input_get(ictx, i, 0, -1)) {
1.131 nicm 1593: case -1:
1594: break;
1.28 nicm 1595: case 4: /* IRM */
1.144 nicm 1596: screen_write_mode_clear(sctx, MODE_INSERT);
1.28 nicm 1597: break;
1.72 nicm 1598: case 34:
1.144 nicm 1599: screen_write_mode_set(sctx, MODE_BLINKING);
1.72 nicm 1600: break;
1.28 nicm 1601: default:
1602: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1603: break;
1604: }
1.64 nicm 1605: }
1606: }
1607:
1608: /* Handle CSI private RM. */
1.104 nicm 1609: static void
1.64 nicm 1610: input_csi_dispatch_rm_private(struct input_ctx *ictx)
1611: {
1.144 nicm 1612: struct screen_write_ctx *sctx = &ictx->ctx;
1.69 nicm 1613: struct window_pane *wp = ictx->wp;
1614: u_int i;
1.64 nicm 1615:
1616: for (i = 0; i < ictx->param_list_len; i++) {
1617: switch (input_get(ictx, i, 0, -1)) {
1.131 nicm 1618: case -1:
1619: break;
1.64 nicm 1620: case 1: /* DECCKM */
1.144 nicm 1621: screen_write_mode_clear(sctx, MODE_KCURSOR);
1.1 nicm 1622: break;
1.17 nicm 1623: case 3: /* DECCOLM */
1.146 nicm 1624: screen_write_cursormove(sctx, 0, 0, 1);
1.144 nicm 1625: screen_write_clearscreen(sctx, ictx->cell.cell.bg);
1.17 nicm 1626: break;
1.141 nicm 1627: case 6: /* DECOM */
1.144 nicm 1628: screen_write_mode_clear(sctx, MODE_ORIGIN);
1.146 nicm 1629: screen_write_cursormove(sctx, 0, 0, 1);
1.141 nicm 1630: break;
1.61 nicm 1631: case 7: /* DECAWM */
1.144 nicm 1632: screen_write_mode_clear(sctx, MODE_WRAP);
1.61 nicm 1633: break;
1.72 nicm 1634: case 12:
1.144 nicm 1635: screen_write_mode_clear(sctx, MODE_BLINKING);
1.72 nicm 1636: break;
1.1 nicm 1637: case 25: /* TCEM */
1.144 nicm 1638: screen_write_mode_clear(sctx, MODE_CURSOR);
1.1 nicm 1639: break;
1640: case 1000:
1.32 nicm 1641: case 1001:
1642: case 1002:
1.109 nicm 1643: case 1003:
1.144 nicm 1644: screen_write_mode_clear(sctx, ALL_MOUSE_MODES);
1.1 nicm 1645: break;
1.62 nicm 1646: case 1004:
1.144 nicm 1647: screen_write_mode_clear(sctx, MODE_FOCUSON);
1.62 nicm 1648: break;
1.96 nicm 1649: case 1005:
1.144 nicm 1650: screen_write_mode_clear(sctx, MODE_MOUSE_UTF8);
1.96 nicm 1651: break;
1.60 nicm 1652: case 1006:
1.144 nicm 1653: screen_write_mode_clear(sctx, MODE_MOUSE_SGR);
1.60 nicm 1654: break;
1.55 nicm 1655: case 47:
1656: case 1047:
1.69 nicm 1657: window_pane_alternate_off(wp, &ictx->cell.cell, 0);
1.55 nicm 1658: break;
1.9 nicm 1659: case 1049:
1.69 nicm 1660: window_pane_alternate_off(wp, &ictx->cell.cell, 1);
1.9 nicm 1661: break;
1.49 nicm 1662: case 2004:
1.144 nicm 1663: screen_write_mode_clear(sctx, MODE_BRACKETPASTE);
1.49 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 SM. */
1.104 nicm 1673: static void
1.64 nicm 1674: input_csi_dispatch_sm(struct input_ctx *ictx)
1675: {
1.144 nicm 1676: struct screen_write_ctx *sctx = &ictx->ctx;
1677: u_int i;
1.64 nicm 1678:
1679: for (i = 0; i < ictx->param_list_len; i++) {
1680: switch (input_get(ictx, i, 0, -1)) {
1.131 nicm 1681: case -1:
1682: break;
1.1 nicm 1683: case 4: /* IRM */
1.144 nicm 1684: screen_write_mode_set(sctx, MODE_INSERT);
1.1 nicm 1685: break;
1.72 nicm 1686: case 34:
1.144 nicm 1687: screen_write_mode_clear(sctx, MODE_BLINKING);
1.72 nicm 1688: break;
1.1 nicm 1689: default:
1.28 nicm 1690: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1.1 nicm 1691: break;
1692: }
1.64 nicm 1693: }
1694: }
1695:
1696: /* Handle CSI private SM. */
1.104 nicm 1697: static void
1.64 nicm 1698: input_csi_dispatch_sm_private(struct input_ctx *ictx)
1699: {
1.144 nicm 1700: struct screen_write_ctx *sctx = &ictx->ctx;
1.69 nicm 1701: struct window_pane *wp = ictx->wp;
1702: u_int i;
1.64 nicm 1703:
1704: for (i = 0; i < ictx->param_list_len; i++) {
1705: switch (input_get(ictx, i, 0, -1)) {
1.131 nicm 1706: case -1:
1707: break;
1.64 nicm 1708: case 1: /* DECCKM */
1.144 nicm 1709: screen_write_mode_set(sctx, MODE_KCURSOR);
1.17 nicm 1710: break;
1711: case 3: /* DECCOLM */
1.146 nicm 1712: screen_write_cursormove(sctx, 0, 0, 1);
1.144 nicm 1713: screen_write_clearscreen(sctx, ictx->cell.cell.bg);
1.141 nicm 1714: break;
1715: case 6: /* DECOM */
1.144 nicm 1716: screen_write_mode_set(sctx, MODE_ORIGIN);
1.146 nicm 1717: screen_write_cursormove(sctx, 0, 0, 1);
1.61 nicm 1718: break;
1719: case 7: /* DECAWM */
1.144 nicm 1720: screen_write_mode_set(sctx, MODE_WRAP);
1.72 nicm 1721: break;
1722: case 12:
1.144 nicm 1723: screen_write_mode_set(sctx, MODE_BLINKING);
1.1 nicm 1724: break;
1725: case 25: /* TCEM */
1.144 nicm 1726: screen_write_mode_set(sctx, MODE_CURSOR);
1.1 nicm 1727: break;
1728: case 1000:
1.144 nicm 1729: screen_write_mode_clear(sctx, ALL_MOUSE_MODES);
1730: screen_write_mode_set(sctx, MODE_MOUSE_STANDARD);
1.32 nicm 1731: break;
1732: case 1002:
1.144 nicm 1733: screen_write_mode_clear(sctx, ALL_MOUSE_MODES);
1734: screen_write_mode_set(sctx, MODE_MOUSE_BUTTON);
1.109 nicm 1735: break;
1736: case 1003:
1.144 nicm 1737: screen_write_mode_clear(sctx, ALL_MOUSE_MODES);
1738: screen_write_mode_set(sctx, MODE_MOUSE_ALL);
1.62 nicm 1739: break;
1740: case 1004:
1.144 nicm 1741: if (sctx->s->mode & MODE_FOCUSON)
1.62 nicm 1742: break;
1.144 nicm 1743: screen_write_mode_set(sctx, MODE_FOCUSON);
1.69 nicm 1744: wp->flags |= PANE_FOCUSPUSH; /* force update */
1.96 nicm 1745: break;
1746: case 1005:
1.144 nicm 1747: screen_write_mode_set(sctx, MODE_MOUSE_UTF8);
1.60 nicm 1748: break;
1749: case 1006:
1.144 nicm 1750: screen_write_mode_set(sctx, MODE_MOUSE_SGR);
1.9 nicm 1751: break;
1.55 nicm 1752: case 47:
1753: case 1047:
1.69 nicm 1754: window_pane_alternate_on(wp, &ictx->cell.cell, 0);
1.55 nicm 1755: break;
1.9 nicm 1756: case 1049:
1.69 nicm 1757: window_pane_alternate_on(wp, &ictx->cell.cell, 1);
1.49 nicm 1758: break;
1759: case 2004:
1.144 nicm 1760: screen_write_mode_set(sctx, MODE_BRACKETPASTE);
1.1 nicm 1761: break;
1762: default:
1.28 nicm 1763: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1.1 nicm 1764: break;
1765: }
1.65 nicm 1766: }
1767: }
1768:
1769: /* Handle CSI window operations. */
1.104 nicm 1770: static void
1.65 nicm 1771: input_csi_dispatch_winops(struct input_ctx *ictx)
1772: {
1.144 nicm 1773: struct screen_write_ctx *sctx = &ictx->ctx;
1.65 nicm 1774: struct window_pane *wp = ictx->wp;
1775: int n, m;
1776:
1777: m = 0;
1778: while ((n = input_get(ictx, m, 0, -1)) != -1) {
1779: switch (n) {
1780: case 1:
1781: case 2:
1782: case 5:
1783: case 6:
1784: case 7:
1785: case 11:
1786: case 13:
1787: case 14:
1788: case 19:
1789: case 20:
1790: case 21:
1791: case 24:
1792: break;
1793: case 3:
1794: case 4:
1795: case 8:
1796: m++;
1797: if (input_get(ictx, m, 0, -1) == -1)
1798: return;
1799: /* FALLTHROUGH */
1800: case 9:
1801: case 10:
1.129 nicm 1802: m++;
1803: if (input_get(ictx, m, 0, -1) == -1)
1804: return;
1805: break;
1.65 nicm 1806: case 22:
1.129 nicm 1807: m++;
1808: switch (input_get(ictx, m, 0, -1)) {
1809: case -1:
1810: return;
1811: case 0:
1812: case 2:
1.144 nicm 1813: screen_push_title(sctx->s);
1.129 nicm 1814: break;
1815: }
1816: break;
1.65 nicm 1817: case 23:
1818: m++;
1.129 nicm 1819: switch (input_get(ictx, m, 0, -1)) {
1820: case -1:
1.65 nicm 1821: return;
1.129 nicm 1822: case 0:
1823: case 2:
1.144 nicm 1824: screen_pop_title(sctx->s);
1.129 nicm 1825: server_status_window(ictx->wp->window);
1826: break;
1827: }
1.65 nicm 1828: break;
1829: case 18:
1.76 nicm 1830: input_reply(ictx, "\033[8;%u;%ut", wp->sy, wp->sx);
1.65 nicm 1831: break;
1832: default:
1833: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1834: break;
1835: }
1836: m++;
1.1 nicm 1837: }
1838: }
1839:
1.131 nicm 1840: /* Helper for 256 colour SGR. */
1841: static int
1842: input_csi_dispatch_sgr_256_do(struct input_ctx *ictx, int fgbg, int c)
1.78 nicm 1843: {
1844: struct grid_cell *gc = &ictx->cell.cell;
1845:
1.131 nicm 1846: if (c == -1 || c > 255) {
1.102 nicm 1847: if (fgbg == 38)
1.78 nicm 1848: gc->fg = 8;
1.102 nicm 1849: else if (fgbg == 48)
1.78 nicm 1850: gc->bg = 8;
1851: } else {
1.102 nicm 1852: if (fgbg == 38)
1853: gc->fg = c | COLOUR_FLAG_256;
1854: else if (fgbg == 48)
1855: gc->bg = c | COLOUR_FLAG_256;
1.158 nicm 1856: else if (fgbg == 58)
1857: gc->us = c | COLOUR_FLAG_256;
1.78 nicm 1858: }
1.131 nicm 1859: return (1);
1.78 nicm 1860: }
1861:
1.131 nicm 1862: /* Handle CSI SGR for 256 colours. */
1.104 nicm 1863: static void
1.131 nicm 1864: input_csi_dispatch_sgr_256(struct input_ctx *ictx, int fgbg, u_int *i)
1865: {
1866: int c;
1867:
1868: c = input_get(ictx, (*i) + 1, 0, -1);
1869: if (input_csi_dispatch_sgr_256_do(ictx, fgbg, c))
1870: (*i)++;
1871: }
1872:
1873: /* Helper for RGB colour SGR. */
1874: static int
1875: input_csi_dispatch_sgr_rgb_do(struct input_ctx *ictx, int fgbg, int r, int g,
1876: int b)
1.78 nicm 1877: {
1878: struct grid_cell *gc = &ictx->cell.cell;
1879:
1880: if (r == -1 || r > 255)
1.131 nicm 1881: return (0);
1.78 nicm 1882: if (g == -1 || g > 255)
1.131 nicm 1883: return (0);
1.78 nicm 1884: if (b == -1 || b > 255)
1.131 nicm 1885: return (0);
1.78 nicm 1886:
1.102 nicm 1887: if (fgbg == 38)
1888: gc->fg = colour_join_rgb(r, g, b);
1889: else if (fgbg == 48)
1890: gc->bg = colour_join_rgb(r, g, b);
1.158 nicm 1891: else if (fgbg == 58)
1892: gc->us = colour_join_rgb(r, g, b);
1.131 nicm 1893: return (1);
1894: }
1895:
1896: /* Handle CSI SGR for RGB colours. */
1897: static void
1898: input_csi_dispatch_sgr_rgb(struct input_ctx *ictx, int fgbg, u_int *i)
1899: {
1900: int r, g, b;
1901:
1902: r = input_get(ictx, (*i) + 1, 0, -1);
1903: g = input_get(ictx, (*i) + 2, 0, -1);
1904: b = input_get(ictx, (*i) + 3, 0, -1);
1905: if (input_csi_dispatch_sgr_rgb_do(ictx, fgbg, r, g, b))
1906: (*i) += 3;
1907: }
1908:
1909: /* Handle CSI SGR with a ISO parameter. */
1910: static void
1911: input_csi_dispatch_sgr_colon(struct input_ctx *ictx, u_int i)
1912: {
1.137 nicm 1913: struct grid_cell *gc = &ictx->cell.cell;
1914: char *s = ictx->param_list[i].str, *copy, *ptr, *out;
1915: int p[8];
1916: u_int n;
1917: const char *errstr;
1.131 nicm 1918:
1919: for (n = 0; n < nitems(p); n++)
1920: p[n] = -1;
1921: n = 0;
1922:
1923: ptr = copy = xstrdup(s);
1924: while ((out = strsep(&ptr, ":")) != NULL) {
1.134 nicm 1925: if (*out != '\0') {
1926: p[n++] = strtonum(out, 0, INT_MAX, &errstr);
1927: if (errstr != NULL || n == nitems(p)) {
1928: free(copy);
1929: return;
1930: }
1.140 nicm 1931: } else
1932: n++;
1.131 nicm 1933: log_debug("%s: %u = %d", __func__, n - 1, p[n - 1]);
1934: }
1935: free(copy);
1936:
1.137 nicm 1937: if (n == 0)
1938: return;
1939: if (p[0] == 4) {
1940: if (n != 2)
1941: return;
1942: switch (p[1]) {
1943: case 0:
1944: gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
1945: break;
1946: case 1:
1947: gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
1948: gc->attr |= GRID_ATTR_UNDERSCORE;
1949: break;
1950: case 2:
1951: gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
1952: gc->attr |= GRID_ATTR_UNDERSCORE_2;
1953: break;
1954: case 3:
1955: gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
1956: gc->attr |= GRID_ATTR_UNDERSCORE_3;
1957: break;
1958: case 4:
1959: gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
1960: gc->attr |= GRID_ATTR_UNDERSCORE_4;
1961: break;
1962: case 5:
1963: gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
1964: gc->attr |= GRID_ATTR_UNDERSCORE_5;
1965: break;
1966: }
1967: return;
1968: }
1.158 nicm 1969: if (n < 2 || (p[0] != 38 && p[0] != 48 && p[0] != 58))
1.131 nicm 1970: return;
1.154 nicm 1971: switch (p[1]) {
1.131 nicm 1972: case 2:
1.154 nicm 1973: if (n < 3)
1974: break;
1975: if (n == 5)
1976: i = 2;
1977: else
1978: i = 3;
1979: if (n < i + 3)
1.131 nicm 1980: break;
1.154 nicm 1981: input_csi_dispatch_sgr_rgb_do(ictx, p[0], p[i], p[i + 1],
1982: p[i + 2]);
1.131 nicm 1983: break;
1984: case 5:
1.154 nicm 1985: if (n < 3)
1.131 nicm 1986: break;
1.154 nicm 1987: input_csi_dispatch_sgr_256_do(ictx, p[0], p[2]);
1.131 nicm 1988: break;
1989: }
1.78 nicm 1990: }
1991:
1.28 nicm 1992: /* Handle CSI SGR. */
1.104 nicm 1993: static void
1.28 nicm 1994: input_csi_dispatch_sgr(struct input_ctx *ictx)
1.1 nicm 1995: {
1.69 nicm 1996: struct grid_cell *gc = &ictx->cell.cell;
1.28 nicm 1997: u_int i;
1.78 nicm 1998: int n;
1.1 nicm 1999:
1.28 nicm 2000: if (ictx->param_list_len == 0) {
1.1 nicm 2001: memcpy(gc, &grid_default_cell, sizeof *gc);
2002: return;
2003: }
2004:
1.28 nicm 2005: for (i = 0; i < ictx->param_list_len; i++) {
1.131 nicm 2006: if (ictx->param_list[i].type == INPUT_STRING) {
2007: input_csi_dispatch_sgr_colon(ictx, i);
2008: continue;
2009: }
1.28 nicm 2010: n = input_get(ictx, i, 0, 0);
1.131 nicm 2011: if (n == -1)
2012: continue;
1.1 nicm 2013:
1.158 nicm 2014: if (n == 38 || n == 48 || n == 58) {
1.1 nicm 2015: i++;
1.78 nicm 2016: switch (input_get(ictx, i, 0, -1)) {
2017: case 2:
2018: input_csi_dispatch_sgr_rgb(ictx, n, &i);
2019: break;
2020: case 5:
2021: input_csi_dispatch_sgr_256(ictx, n, &i);
2022: break;
1.1 nicm 2023: }
2024: continue;
2025: }
2026:
1.28 nicm 2027: switch (n) {
1.1 nicm 2028: case 0:
2029: memcpy(gc, &grid_default_cell, sizeof *gc);
2030: break;
2031: case 1:
2032: gc->attr |= GRID_ATTR_BRIGHT;
2033: break;
2034: case 2:
2035: gc->attr |= GRID_ATTR_DIM;
2036: break;
2037: case 3:
2038: gc->attr |= GRID_ATTR_ITALICS;
2039: break;
2040: case 4:
1.137 nicm 2041: gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
1.1 nicm 2042: gc->attr |= GRID_ATTR_UNDERSCORE;
2043: break;
2044: case 5:
2045: gc->attr |= GRID_ATTR_BLINK;
2046: break;
2047: case 7:
2048: gc->attr |= GRID_ATTR_REVERSE;
2049: break;
2050: case 8:
2051: gc->attr |= GRID_ATTR_HIDDEN;
2052: break;
1.118 nicm 2053: case 9:
2054: gc->attr |= GRID_ATTR_STRIKETHROUGH;
2055: break;
1.1 nicm 2056: case 22:
2057: gc->attr &= ~(GRID_ATTR_BRIGHT|GRID_ATTR_DIM);
2058: break;
2059: case 23:
2060: gc->attr &= ~GRID_ATTR_ITALICS;
2061: break;
2062: case 24:
1.137 nicm 2063: gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
1.1 nicm 2064: break;
2065: case 25:
2066: gc->attr &= ~GRID_ATTR_BLINK;
2067: break;
2068: case 27:
2069: gc->attr &= ~GRID_ATTR_REVERSE;
1.117 nicm 2070: break;
2071: case 28:
2072: gc->attr &= ~GRID_ATTR_HIDDEN;
1.118 nicm 2073: break;
2074: case 29:
2075: gc->attr &= ~GRID_ATTR_STRIKETHROUGH;
1.1 nicm 2076: break;
2077: case 30:
2078: case 31:
2079: case 32:
2080: case 33:
2081: case 34:
2082: case 35:
2083: case 36:
2084: case 37:
1.28 nicm 2085: gc->fg = n - 30;
1.1 nicm 2086: break;
2087: case 39:
2088: gc->fg = 8;
2089: break;
2090: case 40:
2091: case 41:
2092: case 42:
2093: case 43:
2094: case 44:
2095: case 45:
2096: case 46:
2097: case 47:
1.28 nicm 2098: gc->bg = n - 40;
1.1 nicm 2099: break;
2100: case 49:
2101: gc->bg = 8;
1.153 nicm 2102: break;
2103: case 53:
2104: gc->attr |= GRID_ATTR_OVERLINE;
2105: break;
2106: case 55:
2107: gc->attr &= ~GRID_ATTR_OVERLINE;
1.158 nicm 2108: break;
2109: case 59:
2110: gc->us = 0;
1.20 nicm 2111: break;
2112: case 90:
2113: case 91:
2114: case 92:
2115: case 93:
2116: case 94:
2117: case 95:
2118: case 96:
2119: case 97:
1.28 nicm 2120: gc->fg = n;
1.20 nicm 2121: break;
2122: case 100:
2123: case 101:
2124: case 102:
2125: case 103:
2126: case 104:
2127: case 105:
2128: case 106:
2129: case 107:
1.47 nicm 2130: gc->bg = n - 10;
1.1 nicm 2131: break;
2132: }
2133: }
1.28 nicm 2134: }
2135:
1.138 nicm 2136: /* End of input with BEL. */
2137: static int
2138: input_end_bel(struct input_ctx *ictx)
2139: {
2140: log_debug("%s", __func__);
2141:
2142: ictx->input_end = INPUT_END_BEL;
2143:
2144: return (0);
2145: }
2146:
1.125 nicm 2147: /* DCS string started. */
2148: static void
2149: input_enter_dcs(struct input_ctx *ictx)
2150: {
2151: log_debug("%s", __func__);
2152:
2153: input_clear(ictx);
2154: input_start_timer(ictx);
1.127 nicm 2155: ictx->last = -1;
1.125 nicm 2156: }
2157:
1.37 nicm 2158: /* DCS terminator (ST) received. */
1.104 nicm 2159: static int
1.37 nicm 2160: input_dcs_dispatch(struct input_ctx *ictx)
1.28 nicm 2161: {
1.144 nicm 2162: struct screen_write_ctx *sctx = &ictx->ctx;
2163: u_char *buf = ictx->input_buf;
2164: size_t len = ictx->input_len;
2165: const char prefix[] = "tmux;";
2166: const u_int prefixlen = (sizeof prefix) - 1;
1.37 nicm 2167:
2168: if (ictx->flags & INPUT_DISCARD)
2169: return (0);
2170:
1.144 nicm 2171: log_debug("%s: \"%s\"", __func__, buf);
1.28 nicm 2172:
1.144 nicm 2173: if (len >= prefixlen && strncmp(buf, prefix, prefixlen) == 0)
2174: screen_write_rawstring(sctx, buf + prefixlen, len - prefixlen);
1.28 nicm 2175:
1.37 nicm 2176: return (0);
1.28 nicm 2177: }
2178:
2179: /* OSC string started. */
1.104 nicm 2180: static void
1.28 nicm 2181: input_enter_osc(struct input_ctx *ictx)
2182: {
2183: log_debug("%s", __func__);
2184:
1.35 nicm 2185: input_clear(ictx);
1.125 nicm 2186: input_start_timer(ictx);
1.127 nicm 2187: ictx->last = -1;
1.28 nicm 2188: }
2189:
2190: /* OSC terminator (ST) received. */
1.104 nicm 2191: static void
1.28 nicm 2192: input_exit_osc(struct input_ctx *ictx)
2193: {
1.144 nicm 2194: struct screen_write_ctx *sctx = &ictx->ctx;
2195: u_char *p = ictx->input_buf;
2196: u_int option;
1.38 nicm 2197:
1.28 nicm 2198: if (ictx->flags & INPUT_DISCARD)
2199: return;
1.38 nicm 2200: if (ictx->input_len < 1 || *p < '0' || *p > '9')
2201: return;
1.28 nicm 2202:
1.138 nicm 2203: log_debug("%s: \"%s\" (end %s)", __func__, p,
2204: ictx->input_end == INPUT_END_ST ? "ST" : "BEL");
1.28 nicm 2205:
1.38 nicm 2206: option = 0;
2207: while (*p >= '0' && *p <= '9')
2208: option = option * 10 + *p++ - '0';
2209: if (*p == ';')
2210: p++;
2211:
2212: switch (option) {
2213: case 0:
2214: case 2:
1.124 nicm 2215: if (utf8_isvalid(p)) {
1.144 nicm 2216: screen_set_title(sctx->s, p);
1.124 nicm 2217: server_status_window(ictx->wp->window);
2218: }
1.38 nicm 2219: break;
1.107 nicm 2220: case 4:
1.138 nicm 2221: input_osc_4(ictx, p);
1.165 nicm 2222: break;
2223: case 7:
2224: if (utf8_isvalid(p)) {
2225: screen_set_path(sctx->s, p);
2226: server_status_window(ictx->wp->window);
2227: }
1.107 nicm 2228: break;
1.122 nicm 2229: case 10:
1.138 nicm 2230: input_osc_10(ictx, p);
1.122 nicm 2231: break;
2232: case 11:
1.138 nicm 2233: input_osc_11(ictx, p);
1.108 nicm 2234: break;
1.38 nicm 2235: case 12:
1.124 nicm 2236: if (utf8_isvalid(p) && *p != '?') /* ? is colour request */
1.144 nicm 2237: screen_set_cursor_colour(sctx->s, p);
1.38 nicm 2238: break;
1.122 nicm 2239: case 52:
1.138 nicm 2240: input_osc_52(ictx, p);
1.122 nicm 2241: break;
1.107 nicm 2242: case 104:
1.138 nicm 2243: input_osc_104(ictx, p);
1.107 nicm 2244: break;
1.38 nicm 2245: case 112:
1.57 nicm 2246: if (*p == '\0') /* no arguments allowed */
1.144 nicm 2247: screen_set_cursor_colour(sctx->s, "");
1.38 nicm 2248: break;
2249: default:
2250: log_debug("%s: unknown '%u'", __func__, option);
2251: break;
2252: }
1.28 nicm 2253: }
2254:
2255: /* APC string started. */
1.104 nicm 2256: static void
1.28 nicm 2257: input_enter_apc(struct input_ctx *ictx)
2258: {
2259: log_debug("%s", __func__);
2260:
1.35 nicm 2261: input_clear(ictx);
1.125 nicm 2262: input_start_timer(ictx);
1.127 nicm 2263: ictx->last = -1;
1.28 nicm 2264: }
2265:
2266: /* APC terminator (ST) received. */
1.104 nicm 2267: static void
1.28 nicm 2268: input_exit_apc(struct input_ctx *ictx)
2269: {
1.144 nicm 2270: struct screen_write_ctx *sctx = &ictx->ctx;
2271:
1.28 nicm 2272: if (ictx->flags & INPUT_DISCARD)
2273: return;
2274: log_debug("%s: \"%s\"", __func__, ictx->input_buf);
2275:
1.124 nicm 2276: if (!utf8_isvalid(ictx->input_buf))
2277: return;
1.144 nicm 2278: screen_set_title(sctx->s, ictx->input_buf);
1.28 nicm 2279: server_status_window(ictx->wp->window);
2280: }
2281:
2282: /* Rename string started. */
1.104 nicm 2283: static void
1.28 nicm 2284: input_enter_rename(struct input_ctx *ictx)
2285: {
2286: log_debug("%s", __func__);
2287:
1.35 nicm 2288: input_clear(ictx);
1.125 nicm 2289: input_start_timer(ictx);
1.127 nicm 2290: ictx->last = -1;
1.28 nicm 2291: }
2292:
2293: /* Rename terminator (ST) received. */
1.104 nicm 2294: static void
1.28 nicm 2295: input_exit_rename(struct input_ctx *ictx)
2296: {
1.162 nicm 2297: struct window_pane *wp = ictx->wp;
2298: struct options_entry *oe;
2299:
1.28 nicm 2300: if (ictx->flags & INPUT_DISCARD)
1.44 nicm 2301: return;
1.157 nicm 2302: if (!options_get_number(ictx->wp->options, "allow-rename"))
1.28 nicm 2303: return;
2304: log_debug("%s: \"%s\"", __func__, ictx->input_buf);
2305:
1.124 nicm 2306: if (!utf8_isvalid(ictx->input_buf))
2307: return;
1.162 nicm 2308:
2309: if (ictx->input_len == 0) {
2310: oe = options_get(wp->window->options, "automatic-rename");
2311: if (oe != NULL)
2312: options_remove(oe);
2313: return;
2314: }
1.48 nicm 2315: window_set_name(ictx->wp->window, ictx->input_buf);
1.87 nicm 2316: options_set_number(ictx->wp->window->options, "automatic-rename", 0);
1.28 nicm 2317: server_status_window(ictx->wp->window);
2318: }
2319:
2320: /* Open UTF-8 character. */
1.104 nicm 2321: static int
1.130 nicm 2322: input_top_bit_set(struct input_ctx *ictx)
1.28 nicm 2323: {
1.144 nicm 2324: struct screen_write_ctx *sctx = &ictx->ctx;
1.90 nicm 2325: struct utf8_data *ud = &ictx->utf8data;
2326:
1.127 nicm 2327: ictx->last = -1;
1.28 nicm 2328:
1.130 nicm 2329: if (!ictx->utf8started) {
2330: if (utf8_open(ud, ictx->ch) != UTF8_MORE)
2331: return (0);
2332: ictx->utf8started = 1;
2333: return (0);
2334: }
1.28 nicm 2335:
1.130 nicm 2336: switch (utf8_append(ud, ictx->ch)) {
2337: case UTF8_MORE:
2338: return (0);
2339: case UTF8_ERROR:
2340: ictx->utf8started = 0;
1.101 nicm 2341: return (0);
1.130 nicm 2342: case UTF8_DONE:
2343: break;
1.101 nicm 2344: }
1.130 nicm 2345: ictx->utf8started = 0;
1.28 nicm 2346:
1.90 nicm 2347: log_debug("%s %hhu '%*s' (width %hhu)", __func__, ud->size,
2348: (int)ud->size, ud->data, ud->width);
1.28 nicm 2349:
1.90 nicm 2350: utf8_copy(&ictx->cell.cell.data, ud);
1.144 nicm 2351: screen_write_collect_add(sctx, &ictx->cell.cell);
1.28 nicm 2352:
2353: return (0);
1.107 nicm 2354: }
2355:
1.163 nicm 2356: /* Parse colour from OSC. */
2357: static int
2358: input_osc_parse_colour(const char *p, u_int *r, u_int *g, u_int *b)
2359: {
2360: u_int rsize, gsize, bsize;
2361: const char *cp, *s = p;
2362:
2363: if (sscanf(p, "rgb:%x/%x/%x", r, g, b) != 3)
2364: return (0);
2365: p += 4;
2366:
2367: cp = strchr(p, '/');
2368: rsize = cp - p;
2369: if (rsize == 1)
2370: (*r) = (*r) | ((*r) << 4);
2371: else if (rsize == 3)
2372: (*r) >>= 4;
2373: else if (rsize == 4)
2374: (*r) >>= 8;
2375: else if (rsize != 2)
2376: return (0);
2377:
2378: p = cp + 1;
2379: cp = strchr(p, '/');
2380: gsize = cp - p;
2381: if (gsize == 1)
2382: (*g) = (*g) | ((*g) << 4);
2383: else if (gsize == 3)
2384: (*g) >>= 4;
2385: else if (gsize == 4)
2386: (*g) >>= 8;
2387: else if (gsize != 2)
2388: return (0);
2389:
2390: bsize = strlen(cp + 1);
2391: if (bsize == 1)
2392: (*b) = (*b) | ((*b) << 4);
2393: else if (bsize == 3)
2394: (*b) >>= 4;
2395: else if (bsize == 4)
2396: (*b) >>= 8;
2397: else if (bsize != 2)
2398: return (0);
2399:
2400: log_debug("%s: %s = %02x%02x%02x", __func__, s, *r, *g, *b);
2401: return (1);
2402: }
2403:
1.107 nicm 2404: /* Handle the OSC 4 sequence for setting (multiple) palette entries. */
2405: static void
1.138 nicm 2406: input_osc_4(struct input_ctx *ictx, const char *p)
1.107 nicm 2407: {
1.138 nicm 2408: struct window_pane *wp = ictx->wp;
2409: char *copy, *s, *next = NULL;
1.144 nicm 2410: long idx;
1.138 nicm 2411: u_int r, g, b;
1.107 nicm 2412:
2413: copy = s = xstrdup(p);
2414: while (s != NULL && *s != '\0') {
2415: idx = strtol(s, &next, 10);
2416: if (*next++ != ';')
2417: goto bad;
2418: if (idx < 0 || idx >= 0x100)
2419: goto bad;
2420:
2421: s = strsep(&next, ";");
1.163 nicm 2422: if (!input_osc_parse_colour(s, &r, &g, &b)) {
1.107 nicm 2423: s = next;
2424: continue;
2425: }
2426:
2427: window_pane_set_palette(wp, idx, colour_join_rgb(r, g, b));
2428: s = next;
2429: }
2430:
2431: free(copy);
2432: return;
2433:
2434: bad:
2435: log_debug("bad OSC 4: %s", p);
2436: free(copy);
1.122 nicm 2437: }
2438:
1.136 nicm 2439: /* Handle the OSC 10 sequence for setting foreground colour. */
1.122 nicm 2440: static void
1.138 nicm 2441: input_osc_10(struct input_ctx *ictx, const char *p)
1.122 nicm 2442: {
1.138 nicm 2443: struct window_pane *wp = ictx->wp;
2444: u_int r, g, b;
1.156 nicm 2445: char tmp[16];
1.122 nicm 2446:
1.163 nicm 2447: if (strcmp(p, "?") == 0)
2448: return;
2449:
2450: if (!input_osc_parse_colour(p, &r, &g, &b))
2451: goto bad;
1.156 nicm 2452: xsnprintf(tmp, sizeof tmp, "fg=#%02x%02x%02x", r, g, b);
2453: options_set_style(wp->options, "window-style", 1, tmp);
2454: options_set_style(wp->options, "window-active-style", 1, tmp);
2455: wp->flags |= (PANE_REDRAW|PANE_STYLECHANGED);
1.122 nicm 2456:
2457: return;
2458:
2459: bad:
2460: log_debug("bad OSC 10: %s", p);
2461: }
2462:
2463: /* Handle the OSC 11 sequence for setting background colour. */
2464: static void
1.138 nicm 2465: input_osc_11(struct input_ctx *ictx, const char *p)
1.122 nicm 2466: {
1.138 nicm 2467: struct window_pane *wp = ictx->wp;
2468: u_int r, g, b;
1.156 nicm 2469: char tmp[16];
1.122 nicm 2470:
1.163 nicm 2471: if (strcmp(p, "?") == 0)
2472: return;
2473:
2474: if (!input_osc_parse_colour(p, &r, &g, &b))
1.122 nicm 2475: goto bad;
1.156 nicm 2476: xsnprintf(tmp, sizeof tmp, "bg=#%02x%02x%02x", r, g, b);
2477: options_set_style(wp->options, "window-style", 1, tmp);
2478: options_set_style(wp->options, "window-active-style", 1, tmp);
2479: wp->flags |= (PANE_REDRAW|PANE_STYLECHANGED);
1.122 nicm 2480:
2481: return;
2482:
2483: bad:
2484: log_debug("bad OSC 11: %s", p);
1.108 nicm 2485: }
2486:
2487: /* Handle the OSC 52 sequence for setting the clipboard. */
2488: static void
1.138 nicm 2489: input_osc_52(struct input_ctx *ictx, const char *p)
1.108 nicm 2490: {
1.138 nicm 2491: struct window_pane *wp = ictx->wp;
1.108 nicm 2492: char *end;
1.138 nicm 2493: const char *buf;
1.108 nicm 2494: size_t len;
2495: u_char *out;
1.123 nicm 2496: int outlen, state;
1.108 nicm 2497: struct screen_write_ctx ctx;
1.138 nicm 2498: struct paste_buffer *pb;
1.108 nicm 2499:
1.123 nicm 2500: state = options_get_number(global_options, "set-clipboard");
2501: if (state != 2)
2502: return;
2503:
1.108 nicm 2504: if ((end = strchr(p, ';')) == NULL)
2505: return;
2506: end++;
2507: if (*end == '\0')
2508: return;
1.138 nicm 2509: log_debug("%s: %s", __func__, end);
2510:
2511: if (strcmp(end, "?") == 0) {
2512: if ((pb = paste_get_top(NULL)) != NULL) {
2513: buf = paste_buffer_data(pb, &len);
2514: outlen = 4 * ((len + 2) / 3) + 1;
2515: out = xmalloc(outlen);
2516: if ((outlen = b64_ntop(buf, len, out, outlen)) == -1) {
2517: free(out);
2518: return;
2519: }
2520: } else {
2521: outlen = 0;
2522: out = NULL;
2523: }
2524: bufferevent_write(wp->event, "\033]52;;", 6);
2525: if (outlen != 0)
2526: bufferevent_write(wp->event, out, outlen);
2527: if (ictx->input_end == INPUT_END_BEL)
2528: bufferevent_write(wp->event, "\007", 1);
2529: else
2530: bufferevent_write(wp->event, "\033\\", 2);
2531: free(out);
2532: return;
2533: }
1.108 nicm 2534:
2535: len = (strlen(end) / 4) * 3;
2536: if (len == 0)
2537: return;
2538:
2539: out = xmalloc(len);
2540: if ((outlen = b64_pton(end, out, len)) == -1) {
2541: free(out);
2542: return;
2543: }
2544:
1.123 nicm 2545: screen_write_start(&ctx, wp, NULL);
2546: screen_write_setselection(&ctx, out, outlen);
2547: screen_write_stop(&ctx);
1.126 nicm 2548: notify_pane("pane-set-clipboard", wp);
1.123 nicm 2549:
1.150 nicm 2550: paste_add(NULL, out, outlen);
1.107 nicm 2551: }
2552:
2553: /* Handle the OSC 104 sequence for unsetting (multiple) palette entries. */
2554: static void
1.138 nicm 2555: input_osc_104(struct input_ctx *ictx, const char *p)
1.107 nicm 2556: {
1.138 nicm 2557: struct window_pane *wp = ictx->wp;
2558: char *copy, *s;
1.144 nicm 2559: long idx;
1.107 nicm 2560:
2561: if (*p == '\0') {
2562: window_pane_reset_palette(wp);
2563: return;
2564: }
2565:
2566: copy = s = xstrdup(p);
2567: while (*s != '\0') {
2568: idx = strtol(s, &s, 10);
2569: if (*s != '\0' && *s != ';')
2570: goto bad;
2571: if (idx < 0 || idx >= 0x100)
2572: goto bad;
2573:
2574: window_pane_unset_palette(wp, idx);
2575: if (*s == ';')
2576: s++;
2577: }
2578: free(copy);
2579: return;
2580:
2581: bad:
2582: log_debug("bad OSC 104: %s", p);
2583: free(copy);
1.1 nicm 2584: }