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