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