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
teken_funcs_bell(const teken_t * t)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
teken_funcs_cursor(const teken_t * t)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
teken_funcs_putchar(const teken_t * t,const teken_pos_t * p,teken_char_t c,const teken_attr_t * a)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
teken_funcs_fill(const teken_t * t,const teken_rect_t * r,const teken_char_t c,const teken_attr_t * a)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
teken_funcs_copy(const teken_t * t,const teken_rect_t * r,const teken_pos_t * p)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
teken_funcs_pre_input(const teken_t * t)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
teken_funcs_post_input(const teken_t * t)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
teken_funcs_param(const teken_t * t,int cmd,unsigned int value)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
teken_funcs_respond(const teken_t * t,const void * buf,size_t len)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
teken_init(teken_t * t,const teken_funcs_t * tf,void * softc)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
teken_input_char(teken_t * t,teken_char_t c)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
teken_input_byte(teken_t * t,unsigned char c)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
teken_input(teken_t * t,const void * buf,size_t len)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 *
teken_get_cursor(const teken_t * t)322 teken_get_cursor(const teken_t *t)
323 {
324
325 return (&t->t_cursor);
326 }
327
328 void
teken_set_cursor(teken_t * t,const teken_pos_t * p)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 *
teken_get_curattr(const teken_t * t)340 teken_get_curattr(const teken_t *t)
341 {
342
343 return (&t->t_curattr);
344 }
345
346 void
teken_set_curattr(teken_t * t,const teken_attr_t * a)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 *
teken_get_defattr(const teken_t * t)354 teken_get_defattr(const teken_t *t)
355 {
356
357 return (&t->t_defattr);
358 }
359
360 void
teken_set_defattr(teken_t * t,const teken_attr_t * a)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 *
teken_get_winsize(const teken_t * t)368 teken_get_winsize(const teken_t *t)
369 {
370
371 return (&t->t_winsize);
372 }
373
374 static void
teken_trim_cursor_pos(teken_t * t,const teken_pos_t * new)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
teken_set_winsize(teken_t * t,const teken_pos_t * p)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
teken_set_winsize_noreset(teken_t * t,const teken_pos_t * p)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
teken_set_8bit(teken_t * t)408 teken_set_8bit(teken_t *t)
409 {
410
411 t->t_stateflags |= TS_8BIT;
412 }
413
414 void
teken_set_cons25(teken_t * t)415 teken_set_cons25(teken_t *t)
416 {
417
418 t->t_stateflags |= TS_CONS25;
419 }
420
421 void
teken_set_cons25keys(teken_t * t)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
teken_state_switch(teken_t * t,teken_state_t * s)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
teken_state_numbers(teken_t * t,teken_char_t c)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
teken_256to8(teken_color_t c)679 teken_256to8(teken_color_t c)
680 {
681
682 return (teken_256to8tab[c % 256]);
683 }
684
685 teken_color_t
teken_256to16(teken_color_t c)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 *
teken_get_sequence(const teken_t * t,unsigned int k)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