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