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