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