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