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