1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2008-2009 Ed Schouten <ed@FreeBSD.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  * $FreeBSD: head/sys/teken/teken.c 333683 2018-05-16 18:12:49Z cem $
29  */
30 
31 #include "config.h"
32 
33 #include <sys/types.h>
34 #include <limits.h>
35 #include <stdint.h>
36 #include <stdio.h>
37 #include <string.h>
38 #define	teken_assert(x)		assert(x)
39 
40 #include "vdef.h"
41 #include "vas.h"
42 
43 /* debug messages */
44 #define	teken_printf(...)
45 
46 /* Private flags for t_stateflags. */
47 #define	TS_FIRSTDIGIT	0x0001	/* First numeric digit in escape sequence. */
48 #define	TS_INSERT	0x0002	/* Insert mode. */
49 #define	TS_AUTOWRAP	0x0004	/* Autowrap. */
50 #define	TS_ORIGIN	0x0008	/* Origin mode. */
51 #define	TS_WRAPPED	0x0010	/* Next character should be printed on col 0. */
52 #define	TS_8BIT		0x0020	/* UTF-8 disabled. */
53 #define	TS_CONS25	0x0040	/* cons25 emulation. */
54 #define	TS_INSTRING	0x0080	/* Inside string. */
55 #define	TS_CURSORKEYS	0x0100	/* Cursor keys mode. */
56 
57 /* Character that blanks a cell. */
58 #define	BLANK	' '
59 
60 #include "teken.h"
61 #include "teken_wcwidth.h"
62 #include "teken_scs.h"
63 
64 static teken_state_t	teken_state_init;
65 
66 /*
67  * Wrappers for hooks.
68  */
69 
70 static inline void
teken_funcs_bell(const teken_t * t)71 teken_funcs_bell(const teken_t *t)
72 {
73 
74 	if (t->t_funcs->tf_bell != NULL)
75 		t->t_funcs->tf_bell(t->t_softc);
76 }
77 
78 static inline void
teken_funcs_cursor(const teken_t * t)79 teken_funcs_cursor(const teken_t *t)
80 {
81 
82 	teken_assert(t->t_cursor.tp_row < t->t_winsize.tp_row);
83 	teken_assert(t->t_cursor.tp_col < t->t_winsize.tp_col);
84 
85 	teken_assert(t->t_funcs->tf_cursor != NULL);
86 	t->t_funcs->tf_cursor(t->t_softc, &t->t_cursor);
87 }
88 
89 static inline void
teken_funcs_putchar(const teken_t * t,const teken_pos_t * p,teken_char_t c,const teken_attr_t * a)90 teken_funcs_putchar(const teken_t *t, const teken_pos_t *p, teken_char_t c,
91     const teken_attr_t *a)
92 {
93 
94 	teken_assert(p->tp_row < t->t_winsize.tp_row);
95 	teken_assert(p->tp_col < t->t_winsize.tp_col);
96 
97 	teken_assert(t->t_funcs->tf_putchar != NULL);
98 	t->t_funcs->tf_putchar(t->t_softc, p, c, a);
99 }
100 
101 static inline void
teken_funcs_fill(const teken_t * t,const teken_rect_t * r,const teken_char_t c,const teken_attr_t * a)102 teken_funcs_fill(const teken_t *t, const teken_rect_t *r,
103     const teken_char_t c, const teken_attr_t *a)
104 {
105 
106 	teken_assert(r->tr_end.tp_row > r->tr_begin.tp_row);
107 	teken_assert(r->tr_end.tp_row <= t->t_winsize.tp_row);
108 	teken_assert(r->tr_end.tp_col > r->tr_begin.tp_col);
109 	teken_assert(r->tr_end.tp_col <= t->t_winsize.tp_col);
110 
111 	teken_assert(t->t_funcs->tf_fill != NULL);
112 	t->t_funcs->tf_fill(t->t_softc, r, c, a);
113 }
114 
115 static inline void
teken_funcs_copy(const teken_t * t,const teken_rect_t * r,const teken_pos_t * p)116 teken_funcs_copy(const teken_t *t, const teken_rect_t *r, const teken_pos_t *p)
117 {
118 
119 	teken_assert(r->tr_end.tp_row > r->tr_begin.tp_row);
120 	teken_assert(r->tr_end.tp_row <= t->t_winsize.tp_row);
121 	teken_assert(r->tr_end.tp_col > r->tr_begin.tp_col);
122 	teken_assert(r->tr_end.tp_col <= t->t_winsize.tp_col);
123 	teken_assert(p->tp_row + (r->tr_end.tp_row - r->tr_begin.tp_row) <= t->t_winsize.tp_row);
124 	teken_assert(p->tp_col + (r->tr_end.tp_col - r->tr_begin.tp_col) <= t->t_winsize.tp_col);
125 
126 	teken_assert(t->t_funcs->tf_copy != NULL);
127 	t->t_funcs->tf_copy(t->t_softc, r, p);
128 }
129 
130 static inline void
teken_funcs_pre_input(const teken_t * t)131 teken_funcs_pre_input(const teken_t *t)
132 {
133 
134 	if (t->t_funcs->tf_pre_input != NULL)
135 		t->t_funcs->tf_pre_input(t->t_softc);
136 }
137 
138 static inline void
teken_funcs_post_input(const teken_t * t)139 teken_funcs_post_input(const teken_t *t)
140 {
141 
142 	if (t->t_funcs->tf_post_input != NULL)
143 		t->t_funcs->tf_post_input(t->t_softc);
144 }
145 
146 static inline void
teken_funcs_param(const teken_t * t,int cmd,unsigned int value)147 teken_funcs_param(const teken_t *t, int cmd, unsigned int value)
148 {
149 
150 	teken_assert(t->t_funcs->tf_param != NULL);
151 	t->t_funcs->tf_param(t->t_softc, cmd, value);
152 }
153 
154 static inline void
teken_funcs_respond(const teken_t * t,const void * buf,size_t len)155 teken_funcs_respond(const teken_t *t, const void *buf, size_t len)
156 {
157 
158 	teken_assert(t->t_funcs->tf_respond != NULL);
159 	t->t_funcs->tf_respond(t->t_softc, buf, len);
160 }
161 
162 #include "teken_subr.h"
163 #include "teken_subr_compat.h"
164 
165 /*
166  * Programming interface.
167  */
168 
169 void
teken_init(teken_t * t,const teken_funcs_t * tf,void * softc)170 teken_init(teken_t *t, const teken_funcs_t *tf, void *softc)
171 {
172 	teken_pos_t tp = { .tp_row = 24, .tp_col = 80 };
173 
174 	t->t_funcs = tf;
175 	t->t_softc = softc;
176 
177 	t->t_nextstate = teken_state_init;
178 	t->t_stateflags = 0;
179 	t->t_utf8_left = 0;
180 
181 	t->t_defattr.ta_format = 0;
182 	t->t_defattr.ta_fgcolor = TC_WHITE;
183 	t->t_defattr.ta_bgcolor = TC_BLACK;
184 	teken_subr_do_reset(t);
185 
186 	teken_set_winsize(t, &tp);
187 }
188 
189 static void
teken_input_char(teken_t * t,teken_char_t c)190 teken_input_char(teken_t *t, teken_char_t c)
191 {
192 
193 	/*
194 	 * There is no support for DCS and OSC.  Just discard strings
195 	 * until we receive characters that may indicate string
196 	 * termination.
197 	 */
198 	if (t->t_stateflags & TS_INSTRING) {
199 		switch (c) {
200 		case '\x1B':
201 			t->t_stateflags &= ~TS_INSTRING;
202 			break;
203 		case '\a':
204 			t->t_stateflags &= ~TS_INSTRING;
205 			return;
206 		default:
207 			return;
208 		}
209 	}
210 
211 	switch (c) {
212 	case '\0':
213 		break;
214 	case '\a':
215 		teken_subr_bell(t);
216 		break;
217 	case '\b':
218 		teken_subr_backspace(t);
219 		break;
220 	case '\n':
221 	case '\x0B':
222 		teken_subr_newline(t);
223 		break;
224 	case '\x0C':
225 		teken_subr_newpage(t);
226 		break;
227 	case '\x0E':
228 		if (t->t_stateflags & TS_CONS25)
229 			t->t_nextstate(t, c);
230 		else
231 			t->t_curscs = 1;
232 		break;
233 	case '\x0F':
234 		if (t->t_stateflags & TS_CONS25)
235 			t->t_nextstate(t, c);
236 		else
237 			t->t_curscs = 0;
238 		break;
239 	case '\r':
240 		teken_subr_carriage_return(t);
241 		break;
242 	case '\t':
243 		teken_subr_horizontal_tab(t);
244 		break;
245 	default:
246 		t->t_nextstate(t, c);
247 		break;
248 	}
249 
250 	/* Post-processing assertions. */
251 	teken_assert(t->t_cursor.tp_row >= t->t_originreg.ts_begin);
252 	teken_assert(t->t_cursor.tp_row < t->t_originreg.ts_end);
253 	teken_assert(t->t_cursor.tp_row < t->t_winsize.tp_row);
254 	teken_assert(t->t_cursor.tp_col < t->t_winsize.tp_col);
255 	teken_assert(t->t_saved_cursor.tp_row < t->t_winsize.tp_row);
256 	teken_assert(t->t_saved_cursor.tp_col < t->t_winsize.tp_col);
257 	teken_assert(t->t_scrollreg.ts_end <= t->t_winsize.tp_row);
258 	teken_assert(t->t_scrollreg.ts_begin < t->t_scrollreg.ts_end);
259 	/* Origin region has to be window size or the same as scrollreg. */
260 	teken_assert((t->t_originreg.ts_begin == t->t_scrollreg.ts_begin &&
261 	    t->t_originreg.ts_end == t->t_scrollreg.ts_end) ||
262 	    (t->t_originreg.ts_begin == 0 &&
263 	    t->t_originreg.ts_end == t->t_winsize.tp_row));
264 }
265 
266 static void
teken_input_byte(teken_t * t,unsigned char c)267 teken_input_byte(teken_t *t, unsigned char c)
268 {
269 
270 	/*
271 	 * UTF-8 handling.
272 	 */
273 	if ((c & 0x80) == 0x00 || t->t_stateflags & TS_8BIT) {
274 		/* One-byte sequence. */
275 		t->t_utf8_left = 0;
276 		teken_input_char(t, c);
277 	} else if ((c & 0xe0) == 0xc0) {
278 		/* Two-byte sequence. */
279 		t->t_utf8_left = 1;
280 		t->t_utf8_partial = c & 0x1f;
281 	} else if ((c & 0xf0) == 0xe0) {
282 		/* Three-byte sequence. */
283 		t->t_utf8_left = 2;
284 		t->t_utf8_partial = c & 0x0f;
285 	} else if ((c & 0xf8) == 0xf0) {
286 		/* Four-byte sequence. */
287 		t->t_utf8_left = 3;
288 		t->t_utf8_partial = c & 0x07;
289 	} else if ((c & 0xc0) == 0x80) {
290 		if (t->t_utf8_left == 0)
291 			return;
292 		t->t_utf8_left--;
293 		t->t_utf8_partial = (t->t_utf8_partial << 6) | (c & 0x3f);
294 		if (t->t_utf8_left == 0) {
295 			teken_printf("Got UTF-8 char %x\n", t->t_utf8_partial);
296 			teken_input_char(t, t->t_utf8_partial);
297 		}
298 	}
299 }
300 
301 void
teken_input(teken_t * t,const void * buf,size_t len)302 teken_input(teken_t *t, const void *buf, size_t len)
303 {
304 	const char *c = buf;
305 
306 	teken_funcs_pre_input(t);
307 	while (len-- > 0)
308 		teken_input_byte(t, *c++);
309 	teken_funcs_post_input(t);
310 }
311 
312 const teken_pos_t *
teken_get_cursor(const teken_t * t)313 teken_get_cursor(const teken_t *t)
314 {
315 
316 	return (&t->t_cursor);
317 }
318 
319 void
teken_set_cursor(teken_t * t,const teken_pos_t * p)320 teken_set_cursor(teken_t *t, const teken_pos_t *p)
321 {
322 
323 	/* XXX: bounds checking with originreg! */
324 	teken_assert(p->tp_row < t->t_winsize.tp_row);
325 	teken_assert(p->tp_col < t->t_winsize.tp_col);
326 
327 	t->t_cursor = *p;
328 }
329 
330 const teken_attr_t *
teken_get_curattr(const teken_t * t)331 teken_get_curattr(const teken_t *t)
332 {
333 
334 	return (&t->t_curattr);
335 }
336 
337 void
teken_set_curattr(teken_t * t,const teken_attr_t * a)338 teken_set_curattr(teken_t *t, const teken_attr_t *a)
339 {
340 
341 	t->t_curattr = *a;
342 }
343 
344 const teken_attr_t *
teken_get_defattr(const teken_t * t)345 teken_get_defattr(const teken_t *t)
346 {
347 
348 	return (&t->t_defattr);
349 }
350 
351 void
teken_set_defattr(teken_t * t,const teken_attr_t * a)352 teken_set_defattr(teken_t *t, const teken_attr_t *a)
353 {
354 
355 	t->t_curattr = t->t_saved_curattr = t->t_defattr = *a;
356 }
357 
358 const teken_pos_t *
teken_get_winsize(const teken_t * t)359 teken_get_winsize(const teken_t *t)
360 {
361 
362 	return (&t->t_winsize);
363 }
364 
365 static void
teken_trim_cursor_pos(teken_t * t,const teken_pos_t * new)366 teken_trim_cursor_pos(teken_t *t, const teken_pos_t *new)
367 {
368 	const teken_pos_t *cur;
369 
370 	cur = &t->t_winsize;
371 
372 	if (cur->tp_row < new->tp_row || cur->tp_col < new->tp_col)
373 		return;
374 	if (t->t_cursor.tp_row >= new->tp_row)
375 		t->t_cursor.tp_row = new->tp_row - 1;
376 	if (t->t_cursor.tp_col >= new->tp_col)
377 		t->t_cursor.tp_col = new->tp_col - 1;
378 }
379 
380 void
teken_set_winsize(teken_t * t,const teken_pos_t * p)381 teken_set_winsize(teken_t *t, const teken_pos_t *p)
382 {
383 
384 	teken_trim_cursor_pos(t, p);
385 	t->t_winsize = *p;
386 	teken_subr_do_reset(t);
387 }
388 
389 void
teken_set_winsize_noreset(teken_t * t,const teken_pos_t * p)390 teken_set_winsize_noreset(teken_t *t, const teken_pos_t *p)
391 {
392 
393 	teken_trim_cursor_pos(t, p);
394 	t->t_winsize = *p;
395 	teken_subr_do_resize(t);
396 }
397 
398 void
teken_set_8bit(teken_t * t)399 teken_set_8bit(teken_t *t)
400 {
401 
402 	t->t_stateflags |= TS_8BIT;
403 }
404 
405 void
teken_set_cons25(teken_t * t)406 teken_set_cons25(teken_t *t)
407 {
408 
409 	t->t_stateflags |= TS_CONS25;
410 }
411 
412 /*
413  * State machine.
414  */
415 
416 static void
teken_state_switch(teken_t * t,teken_state_t * s)417 teken_state_switch(teken_t *t, teken_state_t *s)
418 {
419 
420 	t->t_nextstate = s;
421 	t->t_curnum = 0;
422 	t->t_stateflags |= TS_FIRSTDIGIT;
423 }
424 
425 static int
teken_state_numbers(teken_t * t,teken_char_t c)426 teken_state_numbers(teken_t *t, teken_char_t c)
427 {
428 
429 	teken_assert(t->t_curnum < T_NUMSIZE);
430 
431 	if (c >= '0' && c <= '9') {
432 		if (t->t_stateflags & TS_FIRSTDIGIT) {
433 			/* First digit. */
434 			t->t_stateflags &= ~TS_FIRSTDIGIT;
435 			t->t_nums[t->t_curnum] = c - '0';
436 		} else if (t->t_nums[t->t_curnum] < UINT_MAX / 100) {
437 			/*
438 			 * There is no need to continue parsing input
439 			 * once the value exceeds the size of the
440 			 * terminal. It would only allow for integer
441 			 * overflows when performing arithmetic on the
442 			 * cursor position.
443 			 *
444 			 * Ignore any further digits if the value is
445 			 * already UINT_MAX / 100.
446 			 */
447 			t->t_nums[t->t_curnum] =
448 			    t->t_nums[t->t_curnum] * 10 + c - '0';
449 		}
450 		return (1);
451 	} else if (c == ';') {
452 		if (t->t_stateflags & TS_FIRSTDIGIT)
453 			t->t_nums[t->t_curnum] = 0;
454 
455 		/* Only allow a limited set of arguments. */
456 		if (++t->t_curnum == T_NUMSIZE) {
457 			teken_state_switch(t, teken_state_init);
458 			return (1);
459 		}
460 
461 		t->t_stateflags |= TS_FIRSTDIGIT;
462 		return (1);
463 	} else {
464 		if (t->t_stateflags & TS_FIRSTDIGIT && t->t_curnum > 0) {
465 			/* Finish off the last empty argument. */
466 			t->t_nums[t->t_curnum] = 0;
467 			t->t_curnum++;
468 		} else if ((t->t_stateflags & TS_FIRSTDIGIT) == 0) {
469 			/* Also count the last argument. */
470 			t->t_curnum++;
471 		}
472 	}
473 
474 	return (0);
475 }
476 
477 #define	k	TC_BLACK
478 #define	b	TC_BLUE
479 #define	y	TC_BROWN
480 #define	c	TC_CYAN
481 #define	g	TC_GREEN
482 #define	m	TC_MAGENTA
483 #define	r	TC_RED
484 #define	w	TC_WHITE
485 #define	K	(TC_BLACK | TC_LIGHT)
486 #define	B	(TC_BLUE | TC_LIGHT)
487 #define	Y	(TC_BROWN | TC_LIGHT)
488 #define	C	(TC_CYAN | TC_LIGHT)
489 #define	G	(TC_GREEN | TC_LIGHT)
490 #define	M	(TC_MAGENTA | TC_LIGHT)
491 #define	R	(TC_RED | TC_LIGHT)
492 #define	W	(TC_WHITE | TC_LIGHT)
493 
494 /**
495  * The xterm-256 color map has steps of 0x28 (in the range 0-0xff), except
496  * for the first step which is 0x5f.  Scale to the range 0-6 by dividing
497  * by 0x28 and rounding down.  The range of 0-5 cannot represent the
498  * larger first step.
499  *
500  * This table is generated by the follow rules:
501  * - if all components are equal, the result is black for (0, 0, 0) and
502  *   (2, 2, 2), else white; otherwise:
503  * - subtract the smallest component from all components
504  * - if this gives only one nonzero component, then that is the color
505  * - else if one component is 2 or more larger than the other nonzero one,
506  *   then that component gives the color
507  * - else there are 2 nonzero components.  The color is that of a small
508  *   equal mixture of these components (cyan, yellow or magenta).  E.g.,
509  *   (0, 5, 6) (Turquoise2) is a much purer cyan than (0, 2, 3)
510  *   (DeepSkyBlue4), but we map both to cyan since we can't represent
511  *   delicate shades of either blue or cyan and blue would be worse.
512  *   Here it is important that components of 1 never occur.  Blue would
513  *   be twice as large as green in (0, 1, 2).
514  */
515 static const teken_color_t teken_256to8tab[] = {
516 	/* xterm normal colors: */
517 	k, r, g, y, b, m, c, w,
518 
519 	/* xterm bright colors: */
520 	k, r, g, y, b, m, c, w,
521 
522 	/* Red0 submap. */
523 	k, b, b, b, b, b,
524 	g, c, c, b, b, b,
525 	g, c, c, c, b, b,
526 	g, g, c, c, c, b,
527 	g, g, g, c, c, c,
528 	g, g, g, g, c, c,
529 
530 	/* Red2 submap. */
531 	r, m, m, b, b, b,
532 	y, k, b, b, b, b,
533 	y, g, c, c, b, b,
534 	g, g, c, c, c, b,
535 	g, g, g, c, c, c,
536 	g, g, g, g, c, c,
537 
538 	/* Red3 submap. */
539 	r, m, m, m, b, b,
540 	y, r, m, m, b, b,
541 	y, y, w, b, b, b,
542 	y, y, g, c, c, b,
543 	g, g, g, c, c, c,
544 	g, g, g, g, c, c,
545 
546 	/* Red4 submap. */
547 	r, r, m, m, m, b,
548 	r, r, m, m, m, b,
549 	y, y, r, m, m, b,
550 	y, y, y, w, b, b,
551 	y, y, y, g, c, c,
552 	g, g, g, g, c, c,
553 
554 	/* Red5 submap. */
555 	r, r, r, m, m, m,
556 	r, r, r, m, m, m,
557 	r, r, r, m, m, m,
558 	y, y, y, r, m, m,
559 	y, y, y, y, w, b,
560 	y, y, y, y, g, c,
561 
562 	/* Red6 submap. */
563 	r, r, r, r, m, m,
564 	r, r, r, r, m, m,
565 	r, r, r, r, m, m,
566 	r, r, r, r, m, m,
567 	y, y, y, y, r, m,
568 	y, y, y, y, y, w,
569 
570 	/* Grey submap. */
571 	k, k, k, k, k, k,
572 	k, k, k, k, k, k,
573 	w, w, w, w, w, w,
574 	w, w, w, w, w, w,
575 };
576 
577 /*
578  * This table is generated from the previous one by setting TC_LIGHT for
579  * entries whose luminosity in the xterm256 color map is 60% or larger.
580  * Thus the previous table is currently not really needed.  It will be
581  * used for different fine tuning of the tables.
582  */
583 static const teken_color_t teken_256to16tab[] = {
584 	/* xterm normal colors: */
585 	k, r, g, y, b, m, c, w,
586 
587 	/* xterm bright colors: */
588 	K, R, G, Y, B, M, C, W,
589 
590 	/* Red0 submap. */
591 	k, b, b, b, b, b,
592 	g, c, c, b, b, b,
593 	g, c, c, c, b, b,
594 	g, g, c, c, c, b,
595 	g, g, g, c, c, c,
596 	g, g, g, g, c, c,
597 
598 	/* Red2 submap. */
599 	r, m, m, b, b, b,
600 	y, K, b, b, B, B,
601 	y, g, c, c, B, B,
602 	g, g, c, c, C, B,
603 	g, G, G, C, C, C,
604 	g, G, G, G, C, C,
605 
606 	/* Red3 submap. */
607 	r, m, m, m, b, b,
608 	y, r, m, m, B, B,
609 	y, y, w, B, B, B,
610 	y, y, G, C, C, B,
611 	g, G, G, C, C, C,
612 	g, G, G, G, C, C,
613 
614 	/* Red4 submap. */
615 	r, r, m, m, m, b,
616 	r, r, m, m, M, B,
617 	y, y, R, M, M, B,
618 	y, y, Y, W, B, B,
619 	y, Y, Y, G, C, C,
620 	g, G, G, G, C, C,
621 
622 	/* Red5 submap. */
623 	r, r, r, m, m, m,
624 	r, R, R, M, M, M,
625 	r, R, R, M, M, M,
626 	y, Y, Y, R, M, M,
627 	y, Y, Y, Y, W, B,
628 	y, Y, Y, Y, G, C,
629 
630 	/* Red6 submap. */
631 	r, r, r, r, m, m,
632 	r, R, R, R, M, M,
633 	r, R, R, R, M, M,
634 	r, R, R, R, M, M,
635 	y, Y, Y, Y, R, M,
636 	y, Y, Y, Y, Y, W,
637 
638 	/* Grey submap. */
639 	k, k, k, k, k, k,
640 	K, K, K, K, K, K,
641 	w, w, w, w, w, w,
642 	W, W, W, W, W, W,
643 };
644 
645 #undef	k
646 #undef	b
647 #undef	y
648 #undef	c
649 #undef	g
650 #undef	m
651 #undef	r
652 #undef	w
653 #undef	K
654 #undef	B
655 #undef	Y
656 #undef	C
657 #undef	G
658 #undef	M
659 #undef	R
660 #undef	W
661 
662 teken_color_t
teken_256to8(teken_color_t c)663 teken_256to8(teken_color_t c)
664 {
665 
666 	return (teken_256to8tab[c % 256]);
667 }
668 
669 teken_color_t
teken_256to16(teken_color_t c)670 teken_256to16(teken_color_t c)
671 {
672 
673 	return (teken_256to16tab[c % 256]);
674 }
675 
676 static const char * const special_strings_cons25[] = {
677 	[TKEY_UP] = "\x1B[A",		[TKEY_DOWN] = "\x1B[B",
678 	[TKEY_LEFT] = "\x1B[D",		[TKEY_RIGHT] = "\x1B[C",
679 
680 	[TKEY_HOME] = "\x1B[H",		[TKEY_END] = "\x1B[F",
681 	[TKEY_INSERT] = "\x1B[L",	[TKEY_DELETE] = "\x7F",
682 	[TKEY_PAGE_UP] = "\x1B[I",	[TKEY_PAGE_DOWN] = "\x1B[G",
683 
684 	[TKEY_F1] = "\x1B[M",		[TKEY_F2] = "\x1B[N",
685 	[TKEY_F3] = "\x1B[O",		[TKEY_F4] = "\x1B[P",
686 	[TKEY_F5] = "\x1B[Q",		[TKEY_F6] = "\x1B[R",
687 	[TKEY_F7] = "\x1B[S",		[TKEY_F8] = "\x1B[T",
688 	[TKEY_F9] = "\x1B[U",		[TKEY_F10] = "\x1B[V",
689 	[TKEY_F11] = "\x1B[W",		[TKEY_F12] = "\x1B[X",
690 };
691 
692 static const char * const special_strings_ckeys[] = {
693 	[TKEY_UP] = "\x1BOA",		[TKEY_DOWN] = "\x1BOB",
694 	[TKEY_LEFT] = "\x1BOD",		[TKEY_RIGHT] = "\x1BOC",
695 
696 	[TKEY_HOME] = "\x1BOH",		[TKEY_END] = "\x1BOF",
697 };
698 
699 static const char * const special_strings_normal[] = {
700 	[TKEY_UP] = "\x1B[A",		[TKEY_DOWN] = "\x1B[B",
701 	[TKEY_LEFT] = "\x1B[D",		[TKEY_RIGHT] = "\x1B[C",
702 
703 	[TKEY_HOME] = "\x1B[H",		[TKEY_END] = "\x1B[F",
704 	[TKEY_INSERT] = "\x1B[2~",	[TKEY_DELETE] = "\x1B[3~",
705 	[TKEY_PAGE_UP] = "\x1B[5~",	[TKEY_PAGE_DOWN] = "\x1B[6~",
706 
707 	[TKEY_F1] = "\x1BOP",		[TKEY_F2] = "\x1BOQ",
708 	[TKEY_F3] = "\x1BOR",		[TKEY_F4] = "\x1BOS",
709 	[TKEY_F5] = "\x1B[15~",		[TKEY_F6] = "\x1B[17~",
710 	[TKEY_F7] = "\x1B[18~",		[TKEY_F8] = "\x1B[19~",
711 	[TKEY_F9] = "\x1B[20~",		[TKEY_F10] = "\x1B[21~",
712 	[TKEY_F11] = "\x1B[23~",	[TKEY_F12] = "\x1B[24~",
713 };
714 
715 const char *
teken_get_sequence(const teken_t * t,unsigned int k)716 teken_get_sequence(const teken_t *t, unsigned int k)
717 {
718 
719 	/* Cons25 mode. */
720 	if (t->t_stateflags & TS_CONS25 &&
721 	    k < sizeof special_strings_cons25 / sizeof(char *))
722 		return (special_strings_cons25[k]);
723 
724 	/* Cursor keys mode. */
725 	if (t->t_stateflags & TS_CURSORKEYS &&
726 	    k < sizeof special_strings_ckeys / sizeof(char *))
727 		return (special_strings_ckeys[k]);
728 
729 	/* Default xterm sequences. */
730 	if (k < sizeof special_strings_normal / sizeof(char *))
731 		return (special_strings_normal[k]);
732 
733 	return (NULL);
734 }
735 
736 #include "teken_state.h"
737