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