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