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