Annotation of src/usr.bin/tmux/input.c, Revision 1.53
1.53 ! nicm 1: /* $OpenBSD: input.c,v 1.52 2012/04/25 21:12:49 nicm Exp $ */
1.1 nicm 2:
3: /*
4: * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
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:
21: #include <stdlib.h>
22: #include <string.h>
23:
24: #include "tmux.h"
25:
1.28 nicm 26: /*
27: * Based on the description by Paul Williams at:
28: *
29: * http://vt100.net/emu/dec_ansi_parser
30: *
31: * With the following changes:
32: *
33: * - 7-bit only.
34: *
35: * - Support for UTF-8.
36: *
37: * - OSC (but not APC) may be terminated by \007 as well as ST.
38: *
39: * - A state for APC similar to OSC. Some terminals appear to use this to set
40: * the title.
41: *
42: * - A state for the screen \033k...\033\\ sequence to rename a window. This is
43: * pretty stupid but not supporting it is more trouble than it is worth.
1.37 nicm 44: *
45: * - Special handling for ESC inside a DCS to allow arbitrary byte sequences to
46: * be passed to the underlying teminal(s).
1.28 nicm 47: */
48:
49: /* Helper functions. */
1.52 nicm 50: struct input_transition;
1.28 nicm 51: int input_split(struct input_ctx *);
52: int input_get(struct input_ctx *, u_int, int, int);
53: void input_reply(struct input_ctx *, const char *, ...);
1.52 nicm 54: void input_set_state(struct window_pane *, const struct input_transition *);
1.28 nicm 55:
56: /* Transition entry/exit handlers. */
57: void input_clear(struct input_ctx *);
58: void input_enter_osc(struct input_ctx *);
59: void input_exit_osc(struct input_ctx *);
60: void input_enter_apc(struct input_ctx *);
61: void input_exit_apc(struct input_ctx *);
62: void input_enter_rename(struct input_ctx *);
63: void input_exit_rename(struct input_ctx *);
64:
65: /* Input state handlers. */
66: int input_print(struct input_ctx *);
67: int input_intermediate(struct input_ctx *);
68: int input_parameter(struct input_ctx *);
69: int input_input(struct input_ctx *);
70: int input_c0_dispatch(struct input_ctx *);
71: int input_esc_dispatch(struct input_ctx *);
72: int input_csi_dispatch(struct input_ctx *);
73: void input_csi_dispatch_sgr(struct input_ctx *);
1.37 nicm 74: int input_dcs_dispatch(struct input_ctx *);
1.28 nicm 75: int input_utf8_open(struct input_ctx *);
76: int input_utf8_add(struct input_ctx *);
77: int input_utf8_close(struct input_ctx *);
78:
79: /* Command table comparison function. */
80: int input_table_compare(const void *, const void *);
81:
82: /* Command table entry. */
83: struct input_table_entry {
84: int ch;
85: const char *interm;
86: int type;
1.1 nicm 87: };
88:
1.28 nicm 89: /* Escape commands. */
90: enum input_esc_type {
91: INPUT_ESC_DECALN,
92: INPUT_ESC_DECKPAM,
93: INPUT_ESC_DECKPNM,
94: INPUT_ESC_DECRC,
95: INPUT_ESC_DECSC,
96: INPUT_ESC_HTS,
97: INPUT_ESC_IND,
98: INPUT_ESC_NEL,
99: INPUT_ESC_RI,
100: INPUT_ESC_RIS,
101: INPUT_ESC_SCSOFF_G0,
102: INPUT_ESC_SCSON_G0,
103: };
1.1 nicm 104:
1.28 nicm 105: /* Escape command table. */
106: const struct input_table_entry input_esc_table[] = {
107: { '0', "(", INPUT_ESC_SCSOFF_G0 },
108: { '7', "", INPUT_ESC_DECSC },
109: { '8', "", INPUT_ESC_DECRC },
110: { '8', "#", INPUT_ESC_DECALN },
111: { '=', "", INPUT_ESC_DECKPAM },
112: { '>', "", INPUT_ESC_DECKPNM },
113: { 'B', "(", INPUT_ESC_SCSON_G0 },
114: { 'D', "", INPUT_ESC_IND },
115: { 'E', "", INPUT_ESC_NEL },
116: { 'H', "", INPUT_ESC_HTS },
117: { 'M', "", INPUT_ESC_RI },
118: { 'c', "", INPUT_ESC_RIS },
119: };
1.1 nicm 120:
1.28 nicm 121: /* Control (CSI) commands. */
122: enum input_csi_type {
123: INPUT_CSI_CBT,
1.43 nicm 124: INPUT_CSI_CNL,
125: INPUT_CSI_CPL,
1.28 nicm 126: INPUT_CSI_CUB,
127: INPUT_CSI_CUD,
128: INPUT_CSI_CUF,
129: INPUT_CSI_CUP,
130: INPUT_CSI_CUU,
131: INPUT_CSI_DA,
1.50 nicm 132: INPUT_CSI_DA_TWO,
1.28 nicm 133: INPUT_CSI_DCH,
1.39 nicm 134: INPUT_CSI_DECSCUSR,
1.28 nicm 135: INPUT_CSI_DECSTBM,
136: INPUT_CSI_DL,
137: INPUT_CSI_DSR,
138: INPUT_CSI_ED,
139: INPUT_CSI_EL,
140: INPUT_CSI_HPA,
141: INPUT_CSI_ICH,
142: INPUT_CSI_IL,
1.42 nicm 143: INPUT_CSI_RCP,
1.28 nicm 144: INPUT_CSI_RM,
145: INPUT_CSI_RM_PRIVATE,
1.42 nicm 146: INPUT_CSI_SCP,
1.28 nicm 147: INPUT_CSI_SGR,
148: INPUT_CSI_SM,
149: INPUT_CSI_SM_PRIVATE,
150: INPUT_CSI_TBC,
151: INPUT_CSI_VPA,
152: };
1.1 nicm 153:
1.28 nicm 154: /* Control (CSI) command table. */
155: const struct input_table_entry input_csi_table[] = {
156: { '@', "", INPUT_CSI_ICH },
157: { 'A', "", INPUT_CSI_CUU },
158: { 'B', "", INPUT_CSI_CUD },
159: { 'C', "", INPUT_CSI_CUF },
160: { 'D', "", INPUT_CSI_CUB },
1.43 nicm 161: { 'E', "", INPUT_CSI_CNL },
162: { 'F', "", INPUT_CSI_CPL },
1.28 nicm 163: { 'G', "", INPUT_CSI_HPA },
164: { 'H', "", INPUT_CSI_CUP },
165: { 'J', "", INPUT_CSI_ED },
166: { 'K', "", INPUT_CSI_EL },
167: { 'L', "", INPUT_CSI_IL },
168: { 'M', "", INPUT_CSI_DL },
169: { 'P', "", INPUT_CSI_DCH },
170: { 'Z', "", INPUT_CSI_CBT },
171: { 'c', "", INPUT_CSI_DA },
1.50 nicm 172: { 'c', ">", INPUT_CSI_DA_TWO },
1.28 nicm 173: { 'd', "", INPUT_CSI_VPA },
174: { 'f', "", INPUT_CSI_CUP },
175: { 'g', "", INPUT_CSI_TBC },
176: { 'h', "", INPUT_CSI_SM },
177: { 'h', "?", INPUT_CSI_SM_PRIVATE },
178: { 'l', "", INPUT_CSI_RM },
179: { 'l', "?", INPUT_CSI_RM_PRIVATE },
180: { 'm', "", INPUT_CSI_SGR },
181: { 'n', "", INPUT_CSI_DSR },
1.39 nicm 182: { 'q', " ", INPUT_CSI_DECSCUSR },
1.28 nicm 183: { 'r', "", INPUT_CSI_DECSTBM },
1.42 nicm 184: { 's', "", INPUT_CSI_SCP },
185: { 'u', "", INPUT_CSI_RCP },
1.28 nicm 186: };
1.1 nicm 187:
1.28 nicm 188: /* Input transition. */
189: struct input_transition {
190: int first;
191: int last;
1.1 nicm 192:
1.28 nicm 193: int (*handler)(struct input_ctx *);
194: const struct input_state *state;
195: };
1.1 nicm 196:
1.28 nicm 197: /* Input state. */
198: struct input_state {
199: const char *name;
200: void (*enter)(struct input_ctx *);
201: void (*exit)(struct input_ctx *);
202: const struct input_transition *transitions;
203: };
1.1 nicm 204:
1.28 nicm 205: /* State transitions available from all states. */
206: #define INPUT_STATE_ANYWHERE \
207: { 0x18, 0x18, input_c0_dispatch, &input_state_ground }, \
208: { 0x1a, 0x1a, input_c0_dispatch, &input_state_ground }, \
209: { 0x1b, 0x1b, NULL, &input_state_esc_enter }
210:
211: /* Forward declarations of state tables. */
212: const struct input_transition input_state_ground_table[];
213: const struct input_transition input_state_esc_enter_table[];
214: const struct input_transition input_state_esc_intermediate_table[];
215: const struct input_transition input_state_csi_enter_table[];
216: const struct input_transition input_state_csi_parameter_table[];
217: const struct input_transition input_state_csi_intermediate_table[];
218: const struct input_transition input_state_csi_ignore_table[];
219: const struct input_transition input_state_dcs_enter_table[];
220: const struct input_transition input_state_dcs_parameter_table[];
221: const struct input_transition input_state_dcs_intermediate_table[];
222: const struct input_transition input_state_dcs_handler_table[];
1.37 nicm 223: const struct input_transition input_state_dcs_escape_table[];
1.28 nicm 224: const struct input_transition input_state_dcs_ignore_table[];
225: const struct input_transition input_state_osc_string_table[];
226: const struct input_transition input_state_apc_string_table[];
227: const struct input_transition input_state_rename_string_table[];
228: const struct input_transition input_state_consume_st_table[];
229: const struct input_transition input_state_utf8_three_table[];
230: const struct input_transition input_state_utf8_two_table[];
231: const struct input_transition input_state_utf8_one_table[];
232:
233: /* ground state definition. */
234: const struct input_state input_state_ground = {
235: "ground",
236: NULL, NULL,
237: input_state_ground_table
238: };
1.1 nicm 239:
1.28 nicm 240: /* esc_enter state definition. */
241: const struct input_state input_state_esc_enter = {
242: "esc_enter",
243: input_clear, NULL,
244: input_state_esc_enter_table
245: };
1.1 nicm 246:
1.28 nicm 247: /* esc_intermediate state definition. */
248: const struct input_state input_state_esc_intermediate = {
249: "esc_intermediate",
250: NULL, NULL,
251: input_state_esc_intermediate_table
252: };
1.1 nicm 253:
1.28 nicm 254: /* csi_enter state definition. */
255: const struct input_state input_state_csi_enter = {
256: "csi_enter",
257: input_clear, NULL,
258: input_state_csi_enter_table
259: };
1.1 nicm 260:
1.28 nicm 261: /* csi_parameter state definition. */
262: const struct input_state input_state_csi_parameter = {
263: "csi_parameter",
264: NULL, NULL,
265: input_state_csi_parameter_table
266: };
1.1 nicm 267:
1.28 nicm 268: /* csi_intermediate state definition. */
269: const struct input_state input_state_csi_intermediate = {
270: "csi_intermediate",
271: NULL, NULL,
272: input_state_csi_intermediate_table
273: };
1.1 nicm 274:
1.28 nicm 275: /* csi_ignore state definition. */
276: const struct input_state input_state_csi_ignore = {
277: "csi_ignore",
278: NULL, NULL,
279: input_state_csi_ignore_table
280: };
1.1 nicm 281:
1.28 nicm 282: /* dcs_enter state definition. */
283: const struct input_state input_state_dcs_enter = {
284: "dcs_enter",
285: input_clear, NULL,
286: input_state_dcs_enter_table
287: };
1.1 nicm 288:
1.28 nicm 289: /* dcs_parameter state definition. */
290: const struct input_state input_state_dcs_parameter = {
291: "dcs_parameter",
292: NULL, NULL,
293: input_state_dcs_parameter_table
294: };
1.1 nicm 295:
1.28 nicm 296: /* dcs_intermediate state definition. */
297: const struct input_state input_state_dcs_intermediate = {
298: "dcs_intermediate",
299: NULL, NULL,
300: input_state_dcs_intermediate_table
301: };
1.1 nicm 302:
1.28 nicm 303: /* dcs_handler state definition. */
304: const struct input_state input_state_dcs_handler = {
305: "dcs_handler",
1.37 nicm 306: NULL, NULL,
1.28 nicm 307: input_state_dcs_handler_table
308: };
1.1 nicm 309:
1.37 nicm 310: /* dcs_escape state definition. */
311: const struct input_state input_state_dcs_escape = {
312: "dcs_escape",
313: NULL, NULL,
314: input_state_dcs_escape_table
315: };
316:
1.28 nicm 317: /* dcs_ignore state definition. */
318: const struct input_state input_state_dcs_ignore = {
319: "dcs_ignore",
320: NULL, NULL,
321: input_state_dcs_ignore_table
322: };
1.1 nicm 323:
1.28 nicm 324: /* osc_string state definition. */
325: const struct input_state input_state_osc_string = {
326: "osc_string",
327: input_enter_osc, input_exit_osc,
328: input_state_osc_string_table
329: };
1.1 nicm 330:
1.28 nicm 331: /* apc_string state definition. */
332: const struct input_state input_state_apc_string = {
333: "apc_string",
334: input_enter_apc, input_exit_apc,
335: input_state_apc_string_table
336: };
1.1 nicm 337:
1.28 nicm 338: /* rename_string state definition. */
339: const struct input_state input_state_rename_string = {
340: "rename_string",
341: input_enter_rename, input_exit_rename,
342: input_state_rename_string_table
343: };
1.1 nicm 344:
1.28 nicm 345: /* consume_st state definition. */
346: const struct input_state input_state_consume_st = {
347: "consume_st",
348: NULL, NULL,
349: input_state_consume_st_table
350: };
1.1 nicm 351:
1.28 nicm 352: /* utf8_three state definition. */
353: const struct input_state input_state_utf8_three = {
354: "utf8_three",
355: NULL, NULL,
356: input_state_utf8_three_table
357: };
1.1 nicm 358:
1.28 nicm 359: /* utf8_two state definition. */
360: const struct input_state input_state_utf8_two = {
361: "utf8_two",
362: NULL, NULL,
363: input_state_utf8_two_table
364: };
1.1 nicm 365:
1.28 nicm 366: /* utf8_one state definition. */
367: const struct input_state input_state_utf8_one = {
368: "utf8_one",
369: NULL, NULL,
370: input_state_utf8_one_table
371: };
1.1 nicm 372:
1.28 nicm 373: /* ground state table. */
374: const struct input_transition input_state_ground_table[] = {
375: INPUT_STATE_ANYWHERE,
376:
377: { 0x00, 0x17, input_c0_dispatch, NULL },
378: { 0x19, 0x19, input_c0_dispatch, NULL },
379: { 0x1c, 0x1f, input_c0_dispatch, NULL },
380: { 0x20, 0x7e, input_print, NULL },
381: { 0x7f, 0x7f, NULL, NULL },
382: { 0x80, 0xc1, input_print, NULL },
383: { 0xc2, 0xdf, input_utf8_open, &input_state_utf8_one },
384: { 0xe0, 0xef, input_utf8_open, &input_state_utf8_two },
385: { 0xf0, 0xf4, input_utf8_open, &input_state_utf8_three },
386: { 0xf5, 0xff, input_print, NULL },
1.1 nicm 387:
1.28 nicm 388: { -1, -1, NULL, NULL }
389: };
1.13 nicm 390:
1.28 nicm 391: /* esc_enter state table. */
392: const struct input_transition input_state_esc_enter_table[] = {
393: INPUT_STATE_ANYWHERE,
394:
395: { 0x00, 0x17, input_c0_dispatch, NULL },
396: { 0x19, 0x19, input_c0_dispatch, NULL },
397: { 0x1c, 0x1f, input_c0_dispatch, NULL },
398: { 0x20, 0x2f, input_intermediate, &input_state_esc_intermediate },
399: { 0x30, 0x4f, input_esc_dispatch, &input_state_ground },
400: { 0x50, 0x50, NULL, &input_state_dcs_enter },
401: { 0x51, 0x57, input_esc_dispatch, &input_state_ground },
402: { 0x58, 0x58, NULL, &input_state_consume_st },
403: { 0x59, 0x59, input_esc_dispatch, &input_state_ground },
404: { 0x5a, 0x5a, input_esc_dispatch, &input_state_ground },
405: { 0x5b, 0x5b, NULL, &input_state_csi_enter },
406: { 0x5c, 0x5c, input_esc_dispatch, &input_state_ground },
407: { 0x5d, 0x5d, NULL, &input_state_osc_string },
408: { 0x5e, 0x5e, NULL, &input_state_consume_st },
409: { 0x5f, 0x5f, NULL, &input_state_apc_string },
410: { 0x60, 0x6a, input_esc_dispatch, &input_state_ground },
411: { 0x6b, 0x6b, NULL, &input_state_rename_string },
1.29 nicm 412: { 0x6c, 0x7e, input_esc_dispatch, &input_state_ground },
1.28 nicm 413: { 0x7f, 0xff, NULL, NULL },
1.1 nicm 414:
1.28 nicm 415: { -1, -1, NULL, NULL }
416: };
1.1 nicm 417:
1.28 nicm 418: /* esc_interm state table. */
419: const struct input_transition input_state_esc_intermediate_table[] = {
420: INPUT_STATE_ANYWHERE,
421:
422: { 0x00, 0x17, input_c0_dispatch, NULL },
423: { 0x19, 0x19, input_c0_dispatch, NULL },
424: { 0x1c, 0x1f, input_c0_dispatch, NULL },
425: { 0x20, 0x2f, input_intermediate, NULL },
426: { 0x30, 0x7e, input_esc_dispatch, &input_state_ground },
427: { 0x7f, 0xff, NULL, NULL },
1.1 nicm 428:
1.28 nicm 429: { -1, -1, NULL, NULL }
430: };
1.1 nicm 431:
1.28 nicm 432: /* csi_enter state table. */
433: const struct input_transition input_state_csi_enter_table[] = {
434: INPUT_STATE_ANYWHERE,
435:
436: { 0x00, 0x17, input_c0_dispatch, NULL },
437: { 0x19, 0x19, input_c0_dispatch, NULL },
438: { 0x1c, 0x1f, input_c0_dispatch, NULL },
439: { 0x20, 0x2f, input_intermediate, &input_state_csi_intermediate },
440: { 0x30, 0x39, input_parameter, &input_state_csi_parameter },
441: { 0x3a, 0x3a, NULL, &input_state_csi_ignore },
442: { 0x3b, 0x3b, input_parameter, &input_state_csi_parameter },
443: { 0x3c, 0x3f, input_intermediate, &input_state_csi_parameter },
444: { 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
445: { 0x7f, 0xff, NULL, NULL },
1.1 nicm 446:
1.28 nicm 447: { -1, -1, NULL, NULL }
448: };
1.1 nicm 449:
1.28 nicm 450: /* csi_parameter state table. */
451: const struct input_transition input_state_csi_parameter_table[] = {
452: INPUT_STATE_ANYWHERE,
453:
454: { 0x00, 0x17, input_c0_dispatch, NULL },
455: { 0x19, 0x19, input_c0_dispatch, NULL },
456: { 0x1c, 0x1f, input_c0_dispatch, NULL },
457: { 0x20, 0x2f, input_intermediate, &input_state_csi_intermediate },
458: { 0x30, 0x39, input_parameter, NULL },
459: { 0x3a, 0x3a, NULL, &input_state_csi_ignore },
460: { 0x3b, 0x3b, input_parameter, NULL },
461: { 0x3c, 0x3f, NULL, &input_state_csi_ignore },
462: { 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
463: { 0x7f, 0xff, NULL, NULL },
1.1 nicm 464:
1.28 nicm 465: { -1, -1, NULL, NULL }
466: };
1.1 nicm 467:
1.28 nicm 468: /* csi_intermediate state table. */
469: const struct input_transition input_state_csi_intermediate_table[] = {
470: INPUT_STATE_ANYWHERE,
471:
472: { 0x00, 0x17, input_c0_dispatch, NULL },
473: { 0x19, 0x19, input_c0_dispatch, NULL },
474: { 0x1c, 0x1f, input_c0_dispatch, NULL },
475: { 0x20, 0x2f, input_intermediate, NULL },
476: { 0x30, 0x3f, NULL, &input_state_csi_ignore },
477: { 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
478: { 0x7f, 0xff, NULL, NULL },
1.1 nicm 479:
1.28 nicm 480: { -1, -1, NULL, NULL }
481: };
1.1 nicm 482:
1.28 nicm 483: /* csi_ignore state table. */
484: const struct input_transition input_state_csi_ignore_table[] = {
485: INPUT_STATE_ANYWHERE,
486:
487: { 0x00, 0x17, input_c0_dispatch, NULL },
488: { 0x19, 0x19, input_c0_dispatch, NULL },
489: { 0x1c, 0x1f, input_c0_dispatch, NULL },
490: { 0x20, 0x3f, NULL, NULL },
491: { 0x40, 0x7e, NULL, &input_state_ground },
492: { 0x7f, 0xff, NULL, NULL },
1.1 nicm 493:
1.28 nicm 494: { -1, -1, NULL, NULL }
495: };
1.1 nicm 496:
1.28 nicm 497: /* dcs_enter state table. */
498: const struct input_transition input_state_dcs_enter_table[] = {
499: INPUT_STATE_ANYWHERE,
500:
501: { 0x00, 0x17, NULL, NULL },
502: { 0x19, 0x19, NULL, NULL },
503: { 0x1c, 0x1f, NULL, NULL },
504: { 0x20, 0x2f, input_intermediate, &input_state_dcs_intermediate },
505: { 0x30, 0x39, input_parameter, &input_state_dcs_parameter },
506: { 0x3a, 0x3a, NULL, &input_state_dcs_ignore },
507: { 0x3b, 0x3b, input_parameter, &input_state_dcs_parameter },
508: { 0x3c, 0x3f, input_intermediate, &input_state_dcs_parameter },
1.37 nicm 509: { 0x40, 0x7e, input_input, &input_state_dcs_handler },
1.28 nicm 510: { 0x7f, 0xff, NULL, NULL },
1.1 nicm 511:
1.28 nicm 512: { -1, -1, NULL, NULL }
513: };
1.1 nicm 514:
1.28 nicm 515: /* dcs_parameter state table. */
516: const struct input_transition input_state_dcs_parameter_table[] = {
517: INPUT_STATE_ANYWHERE,
518:
519: { 0x00, 0x17, NULL, NULL },
520: { 0x19, 0x19, NULL, NULL },
521: { 0x1c, 0x1f, NULL, NULL },
522: { 0x20, 0x2f, input_intermediate, &input_state_dcs_intermediate },
523: { 0x30, 0x39, input_parameter, NULL },
524: { 0x3a, 0x3a, NULL, &input_state_dcs_ignore },
525: { 0x3b, 0x3b, input_parameter, NULL },
526: { 0x3c, 0x3f, NULL, &input_state_dcs_ignore },
1.37 nicm 527: { 0x40, 0x7e, input_input, &input_state_dcs_handler },
1.28 nicm 528: { 0x7f, 0xff, NULL, NULL },
1.1 nicm 529:
1.28 nicm 530: { -1, -1, NULL, NULL }
531: };
1.1 nicm 532:
1.28 nicm 533: /* dcs_interm state table. */
534: const struct input_transition input_state_dcs_intermediate_table[] = {
535: INPUT_STATE_ANYWHERE,
536:
537: { 0x00, 0x17, NULL, NULL },
538: { 0x19, 0x19, NULL, NULL },
539: { 0x1c, 0x1f, NULL, NULL },
540: { 0x20, 0x2f, input_intermediate, NULL },
541: { 0x30, 0x3f, NULL, &input_state_dcs_ignore },
1.37 nicm 542: { 0x40, 0x7e, input_input, &input_state_dcs_handler },
1.28 nicm 543: { 0x7f, 0xff, NULL, NULL },
1.1 nicm 544:
1.28 nicm 545: { -1, -1, NULL, NULL }
546: };
1.1 nicm 547:
1.28 nicm 548: /* dcs_handler state table. */
549: const struct input_transition input_state_dcs_handler_table[] = {
1.37 nicm 550: /* No INPUT_STATE_ANYWHERE */
551:
552: { 0x00, 0x1a, input_input, NULL },
553: { 0x1b, 0x1b, NULL, &input_state_dcs_escape },
554: { 0x1c, 0xff, input_input, NULL },
555:
556: { -1, -1, NULL, NULL }
557: };
558:
559: /* dcs_escape state table. */
560: const struct input_transition input_state_dcs_escape_table[] = {
561: /* No INPUT_STATE_ANYWHERE */
1.28 nicm 562:
1.37 nicm 563: { 0x00, 0x5b, input_input, &input_state_dcs_handler },
564: { 0x5c, 0x5c, input_dcs_dispatch, &input_state_ground },
565: { 0x5d, 0xff, input_input, &input_state_dcs_handler },
1.1 nicm 566:
1.28 nicm 567: { -1, -1, NULL, NULL }
568: };
1.1 nicm 569:
1.40 nicm 570: /* dcs_ignore state table. */
1.28 nicm 571: const struct input_transition input_state_dcs_ignore_table[] = {
572: INPUT_STATE_ANYWHERE,
573:
574: { 0x00, 0x17, NULL, NULL },
575: { 0x19, 0x19, NULL, NULL },
576: { 0x1c, 0x1f, NULL, NULL },
577: { 0x20, 0xff, NULL, NULL },
1.1 nicm 578:
1.28 nicm 579: { -1, -1, NULL, NULL }
580: };
1.1 nicm 581:
1.28 nicm 582: /* osc_string state table. */
583: const struct input_transition input_state_osc_string_table[] = {
584: INPUT_STATE_ANYWHERE,
585:
586: { 0x00, 0x06, NULL, NULL },
587: { 0x07, 0x07, NULL, &input_state_ground },
588: { 0x08, 0x17, NULL, NULL },
589: { 0x19, 0x19, NULL, NULL },
590: { 0x1c, 0x1f, NULL, NULL },
591: { 0x20, 0xff, input_input, NULL },
1.1 nicm 592:
1.28 nicm 593: { -1, -1, NULL, NULL }
594: };
1.1 nicm 595:
1.28 nicm 596: /* apc_string state table. */
597: const struct input_transition input_state_apc_string_table[] = {
598: INPUT_STATE_ANYWHERE,
599:
600: { 0x00, 0x17, NULL, NULL },
601: { 0x19, 0x19, NULL, NULL },
602: { 0x1c, 0x1f, NULL, NULL },
603: { 0x20, 0xff, input_input, NULL },
1.1 nicm 604:
1.28 nicm 605: { -1, -1, NULL, NULL }
606: };
1.1 nicm 607:
1.28 nicm 608: /* rename_string state table. */
609: const struct input_transition input_state_rename_string_table[] = {
610: INPUT_STATE_ANYWHERE,
611:
612: { 0x00, 0x17, NULL, NULL },
613: { 0x19, 0x19, NULL, NULL },
614: { 0x1c, 0x1f, NULL, NULL },
615: { 0x20, 0xff, input_input, NULL },
1.1 nicm 616:
1.28 nicm 617: { -1, -1, NULL, NULL }
618: };
1.1 nicm 619:
1.28 nicm 620: /* consume_st state table. */
621: const struct input_transition input_state_consume_st_table[] = {
622: INPUT_STATE_ANYWHERE,
623:
624: { 0x00, 0x17, NULL, NULL },
625: { 0x19, 0x19, NULL, NULL },
626: { 0x1c, 0x1f, NULL, NULL },
627: { 0x20, 0xff, NULL, NULL },
1.6 nicm 628:
1.28 nicm 629: { -1, -1, NULL, NULL }
630: };
1.6 nicm 631:
1.28 nicm 632: /* utf8_three state table. */
633: const struct input_transition input_state_utf8_three_table[] = {
634: /* No INPUT_STATE_ANYWHERE */
635:
636: { 0x00, 0x7f, NULL, &input_state_ground },
637: { 0x80, 0xbf, input_utf8_add, &input_state_utf8_two },
638: { 0xc0, 0xff, NULL, &input_state_ground },
1.4 nicm 639:
1.28 nicm 640: { -1, -1, NULL, NULL }
641: };
1.1 nicm 642:
1.28 nicm 643: /* utf8_two state table. */
644: const struct input_transition input_state_utf8_two_table[] = {
645: /* No INPUT_STATE_ANYWHERE */
646:
647: { 0x00, 0x7f, NULL, &input_state_ground },
648: { 0x80, 0xbf, input_utf8_add, &input_state_utf8_one },
649: { 0xc0, 0xff, NULL, &input_state_ground },
1.1 nicm 650:
1.28 nicm 651: { -1, -1, NULL, NULL }
652: };
1.1 nicm 653:
1.28 nicm 654: /* utf8_one state table. */
655: const struct input_transition input_state_utf8_one_table[] = {
656: /* No INPUT_STATE_ANYWHERE */
657:
658: { 0x00, 0x7f, NULL, &input_state_ground },
659: { 0x80, 0xbf, input_utf8_close, &input_state_ground },
660: { 0xc0, 0xff, NULL, &input_state_ground },
1.1 nicm 661:
1.28 nicm 662: { -1, -1, NULL, NULL }
663: };
1.1 nicm 664:
1.28 nicm 665: /* Input table compare. */
666: int
667: input_table_compare(const void *key, const void *value)
1.1 nicm 668: {
1.28 nicm 669: const struct input_ctx *ictx = key;
670: const struct input_table_entry *entry = value;
1.1 nicm 671:
1.28 nicm 672: if (ictx->ch != entry->ch)
673: return (ictx->ch - entry->ch);
674: return (strcmp(ictx->interm_buf, entry->interm));
1.1 nicm 675: }
676:
1.28 nicm 677: /* Initialise input parser. */
1.1 nicm 678: void
1.28 nicm 679: input_init(struct window_pane *wp)
1.1 nicm 680: {
1.28 nicm 681: struct input_ctx *ictx = &wp->ictx;
1.1 nicm 682:
1.28 nicm 683: memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell);
1.1 nicm 684:
1.28 nicm 685: memcpy(&ictx->old_cell, &grid_default_cell, sizeof ictx->old_cell);
686: ictx->old_cx = 0;
687: ictx->old_cy = 0;
1.1 nicm 688:
1.28 nicm 689: *ictx->interm_buf = '\0';
690: ictx->interm_len = 0;
1.1 nicm 691:
1.28 nicm 692: *ictx->param_buf = '\0';
693: ictx->param_len = 0;
1.1 nicm 694:
1.28 nicm 695: ictx->state = &input_state_ground;
696: ictx->flags = 0;
1.52 nicm 697:
698: ictx->since_ground = evbuffer_new();
1.1 nicm 699: }
700:
1.28 nicm 701: /* Destroy input parser. */
1.1 nicm 702: void
1.52 nicm 703: input_free(struct window_pane *wp)
1.1 nicm 704: {
1.52 nicm 705: if (wp != NULL)
706: evbuffer_free(wp->ictx.since_ground);
707: }
708:
709: /* Change input state. */
710: void
711: input_set_state(struct window_pane *wp, const struct input_transition *itr)
712: {
713: struct input_ctx *ictx = &wp->ictx;
714: struct evbuffer *ground_evb = ictx->since_ground;
715:
716: if (ictx->state->exit != NULL)
717: ictx->state->exit(ictx);
718:
719: if (itr->state == &input_state_ground)
720: evbuffer_drain(ground_evb, EVBUFFER_LENGTH(ground_evb));
721:
722: ictx->state = itr->state;
723: if (ictx->state->enter != NULL)
724: ictx->state->enter(ictx);
1.1 nicm 725: }
726:
1.28 nicm 727: /* Parse input. */
1.1 nicm 728: void
1.28 nicm 729: input_parse(struct window_pane *wp)
1.1 nicm 730: {
1.28 nicm 731: struct input_ctx *ictx = &wp->ictx;
732: const struct input_transition *itr;
733: struct evbuffer *evb = wp->event->input;
734: u_char *buf;
735: size_t len, off;
1.1 nicm 736:
1.28 nicm 737: if (EVBUFFER_LENGTH(evb) == 0)
738: return;
1.30 nicm 739:
1.28 nicm 740: wp->window->flags |= WINDOW_ACTIVITY;
1.30 nicm 741: wp->window->flags &= ~WINDOW_SILENCE;
1.1 nicm 742:
1.28 nicm 743: /*
744: * Open the screen. Use NULL wp if there is a mode set as don't want to
745: * update the tty.
746: */
747: if (wp->mode == NULL)
748: screen_write_start(&ictx->ctx, wp, &wp->base);
749: else
750: screen_write_start(&ictx->ctx, NULL, &wp->base);
751: ictx->wp = wp;
1.7 nicm 752:
1.28 nicm 753: buf = EVBUFFER_DATA(evb);
754: len = EVBUFFER_LENGTH(evb);
755: off = 0;
756:
757: /* Parse the input. */
758: while (off < len) {
759: ictx->ch = buf[off++];
760: log_debug("%s: '%c' %s", __func__, ictx->ch, ictx->state->name);
761:
762: /* Find the transition. */
763: itr = ictx->state->transitions;
764: while (itr->first != -1 && itr->last != -1) {
765: if (ictx->ch >= itr->first && ictx->ch <= itr->last)
1.7 nicm 766: break;
1.28 nicm 767: itr++;
1.1 nicm 768: }
1.28 nicm 769: if (itr->first == -1 || itr->last == -1) {
770: /* No transition? Eh? */
771: fatalx("No transition from state!");
1.3 nicm 772: }
1.1 nicm 773:
774: /*
1.28 nicm 775: * Execute the handler, if any. Don't switch state if it
776: * returns non-zero.
1.1 nicm 777: */
1.31 nicm 778: if (itr->handler != NULL && itr->handler(ictx) != 0)
1.28 nicm 779: continue;
780:
781: /* And switch state, if necessary. */
1.52 nicm 782: if (itr->state != NULL)
783: input_set_state(wp, itr);
784:
785: /* If not in ground state, save input. */
786: if (ictx->state != &input_state_ground)
787: evbuffer_add(ictx->since_ground, &ictx->ch, 1);
1.1 nicm 788: }
789:
1.28 nicm 790: /* Close the screen. */
791: screen_write_stop(&ictx->ctx);
1.1 nicm 792:
1.28 nicm 793: evbuffer_drain(evb, len);
1.1 nicm 794: }
795:
1.28 nicm 796: /* Split the parameter list (if any). */
797: int
798: input_split(struct input_ctx *ictx)
1.1 nicm 799:
800: {
1.28 nicm 801: const char *errstr;
802: char *ptr, *out;
803: int n;
1.1 nicm 804:
1.28 nicm 805: ictx->param_list_len = 0;
806: if (ictx->param_len == 0)
807: return (0);
1.1 nicm 808:
1.28 nicm 809: ptr = ictx->param_buf;
810: while ((out = strsep(&ptr, ";")) != NULL) {
811: if (*out == '\0')
812: n = -1;
813: else {
814: n = strtonum(out, 0, INT_MAX, &errstr);
815: if (errstr != NULL)
816: return (-1);
817: }
1.1 nicm 818:
1.28 nicm 819: ictx->param_list[ictx->param_list_len++] = n;
820: if (ictx->param_list_len == nitems(ictx->param_list))
821: return (-1);
822: }
1.1 nicm 823:
1.28 nicm 824: return (0);
1.1 nicm 825: }
826:
1.40 nicm 827: /* Get an argument or return default value. */
1.28 nicm 828: int
829: input_get(struct input_ctx *ictx, u_int validx, int minval, int defval)
1.1 nicm 830: {
1.28 nicm 831: int retval;
1.1 nicm 832:
1.28 nicm 833: if (validx >= ictx->param_list_len)
834: return (defval);
1.1 nicm 835:
1.28 nicm 836: retval = ictx->param_list[validx];
837: if (retval == -1)
838: return (defval);
839: if (retval < minval)
840: return (minval);
841: return (retval);
1.1 nicm 842: }
843:
1.28 nicm 844: /* Reply to terminal query. */
1.1 nicm 845: void
1.28 nicm 846: input_reply(struct input_ctx *ictx, const char *fmt, ...)
1.1 nicm 847: {
1.28 nicm 848: va_list ap;
849: char *reply;
1.1 nicm 850:
1.28 nicm 851: va_start(ap, fmt);
852: vasprintf(&reply, fmt, ap);
853: va_end(ap);
1.1 nicm 854:
1.28 nicm 855: bufferevent_write(ictx->wp->event, reply, strlen(reply));
1.53 ! nicm 856: free(reply);
1.8 nicm 857: }
858:
1.28 nicm 859: /* Clear saved state. */
1.8 nicm 860: void
1.28 nicm 861: input_clear(struct input_ctx *ictx)
1.8 nicm 862: {
1.28 nicm 863: *ictx->interm_buf = '\0';
864: ictx->interm_len = 0;
1.8 nicm 865:
1.28 nicm 866: *ictx->param_buf = '\0';
867: ictx->param_len = 0;
1.8 nicm 868:
1.35 nicm 869: *ictx->input_buf = '\0';
870: ictx->input_len = 0;
871:
1.28 nicm 872: ictx->flags &= ~INPUT_DISCARD;
1.14 nicm 873: }
874:
1.28 nicm 875: /* Output this character to the screen. */
876: int
877: input_print(struct input_ctx *ictx)
1.14 nicm 878: {
1.28 nicm 879: ictx->cell.data = ictx->ch;
880: screen_write_cell(&ictx->ctx, &ictx->cell, NULL);
1.14 nicm 881:
1.28 nicm 882: return (0);
1.1 nicm 883: }
884:
1.28 nicm 885: /* Collect intermediate string. */
886: int
887: input_intermediate(struct input_ctx *ictx)
1.1 nicm 888: {
1.28 nicm 889: if (ictx->interm_len == (sizeof ictx->interm_buf) - 1)
890: ictx->flags |= INPUT_DISCARD;
891: else {
892: ictx->interm_buf[ictx->interm_len++] = ictx->ch;
893: ictx->interm_buf[ictx->interm_len] = '\0';
894: }
1.1 nicm 895:
1.28 nicm 896: return (0);
1.1 nicm 897: }
898:
1.28 nicm 899: /* Collect parameter string. */
900: int
901: input_parameter(struct input_ctx *ictx)
1.1 nicm 902: {
1.28 nicm 903: if (ictx->param_len == (sizeof ictx->param_buf) - 1)
904: ictx->flags |= INPUT_DISCARD;
905: else {
906: ictx->param_buf[ictx->param_len++] = ictx->ch;
907: ictx->param_buf[ictx->param_len] = '\0';
908: }
1.1 nicm 909:
1.28 nicm 910: return (0);
1.1 nicm 911: }
912:
1.28 nicm 913: /* Collect input string. */
914: int
915: input_input(struct input_ctx *ictx)
1.1 nicm 916: {
1.28 nicm 917: if (ictx->input_len == (sizeof ictx->input_buf) - 1)
918: ictx->flags |= INPUT_DISCARD;
919: else {
920: ictx->input_buf[ictx->input_len++] = ictx->ch;
921: ictx->input_buf[ictx->input_len] = '\0';
922: }
1.1 nicm 923:
1.28 nicm 924: return (0);
1.1 nicm 925: }
926:
1.28 nicm 927: /* Execute C0 control sequence. */
928: int
929: input_c0_dispatch(struct input_ctx *ictx)
1.1 nicm 930: {
1.28 nicm 931: struct screen_write_ctx *sctx = &ictx->ctx;
932: struct window_pane *wp = ictx->wp;
933: struct screen *s = sctx->s;
1.51 nicm 934: u_int trigger;
1.1 nicm 935:
1.28 nicm 936: log_debug("%s: '%c", __func__, ictx->ch);
1.1 nicm 937:
1.28 nicm 938: switch (ictx->ch) {
939: case '\000': /* NUL */
940: break;
941: case '\007': /* BEL */
942: wp->window->flags |= WINDOW_BELL;
943: break;
944: case '\010': /* BS */
945: screen_write_backspace(sctx);
1.51 nicm 946: goto count_c0;
1.28 nicm 947: case '\011': /* HT */
948: /* Don't tab beyond the end of the line. */
949: if (s->cx >= screen_size_x(s) - 1)
950: break;
1.1 nicm 951:
1.28 nicm 952: /* Find the next tab point, or use the last column if none. */
953: do {
954: s->cx++;
955: if (bit_test(s->tabs, s->cx))
956: break;
957: } while (s->cx < screen_size_x(s) - 1);
958: break;
959: case '\012': /* LF */
960: case '\013': /* VT */
961: case '\014': /* FF */
962: screen_write_linefeed(sctx, 0);
1.51 nicm 963: goto count_c0;
1.28 nicm 964: case '\015': /* CR */
965: screen_write_carriagereturn(sctx);
1.51 nicm 966: goto count_c0;
1.28 nicm 967: case '\016': /* SO */
968: ictx->cell.attr |= GRID_ATTR_CHARSET;
969: break;
970: case '\017': /* SI */
971: ictx->cell.attr &= ~GRID_ATTR_CHARSET;
972: break;
973: default:
974: log_debug("%s: unknown '%c'", __func__, ictx->ch);
975: break;
1.51 nicm 976: }
977:
978: return (0);
979:
980: count_c0:
981: trigger = options_get_number(&wp->window->options, "c0-change-trigger");
982: if (++wp->changes == trigger) {
983: wp->flags |= PANE_DROP;
984: window_pane_timer_start(wp);
1.28 nicm 985: }
1.1 nicm 986:
1.28 nicm 987: return (0);
1.7 nicm 988: }
989:
1.28 nicm 990: /* Execute escape sequence. */
991: int
992: input_esc_dispatch(struct input_ctx *ictx)
1.7 nicm 993: {
1.31 nicm 994: struct screen_write_ctx *sctx = &ictx->ctx;
995: struct screen *s = sctx->s;
996: struct input_table_entry *entry;
1.7 nicm 997:
1.28 nicm 998: if (ictx->flags & INPUT_DISCARD)
999: return (0);
1000: log_debug("%s: '%c', %s", __func__, ictx->ch, ictx->interm_buf);
1.7 nicm 1001:
1.28 nicm 1002: entry = bsearch(ictx, input_esc_table, nitems(input_esc_table),
1003: sizeof input_esc_table[0], input_table_compare);
1004: if (entry == NULL) {
1005: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1006: return (0);
1007: }
1.7 nicm 1008:
1.28 nicm 1009: switch (entry->type) {
1010: case INPUT_ESC_RIS:
1011: memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell);
1012: memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
1013: ictx->old_cx = 0;
1014: ictx->old_cy = 0;
1.1 nicm 1015:
1.46 nicm 1016: screen_write_reset(sctx);
1.28 nicm 1017: break;
1018: case INPUT_ESC_IND:
1019: screen_write_linefeed(sctx, 0);
1020: break;
1021: case INPUT_ESC_NEL:
1022: screen_write_carriagereturn(sctx);
1023: screen_write_linefeed(sctx, 0);
1024: break;
1025: case INPUT_ESC_HTS:
1026: if (s->cx < screen_size_x(s))
1027: bit_set(s->tabs, s->cx);
1028: break;
1029: case INPUT_ESC_RI:
1030: screen_write_reverseindex(sctx);
1031: break;
1032: case INPUT_ESC_DECKPAM:
1033: screen_write_kkeypadmode(sctx, 1);
1034: break;
1035: case INPUT_ESC_DECKPNM:
1036: screen_write_kkeypadmode(sctx, 0);
1.1 nicm 1037: break;
1.28 nicm 1038: case INPUT_ESC_DECSC:
1039: memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
1040: ictx->old_cx = s->cx;
1041: ictx->old_cy = s->cy;
1042: break;
1043: case INPUT_ESC_DECRC:
1044: memcpy(&ictx->cell, &ictx->old_cell, sizeof ictx->cell);
1045: screen_write_cursormove(sctx, ictx->old_cx, ictx->old_cy);
1046: break;
1047: case INPUT_ESC_DECALN:
1048: screen_write_alignmenttest(sctx);
1049: break;
1050: case INPUT_ESC_SCSON_G0:
1051: /*
1052: * Not really supported, but fake it up enough for those that
1053: * use it to switch character sets (by redefining G0 to
1054: * graphics set, rather than switching to G1).
1055: */
1056: ictx->cell.attr &= ~GRID_ATTR_CHARSET;
1.1 nicm 1057: break;
1.28 nicm 1058: case INPUT_ESC_SCSOFF_G0:
1059: ictx->cell.attr |= GRID_ATTR_CHARSET;
1.1 nicm 1060: break;
1061: }
1.28 nicm 1062:
1063: return (0);
1.1 nicm 1064: }
1065:
1.28 nicm 1066: /* Execute control sequence. */
1067: int
1068: input_csi_dispatch(struct input_ctx *ictx)
1.1 nicm 1069: {
1.28 nicm 1070: struct screen_write_ctx *sctx = &ictx->ctx;
1071: struct window_pane *wp = ictx->wp;
1072: struct screen *s = sctx->s;
1073: struct input_table_entry *entry;
1074: int n, m;
1.1 nicm 1075:
1.28 nicm 1076: if (ictx->flags & INPUT_DISCARD)
1077: return (0);
1078: if (input_split(ictx) != 0)
1079: return (0);
1080: log_debug("%s: '%c' \"%s\" \"%s\"",
1081: __func__, ictx->ch, ictx->interm_buf, ictx->param_buf);
1.1 nicm 1082:
1.28 nicm 1083: entry = bsearch(ictx, input_csi_table, nitems(input_csi_table),
1084: sizeof input_csi_table[0], input_table_compare);
1085: if (entry == NULL) {
1086: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1087: return (0);
1088: }
1.1 nicm 1089:
1.28 nicm 1090: switch (entry->type) {
1091: case INPUT_CSI_CBT:
1092: /* Find the previous tab point, n times. */
1093: n = input_get(ictx, 0, 1, 1);
1094: while (s->cx > 0 && n-- > 0) {
1095: do
1096: s->cx--;
1097: while (s->cx > 0 && !bit_test(s->tabs, s->cx));
1098: }
1099: break;
1100: case INPUT_CSI_CUB:
1101: screen_write_cursorleft(sctx, input_get(ictx, 0, 1, 1));
1102: break;
1103: case INPUT_CSI_CUD:
1104: screen_write_cursordown(sctx, input_get(ictx, 0, 1, 1));
1105: break;
1106: case INPUT_CSI_CUF:
1107: screen_write_cursorright(sctx, input_get(ictx, 0, 1, 1));
1108: break;
1109: case INPUT_CSI_CUP:
1110: n = input_get(ictx, 0, 1, 1);
1111: m = input_get(ictx, 1, 1, 1);
1112: screen_write_cursormove(sctx, m - 1, n - 1);
1113: break;
1114: case INPUT_CSI_CUU:
1.43 nicm 1115: screen_write_cursorup(sctx, input_get(ictx, 0, 1, 1));
1116: break;
1117: case INPUT_CSI_CNL:
1118: screen_write_carriagereturn(sctx);
1119: screen_write_cursordown(sctx, input_get(ictx, 0, 1, 1));
1120: break;
1121: case INPUT_CSI_CPL:
1122: screen_write_carriagereturn(sctx);
1.28 nicm 1123: screen_write_cursorup(sctx, input_get(ictx, 0, 1, 1));
1124: break;
1125: case INPUT_CSI_DA:
1126: switch (input_get(ictx, 0, 0, 0)) {
1127: case 0:
1128: input_reply(ictx, "\033[?1;2c");
1.50 nicm 1129: break;
1130: default:
1131: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1132: break;
1133: }
1134: break;
1135: case INPUT_CSI_DA_TWO:
1136: switch (input_get(ictx, 0, 0, 0)) {
1137: case 0:
1138: input_reply(ictx, "\033[>0;95;0c");
1.28 nicm 1139: break;
1140: default:
1141: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1142: break;
1143: }
1144: break;
1145: case INPUT_CSI_DCH:
1146: screen_write_deletecharacter(sctx, input_get(ictx, 0, 1, 1));
1147: break;
1148: case INPUT_CSI_DECSTBM:
1149: n = input_get(ictx, 0, 1, 1);
1150: m = input_get(ictx, 1, 1, screen_size_y(s));
1151: screen_write_scrollregion(sctx, n - 1, m - 1);
1.1 nicm 1152: break;
1.28 nicm 1153: case INPUT_CSI_DL:
1154: screen_write_deleteline(sctx, input_get(ictx, 0, 1, 1));
1.1 nicm 1155: break;
1.28 nicm 1156: case INPUT_CSI_DSR:
1157: switch (input_get(ictx, 0, 0, 0)) {
1158: case 5:
1159: input_reply(ictx, "\033[0n");
1160: break;
1161: case 6:
1162: input_reply(ictx, "\033[%u;%uR", s->cy + 1, s->cx + 1);
1163: break;
1164: default:
1165: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1166: break;
1167: }
1168: break;
1169: case INPUT_CSI_ED:
1170: switch (input_get(ictx, 0, 0, 0)) {
1171: case 0:
1172: screen_write_clearendofscreen(sctx);
1173: break;
1174: case 1:
1175: screen_write_clearstartofscreen(sctx);
1176: break;
1177: case 2:
1178: screen_write_clearscreen(sctx);
1.41 nicm 1179: break;
1180: case 3:
1181: switch (input_get(ictx, 1, 0, 0)) {
1182: case 0:
1183: /*
1184: * Linux console extension to clear history
1185: * (for example before locking the screen).
1186: */
1187: screen_write_clearhistory(sctx);
1188: break;
1189: }
1.28 nicm 1190: break;
1191: default:
1192: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1193: break;
1194: }
1195: break;
1196: case INPUT_CSI_EL:
1197: switch (input_get(ictx, 0, 0, 0)) {
1198: case 0:
1199: screen_write_clearendofline(sctx);
1200: break;
1201: case 1:
1202: screen_write_clearstartofline(sctx);
1203: break;
1204: case 2:
1205: screen_write_clearline(sctx);
1206: break;
1207: default:
1208: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1209: break;
1210: }
1211: break;
1212: case INPUT_CSI_HPA:
1213: n = input_get(ictx, 0, 1, 1);
1214: screen_write_cursormove(sctx, n - 1, s->cy);
1215: break;
1216: case INPUT_CSI_ICH:
1217: screen_write_insertcharacter(sctx, input_get(ictx, 0, 1, 1));
1218: break;
1219: case INPUT_CSI_IL:
1220: screen_write_insertline(sctx, input_get(ictx, 0, 1, 1));
1221: break;
1.42 nicm 1222: case INPUT_CSI_RCP:
1223: memcpy(&ictx->cell, &ictx->old_cell, sizeof ictx->cell);
1224: screen_write_cursormove(sctx, ictx->old_cx, ictx->old_cy);
1225: break;
1.28 nicm 1226: case INPUT_CSI_RM:
1227: switch (input_get(ictx, 0, 0, -1)) {
1228: case 4: /* IRM */
1229: screen_write_insertmode(&ictx->ctx, 0);
1230: break;
1231: default:
1232: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1233: break;
1234: }
1.1 nicm 1235: break;
1.28 nicm 1236: case INPUT_CSI_RM_PRIVATE:
1237: switch (input_get(ictx, 0, 0, -1)) {
1.1 nicm 1238: case 1: /* GATM */
1.28 nicm 1239: screen_write_kcursormode(&ictx->ctx, 0);
1.1 nicm 1240: break;
1.17 nicm 1241: case 3: /* DECCOLM */
1.24 nicm 1242: screen_write_cursormove(&ictx->ctx, 0, 0);
1.17 nicm 1243: screen_write_clearscreen(&ictx->ctx);
1244: break;
1.1 nicm 1245: case 25: /* TCEM */
1.28 nicm 1246: screen_write_cursormode(&ictx->ctx, 0);
1.1 nicm 1247: break;
1248: case 1000:
1.32 nicm 1249: case 1001:
1250: case 1002:
1251: case 1003:
1252: screen_write_mousemode_off(&ictx->ctx);
1.1 nicm 1253: break;
1.33 nicm 1254: case 1005:
1255: screen_write_utf8mousemode(&ictx->ctx, 0);
1256: break;
1.9 nicm 1257: case 1049:
1.28 nicm 1258: window_pane_alternate_off(wp, &ictx->cell);
1.9 nicm 1259: break;
1.49 nicm 1260: case 2004:
1261: screen_write_bracketpaste(&ictx->ctx, 0);
1262: break;
1.1 nicm 1263: default:
1.28 nicm 1264: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1.1 nicm 1265: break;
1266: }
1.42 nicm 1267: break;
1268: case INPUT_CSI_SCP:
1269: memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
1270: ictx->old_cx = s->cx;
1271: ictx->old_cy = s->cy;
1.28 nicm 1272: break;
1273: case INPUT_CSI_SGR:
1274: input_csi_dispatch_sgr(ictx);
1275: break;
1276: case INPUT_CSI_SM:
1277: switch (input_get(ictx, 0, 0, -1)) {
1.1 nicm 1278: case 4: /* IRM */
1279: screen_write_insertmode(&ictx->ctx, 1);
1280: break;
1281: default:
1.28 nicm 1282: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1.1 nicm 1283: break;
1284: }
1.28 nicm 1285: break;
1286: case INPUT_CSI_SM_PRIVATE:
1287: switch (input_get(ictx, 0, 0, -1)) {
1.1 nicm 1288: case 1: /* GATM */
1.28 nicm 1289: screen_write_kcursormode(&ictx->ctx, 1);
1.17 nicm 1290: break;
1291: case 3: /* DECCOLM */
1.24 nicm 1292: screen_write_cursormove(&ictx->ctx, 0, 0);
1.17 nicm 1293: screen_write_clearscreen(&ictx->ctx);
1.1 nicm 1294: break;
1295: case 25: /* TCEM */
1.28 nicm 1296: screen_write_cursormode(&ictx->ctx, 1);
1.1 nicm 1297: break;
1298: case 1000:
1.32 nicm 1299: screen_write_mousemode_on(
1300: &ictx->ctx, MODE_MOUSE_STANDARD);
1301: break;
1302: case 1002:
1303: screen_write_mousemode_on(
1304: &ictx->ctx, MODE_MOUSE_BUTTON);
1305: break;
1306: case 1003:
1307: screen_write_mousemode_on(&ictx->ctx, MODE_MOUSE_ANY);
1.33 nicm 1308: break;
1309: case 1005:
1310: screen_write_utf8mousemode(&ictx->ctx, 1);
1.9 nicm 1311: break;
1312: case 1049:
1.28 nicm 1313: window_pane_alternate_on(wp, &ictx->cell);
1.49 nicm 1314: break;
1315: case 2004:
1316: screen_write_bracketpaste(&ictx->ctx, 1);
1.1 nicm 1317: break;
1318: default:
1.28 nicm 1319: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1.1 nicm 1320: break;
1321: }
1.28 nicm 1322: break;
1323: case INPUT_CSI_TBC:
1324: switch (input_get(ictx, 0, 0, 0)) {
1325: case 0:
1326: if (s->cx < screen_size_x(s))
1327: bit_clear(s->tabs, s->cx);
1.1 nicm 1328: break;
1.28 nicm 1329: case 3:
1330: bit_nclear(s->tabs, 0, screen_size_x(s) - 1);
1.1 nicm 1331: break;
1332: default:
1.28 nicm 1333: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1.1 nicm 1334: break;
1335: }
1.28 nicm 1336: break;
1337: case INPUT_CSI_VPA:
1338: n = input_get(ictx, 0, 1, 1);
1339: screen_write_cursormove(sctx, s->cx, n - 1);
1.39 nicm 1340: break;
1341: case INPUT_CSI_DECSCUSR:
1342: n = input_get(ictx, 0, 0, 0);
1343: screen_set_cursor_style(s, n);
1.28 nicm 1344: break;
1.1 nicm 1345: }
1346:
1.28 nicm 1347: return (0);
1.1 nicm 1348: }
1349:
1.28 nicm 1350: /* Handle CSI SGR. */
1.1 nicm 1351: void
1.28 nicm 1352: input_csi_dispatch_sgr(struct input_ctx *ictx)
1.1 nicm 1353: {
1.28 nicm 1354: struct grid_cell *gc = &ictx->cell;
1355: u_int i;
1356: int n, m;
1357: u_char attr;
1.1 nicm 1358:
1.28 nicm 1359: if (ictx->param_list_len == 0) {
1.1 nicm 1360: attr = gc->attr;
1361: memcpy(gc, &grid_default_cell, sizeof *gc);
1.24 nicm 1362: gc->attr |= (attr & GRID_ATTR_CHARSET);
1.1 nicm 1363: return;
1364: }
1365:
1.28 nicm 1366: for (i = 0; i < ictx->param_list_len; i++) {
1367: n = input_get(ictx, i, 0, 0);
1.1 nicm 1368:
1.28 nicm 1369: if (n == 38 || n == 48) {
1.1 nicm 1370: i++;
1.28 nicm 1371: if (input_get(ictx, i, 0, -1) != 5)
1.1 nicm 1372: continue;
1373:
1374: i++;
1.28 nicm 1375: m = input_get(ictx, i, 0, -1);
1376: if (m == -1) {
1377: if (n == 38) {
1378: gc->flags &= ~GRID_FLAG_FG256;
1379: gc->fg = 8;
1380: } else if (n == 48) {
1381: gc->flags &= ~GRID_FLAG_BG256;
1.36 nicm 1382: gc->bg = 8;
1.28 nicm 1383: }
1384:
1385: } else {
1386: if (n == 38) {
1387: gc->flags |= GRID_FLAG_FG256;
1388: gc->fg = m;
1389: } else if (n == 48) {
1390: gc->flags |= GRID_FLAG_BG256;
1391: gc->bg = m;
1392: }
1.1 nicm 1393: }
1394: continue;
1395: }
1396:
1.28 nicm 1397: switch (n) {
1.1 nicm 1398: case 0:
1399: case 10:
1400: attr = gc->attr;
1401: memcpy(gc, &grid_default_cell, sizeof *gc);
1402: gc->attr |= (attr & GRID_ATTR_CHARSET);
1403: break;
1404: case 1:
1405: gc->attr |= GRID_ATTR_BRIGHT;
1406: break;
1407: case 2:
1408: gc->attr |= GRID_ATTR_DIM;
1409: break;
1410: case 3:
1411: gc->attr |= GRID_ATTR_ITALICS;
1412: break;
1413: case 4:
1414: gc->attr |= GRID_ATTR_UNDERSCORE;
1415: break;
1416: case 5:
1417: gc->attr |= GRID_ATTR_BLINK;
1418: break;
1419: case 7:
1420: gc->attr |= GRID_ATTR_REVERSE;
1421: break;
1422: case 8:
1423: gc->attr |= GRID_ATTR_HIDDEN;
1424: break;
1425: case 22:
1426: gc->attr &= ~(GRID_ATTR_BRIGHT|GRID_ATTR_DIM);
1427: break;
1428: case 23:
1429: gc->attr &= ~GRID_ATTR_ITALICS;
1430: break;
1431: case 24:
1432: gc->attr &= ~GRID_ATTR_UNDERSCORE;
1433: break;
1434: case 25:
1435: gc->attr &= ~GRID_ATTR_BLINK;
1436: break;
1437: case 27:
1438: gc->attr &= ~GRID_ATTR_REVERSE;
1439: break;
1440: case 30:
1441: case 31:
1442: case 32:
1443: case 33:
1444: case 34:
1445: case 35:
1446: case 36:
1447: case 37:
1448: gc->flags &= ~GRID_FLAG_FG256;
1.28 nicm 1449: gc->fg = n - 30;
1.1 nicm 1450: break;
1451: case 39:
1452: gc->flags &= ~GRID_FLAG_FG256;
1453: gc->fg = 8;
1454: break;
1455: case 40:
1456: case 41:
1457: case 42:
1458: case 43:
1459: case 44:
1460: case 45:
1461: case 46:
1462: case 47:
1463: gc->flags &= ~GRID_FLAG_BG256;
1.28 nicm 1464: gc->bg = n - 40;
1.1 nicm 1465: break;
1466: case 49:
1467: gc->flags &= ~GRID_FLAG_BG256;
1468: gc->bg = 8;
1.20 nicm 1469: break;
1470: case 90:
1471: case 91:
1472: case 92:
1473: case 93:
1474: case 94:
1475: case 95:
1476: case 96:
1477: case 97:
1.26 nicm 1478: gc->flags &= ~GRID_FLAG_FG256;
1.28 nicm 1479: gc->fg = n;
1.20 nicm 1480: break;
1481: case 100:
1482: case 101:
1483: case 102:
1484: case 103:
1485: case 104:
1486: case 105:
1487: case 106:
1488: case 107:
1.26 nicm 1489: gc->flags &= ~GRID_FLAG_BG256;
1.47 nicm 1490: gc->bg = n - 10;
1.1 nicm 1491: break;
1492: }
1493: }
1.28 nicm 1494: }
1495:
1.37 nicm 1496: /* DCS terminator (ST) received. */
1497: int
1498: input_dcs_dispatch(struct input_ctx *ictx)
1.28 nicm 1499: {
1.37 nicm 1500: const char prefix[] = "tmux;";
1501: const u_int prefix_len = (sizeof prefix) - 1;
1502:
1503: if (ictx->flags & INPUT_DISCARD)
1504: return (0);
1505:
1506: log_debug("%s: \"%s\"", __func__, ictx->input_buf);
1.28 nicm 1507:
1.37 nicm 1508: /* Check for tmux prefix. */
1509: if (ictx->input_len >= prefix_len &&
1510: strncmp(ictx->input_buf, prefix, prefix_len) == 0) {
1511: screen_write_rawstring(&ictx->ctx,
1512: ictx->input_buf + prefix_len, ictx->input_len - prefix_len);
1513: }
1.28 nicm 1514:
1.37 nicm 1515: return (0);
1.28 nicm 1516: }
1517:
1518: /* OSC string started. */
1519: void
1520: input_enter_osc(struct input_ctx *ictx)
1521: {
1522: log_debug("%s", __func__);
1523:
1.35 nicm 1524: input_clear(ictx);
1.28 nicm 1525: }
1526:
1527: /* OSC terminator (ST) received. */
1528: void
1529: input_exit_osc(struct input_ctx *ictx)
1530: {
1.38 nicm 1531: u_char *p = ictx->input_buf;
1532: int option;
1533:
1.28 nicm 1534: if (ictx->flags & INPUT_DISCARD)
1535: return;
1.38 nicm 1536: if (ictx->input_len < 1 || *p < '0' || *p > '9')
1537: return;
1.28 nicm 1538:
1.38 nicm 1539: log_debug("%s: \"%s\"", __func__, p);
1.28 nicm 1540:
1.38 nicm 1541: option = 0;
1542: while (*p >= '0' && *p <= '9')
1543: option = option * 10 + *p++ - '0';
1544: if (*p == ';')
1545: p++;
1546:
1547: switch (option) {
1548: case 0:
1549: case 2:
1550: screen_set_title(ictx->ctx.s, p);
1551: server_status_window(ictx->wp->window);
1552: break;
1553: case 12:
1554: screen_set_cursor_colour(ictx->ctx.s, p);
1555: break;
1556: case 112:
1557: if (*p == '\0') /* No arguments allowed. */
1558: screen_set_cursor_colour(ictx->ctx.s, "");
1559: break;
1560: default:
1561: log_debug("%s: unknown '%u'", __func__, option);
1562: break;
1563: }
1.28 nicm 1564: }
1565:
1566: /* APC string started. */
1567: void
1568: input_enter_apc(struct input_ctx *ictx)
1569: {
1570: log_debug("%s", __func__);
1571:
1.35 nicm 1572: input_clear(ictx);
1.28 nicm 1573: }
1574:
1575: /* APC terminator (ST) received. */
1576: void
1577: input_exit_apc(struct input_ctx *ictx)
1578: {
1579: if (ictx->flags & INPUT_DISCARD)
1580: return;
1581: log_debug("%s: \"%s\"", __func__, ictx->input_buf);
1582:
1583: screen_set_title(ictx->ctx.s, ictx->input_buf);
1584: server_status_window(ictx->wp->window);
1585: }
1586:
1587: /* Rename string started. */
1588: void
1589: input_enter_rename(struct input_ctx *ictx)
1590: {
1591: log_debug("%s", __func__);
1592:
1.35 nicm 1593: input_clear(ictx);
1.28 nicm 1594: }
1595:
1596: /* Rename terminator (ST) received. */
1597: void
1598: input_exit_rename(struct input_ctx *ictx)
1599: {
1600: if (ictx->flags & INPUT_DISCARD)
1.44 nicm 1601: return;
1602: if (!options_get_number(&ictx->wp->window->options, "allow-rename"))
1.28 nicm 1603: return;
1604: log_debug("%s: \"%s\"", __func__, ictx->input_buf);
1605:
1.48 nicm 1606: window_set_name(ictx->wp->window, ictx->input_buf);
1.28 nicm 1607: options_set_number(&ictx->wp->window->options, "automatic-rename", 0);
1608:
1609: server_status_window(ictx->wp->window);
1610: }
1611:
1612: /* Open UTF-8 character. */
1613: int
1614: input_utf8_open(struct input_ctx *ictx)
1615: {
1616: if (!options_get_number(&ictx->wp->window->options, "utf8")) {
1617: /* Print, and do not switch state. */
1618: input_print(ictx);
1619: return (-1);
1620: }
1621: log_debug("%s", __func__);
1622:
1623: utf8_open(&ictx->utf8data, ictx->ch);
1624: return (0);
1625: }
1626:
1627: /* Append to UTF-8 character. */
1628: int
1629: input_utf8_add(struct input_ctx *ictx)
1630: {
1631: log_debug("%s", __func__);
1632:
1633: utf8_append(&ictx->utf8data, ictx->ch);
1634: return (0);
1635: }
1636:
1637: /* Close UTF-8 string. */
1638: int
1639: input_utf8_close(struct input_ctx *ictx)
1640: {
1641: log_debug("%s", __func__);
1642:
1643: utf8_append(&ictx->utf8data, ictx->ch);
1644:
1645: ictx->cell.flags |= GRID_FLAG_UTF8;
1646: screen_write_cell(&ictx->ctx, &ictx->cell, &ictx->utf8data);
1647: ictx->cell.flags &= ~GRID_FLAG_UTF8;
1648:
1649: return (0);
1.1 nicm 1650: }