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