input.c revision 1.12
1/* $OpenBSD: input.c,v 1.12 2009/08/08 15:57:49 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 <stdint.h>
22#include <stdlib.h>
23#include <string.h>
24
25#include "tmux.h"
26
27#define INPUT_C0CONTROL(ch) 	(ch <= 0x1f)
28#define INPUT_INTERMEDIATE(ch)	(ch == 0xa0 || (ch >= 0x20 && ch <= 0x2f))
29#define INPUT_PARAMETER(ch)	(ch >= 0x30 && ch <= 0x3f)
30#define INPUT_UPPERCASE(ch)	(ch >= 0x40 && ch <= 0x5f)
31#define INPUT_LOWERCASE(ch)	(ch >= 0x60 && ch <= 0x7e)
32#define INPUT_DELETE(ch)	(ch == 0x7f)
33#define INPUT_C1CONTROL(ch)	(ch >= 0x80 && ch <= 0x9f)
34#define INPUT_G1DISPLAYABLE(ch)	(ch >= 0xa1 && ch <= 0xfe)
35#define INPUT_SPECIAL(ch)	(ch == 0xff)
36
37int	 input_get_argument(struct input_ctx *, u_int, uint16_t *, uint16_t);
38void	 input_new_argument(struct input_ctx *);
39int	 input_add_argument(struct input_ctx *, u_char);
40
41void	 input_start_string(struct input_ctx *, int);
42void	 input_abort_string(struct input_ctx *);
43int	 input_add_string(struct input_ctx *, u_char);
44char	*input_get_string(struct input_ctx *);
45
46void	 input_state(struct input_ctx *, void *);
47
48void	 input_state_first(u_char, struct input_ctx *);
49void	 input_state_escape(u_char, struct input_ctx *);
50void	 input_state_intermediate(u_char, struct input_ctx *);
51void	 input_state_sequence_first(u_char, struct input_ctx *);
52void	 input_state_sequence_next(u_char, struct input_ctx *);
53void	 input_state_sequence_intermediate(u_char, struct input_ctx *);
54void	 input_state_string_next(u_char, struct input_ctx *);
55void	 input_state_string_escape(u_char, struct input_ctx *);
56void	 input_state_utf8(u_char, struct input_ctx *);
57
58void	 input_handle_character(u_char, struct input_ctx *);
59void	 input_handle_c0_control(u_char, struct input_ctx *);
60void	 input_handle_c1_control(u_char, struct input_ctx *);
61void	 input_handle_private_two(u_char, struct input_ctx *);
62void	 input_handle_standard_two(u_char, struct input_ctx *);
63void	 input_handle_sequence(u_char, struct input_ctx *);
64
65void	 input_handle_sequence_cuu(struct input_ctx *);
66void	 input_handle_sequence_cud(struct input_ctx *);
67void	 input_handle_sequence_cuf(struct input_ctx *);
68void	 input_handle_sequence_cub(struct input_ctx *);
69void	 input_handle_sequence_dch(struct input_ctx *);
70void	 input_handle_sequence_cbt(struct input_ctx *);
71void	 input_handle_sequence_dl(struct input_ctx *);
72void	 input_handle_sequence_ich(struct input_ctx *);
73void	 input_handle_sequence_il(struct input_ctx *);
74void	 input_handle_sequence_vpa(struct input_ctx *);
75void	 input_handle_sequence_hpa(struct input_ctx *);
76void	 input_handle_sequence_cup(struct input_ctx *);
77void	 input_handle_sequence_cup(struct input_ctx *);
78void	 input_handle_sequence_tbc(struct input_ctx *);
79void	 input_handle_sequence_ed(struct input_ctx *);
80void	 input_handle_sequence_el(struct input_ctx *);
81void	 input_handle_sequence_sm(struct input_ctx *);
82void	 input_handle_sequence_rm(struct input_ctx *);
83void	 input_handle_sequence_decstbm(struct input_ctx *);
84void	 input_handle_sequence_sgr(struct input_ctx *);
85void	 input_handle_sequence_dsr(struct input_ctx *);
86
87int	 input_sequence_cmp(const void *, const void *);
88
89struct input_sequence_entry {
90	u_char	ch;
91	void	(*fn)(struct input_ctx *);
92};
93const struct input_sequence_entry input_sequence_table[] = {
94	{ '@', input_handle_sequence_ich },
95	{ 'A', input_handle_sequence_cuu },
96	{ 'B', input_handle_sequence_cud },
97	{ 'C', input_handle_sequence_cuf },
98	{ 'D', input_handle_sequence_cub },
99	{ 'G', input_handle_sequence_hpa },
100	{ 'H', input_handle_sequence_cup },
101	{ 'J', input_handle_sequence_ed },
102	{ 'K', input_handle_sequence_el },
103	{ 'L', input_handle_sequence_il },
104	{ 'M', input_handle_sequence_dl },
105	{ 'P', input_handle_sequence_dch },
106	{ 'Z', input_handle_sequence_cbt },
107	{ 'd', input_handle_sequence_vpa },
108	{ 'f', input_handle_sequence_cup },
109	{ 'g', input_handle_sequence_tbc },
110	{ 'h', input_handle_sequence_sm },
111	{ 'l', input_handle_sequence_rm },
112	{ 'm', input_handle_sequence_sgr },
113	{ 'n', input_handle_sequence_dsr },
114	{ 'r', input_handle_sequence_decstbm },
115};
116
117int
118input_sequence_cmp(const void *a, const void *b)
119{
120	int	ai = ((const struct input_sequence_entry *) a)->ch;
121	int	bi = ((const struct input_sequence_entry *) b)->ch;
122
123	return (ai - bi);
124}
125
126void
127input_new_argument(struct input_ctx *ictx)
128{
129	struct input_arg       *arg;
130
131	ARRAY_EXPAND(&ictx->args, 1);
132
133	arg = &ARRAY_LAST(&ictx->args);
134	arg->used = 0;
135}
136
137int
138input_add_argument(struct input_ctx *ictx, u_char ch)
139{
140	struct input_arg       *arg;
141
142	if (ARRAY_LENGTH(&ictx->args) == 0)
143		return (0);
144
145	arg = &ARRAY_LAST(&ictx->args);
146	if (arg->used > (sizeof arg->data) - 1)
147		return (-1);
148	arg->data[arg->used++] = ch;
149
150	return (0);
151}
152
153int
154input_get_argument(struct input_ctx *ictx, u_int i, uint16_t *n, uint16_t d)
155{
156	struct input_arg	*arg;
157	const char		*errstr;
158
159	*n = d;
160	if (i >= ARRAY_LENGTH(&ictx->args))
161		return (0);
162
163	arg = &ARRAY_ITEM(&ictx->args, i);
164	if (*arg->data == '\0')
165		return (0);
166
167	*n = strtonum(arg->data, 0, UINT16_MAX, &errstr);
168	if (errstr != NULL)
169		return (-1);
170	return (0);
171}
172
173void
174input_start_string(struct input_ctx *ictx, int type)
175{
176	ictx->string_type = type;
177	ictx->string_len = 0;
178}
179
180void
181input_abort_string(struct input_ctx *ictx)
182{
183	if (ictx->string_buf != NULL)
184		xfree(ictx->string_buf);
185	ictx->string_buf = NULL;
186}
187
188int
189input_add_string(struct input_ctx *ictx, u_char ch)
190{
191	ictx->string_buf = xrealloc(ictx->string_buf, 1, ictx->string_len + 1);
192	ictx->string_buf[ictx->string_len++] = ch;
193
194	if (ictx->string_len >= MAXSTRINGLEN) {
195		input_abort_string(ictx);
196		return (1);
197	}
198
199	return (0);
200}
201
202char *
203input_get_string(struct input_ctx *ictx)
204{
205	char	*s;
206
207	if (ictx->string_buf == NULL || input_add_string(ictx, '\0') != 0)
208		return (xstrdup(""));
209
210	s = ictx->string_buf;
211	ictx->string_buf = NULL;
212	return (s);
213}
214
215void
216input_state(struct input_ctx *ictx, void *state)
217{
218	ictx->state = state;
219}
220
221void
222input_init(struct window_pane *wp)
223{
224	struct input_ctx	*ictx = &wp->ictx;
225
226	ARRAY_INIT(&ictx->args);
227
228	ictx->string_len = 0;
229	ictx->string_buf = NULL;
230
231 	memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell);
232
233	memcpy(&ictx->saved_cell, &grid_default_cell, sizeof ictx->saved_cell);
234	ictx->saved_cx = 0;
235	ictx->saved_cy = 0;
236
237	input_state(ictx, input_state_first);
238}
239
240void
241input_free(struct window_pane *wp)
242{
243	if (wp->ictx.string_buf != NULL)
244		xfree(wp->ictx.string_buf);
245
246	ARRAY_FREE(&wp->ictx.args);
247}
248
249void
250input_parse(struct window_pane *wp)
251{
252	struct input_ctx	*ictx = &wp->ictx;
253	u_char			 ch;
254
255	if (BUFFER_USED(wp->in) == 0)
256		return;
257
258	ictx->buf = BUFFER_OUT(wp->in);
259	ictx->len = BUFFER_USED(wp->in);
260	ictx->off = 0;
261
262	ictx->wp = wp;
263
264	log_debug2("entry; buffer=%zu", ictx->len);
265
266	if (wp->mode == NULL)
267		screen_write_start(&ictx->ctx, wp, &wp->base);
268	else
269		screen_write_start(&ictx->ctx, NULL, &wp->base);
270
271	if (ictx->off != ictx->len)
272		wp->window->flags |= WINDOW_ACTIVITY;
273	while (ictx->off < ictx->len) {
274		ch = ictx->buf[ictx->off++];
275		ictx->state(ch, ictx);
276	}
277
278	screen_write_stop(&ictx->ctx);
279
280	buffer_remove(wp->in, ictx->len);
281}
282
283void
284input_state_first(u_char ch, struct input_ctx *ictx)
285{
286	ictx->intermediate = '\0';
287
288	if (INPUT_C0CONTROL(ch)) {
289		if (ch == 0x1b)
290			input_state(ictx, input_state_escape);
291		else
292			input_handle_c0_control(ch, ictx);
293		return;
294	}
295
296#if 0
297  	if (INPUT_C1CONTROL(ch)) {
298		ch -= 0x40;
299		if (ch == '[')
300			input_state(ictx, input_state_sequence_first);
301		else if (ch == ']') {
302			input_start_string(ictx, STRING_SYSTEM);
303			input_state(ictx, input_state_string_next);
304		} else if (ch == '_') {
305			input_start_string(ictx, STRING_APPLICATION);
306			input_state(ictx, input_state_string_next);
307		} else
308			input_handle_c1_control(ch, ictx);
309		return;
310	}
311#endif
312
313	if (INPUT_DELETE(ch))
314		return;
315
316	input_handle_character(ch, ictx);
317}
318
319void
320input_state_escape(u_char ch, struct input_ctx *ictx)
321{
322	/* Treat C1 control and G1 displayable as 7-bit equivalent. */
323	if (INPUT_C1CONTROL(ch) || INPUT_G1DISPLAYABLE(ch))
324		ch &= 0x7f;
325
326	if (INPUT_C0CONTROL(ch)) {
327		input_handle_c0_control(ch, ictx);
328		return;
329	}
330
331	if (INPUT_INTERMEDIATE(ch)) {
332		log_debug2(":: in1 %zu: %hhu (%c)", ictx->off, ch, ch);
333		ictx->intermediate = ch;
334		input_state(ictx, input_state_intermediate);
335		return;
336	}
337
338	if (INPUT_PARAMETER(ch)) {
339		input_state(ictx, input_state_first);
340		input_handle_private_two(ch, ictx);
341		return;
342	}
343
344	if (INPUT_UPPERCASE(ch)) {
345		if (ch == '[')
346			input_state(ictx, input_state_sequence_first);
347		else if (ch == ']') {
348			input_start_string(ictx, STRING_SYSTEM);
349			input_state(ictx, input_state_string_next);
350		} else if (ch == '_') {
351			input_start_string(ictx, STRING_APPLICATION);
352			input_state(ictx, input_state_string_next);
353		} else {
354			input_state(ictx, input_state_first);
355			input_handle_c1_control(ch, ictx);
356		}
357		return;
358	}
359
360	if (INPUT_LOWERCASE(ch)) {
361		input_state(ictx, input_state_first);
362		input_handle_standard_two(ch, ictx);
363		return;
364	}
365
366	input_state(ictx, input_state_first);
367}
368
369void
370input_state_intermediate(u_char ch, struct input_ctx *ictx)
371{
372	if (INPUT_INTERMEDIATE(ch)) {
373		/* Multiple intermediates currently ignored. */
374		log_debug2(":: in2 %zu: %hhu (%c)", ictx->off, ch, ch);
375		return;
376	}
377
378	if (INPUT_PARAMETER(ch)) {
379		input_state(ictx, input_state_first);
380		input_handle_private_two(ch, ictx);
381		return;
382	}
383
384	if (INPUT_UPPERCASE(ch) || INPUT_LOWERCASE(ch)) {
385		input_state(ictx, input_state_first);
386		input_handle_standard_two(ch, ictx);
387		return;
388	}
389
390	input_state(ictx, input_state_first);
391}
392
393void
394input_state_sequence_first(u_char ch, struct input_ctx *ictx)
395{
396	ictx->private = '\0';
397	ARRAY_CLEAR(&ictx->args);
398
399	/* Most C0 control are accepted within CSI. */
400	if (INPUT_C0CONTROL(ch)) {
401		if (ch == 0x1b) {			/* ESC */
402			/* Abort sequence and begin with new. */
403			input_state(ictx, input_state_escape);
404			return;
405		} else if (ch == 0x18 || ch == 0x1a) {	/* CAN and SUB */
406			/* Abort sequence. */
407			input_state(ictx, input_state_first);
408			return;
409		}
410
411		/* Handle C0 immediately. */
412		input_handle_c0_control(ch, ictx);
413
414		/*
415		 * Just come back to this state, in case the next character
416		 * is the start of a private sequence.
417		 */
418		return;
419	}
420
421	input_state(ictx, input_state_sequence_next);
422
423	/* Private sequence: always the first character. */
424	if (ch >= 0x3c && ch <= 0x3f) {
425		ictx->private = ch;
426		return;
427	}
428
429	/* Pass character on directly. */
430	input_state_sequence_next(ch, ictx);
431}
432
433void
434input_state_sequence_next(u_char ch, struct input_ctx *ictx)
435{
436	if (INPUT_INTERMEDIATE(ch)) {
437		if (input_add_argument(ictx, '\0') != 0)
438			input_state(ictx, input_state_first);
439		else {
440			log_debug2(":: si1 %zu: %hhu (%c)", ictx->off, ch, ch);
441			input_state(ictx, input_state_sequence_intermediate);
442		}
443		return;
444	}
445
446	if (INPUT_PARAMETER(ch)) {
447		if (ARRAY_EMPTY(&ictx->args))
448			input_new_argument(ictx);
449
450		if (ch == ';') {
451			if (input_add_argument(ictx, '\0') != 0)
452				input_state(ictx, input_state_first);
453			else
454				input_new_argument(ictx);
455		} else if (input_add_argument(ictx, ch) != 0)
456			input_state(ictx, input_state_first);
457		return;
458	}
459
460	if (INPUT_UPPERCASE(ch) || INPUT_LOWERCASE(ch)) {
461		if (input_add_argument(ictx, '\0') != 0)
462			input_state(ictx, input_state_first);
463		else {
464			input_state(ictx, input_state_first);
465			input_handle_sequence(ch, ictx);
466		}
467		return;
468	}
469
470	/* Most C0 control are accepted within CSI. */
471	if (INPUT_C0CONTROL(ch)) {
472		if (ch == 0x1b) {			/* ESC */
473			/* Abort sequence and begin with new. */
474			input_state(ictx, input_state_escape);
475			return;
476		} else if (ch == 0x18 || ch == 0x1a) {	/* CAN and SUB */
477			/* Abort sequence. */
478			input_state(ictx, input_state_first);
479			return;
480		}
481
482		/* Handle C0 immediately. */
483		input_handle_c0_control(ch, ictx);
484
485		return;
486	}
487
488	input_state(ictx, input_state_first);
489}
490
491void
492input_state_sequence_intermediate(u_char ch, struct input_ctx *ictx)
493{
494	if (INPUT_INTERMEDIATE(ch)) {
495		log_debug2(":: si2 %zu: %hhu (%c)", ictx->off, ch, ch);
496		return;
497	}
498
499	if (INPUT_UPPERCASE(ch) || INPUT_LOWERCASE(ch)) {
500		input_state(ictx, input_state_first);
501		input_handle_sequence(ch, ictx);
502		return;
503	}
504
505	input_state(ictx, input_state_first);
506}
507
508void
509input_state_string_next(u_char ch, struct input_ctx *ictx)
510{
511	if (ch == 0x1b) {
512		input_state(ictx, input_state_string_escape);
513		return;
514	}
515	if (ch == 0x07) {
516		input_state_string_escape(ch, ictx);
517		return;
518	}
519
520	if (ch >= 0x20) {
521		if (input_add_string(ictx, ch) != 0)
522			input_state(ictx, input_state_first);
523		return;
524	}
525}
526
527void
528input_state_string_escape(u_char ch, struct input_ctx *ictx)
529{
530	char	*s;
531
532	if (ch == '\007' || ch == '\\') {
533		input_state(ictx, input_state_first);
534		switch (ictx->string_type) {
535		case STRING_SYSTEM:
536			if (ch != '\007')
537				return;
538			s = input_get_string(ictx);
539			if ((s[0] != '0' && s[0] != '2') || s[1] != ';') {
540				xfree(s);
541				return;
542			}
543			screen_set_title(ictx->ctx.s, s + 2);
544			server_status_window(ictx->wp->window);
545			xfree(s);
546			break;
547		case STRING_APPLICATION:
548			if (ch != '\\')
549				return;
550			s = input_get_string(ictx);
551			screen_set_title(ictx->ctx.s, s);
552			server_status_window(ictx->wp->window);
553			xfree(s);
554			break;
555		case STRING_NAME:
556			if (ch != '\\')
557				return;
558			xfree(ictx->wp->window->name);
559			ictx->wp->window->name = input_get_string(ictx);
560			server_status_window(ictx->wp->window);
561			break;
562		}
563		return;
564	}
565
566	input_state(ictx, input_state_string_next);
567	input_state_string_next(ch, ictx);
568}
569
570void
571input_state_utf8(u_char ch, struct input_ctx *ictx)
572{
573	log_debug2("-- un %zu: %hhu (%c)", ictx->off, ch, ch);
574
575	ictx->utf8_buf[ictx->utf8_off++] = ch;
576	if (--ictx->utf8_len != 0)
577		return;
578	input_state(ictx, input_state_first);
579
580	ictx->cell.flags |= GRID_FLAG_UTF8;
581	screen_write_cell(&ictx->ctx, &ictx->cell, ictx->utf8_buf);
582	ictx->cell.flags &= ~GRID_FLAG_UTF8;
583}
584
585void
586input_handle_character(u_char ch, struct input_ctx *ictx)
587{
588	struct window_pane	*wp = ictx->wp;
589
590	if (ch > 0x7f && options_get_number(&wp->window->options, "utf8")) {
591		/*
592		 * UTF-8 sequence.
593		 *
594		 * 11000010-11011111 C2-DF start of 2-byte sequence
595		 * 11100000-11101111 E0-EF start of 3-byte sequence
596		 * 11110000-11110100 F0-F4 start of 4-byte sequence
597		 */
598		memset(ictx->utf8_buf, 0xff, sizeof ictx->utf8_buf);
599		ictx->utf8_buf[0] = ch;
600		ictx->utf8_off = 1;
601
602		if (ch >= 0xc2 && ch <= 0xdf) {
603			log_debug2("-- u2 %zu: %hhu (%c)", ictx->off, ch, ch);
604			input_state(ictx, input_state_utf8);
605			ictx->utf8_len = 1;
606			return;
607		}
608		if (ch >= 0xe0 && ch <= 0xef) {
609			log_debug2("-- u3 %zu: %hhu (%c)", ictx->off, ch, ch);
610			input_state(ictx, input_state_utf8);
611			ictx->utf8_len = 2;
612			return;
613		}
614		if (ch >= 0xf0 && ch <= 0xf4) {
615			log_debug2("-- u4 %zu: %hhu (%c)", ictx->off, ch, ch);
616			input_state(ictx, input_state_utf8);
617			ictx->utf8_len = 3;
618			return;
619		}
620	}
621	log_debug2("-- ch %zu: %hhu (%c)", ictx->off, ch, ch);
622
623	ictx->cell.data = ch;
624	screen_write_cell(&ictx->ctx, &ictx->cell, ictx->utf8_buf);
625}
626
627void
628input_handle_c0_control(u_char ch, struct input_ctx *ictx)
629{
630	struct screen	*s = ictx->ctx.s;
631
632	log_debug2("-- c0 %zu: %hhu", ictx->off, ch);
633
634	switch (ch) {
635	case '\0':	/* NUL */
636		break;
637	case '\n':	/* LF */
638		screen_write_linefeed(&ictx->ctx, 0);
639		break;
640	case '\r':	/* CR */
641		screen_write_carriagereturn(&ictx->ctx);
642		break;
643	case '\007':	/* BELL */
644		ictx->wp->window->flags |= WINDOW_BELL;
645		break;
646	case '\010': 	/* BS */
647		screen_write_cursorleft(&ictx->ctx, 1);
648		break;
649	case '\011': 	/* TAB */
650		/* Don't tab beyond the end of the line. */
651		if (s->cx >= screen_size_x(s) - 1)
652			break;
653
654		/* Find the next tab point, or use the last column if none. */
655		do {
656			s->cx++;
657			if (bit_test(s->tabs, s->cx))
658				break;
659		} while (s->cx < screen_size_x(s) - 1);
660		break;
661	case '\013':	/* VT */
662		screen_write_linefeed(&ictx->ctx, 0);
663		break;
664	case '\016':	/* SO */
665		ictx->cell.attr |= GRID_ATTR_CHARSET;
666		break;
667	case '\017':	/* SI */
668		ictx->cell.attr &= ~GRID_ATTR_CHARSET;
669		break;
670	default:
671		log_debug("unknown c0: %hhu", ch);
672		break;
673	}
674}
675
676void
677input_handle_c1_control(u_char ch, struct input_ctx *ictx)
678{
679	struct screen  *s = ictx->ctx.s;
680
681	log_debug2("-- c1 %zu: %hhu (%c)", ictx->off, ch, ch);
682
683	switch (ch) {
684	case 'D':	/* IND */
685		screen_write_linefeed(&ictx->ctx, 0);
686		break;
687	case 'E': 	/* NEL */
688		screen_write_carriagereturn(&ictx->ctx);
689		screen_write_linefeed(&ictx->ctx, 0);
690		break;
691	case 'H':	/* HTS */
692		if (s->cx < screen_size_x(s))
693			bit_set(s->tabs, s->cx);
694		break;
695	case 'M':	/* RI */
696		screen_write_reverseindex(&ictx->ctx);
697		break;
698	default:
699		log_debug("unknown c1: %hhu", ch);
700		break;
701	}
702}
703
704void
705input_handle_private_two(u_char ch, struct input_ctx *ictx)
706{
707	struct screen	*s = ictx->ctx.s;
708
709	log_debug2(
710	    "-- p2 %zu: %hhu (%c) %hhu", ictx->off, ch, ch, ictx->intermediate);
711
712	switch (ch) {
713	case '0':	/* SCS */
714		/*
715		 * Not really supported, but fake it up enough for those that
716		 * use it to switch character sets (by redefining G0 to
717		 * graphics set, rather than switching to G1).
718		 */
719		switch (ictx->intermediate) {
720		case '(':	/* G0 */
721			ictx->cell.attr |= GRID_ATTR_CHARSET;
722			break;
723		}
724		break;
725	case '=':	/* DECKPAM */
726		if (ictx->intermediate != '\0')
727			break;
728		screen_write_kkeypadmode(&ictx->ctx, 1);
729		log_debug("kkeypad on (application mode)");
730		break;
731	case '>':	/* DECKPNM */
732		if (ictx->intermediate != '\0')
733			break;
734		screen_write_kkeypadmode(&ictx->ctx, 0);
735		log_debug("kkeypad off (number mode)");
736		break;
737	case '7':	/* DECSC */
738		if (ictx->intermediate != '\0')
739			break;
740		memcpy(&ictx->saved_cell, &ictx->cell, sizeof ictx->saved_cell);
741		ictx->saved_cx = s->cx;
742		ictx->saved_cy = s->cy;
743		break;
744	case '8':
745		switch (ictx->intermediate) {
746		case '\0':	/* DECRC */
747			memcpy(
748			    &ictx->cell, &ictx->saved_cell, sizeof ictx->cell);
749			screen_write_cursormove(
750			    &ictx->ctx, ictx->saved_cx, ictx->saved_cy);
751			break;
752		case '#':	/* DECALN */
753			screen_write_alignmenttest(&ictx->ctx);
754			break;
755		}
756		break;
757	default:
758		log_debug("unknown p2: %hhu", ch);
759		break;
760	}
761}
762
763void
764input_handle_standard_two(u_char ch, struct input_ctx *ictx)
765{
766	log_debug2(
767	    "-- s2 %zu: %hhu (%c) %hhu", ictx->off, ch, ch, ictx->intermediate);
768
769	switch (ch) {
770	case 'B':	/* SCS */
771		/*
772		 * Not really supported, but fake it up enough for those that
773		 * use it to switch character sets (by redefining G0 to
774		 * graphics set, rather than switching to G1).
775		 */
776		switch (ictx->intermediate) {
777		case '(':	/* G0 */
778			ictx->cell.attr &= ~GRID_ATTR_CHARSET;
779			break;
780		}
781		break;
782	case 'c':	/* RIS */
783		memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell);
784
785		memcpy(&ictx->saved_cell, &ictx->cell, sizeof ictx->saved_cell);
786		ictx->saved_cx = 0;
787		ictx->saved_cy = 0;
788
789		screen_reset_tabs(ictx->ctx.s);
790
791		screen_write_scrollregion(
792		    &ictx->ctx, 0, screen_size_y(ictx->ctx.s) - 1);
793
794		screen_write_insertmode(&ictx->ctx, 0);
795		screen_write_kcursormode(&ictx->ctx, 0);
796		screen_write_kkeypadmode(&ictx->ctx, 0);
797		screen_write_mousemode(&ictx->ctx, 0);
798
799		screen_write_clearscreen(&ictx->ctx);
800		screen_write_cursormove(&ictx->ctx, 0, 0);
801		break;
802	case 'k':
803		input_start_string(ictx, STRING_NAME);
804		input_state(ictx, input_state_string_next);
805		break;
806	default:
807		log_debug("unknown s2: %hhu", ch);
808		break;
809	}
810}
811
812void
813input_handle_sequence(u_char ch, struct input_ctx *ictx)
814{
815	struct input_sequence_entry	*entry, find;
816	struct screen	 		*s = ictx->ctx.s;
817	u_int			         i;
818	struct input_arg 		*iarg;
819
820	log_debug2("-- sq %zu: %hhu (%c): %u [sx=%u, sy=%u, cx=%u, cy=%u, "
821	    "ru=%u, rl=%u]", ictx->off, ch, ch, ARRAY_LENGTH(&ictx->args),
822	    screen_size_x(s), screen_size_y(s), s->cx, s->cy, s->rupper,
823	    s->rlower);
824	for (i = 0; i < ARRAY_LENGTH(&ictx->args); i++) {
825		iarg = &ARRAY_ITEM(&ictx->args, i);
826		if (*iarg->data != '\0')
827			log_debug2("      ++ %u: %s", i, iarg->data);
828	}
829
830	find.ch = ch;
831	entry = bsearch(&find,
832	    input_sequence_table, nitems(input_sequence_table),
833	    sizeof input_sequence_table[0], input_sequence_cmp);
834	if (entry != NULL)
835		entry->fn(ictx);
836	else
837		log_debug("unknown sq: %c (%hhu %hhu)", ch, ch, ictx->private);
838}
839
840void
841input_handle_sequence_cuu(struct input_ctx *ictx)
842{
843	uint16_t	n;
844
845	if (ictx->private != '\0')
846		return;
847
848	if (ARRAY_LENGTH(&ictx->args) > 1)
849		return;
850	if (input_get_argument(ictx, 0, &n, 1) != 0)
851		return;
852	if (n == 0)
853		n = 1;
854
855	screen_write_cursorup(&ictx->ctx, n);
856}
857
858void
859input_handle_sequence_cud(struct input_ctx *ictx)
860{
861	uint16_t	n;
862
863	if (ictx->private != '\0')
864		return;
865
866	if (ARRAY_LENGTH(&ictx->args) > 1)
867		return;
868	if (input_get_argument(ictx, 0, &n, 1) != 0)
869		return;
870	if (n == 0)
871		n = 1;
872
873	screen_write_cursordown(&ictx->ctx, n);
874}
875
876void
877input_handle_sequence_cuf(struct input_ctx *ictx)
878{
879	uint16_t n;
880
881	if (ictx->private != '\0')
882		return;
883
884	if (ARRAY_LENGTH(&ictx->args) > 1)
885		return;
886	if (input_get_argument(ictx, 0, &n, 1) != 0)
887		return;
888	if (n == 0)
889		n = 1;
890
891	screen_write_cursorright(&ictx->ctx, n);
892}
893
894void
895input_handle_sequence_cub(struct input_ctx *ictx)
896{
897	uint16_t	n;
898
899	if (ictx->private != '\0')
900		return;
901
902	if (ARRAY_LENGTH(&ictx->args) > 1)
903		return;
904	if (input_get_argument(ictx, 0, &n, 1) != 0)
905		return;
906	if (n == 0)
907		n = 1;
908
909	screen_write_cursorleft(&ictx->ctx, n);
910}
911
912void
913input_handle_sequence_dch(struct input_ctx *ictx)
914{
915	uint16_t	n;
916
917	if (ictx->private != '\0')
918		return;
919
920	if (ARRAY_LENGTH(&ictx->args) > 1)
921		return;
922	if (input_get_argument(ictx, 0, &n, 1) != 0)
923		return;
924	if (n == 0)
925		n = 1;
926
927	screen_write_deletecharacter(&ictx->ctx, n);
928}
929
930void
931input_handle_sequence_cbt(struct input_ctx *ictx)
932{
933	struct screen  *s = ictx->ctx.s;
934	uint16_t	n;
935
936	if (ictx->private != '\0')
937		return;
938
939	if (ARRAY_LENGTH(&ictx->args) > 1)
940		return;
941	if (input_get_argument(ictx, 0, &n, 1) != 0)
942		return;
943	if (n == 0)
944		n = 1;
945
946	/* Find the previous tab point, n times. */
947	while (s->cx > 0 && n-- > 0) {
948		do
949			s->cx--;
950		while (s->cx > 0 && !bit_test(s->tabs, s->cx));
951	}
952}
953
954void
955input_handle_sequence_dl(struct input_ctx *ictx)
956{
957	uint16_t	n;
958
959	if (ictx->private != '\0')
960		return;
961
962	if (ARRAY_LENGTH(&ictx->args) > 1)
963		return;
964	if (input_get_argument(ictx, 0, &n, 1) != 0)
965		return;
966	if (n == 0)
967		n = 1;
968
969	screen_write_deleteline(&ictx->ctx, n);
970}
971
972void
973input_handle_sequence_ich(struct input_ctx *ictx)
974{
975	uint16_t	n;
976
977	if (ictx->private != '\0')
978		return;
979
980	if (ARRAY_LENGTH(&ictx->args) > 1)
981		return;
982	if (input_get_argument(ictx, 0, &n, 1) != 0)
983		return;
984	if (n == 0)
985		n = 1;
986
987	screen_write_insertcharacter(&ictx->ctx, n);
988}
989
990void
991input_handle_sequence_il(struct input_ctx *ictx)
992{
993	uint16_t	n;
994
995	if (ictx->private != '\0')
996		return;
997
998	if (ARRAY_LENGTH(&ictx->args) > 1)
999		return;
1000	if (input_get_argument(ictx, 0, &n, 1) != 0)
1001		return;
1002	if (n == 0)
1003		n = 1;
1004
1005	screen_write_insertline(&ictx->ctx, n);
1006}
1007
1008void
1009input_handle_sequence_vpa(struct input_ctx *ictx)
1010{
1011	struct screen  *s = ictx->ctx.s;
1012	uint16_t	n;
1013
1014	if (ictx->private != '\0')
1015		return;
1016
1017	if (ARRAY_LENGTH(&ictx->args) > 1)
1018		return;
1019	if (input_get_argument(ictx, 0, &n, 1) != 0)
1020		return;
1021	if (n == 0)
1022		n = 1;
1023
1024	screen_write_cursormove(&ictx->ctx, s->cx, n - 1);
1025}
1026
1027void
1028input_handle_sequence_hpa(struct input_ctx *ictx)
1029{
1030	struct screen  *s = ictx->ctx.s;
1031	uint16_t	n;
1032
1033	if (ictx->private != '\0')
1034		return;
1035
1036	if (ARRAY_LENGTH(&ictx->args) > 1)
1037		return;
1038	if (input_get_argument(ictx, 0, &n, 1) != 0)
1039		return;
1040	if (n == 0)
1041		n = 1;
1042
1043	screen_write_cursormove(&ictx->ctx, n - 1, s->cy);
1044}
1045
1046void
1047input_handle_sequence_cup(struct input_ctx *ictx)
1048{
1049	uint16_t	n, m;
1050
1051	if (ictx->private != '\0')
1052		return;
1053
1054	if (ARRAY_LENGTH(&ictx->args) > 2)
1055		return;
1056	if (input_get_argument(ictx, 0, &n, 1) != 0)
1057		return;
1058	if (input_get_argument(ictx, 1, &m, 1) != 0)
1059		return;
1060	if (n == 0)
1061		n = 1;
1062	if (m == 0)
1063		m = 1;
1064
1065	screen_write_cursormove(&ictx->ctx, m - 1, n - 1);
1066}
1067
1068void
1069input_handle_sequence_tbc(struct input_ctx *ictx)
1070{
1071	struct screen  *s = ictx->ctx.s;
1072	uint16_t	n;
1073
1074	if (ictx->private != '\0')
1075		return;
1076
1077	if (ARRAY_LENGTH(&ictx->args) > 1)
1078		return;
1079	if (input_get_argument(ictx, 0, &n, 1) != 0)
1080		return;
1081
1082	switch (n) {
1083	case 0:
1084		if (s->cx < screen_size_x(s))
1085			bit_clear(s->tabs, s->cx);
1086		break;
1087	case 3:
1088		bit_nclear(s->tabs, 0, screen_size_x(s) - 1);
1089		break;
1090	}
1091}
1092
1093void
1094input_handle_sequence_ed(struct input_ctx *ictx)
1095{
1096	uint16_t	n;
1097
1098	if (ictx->private != '\0')
1099		return;
1100
1101	if (ARRAY_LENGTH(&ictx->args) > 1)
1102		return;
1103	if (input_get_argument(ictx, 0, &n, 0) != 0)
1104		return;
1105	if (n > 2)
1106		return;
1107
1108	switch (n) {
1109	case 0:
1110		screen_write_clearendofscreen(&ictx->ctx);
1111		break;
1112	case 1:
1113		screen_write_clearstartofscreen(&ictx->ctx);
1114		break;
1115	case 2:
1116		screen_write_clearscreen(&ictx->ctx);
1117		break;
1118	}
1119}
1120
1121void
1122input_handle_sequence_el(struct input_ctx *ictx)
1123{
1124	uint16_t	n;
1125
1126	if (ictx->private != '\0')
1127		return;
1128
1129	if (ARRAY_LENGTH(&ictx->args) > 1)
1130		return;
1131	if (input_get_argument(ictx, 0, &n, 0) != 0)
1132		return;
1133	if (n > 2)
1134		return;
1135
1136	switch (n) {
1137	case 0:
1138		screen_write_clearendofline(&ictx->ctx);
1139		break;
1140	case 1:
1141		screen_write_clearstartofline(&ictx->ctx);
1142		break;
1143	case 2:
1144		screen_write_clearline(&ictx->ctx);
1145		break;
1146	}
1147}
1148
1149void
1150input_handle_sequence_sm(struct input_ctx *ictx)
1151{
1152	struct window_pane	*wp = ictx->wp;
1153	struct screen		*s = &wp->base;
1154	u_int			 sx, sy;
1155	uint16_t		 n;
1156
1157	if (ARRAY_LENGTH(&ictx->args) > 1)
1158		return;
1159	if (input_get_argument(ictx, 0, &n, 0) != 0)
1160		return;
1161
1162	if (ictx->private == '?') {
1163		switch (n) {
1164		case 1:		/* GATM */
1165			screen_write_kcursormode(&ictx->ctx, 1);
1166			log_debug("kcursor on");
1167			break;
1168		case 25:	/* TCEM */
1169			screen_write_cursormode(&ictx->ctx, 1);
1170			log_debug("cursor on");
1171			break;
1172		case 1000:
1173			screen_write_mousemode(&ictx->ctx, 1);
1174			log_debug("mouse on");
1175			break;
1176		case 1049:
1177			if (wp->saved_grid != NULL)
1178				break;
1179			sx = screen_size_x(s);
1180			sy = screen_size_y(s);
1181
1182			/*
1183			 * Enter alternative screen mode. A copy of the visible
1184			 * screen is saved and the history is not updated
1185			 */
1186
1187			wp->saved_grid = grid_create(sx, sy, 0);
1188			grid_duplicate_lines(
1189			    wp->saved_grid, 0, s->grid, screen_hsize(s), sy);
1190			wp->saved_cx = s->cx;
1191			wp->saved_cy = s->cy;
1192			memcpy(&wp->saved_cell,
1193			    &ictx->cell, sizeof wp->saved_cell);
1194
1195			grid_view_clear(s->grid, 0, 0, sx, sy);
1196
1197			wp->base.grid->flags &= ~GRID_HISTORY;
1198
1199			wp->flags |= PANE_REDRAW;
1200			break;
1201		default:
1202			log_debug("unknown SM [%hhu]: %u", ictx->private, n);
1203			break;
1204		}
1205	} else {
1206		switch (n) {
1207		case 4:		/* IRM */
1208			screen_write_insertmode(&ictx->ctx, 1);
1209			log_debug("insert on");
1210			break;
1211		case 34:
1212			/* Cursor high visibility not supported. */
1213			break;
1214		default:
1215			log_debug("unknown SM [%hhu]: %u", ictx->private, n);
1216			break;
1217		}
1218	}
1219}
1220
1221void
1222input_handle_sequence_rm(struct input_ctx *ictx)
1223{
1224	struct window_pane	*wp = ictx->wp;
1225	struct screen		*s = &wp->base;
1226	u_int			 sx, sy;
1227	uint16_t		 n;
1228
1229	if (ARRAY_LENGTH(&ictx->args) > 1)
1230		return;
1231	if (input_get_argument(ictx, 0, &n, 0) != 0)
1232		return;
1233
1234	if (ictx->private == '?') {
1235		switch (n) {
1236		case 1:		/* GATM */
1237			screen_write_kcursormode(&ictx->ctx, 0);
1238			log_debug("kcursor off");
1239			break;
1240		case 25:	/* TCEM */
1241			screen_write_cursormode(&ictx->ctx, 0);
1242			log_debug("cursor off");
1243			break;
1244		case 1000:
1245			screen_write_mousemode(&ictx->ctx, 0);
1246			log_debug("mouse off");
1247			break;
1248		case 1049:
1249			if (wp->saved_grid == NULL)
1250				break;
1251			sx = screen_size_x(s);
1252			sy = screen_size_y(s);
1253
1254			/*
1255			 * Exit alternative screen mode and restore the copied
1256			 * grid.
1257			 */
1258
1259			/*
1260			 * If the current size is bigger, temporarily resize
1261			 * to the old size before copying back.
1262			 */
1263			if (sy > wp->saved_grid->sy)
1264				screen_resize(s, sx, wp->saved_grid->sy);
1265
1266			/* Restore the grid, cursor position and cell. */
1267			grid_duplicate_lines(
1268			    s->grid, screen_hsize(s), wp->saved_grid, 0, sy);
1269			s->cx = wp->saved_cx;
1270			if (s->cx > screen_size_x(s) - 1)
1271				s->cx = screen_size_x(s) - 1;
1272			s->cy = wp->saved_cy;
1273			if (s->cy > screen_size_y(s) - 1)
1274				s->cy = screen_size_y(s) - 1;
1275			memcpy(&ictx->cell, &wp->saved_cell, sizeof ictx->cell);
1276
1277			/*
1278			 * Turn history back on (so resize can use it) and then
1279			 * resize back to the current size.
1280			 */
1281  			wp->base.grid->flags |= GRID_HISTORY;
1282			if (sy > wp->saved_grid->sy)
1283				screen_resize(s, sx, sy);
1284
1285			grid_destroy(wp->saved_grid);
1286			wp->saved_grid = NULL;
1287
1288			wp->flags |= PANE_REDRAW;
1289			break;
1290		default:
1291			log_debug("unknown RM [%hhu]: %u", ictx->private, n);
1292			break;
1293		}
1294	} else if (ictx->private == '\0') {
1295		switch (n) {
1296		case 4:		/* IRM */
1297			screen_write_insertmode(&ictx->ctx, 0);
1298			log_debug("insert off");
1299			break;
1300		case 34:
1301			/* Cursor high visibility not supported. */
1302			break;
1303		default:
1304			log_debug("unknown RM [%hhu]: %u", ictx->private, n);
1305			break;
1306		}
1307	}
1308}
1309
1310void
1311input_handle_sequence_dsr(struct input_ctx *ictx)
1312{
1313	struct screen  *s = ictx->ctx.s;
1314	uint16_t	n;
1315	char		reply[32];
1316
1317	if (ARRAY_LENGTH(&ictx->args) > 1)
1318		return;
1319	if (input_get_argument(ictx, 0, &n, 0) != 0)
1320		return;
1321
1322	if (ictx->private == '\0') {
1323		switch (n) {
1324		case 6:	/* cursor position */
1325			xsnprintf(reply, sizeof reply,
1326			    "\033[%u;%uR", s->cy + 1, s->cx + 1);
1327			log_debug("cursor request, reply: %s", reply);
1328			buffer_write(ictx->wp->out, reply, strlen(reply));
1329			break;
1330		}
1331	}
1332}
1333
1334void
1335input_handle_sequence_decstbm(struct input_ctx *ictx)
1336{
1337	struct screen  *s = ictx->ctx.s;
1338	uint16_t	n, m;
1339
1340	if (ictx->private != '\0')
1341		return;
1342
1343	if (ARRAY_LENGTH(&ictx->args) > 2)
1344		return;
1345	if (input_get_argument(ictx, 0, &n, 0) != 0)
1346		return;
1347	if (input_get_argument(ictx, 1, &m, 0) != 0)
1348		return;
1349	if (n == 0)
1350		n = 1;
1351	if (m == 0)
1352		m = screen_size_y(s);
1353
1354	screen_write_scrollregion(&ictx->ctx, n - 1, m - 1);
1355}
1356
1357void
1358input_handle_sequence_sgr(struct input_ctx *ictx)
1359{
1360	struct grid_cell       *gc = &ictx->cell;
1361	u_int			i;
1362	uint16_t		m, o;
1363	u_char			attr;
1364
1365	if (ARRAY_LENGTH(&ictx->args) == 0) {
1366		attr = gc->attr;
1367		memcpy(gc, &grid_default_cell, sizeof *gc);
1368 		gc->attr |= (attr & GRID_ATTR_CHARSET);
1369		return;
1370	}
1371
1372	for (i = 0; i < ARRAY_LENGTH(&ictx->args); i++) {
1373		if (input_get_argument(ictx, i, &m, 0) != 0)
1374			return;
1375
1376		if (m == 38 || m == 48) {
1377			i++;
1378			if (input_get_argument(ictx, i, &o, 0) != 0)
1379				return;
1380			if (o != 5)
1381				continue;
1382
1383			i++;
1384			if (input_get_argument(ictx, i, &o, 0) != 0)
1385				return;
1386			if (m == 38) {
1387				gc->flags |= GRID_FLAG_FG256;
1388				gc->fg = o;
1389			} else if (m == 48) {
1390				gc->flags |= GRID_FLAG_BG256;
1391				gc->bg = o;
1392			}
1393			continue;
1394		}
1395
1396		switch (m) {
1397		case 0:
1398		case 10:
1399			attr = gc->attr;
1400			memcpy(gc, &grid_default_cell, sizeof *gc);
1401			gc->attr |= (attr & GRID_ATTR_CHARSET);
1402			break;
1403		case 1:
1404			gc->attr |= GRID_ATTR_BRIGHT;
1405			break;
1406		case 2:
1407			gc->attr |= GRID_ATTR_DIM;
1408			break;
1409		case 3:
1410			gc->attr |= GRID_ATTR_ITALICS;
1411			break;
1412		case 4:
1413			gc->attr |= GRID_ATTR_UNDERSCORE;
1414			break;
1415		case 5:
1416			gc->attr |= GRID_ATTR_BLINK;
1417			break;
1418		case 7:
1419			gc->attr |= GRID_ATTR_REVERSE;
1420			break;
1421		case 8:
1422			gc->attr |= GRID_ATTR_HIDDEN;
1423			break;
1424		case 22:
1425			gc->attr &= ~(GRID_ATTR_BRIGHT|GRID_ATTR_DIM);
1426			break;
1427		case 23:
1428			gc->attr &= ~GRID_ATTR_ITALICS;
1429			break;
1430		case 24:
1431			gc->attr &= ~GRID_ATTR_UNDERSCORE;
1432			break;
1433		case 25:
1434			gc->attr &= ~GRID_ATTR_BLINK;
1435			break;
1436		case 27:
1437			gc->attr &= ~GRID_ATTR_REVERSE;
1438			break;
1439		case 30:
1440		case 31:
1441		case 32:
1442		case 33:
1443		case 34:
1444		case 35:
1445		case 36:
1446		case 37:
1447			gc->flags &= ~GRID_FLAG_FG256;
1448			gc->fg = m - 30;
1449			break;
1450		case 39:
1451			gc->flags &= ~GRID_FLAG_FG256;
1452			gc->fg = 8;
1453			break;
1454		case 40:
1455		case 41:
1456		case 42:
1457		case 43:
1458		case 44:
1459		case 45:
1460		case 46:
1461		case 47:
1462			gc->flags &= ~GRID_FLAG_BG256;
1463			gc->bg = m - 40;
1464			break;
1465		case 49:
1466			gc->flags &= ~GRID_FLAG_BG256;
1467			gc->bg = 8;
1468			break;
1469		}
1470	}
1471}
1472