xref: /openbsd-src/usr.bin/tmux/input.c (revision 5054e3e78af0749a9bb00ba9a024b3ee2d90290f)
1 /* $OpenBSD: input.c,v 1.22 2009/11/04 22:43:11 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 
37 int	 input_get_argument(struct input_ctx *, u_int, uint16_t *, uint16_t);
38 void	 input_new_argument(struct input_ctx *);
39 int	 input_add_argument(struct input_ctx *, u_char);
40 
41 void	 input_start_string(struct input_ctx *, int);
42 void	 input_abort_string(struct input_ctx *);
43 int	 input_add_string(struct input_ctx *, u_char);
44 char	*input_get_string(struct input_ctx *);
45 
46 void	 input_state(struct input_ctx *, void *);
47 
48 void	 input_state_first(u_char, struct input_ctx *);
49 void	 input_state_escape(u_char, struct input_ctx *);
50 void	 input_state_intermediate(u_char, struct input_ctx *);
51 void	 input_state_sequence_first(u_char, struct input_ctx *);
52 void	 input_state_sequence_next(u_char, struct input_ctx *);
53 void	 input_state_sequence_intermediate(u_char, struct input_ctx *);
54 void	 input_state_string_next(u_char, struct input_ctx *);
55 void	 input_state_string_escape(u_char, struct input_ctx *);
56 void	 input_state_utf8(u_char, struct input_ctx *);
57 
58 void	 input_handle_character(u_char, struct input_ctx *);
59 void	 input_handle_c0_control(u_char, struct input_ctx *);
60 void	 input_handle_c1_control(u_char, struct input_ctx *);
61 void	 input_handle_private_two(u_char, struct input_ctx *);
62 void	 input_handle_standard_two(u_char, struct input_ctx *);
63 void	 input_handle_sequence(u_char, struct input_ctx *);
64 
65 void	 input_handle_sequence_cuu(struct input_ctx *);
66 void	 input_handle_sequence_cud(struct input_ctx *);
67 void	 input_handle_sequence_cuf(struct input_ctx *);
68 void	 input_handle_sequence_cub(struct input_ctx *);
69 void	 input_handle_sequence_dch(struct input_ctx *);
70 void	 input_handle_sequence_cbt(struct input_ctx *);
71 void	 input_handle_sequence_da(struct input_ctx *);
72 void	 input_handle_sequence_dl(struct input_ctx *);
73 void	 input_handle_sequence_ich(struct input_ctx *);
74 void	 input_handle_sequence_il(struct input_ctx *);
75 void	 input_handle_sequence_vpa(struct input_ctx *);
76 void	 input_handle_sequence_hpa(struct input_ctx *);
77 void	 input_handle_sequence_cup(struct input_ctx *);
78 void	 input_handle_sequence_cup(struct input_ctx *);
79 void	 input_handle_sequence_tbc(struct input_ctx *);
80 void	 input_handle_sequence_ed(struct input_ctx *);
81 void	 input_handle_sequence_el(struct input_ctx *);
82 void	 input_handle_sequence_sm(struct input_ctx *);
83 void	 input_handle_sequence_rm(struct input_ctx *);
84 void	 input_handle_sequence_decstbm(struct input_ctx *);
85 void	 input_handle_sequence_sgr(struct input_ctx *);
86 void	 input_handle_sequence_dsr(struct input_ctx *);
87 
88 int	 input_sequence_cmp(const void *, const void *);
89 
90 struct input_sequence_entry {
91 	u_char	ch;
92 	void	(*fn)(struct input_ctx *);
93 };
94 const 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 
119 int
120 input_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 
128 void
129 input_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 
139 int
140 input_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 
155 int
156 input_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 
175 void
176 input_start_string(struct input_ctx *ictx, int type)
177 {
178 	ictx->string_type = type;
179 	ictx->string_len = 0;
180 }
181 
182 void
183 input_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 
190 int
191 input_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 
204 char *
205 input_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 
217 void
218 input_state(struct input_ctx *ictx, void *state)
219 {
220 	ictx->state = state;
221 }
222 
223 void
224 input_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 
244 void
245 input_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 
253 void
254 input_parse(struct window_pane *wp)
255 {
256 	struct input_ctx	*ictx = &wp->ictx;
257 	u_char			 ch;
258 
259 	if (EVBUFFER_LENGTH(wp->event->input) == ictx->was)
260 		return;
261 	wp->window->flags |= WINDOW_ACTIVITY;
262 
263 	ictx->buf = EVBUFFER_DATA(wp->event->input);
264 	ictx->len = EVBUFFER_LENGTH(wp->event->input);
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 	evbuffer_drain(wp->event->input, ictx->len);
282 	ictx->was = EVBUFFER_LENGTH(wp->event->input);
283 }
284 
285 void
286 input_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 
321 void
322 input_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 
371 void
372 input_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 
395 void
396 input_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 
435 void
436 input_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 
493 void
494 input_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 
510 void
511 input_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 
529 void
530 input_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 
572 void
573 input_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 
586 void
587 input_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 
605 void
606 input_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 
654 void
655 input_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 
682 void
683 input_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 
741 void
742 input_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 
790 void
791 input_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 
818 void
819 input_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 
836 void
837 input_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 
854 void
855 input_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 
872 void
873 input_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 
890 void
891 input_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 
908 void
909 input_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 
932 void
933 input_handle_sequence_da(struct input_ctx *ictx)
934 {
935 	struct window_pane	*wp = ictx->wp;
936 	uint16_t		 n;
937 
938 	if (ictx->private != '\0')
939 		return;
940 
941 	if (ARRAY_LENGTH(&ictx->args) > 1)
942 		return;
943 	if (input_get_argument(ictx, 0, &n, 0) != 0)
944 		return;
945 	if (n != 0)
946 		return;
947 
948 	bufferevent_write(wp->event, "\033[?1;2c", (sizeof "\033[?1;2c") - 1);
949 }
950 
951 void
952 input_handle_sequence_dl(struct input_ctx *ictx)
953 {
954 	uint16_t	n;
955 
956 	if (ictx->private != '\0')
957 		return;
958 
959 	if (ARRAY_LENGTH(&ictx->args) > 1)
960 		return;
961 	if (input_get_argument(ictx, 0, &n, 1) != 0)
962 		return;
963 	if (n == 0)
964 		n = 1;
965 
966 	screen_write_deleteline(&ictx->ctx, n);
967 }
968 
969 void
970 input_handle_sequence_ich(struct input_ctx *ictx)
971 {
972 	uint16_t	n;
973 
974 	if (ictx->private != '\0')
975 		return;
976 
977 	if (ARRAY_LENGTH(&ictx->args) > 1)
978 		return;
979 	if (input_get_argument(ictx, 0, &n, 1) != 0)
980 		return;
981 	if (n == 0)
982 		n = 1;
983 
984 	screen_write_insertcharacter(&ictx->ctx, n);
985 }
986 
987 void
988 input_handle_sequence_il(struct input_ctx *ictx)
989 {
990 	uint16_t	n;
991 
992 	if (ictx->private != '\0')
993 		return;
994 
995 	if (ARRAY_LENGTH(&ictx->args) > 1)
996 		return;
997 	if (input_get_argument(ictx, 0, &n, 1) != 0)
998 		return;
999 	if (n == 0)
1000 		n = 1;
1001 
1002 	screen_write_insertline(&ictx->ctx, n);
1003 }
1004 
1005 void
1006 input_handle_sequence_vpa(struct input_ctx *ictx)
1007 {
1008 	struct screen  *s = ictx->ctx.s;
1009 	uint16_t	n;
1010 
1011 	if (ictx->private != '\0')
1012 		return;
1013 
1014 	if (ARRAY_LENGTH(&ictx->args) > 1)
1015 		return;
1016 	if (input_get_argument(ictx, 0, &n, 1) != 0)
1017 		return;
1018 	if (n == 0)
1019 		n = 1;
1020 
1021 	screen_write_cursormove(&ictx->ctx, s->cx, n - 1);
1022 }
1023 
1024 void
1025 input_handle_sequence_hpa(struct input_ctx *ictx)
1026 {
1027 	struct screen  *s = ictx->ctx.s;
1028 	uint16_t	n;
1029 
1030 	if (ictx->private != '\0')
1031 		return;
1032 
1033 	if (ARRAY_LENGTH(&ictx->args) > 1)
1034 		return;
1035 	if (input_get_argument(ictx, 0, &n, 1) != 0)
1036 		return;
1037 	if (n == 0)
1038 		n = 1;
1039 
1040 	screen_write_cursormove(&ictx->ctx, n - 1, s->cy);
1041 }
1042 
1043 void
1044 input_handle_sequence_cup(struct input_ctx *ictx)
1045 {
1046 	uint16_t	n, m;
1047 
1048 	if (ictx->private != '\0')
1049 		return;
1050 
1051 	if (ARRAY_LENGTH(&ictx->args) > 2)
1052 		return;
1053 	if (input_get_argument(ictx, 0, &n, 1) != 0)
1054 		return;
1055 	if (input_get_argument(ictx, 1, &m, 1) != 0)
1056 		return;
1057 	if (n == 0)
1058 		n = 1;
1059 	if (m == 0)
1060 		m = 1;
1061 
1062 	screen_write_cursormove(&ictx->ctx, m - 1, n - 1);
1063 }
1064 
1065 void
1066 input_handle_sequence_tbc(struct input_ctx *ictx)
1067 {
1068 	struct screen  *s = ictx->ctx.s;
1069 	uint16_t	n;
1070 
1071 	if (ictx->private != '\0')
1072 		return;
1073 
1074 	if (ARRAY_LENGTH(&ictx->args) > 1)
1075 		return;
1076 	if (input_get_argument(ictx, 0, &n, 1) != 0)
1077 		return;
1078 
1079 	switch (n) {
1080 	case 0:
1081 		if (s->cx < screen_size_x(s))
1082 			bit_clear(s->tabs, s->cx);
1083 		break;
1084 	case 3:
1085 		bit_nclear(s->tabs, 0, screen_size_x(s) - 1);
1086 		break;
1087 	}
1088 }
1089 
1090 void
1091 input_handle_sequence_ed(struct input_ctx *ictx)
1092 {
1093 	uint16_t	n;
1094 
1095 	if (ictx->private != '\0')
1096 		return;
1097 
1098 	if (ARRAY_LENGTH(&ictx->args) > 1)
1099 		return;
1100 	if (input_get_argument(ictx, 0, &n, 0) != 0)
1101 		return;
1102 	if (n > 2)
1103 		return;
1104 
1105 	switch (n) {
1106 	case 0:
1107 		screen_write_clearendofscreen(&ictx->ctx);
1108 		break;
1109 	case 1:
1110 		screen_write_clearstartofscreen(&ictx->ctx);
1111 		break;
1112 	case 2:
1113 		screen_write_clearscreen(&ictx->ctx);
1114 		break;
1115 	}
1116 }
1117 
1118 void
1119 input_handle_sequence_el(struct input_ctx *ictx)
1120 {
1121 	uint16_t	n;
1122 
1123 	if (ictx->private != '\0')
1124 		return;
1125 
1126 	if (ARRAY_LENGTH(&ictx->args) > 1)
1127 		return;
1128 	if (input_get_argument(ictx, 0, &n, 0) != 0)
1129 		return;
1130 	if (n > 2)
1131 		return;
1132 
1133 	switch (n) {
1134 	case 0:
1135 		screen_write_clearendofline(&ictx->ctx);
1136 		break;
1137 	case 1:
1138 		screen_write_clearstartofline(&ictx->ctx);
1139 		break;
1140 	case 2:
1141 		screen_write_clearline(&ictx->ctx);
1142 		break;
1143 	}
1144 }
1145 
1146 void
1147 input_handle_sequence_sm(struct input_ctx *ictx)
1148 {
1149 	struct window_pane	*wp = ictx->wp;
1150 	struct screen		*s = &wp->base;
1151 	u_int			 sx, sy;
1152 	uint16_t		 n;
1153 
1154 	if (ARRAY_LENGTH(&ictx->args) > 1)
1155 		return;
1156 	if (input_get_argument(ictx, 0, &n, 0) != 0)
1157 		return;
1158 
1159 	if (ictx->private == '?') {
1160 		switch (n) {
1161 		case 1:		/* GATM */
1162 			screen_write_kcursormode(&ictx->ctx, 1);
1163 			log_debug("kcursor on");
1164 			break;
1165 		case 3:		/* DECCOLM */
1166 			screen_write_cursormove(&ictx->ctx, 0, 0);
1167 			screen_write_clearscreen(&ictx->ctx);
1168 			break;
1169 		case 25:	/* TCEM */
1170 			screen_write_cursormode(&ictx->ctx, 1);
1171 			log_debug("cursor on");
1172 			break;
1173 		case 1000:
1174 			screen_write_mousemode(&ictx->ctx, 1);
1175 			log_debug("mouse on");
1176 			break;
1177 		case 1049:
1178 			if (wp->saved_grid != NULL)
1179 				break;
1180 			sx = screen_size_x(s);
1181 			sy = screen_size_y(s);
1182 
1183 			/*
1184 			 * Enter alternative screen mode. A copy of the visible
1185 			 * screen is saved and the history is not updated
1186 			 */
1187 
1188 			wp->saved_grid = grid_create(sx, sy, 0);
1189 			grid_duplicate_lines(
1190 			    wp->saved_grid, 0, s->grid, screen_hsize(s), sy);
1191 			wp->saved_cx = s->cx;
1192 			wp->saved_cy = s->cy;
1193 			memcpy(&wp->saved_cell,
1194 			    &ictx->cell, sizeof wp->saved_cell);
1195 
1196 			grid_view_clear(s->grid, 0, 0, sx, sy);
1197 
1198 			wp->base.grid->flags &= ~GRID_HISTORY;
1199 
1200 			wp->flags |= PANE_REDRAW;
1201 			break;
1202 		default:
1203 			log_debug("unknown SM [%hhu]: %u", ictx->private, n);
1204 			break;
1205 		}
1206 	} else {
1207 		switch (n) {
1208 		case 4:		/* IRM */
1209 			screen_write_insertmode(&ictx->ctx, 1);
1210 			log_debug("insert on");
1211 			break;
1212 		case 34:
1213 			/* Cursor high visibility not supported. */
1214 			break;
1215 		default:
1216 			log_debug("unknown SM [%hhu]: %u", ictx->private, n);
1217 			break;
1218 		}
1219 	}
1220 }
1221 
1222 void
1223 input_handle_sequence_rm(struct input_ctx *ictx)
1224 {
1225 	struct window_pane	*wp = ictx->wp;
1226 	struct screen		*s = &wp->base;
1227 	u_int			 sx, sy;
1228 	uint16_t		 n;
1229 
1230 	if (ARRAY_LENGTH(&ictx->args) > 1)
1231 		return;
1232 	if (input_get_argument(ictx, 0, &n, 0) != 0)
1233 		return;
1234 
1235 	if (ictx->private == '?') {
1236 		switch (n) {
1237 		case 1:		/* GATM */
1238 			screen_write_kcursormode(&ictx->ctx, 0);
1239 			log_debug("kcursor off");
1240 			break;
1241 		case 3:		/* DECCOLM */
1242 			screen_write_cursormove(&ictx->ctx, 0, 0);
1243 			screen_write_clearscreen(&ictx->ctx);
1244 			break;
1245 		case 25:	/* TCEM */
1246 			screen_write_cursormode(&ictx->ctx, 0);
1247 			log_debug("cursor off");
1248 			break;
1249 		case 1000:
1250 			screen_write_mousemode(&ictx->ctx, 0);
1251 			log_debug("mouse off");
1252 			break;
1253 		case 1049:
1254 			if (wp->saved_grid == NULL)
1255 				break;
1256 			sx = screen_size_x(s);
1257 			sy = screen_size_y(s);
1258 
1259 			/*
1260 			 * Exit alternative screen mode and restore the copied
1261 			 * grid.
1262 			 */
1263 
1264 			/*
1265 			 * If the current size is bigger, temporarily resize
1266 			 * to the old size before copying back.
1267 			 */
1268 			if (sy > wp->saved_grid->sy)
1269 				screen_resize(s, sx, wp->saved_grid->sy);
1270 
1271 			/* Restore the grid, cursor position and cell. */
1272 			grid_duplicate_lines(
1273 			    s->grid, screen_hsize(s), wp->saved_grid, 0, sy);
1274 			s->cx = wp->saved_cx;
1275 			if (s->cx > screen_size_x(s) - 1)
1276 				s->cx = screen_size_x(s) - 1;
1277 			s->cy = wp->saved_cy;
1278 			if (s->cy > screen_size_y(s) - 1)
1279 				s->cy = screen_size_y(s) - 1;
1280 			memcpy(&ictx->cell, &wp->saved_cell, sizeof ictx->cell);
1281 
1282 			/*
1283 			 * Turn history back on (so resize can use it) and then
1284 			 * resize back to the current size.
1285 			 */
1286   			wp->base.grid->flags |= GRID_HISTORY;
1287 			if (sy > wp->saved_grid->sy)
1288 				screen_resize(s, sx, sy);
1289 
1290 			grid_destroy(wp->saved_grid);
1291 			wp->saved_grid = NULL;
1292 
1293 			wp->flags |= PANE_REDRAW;
1294 			break;
1295 		default:
1296 			log_debug("unknown RM [%hhu]: %u", ictx->private, n);
1297 			break;
1298 		}
1299 	} else if (ictx->private == '\0') {
1300 		switch (n) {
1301 		case 4:		/* IRM */
1302 			screen_write_insertmode(&ictx->ctx, 0);
1303 			log_debug("insert off");
1304 			break;
1305 		case 34:
1306 			/* Cursor high visibility not supported. */
1307 			break;
1308 		default:
1309 			log_debug("unknown RM [%hhu]: %u", ictx->private, n);
1310 			break;
1311 		}
1312 	}
1313 }
1314 
1315 void
1316 input_handle_sequence_dsr(struct input_ctx *ictx)
1317 {
1318 	struct window_pane	*wp = ictx->wp;
1319 	struct screen		*s = ictx->ctx.s;
1320 	uint16_t		 n;
1321 	char			reply[32];
1322 
1323 	if (ARRAY_LENGTH(&ictx->args) > 1)
1324 		return;
1325 	if (input_get_argument(ictx, 0, &n, 0) != 0)
1326 		return;
1327 
1328 	if (ictx->private == '\0') {
1329 		switch (n) {
1330 		case 6:	/* cursor position */
1331 			xsnprintf(reply, sizeof reply,
1332 			    "\033[%u;%uR", s->cy + 1, s->cx + 1);
1333 			log_debug("cursor request, reply: %s", reply);
1334 			bufferevent_write(wp->event, reply, strlen(reply));
1335 			break;
1336 		}
1337 	}
1338 }
1339 
1340 void
1341 input_handle_sequence_decstbm(struct input_ctx *ictx)
1342 {
1343 	struct screen  *s = ictx->ctx.s;
1344 	uint16_t	n, m;
1345 
1346 	if (ictx->private != '\0')
1347 		return;
1348 
1349 	if (ARRAY_LENGTH(&ictx->args) > 2)
1350 		return;
1351 	if (input_get_argument(ictx, 0, &n, 0) != 0)
1352 		return;
1353 	if (input_get_argument(ictx, 1, &m, 0) != 0)
1354 		return;
1355 	if (n == 0)
1356 		n = 1;
1357 	if (m == 0)
1358 		m = screen_size_y(s);
1359 
1360 	screen_write_scrollregion(&ictx->ctx, n - 1, m - 1);
1361 }
1362 
1363 void
1364 input_handle_sequence_sgr(struct input_ctx *ictx)
1365 {
1366 	struct grid_cell       *gc = &ictx->cell;
1367 	u_int			i;
1368 	uint16_t		m, o;
1369 	u_char			attr;
1370 
1371 	if (ARRAY_LENGTH(&ictx->args) == 0) {
1372 		attr = gc->attr;
1373 		memcpy(gc, &grid_default_cell, sizeof *gc);
1374  		gc->attr |= (attr & GRID_ATTR_CHARSET);
1375 		return;
1376 	}
1377 
1378 	for (i = 0; i < ARRAY_LENGTH(&ictx->args); i++) {
1379 		if (input_get_argument(ictx, i, &m, 0) != 0)
1380 			return;
1381 
1382 		if (m == 38 || m == 48) {
1383 			i++;
1384 			if (input_get_argument(ictx, i, &o, 0) != 0)
1385 				return;
1386 			if (o != 5)
1387 				continue;
1388 
1389 			i++;
1390 			if (input_get_argument(ictx, i, &o, 0) != 0)
1391 				return;
1392 			if (m == 38) {
1393 				gc->flags |= GRID_FLAG_FG256;
1394 				gc->fg = o;
1395 			} else if (m == 48) {
1396 				gc->flags |= GRID_FLAG_BG256;
1397 				gc->bg = o;
1398 			}
1399 			continue;
1400 		}
1401 
1402 		switch (m) {
1403 		case 0:
1404 		case 10:
1405 			attr = gc->attr;
1406 			memcpy(gc, &grid_default_cell, sizeof *gc);
1407 			gc->attr |= (attr & GRID_ATTR_CHARSET);
1408 			break;
1409 		case 1:
1410 			gc->attr |= GRID_ATTR_BRIGHT;
1411 			break;
1412 		case 2:
1413 			gc->attr |= GRID_ATTR_DIM;
1414 			break;
1415 		case 3:
1416 			gc->attr |= GRID_ATTR_ITALICS;
1417 			break;
1418 		case 4:
1419 			gc->attr |= GRID_ATTR_UNDERSCORE;
1420 			break;
1421 		case 5:
1422 			gc->attr |= GRID_ATTR_BLINK;
1423 			break;
1424 		case 7:
1425 			gc->attr |= GRID_ATTR_REVERSE;
1426 			break;
1427 		case 8:
1428 			gc->attr |= GRID_ATTR_HIDDEN;
1429 			break;
1430 		case 22:
1431 			gc->attr &= ~(GRID_ATTR_BRIGHT|GRID_ATTR_DIM);
1432 			break;
1433 		case 23:
1434 			gc->attr &= ~GRID_ATTR_ITALICS;
1435 			break;
1436 		case 24:
1437 			gc->attr &= ~GRID_ATTR_UNDERSCORE;
1438 			break;
1439 		case 25:
1440 			gc->attr &= ~GRID_ATTR_BLINK;
1441 			break;
1442 		case 27:
1443 			gc->attr &= ~GRID_ATTR_REVERSE;
1444 			break;
1445 		case 30:
1446 		case 31:
1447 		case 32:
1448 		case 33:
1449 		case 34:
1450 		case 35:
1451 		case 36:
1452 		case 37:
1453 			gc->flags &= ~GRID_FLAG_FG256;
1454 			gc->fg = m - 30;
1455 			break;
1456 		case 39:
1457 			gc->flags &= ~GRID_FLAG_FG256;
1458 			gc->fg = 8;
1459 			break;
1460 		case 40:
1461 		case 41:
1462 		case 42:
1463 		case 43:
1464 		case 44:
1465 		case 45:
1466 		case 46:
1467 		case 47:
1468 			gc->flags &= ~GRID_FLAG_BG256;
1469 			gc->bg = m - 40;
1470 			break;
1471 		case 49:
1472 			gc->flags &= ~GRID_FLAG_BG256;
1473 			gc->bg = 8;
1474 			break;
1475 		case 90:
1476 		case 91:
1477 		case 92:
1478 		case 93:
1479 		case 94:
1480 		case 95:
1481 		case 96:
1482 		case 97:
1483 			gc->flags |= GRID_FLAG_FG256;
1484 			gc->fg = m - 82;
1485 			break;
1486 		case 100:
1487 		case 101:
1488 		case 102:
1489 		case 103:
1490 		case 104:
1491 		case 105:
1492 		case 106:
1493 		case 107:
1494 			gc->flags |= GRID_FLAG_BG256;
1495 			gc->bg = m - 92;
1496 			break;
1497 		}
1498 	}
1499 }
1500