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