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