Annotation of src/usr.bin/tmux/input.c, Revision 1.59
1.59 ! nicm 1: /* $OpenBSD: input.c,v 1.58 2013/01/18 02:16:21 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:
1.59 ! nicm 1036: screen_write_mode_set(sctx, MODE_KKEYPAD);
1.28 nicm 1037: break;
1038: case INPUT_ESC_DECKPNM:
1.59 ! nicm 1039: screen_write_mode_clear(sctx, MODE_KKEYPAD);
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 */
1.59 ! nicm 1235: screen_write_mode_clear(&ictx->ctx, MODE_INSERT);
1.28 nicm 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.59 ! nicm 1245: screen_write_mode_clear(&ictx->ctx, MODE_KCURSOR);
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.59 ! nicm 1252: screen_write_mode_clear(&ictx->ctx, MODE_CURSOR);
1.1 nicm 1253: break;
1254: case 1000:
1.32 nicm 1255: case 1001:
1256: case 1002:
1257: case 1003:
1.59 ! nicm 1258: screen_write_mode_clear(&ictx->ctx, ALL_MOUSE_MODES);
1.1 nicm 1259: break;
1.33 nicm 1260: case 1005:
1.59 ! nicm 1261: screen_write_mode_clear(&ictx->ctx, MODE_MOUSE_UTF8);
1.33 nicm 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:
1.59 ! nicm 1271: screen_write_mode_clear(&ictx->ctx, MODE_BRACKETPASTE);
1.49 nicm 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 */
1.59 ! nicm 1289: screen_write_mode_set(&ictx->ctx, MODE_INSERT);
1.1 nicm 1290: break;
1291: default:
1.28 nicm 1292: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1.1 nicm 1293: break;
1294: }
1.28 nicm 1295: break;
1296: case INPUT_CSI_SM_PRIVATE:
1297: switch (input_get(ictx, 0, 0, -1)) {
1.1 nicm 1298: case 1: /* GATM */
1.59 ! nicm 1299: screen_write_mode_set(&ictx->ctx, MODE_KCURSOR);
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.59 ! nicm 1306: screen_write_mode_set(&ictx->ctx, MODE_CURSOR);
1.1 nicm 1307: break;
1308: case 1000:
1.59 ! nicm 1309: screen_write_mode_clear(&ictx->ctx, ALL_MOUSE_MODES);
! 1310: screen_write_mode_set(&ictx->ctx, MODE_MOUSE_STANDARD);
1.32 nicm 1311: break;
1312: case 1002:
1.59 ! nicm 1313: screen_write_mode_clear(&ictx->ctx, ALL_MOUSE_MODES);
! 1314: screen_write_mode_set(&ictx->ctx, MODE_MOUSE_BUTTON);
1.32 nicm 1315: break;
1316: case 1003:
1.59 ! nicm 1317: screen_write_mode_clear(&ictx->ctx, ALL_MOUSE_MODES);
! 1318: screen_write_mode_set(&ictx->ctx, MODE_MOUSE_ANY);
1.33 nicm 1319: break;
1320: case 1005:
1.59 ! nicm 1321: screen_write_mode_set(&ictx->ctx, MODE_MOUSE_UTF8);
1.9 nicm 1322: break;
1.55 nicm 1323: case 47:
1324: case 1047:
1325: window_pane_alternate_on(wp, &ictx->cell, 0);
1326: break;
1.9 nicm 1327: case 1049:
1.55 nicm 1328: window_pane_alternate_on(wp, &ictx->cell, 1);
1.49 nicm 1329: break;
1330: case 2004:
1.59 ! nicm 1331: screen_write_mode_set(&ictx->ctx, MODE_BRACKETPASTE);
1.1 nicm 1332: break;
1333: default:
1.28 nicm 1334: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1.1 nicm 1335: break;
1336: }
1.28 nicm 1337: break;
1338: case INPUT_CSI_TBC:
1339: switch (input_get(ictx, 0, 0, 0)) {
1340: case 0:
1341: if (s->cx < screen_size_x(s))
1342: bit_clear(s->tabs, s->cx);
1.1 nicm 1343: break;
1.28 nicm 1344: case 3:
1345: bit_nclear(s->tabs, 0, screen_size_x(s) - 1);
1.1 nicm 1346: break;
1347: default:
1.28 nicm 1348: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1.1 nicm 1349: break;
1350: }
1.28 nicm 1351: break;
1352: case INPUT_CSI_VPA:
1353: n = input_get(ictx, 0, 1, 1);
1354: screen_write_cursormove(sctx, s->cx, n - 1);
1.39 nicm 1355: break;
1356: case INPUT_CSI_DECSCUSR:
1357: n = input_get(ictx, 0, 0, 0);
1358: screen_set_cursor_style(s, n);
1.28 nicm 1359: break;
1.1 nicm 1360: }
1361:
1.28 nicm 1362: return (0);
1.1 nicm 1363: }
1364:
1.28 nicm 1365: /* Handle CSI SGR. */
1.1 nicm 1366: void
1.28 nicm 1367: input_csi_dispatch_sgr(struct input_ctx *ictx)
1.1 nicm 1368: {
1.28 nicm 1369: struct grid_cell *gc = &ictx->cell;
1370: u_int i;
1371: int n, m;
1372: u_char attr;
1.1 nicm 1373:
1.28 nicm 1374: if (ictx->param_list_len == 0) {
1.1 nicm 1375: attr = gc->attr;
1376: memcpy(gc, &grid_default_cell, sizeof *gc);
1.24 nicm 1377: gc->attr |= (attr & GRID_ATTR_CHARSET);
1.1 nicm 1378: return;
1379: }
1380:
1.28 nicm 1381: for (i = 0; i < ictx->param_list_len; i++) {
1382: n = input_get(ictx, i, 0, 0);
1.1 nicm 1383:
1.28 nicm 1384: if (n == 38 || n == 48) {
1.1 nicm 1385: i++;
1.28 nicm 1386: if (input_get(ictx, i, 0, -1) != 5)
1.1 nicm 1387: continue;
1388:
1389: i++;
1.28 nicm 1390: m = input_get(ictx, i, 0, -1);
1391: if (m == -1) {
1392: if (n == 38) {
1393: gc->flags &= ~GRID_FLAG_FG256;
1394: gc->fg = 8;
1395: } else if (n == 48) {
1396: gc->flags &= ~GRID_FLAG_BG256;
1.36 nicm 1397: gc->bg = 8;
1.28 nicm 1398: }
1399:
1400: } else {
1401: if (n == 38) {
1402: gc->flags |= GRID_FLAG_FG256;
1403: gc->fg = m;
1404: } else if (n == 48) {
1405: gc->flags |= GRID_FLAG_BG256;
1406: gc->bg = m;
1407: }
1.1 nicm 1408: }
1409: continue;
1410: }
1411:
1.28 nicm 1412: switch (n) {
1.1 nicm 1413: case 0:
1414: case 10:
1415: attr = gc->attr;
1416: memcpy(gc, &grid_default_cell, sizeof *gc);
1417: gc->attr |= (attr & GRID_ATTR_CHARSET);
1418: break;
1419: case 1:
1420: gc->attr |= GRID_ATTR_BRIGHT;
1421: break;
1422: case 2:
1423: gc->attr |= GRID_ATTR_DIM;
1424: break;
1425: case 3:
1426: gc->attr |= GRID_ATTR_ITALICS;
1427: break;
1428: case 4:
1429: gc->attr |= GRID_ATTR_UNDERSCORE;
1430: break;
1431: case 5:
1432: gc->attr |= GRID_ATTR_BLINK;
1433: break;
1434: case 7:
1435: gc->attr |= GRID_ATTR_REVERSE;
1436: break;
1437: case 8:
1438: gc->attr |= GRID_ATTR_HIDDEN;
1439: break;
1440: case 22:
1441: gc->attr &= ~(GRID_ATTR_BRIGHT|GRID_ATTR_DIM);
1442: break;
1443: case 23:
1444: gc->attr &= ~GRID_ATTR_ITALICS;
1445: break;
1446: case 24:
1447: gc->attr &= ~GRID_ATTR_UNDERSCORE;
1448: break;
1449: case 25:
1450: gc->attr &= ~GRID_ATTR_BLINK;
1451: break;
1452: case 27:
1453: gc->attr &= ~GRID_ATTR_REVERSE;
1454: break;
1455: case 30:
1456: case 31:
1457: case 32:
1458: case 33:
1459: case 34:
1460: case 35:
1461: case 36:
1462: case 37:
1463: gc->flags &= ~GRID_FLAG_FG256;
1.28 nicm 1464: gc->fg = n - 30;
1.1 nicm 1465: break;
1466: case 39:
1467: gc->flags &= ~GRID_FLAG_FG256;
1468: gc->fg = 8;
1469: break;
1470: case 40:
1471: case 41:
1472: case 42:
1473: case 43:
1474: case 44:
1475: case 45:
1476: case 46:
1477: case 47:
1478: gc->flags &= ~GRID_FLAG_BG256;
1.28 nicm 1479: gc->bg = n - 40;
1.1 nicm 1480: break;
1481: case 49:
1482: gc->flags &= ~GRID_FLAG_BG256;
1483: gc->bg = 8;
1.20 nicm 1484: break;
1485: case 90:
1486: case 91:
1487: case 92:
1488: case 93:
1489: case 94:
1490: case 95:
1491: case 96:
1492: case 97:
1.26 nicm 1493: gc->flags &= ~GRID_FLAG_FG256;
1.28 nicm 1494: gc->fg = n;
1.20 nicm 1495: break;
1496: case 100:
1497: case 101:
1498: case 102:
1499: case 103:
1500: case 104:
1501: case 105:
1502: case 106:
1503: case 107:
1.26 nicm 1504: gc->flags &= ~GRID_FLAG_BG256;
1.47 nicm 1505: gc->bg = n - 10;
1.1 nicm 1506: break;
1507: }
1508: }
1.28 nicm 1509: }
1510:
1.37 nicm 1511: /* DCS terminator (ST) received. */
1512: int
1513: input_dcs_dispatch(struct input_ctx *ictx)
1.28 nicm 1514: {
1.37 nicm 1515: const char prefix[] = "tmux;";
1516: const u_int prefix_len = (sizeof prefix) - 1;
1517:
1518: if (ictx->flags & INPUT_DISCARD)
1519: return (0);
1520:
1521: log_debug("%s: \"%s\"", __func__, ictx->input_buf);
1.28 nicm 1522:
1.37 nicm 1523: /* Check for tmux prefix. */
1524: if (ictx->input_len >= prefix_len &&
1525: strncmp(ictx->input_buf, prefix, prefix_len) == 0) {
1526: screen_write_rawstring(&ictx->ctx,
1527: ictx->input_buf + prefix_len, ictx->input_len - prefix_len);
1528: }
1.28 nicm 1529:
1.37 nicm 1530: return (0);
1.28 nicm 1531: }
1532:
1533: /* OSC string started. */
1534: void
1535: input_enter_osc(struct input_ctx *ictx)
1536: {
1537: log_debug("%s", __func__);
1538:
1.35 nicm 1539: input_clear(ictx);
1.28 nicm 1540: }
1541:
1542: /* OSC terminator (ST) received. */
1543: void
1544: input_exit_osc(struct input_ctx *ictx)
1545: {
1.38 nicm 1546: u_char *p = ictx->input_buf;
1547: int option;
1548:
1.28 nicm 1549: if (ictx->flags & INPUT_DISCARD)
1550: return;
1.38 nicm 1551: if (ictx->input_len < 1 || *p < '0' || *p > '9')
1552: return;
1.28 nicm 1553:
1.38 nicm 1554: log_debug("%s: \"%s\"", __func__, p);
1.28 nicm 1555:
1.38 nicm 1556: option = 0;
1557: while (*p >= '0' && *p <= '9')
1558: option = option * 10 + *p++ - '0';
1559: if (*p == ';')
1560: p++;
1561:
1562: switch (option) {
1563: case 0:
1564: case 2:
1565: screen_set_title(ictx->ctx.s, p);
1566: server_status_window(ictx->wp->window);
1567: break;
1568: case 12:
1.57 nicm 1569: if (*p != '?') /* ? is colour request */
1570: screen_set_cursor_colour(ictx->ctx.s, p);
1.38 nicm 1571: break;
1572: case 112:
1.57 nicm 1573: if (*p == '\0') /* no arguments allowed */
1.38 nicm 1574: screen_set_cursor_colour(ictx->ctx.s, "");
1575: break;
1576: default:
1577: log_debug("%s: unknown '%u'", __func__, option);
1578: break;
1579: }
1.28 nicm 1580: }
1581:
1582: /* APC string started. */
1583: void
1584: input_enter_apc(struct input_ctx *ictx)
1585: {
1586: log_debug("%s", __func__);
1587:
1.35 nicm 1588: input_clear(ictx);
1.28 nicm 1589: }
1590:
1591: /* APC terminator (ST) received. */
1592: void
1593: input_exit_apc(struct input_ctx *ictx)
1594: {
1595: if (ictx->flags & INPUT_DISCARD)
1596: return;
1597: log_debug("%s: \"%s\"", __func__, ictx->input_buf);
1598:
1599: screen_set_title(ictx->ctx.s, ictx->input_buf);
1600: server_status_window(ictx->wp->window);
1601: }
1602:
1603: /* Rename string started. */
1604: void
1605: input_enter_rename(struct input_ctx *ictx)
1606: {
1607: log_debug("%s", __func__);
1608:
1.35 nicm 1609: input_clear(ictx);
1.28 nicm 1610: }
1611:
1612: /* Rename terminator (ST) received. */
1613: void
1614: input_exit_rename(struct input_ctx *ictx)
1615: {
1616: if (ictx->flags & INPUT_DISCARD)
1.44 nicm 1617: return;
1618: if (!options_get_number(&ictx->wp->window->options, "allow-rename"))
1.28 nicm 1619: return;
1620: log_debug("%s: \"%s\"", __func__, ictx->input_buf);
1621:
1.48 nicm 1622: window_set_name(ictx->wp->window, ictx->input_buf);
1.28 nicm 1623: options_set_number(&ictx->wp->window->options, "automatic-rename", 0);
1624:
1625: server_status_window(ictx->wp->window);
1626: }
1627:
1628: /* Open UTF-8 character. */
1629: int
1630: input_utf8_open(struct input_ctx *ictx)
1631: {
1632: if (!options_get_number(&ictx->wp->window->options, "utf8")) {
1633: /* Print, and do not switch state. */
1634: input_print(ictx);
1635: return (-1);
1636: }
1637: log_debug("%s", __func__);
1638:
1639: utf8_open(&ictx->utf8data, ictx->ch);
1640: return (0);
1641: }
1642:
1643: /* Append to UTF-8 character. */
1644: int
1645: input_utf8_add(struct input_ctx *ictx)
1646: {
1647: log_debug("%s", __func__);
1648:
1649: utf8_append(&ictx->utf8data, ictx->ch);
1650: return (0);
1651: }
1652:
1653: /* Close UTF-8 string. */
1654: int
1655: input_utf8_close(struct input_ctx *ictx)
1656: {
1657: log_debug("%s", __func__);
1658:
1659: utf8_append(&ictx->utf8data, ictx->ch);
1660:
1.58 nicm 1661: grid_cell_set(&ictx->cell, &ictx->utf8data);
1662: screen_write_cell(&ictx->ctx, &ictx->cell);
1.28 nicm 1663:
1664: return (0);
1.1 nicm 1665: }