aboutsummaryrefslogtreecommitdiff
path: root/termbox2.h
diff options
context:
space:
mode:
Diffstat (limited to 'termbox2.h')
-rw-r--r--termbox2.h4305
1 files changed, 4305 insertions, 0 deletions
diff --git a/termbox2.h b/termbox2.h
new file mode 100644
index 0000000..e42bca6
--- /dev/null
+++ b/termbox2.h
@@ -0,0 +1,4305 @@
1/*
2MIT License
3
4Copyright (c) 2010-2020 nsf <no.smile.face@gmail.com>
5 2015-2025 Adam Saponara <as@php.net>
6
7Permission is hereby granted, free of charge, to any person obtaining a copy
8of this software and associated documentation files (the "Software"), to deal
9in the Software without restriction, including without limitation the rights
10to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11copies of the Software, and to permit persons to whom the Software is
12furnished to do so, subject to the following conditions:
13
14The above copyright notice and this permission notice shall be included in all
15copies or substantial portions of the Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23SOFTWARE.
24*/
25#ifndef TERMBOX_H_INCL
26#define TERMBOX_H_INCL
27
28#ifndef _XOPEN_SOURCE
29#define _XOPEN_SOURCE
30#endif
31
32#ifndef _DEFAULT_SOURCE
33#define _DEFAULT_SOURCE
34#endif
35
36#include <errno.h>
37#include <fcntl.h>
38#include <limits.h>
39#include <signal.h>
40#include <stdarg.h>
41#include <stdint.h>
42#include <stdio.h>
43#include <stdlib.h>
44#include <string.h>
45#include <sys/ioctl.h>
46#include <sys/select.h>
47#include <sys/stat.h>
48#include <sys/time.h>
49#include <sys/types.h>
50#include <termios.h>
51#include <unistd.h>
52
53#ifdef PATH_MAX
54#define TB_PATH_MAX PATH_MAX
55#else
56#define TB_PATH_MAX 4096
57#endif
58
59#ifdef __cplusplus
60extern "C" {
61#endif
62
63// __ffi_start
64
65#define TB_VERSION_STR "2.7.0-dev"
66
67/* The following compile-time options are supported:
68 *
69 * TB_OPT_ATTR_W: Integer width of `fg` and `bg` attributes. Valid values
70 * (assuming system support) are 16, 32, and 64. (See
71 * `uintattr_t`). 32 or 64 enables output mode
72 * `TB_OUTPUT_TRUECOLOR`. 64 enables additional style
73 * attributes. (See `tb_set_output_mode`.) Larger values
74 * consume more memory in exchange for more features.
75 * Defaults to 16.
76 *
77 * TB_OPT_EGC: If set, enable extended grapheme cluster support
78 * (`tb_extend_cell`, `tb_set_cell_ex`). Consumes more
79 * memory. Defaults off.
80 *
81 * TB_OPT_PRINTF_BUF: Write buffer size for printf operations. Represents the
82 * largest string that can be sent in one call to
83 * `tb_print*` and `tb_send*` functions. Defaults to 4096.
84 *
85 * TB_OPT_READ_BUF: Read buffer size for tty reads. Defaults to 64.
86 *
87 * TB_OPT_LIBC_WCHAR: If set, use libc's `wcwidth(3)`, `iswprint(3)`, etc
88 * instead of the built-in Unicode-aware versions. Note,
89 * libc's are locale-dependent and the caller must
90 * `setlocale(3)` `LC_CTYPE` to UTF-8. Defaults to built-in.
91 *
92 * TB_OPT_TRUECOLOR: Deprecated. Sets TB_OPT_ATTR_W to 32 if not already set.
93 */
94
95#if defined(TB_LIB_OPTS) || 0 // __tb_lib_opts
96/* Ensure consistent compile-time options when using as a shared library */
97#undef TB_OPT_ATTR_W
98#undef TB_OPT_EGC
99#undef TB_OPT_PRINTF_BUF
100#undef TB_OPT_READ_BUF
101#undef TB_OPT_LIBC_WCHAR
102#define TB_OPT_ATTR_W 64
103#define TB_OPT_EGC
104#endif
105
106/* Ensure sane `TB_OPT_ATTR_W` (16, 32, or 64) */
107#if defined TB_OPT_ATTR_W && TB_OPT_ATTR_W == 16
108#elif defined TB_OPT_ATTR_W && TB_OPT_ATTR_W == 32
109#elif defined TB_OPT_ATTR_W && TB_OPT_ATTR_W == 64
110#else
111#undef TB_OPT_ATTR_W
112#if defined TB_OPT_TRUECOLOR // Deprecated. Back-compat for old flag.
113#define TB_OPT_ATTR_W 32
114#else
115#define TB_OPT_ATTR_W 16
116#endif
117#endif
118
119/* Include wchar if opting libc */
120#ifdef TB_OPT_LIBC_WCHAR
121#include <wchar.h>
122#include <wctype.h>
123#endif
124
125/* ASCII key constants (`tb_event.key`) */
126#define TB_KEY_CTRL_TILDE 0x00
127#define TB_KEY_CTRL_2 0x00 // clash with `CTRL_TILDE`
128#define TB_KEY_CTRL_A 0x01
129#define TB_KEY_CTRL_B 0x02
130#define TB_KEY_CTRL_C 0x03
131#define TB_KEY_CTRL_D 0x04
132#define TB_KEY_CTRL_E 0x05
133#define TB_KEY_CTRL_F 0x06
134#define TB_KEY_CTRL_G 0x07
135#define TB_KEY_BACKSPACE 0x08
136#define TB_KEY_CTRL_H 0x08 // clash with `CTRL_BACKSPACE`
137#define TB_KEY_TAB 0x09
138#define TB_KEY_CTRL_I 0x09 // clash with `TAB`
139#define TB_KEY_CTRL_J 0x0a
140#define TB_KEY_CTRL_K 0x0b
141#define TB_KEY_CTRL_L 0x0c
142#define TB_KEY_ENTER 0x0d
143#define TB_KEY_CTRL_M 0x0d // clash with `ENTER`
144#define TB_KEY_CTRL_N 0x0e
145#define TB_KEY_CTRL_O 0x0f
146#define TB_KEY_CTRL_P 0x10
147#define TB_KEY_CTRL_Q 0x11
148#define TB_KEY_CTRL_R 0x12
149#define TB_KEY_CTRL_S 0x13
150#define TB_KEY_CTRL_T 0x14
151#define TB_KEY_CTRL_U 0x15
152#define TB_KEY_CTRL_V 0x16
153#define TB_KEY_CTRL_W 0x17
154#define TB_KEY_CTRL_X 0x18
155#define TB_KEY_CTRL_Y 0x19
156#define TB_KEY_CTRL_Z 0x1a
157#define TB_KEY_ESC 0x1b
158#define TB_KEY_CTRL_LSQ_BRACKET 0x1b // clash with 'ESC'
159#define TB_KEY_CTRL_3 0x1b // clash with 'ESC'
160#define TB_KEY_CTRL_4 0x1c
161#define TB_KEY_CTRL_BACKSLASH 0x1c // clash with 'CTRL_4'
162#define TB_KEY_CTRL_5 0x1d
163#define TB_KEY_CTRL_RSQ_BRACKET 0x1d // clash with 'CTRL_5'
164#define TB_KEY_CTRL_6 0x1e
165#define TB_KEY_CTRL_7 0x1f
166#define TB_KEY_CTRL_SLASH 0x1f // clash with 'CTRL_7'
167#define TB_KEY_CTRL_UNDERSCORE 0x1f // clash with 'CTRL_7'
168#define TB_KEY_SPACE 0x20
169#define TB_KEY_BACKSPACE2 0x7f
170#define TB_KEY_CTRL_8 0x7f // clash with 'BACKSPACE2'
171
172#define tb_key_i(i) 0xffff - (i)
173/* Terminal-dependent key constants (`tb_event.key`) and terminfo caps */
174/* BEGIN codegen h */
175/* Produced by ./codegen.sh on Tue, 03 Sep 2024 04:17:47 +0000 */
176#define TB_KEY_F1 (0xffff - 0)
177#define TB_KEY_F2 (0xffff - 1)
178#define TB_KEY_F3 (0xffff - 2)
179#define TB_KEY_F4 (0xffff - 3)
180#define TB_KEY_F5 (0xffff - 4)
181#define TB_KEY_F6 (0xffff - 5)
182#define TB_KEY_F7 (0xffff - 6)
183#define TB_KEY_F8 (0xffff - 7)
184#define TB_KEY_F9 (0xffff - 8)
185#define TB_KEY_F10 (0xffff - 9)
186#define TB_KEY_F11 (0xffff - 10)
187#define TB_KEY_F12 (0xffff - 11)
188#define TB_KEY_INSERT (0xffff - 12)
189#define TB_KEY_DELETE (0xffff - 13)
190#define TB_KEY_HOME (0xffff - 14)
191#define TB_KEY_END (0xffff - 15)
192#define TB_KEY_PGUP (0xffff - 16)
193#define TB_KEY_PGDN (0xffff - 17)
194#define TB_KEY_ARROW_UP (0xffff - 18)
195#define TB_KEY_ARROW_DOWN (0xffff - 19)
196#define TB_KEY_ARROW_LEFT (0xffff - 20)
197#define TB_KEY_ARROW_RIGHT (0xffff - 21)
198#define TB_KEY_BACK_TAB (0xffff - 22)
199#define TB_KEY_MOUSE_LEFT (0xffff - 23)
200#define TB_KEY_MOUSE_RIGHT (0xffff - 24)
201#define TB_KEY_MOUSE_MIDDLE (0xffff - 25)
202#define TB_KEY_MOUSE_RELEASE (0xffff - 26)
203#define TB_KEY_MOUSE_WHEEL_UP (0xffff - 27)
204#define TB_KEY_MOUSE_WHEEL_DOWN (0xffff - 28)
205
206#define TB_CAP_F1 0
207#define TB_CAP_F2 1
208#define TB_CAP_F3 2
209#define TB_CAP_F4 3
210#define TB_CAP_F5 4
211#define TB_CAP_F6 5
212#define TB_CAP_F7 6
213#define TB_CAP_F8 7
214#define TB_CAP_F9 8
215#define TB_CAP_F10 9
216#define TB_CAP_F11 10
217#define TB_CAP_F12 11
218#define TB_CAP_INSERT 12
219#define TB_CAP_DELETE 13
220#define TB_CAP_HOME 14
221#define TB_CAP_END 15
222#define TB_CAP_PGUP 16
223#define TB_CAP_PGDN 17
224#define TB_CAP_ARROW_UP 18
225#define TB_CAP_ARROW_DOWN 19
226#define TB_CAP_ARROW_LEFT 20
227#define TB_CAP_ARROW_RIGHT 21
228#define TB_CAP_BACK_TAB 22
229#define TB_CAP__COUNT_KEYS 23
230#define TB_CAP_ENTER_CA 23
231#define TB_CAP_EXIT_CA 24
232#define TB_CAP_SHOW_CURSOR 25
233#define TB_CAP_HIDE_CURSOR 26
234#define TB_CAP_CLEAR_SCREEN 27
235#define TB_CAP_SGR0 28
236#define TB_CAP_UNDERLINE 29
237#define TB_CAP_BOLD 30
238#define TB_CAP_BLINK 31
239#define TB_CAP_ITALIC 32
240#define TB_CAP_REVERSE 33
241#define TB_CAP_ENTER_KEYPAD 34
242#define TB_CAP_EXIT_KEYPAD 35
243#define TB_CAP_DIM 36
244#define TB_CAP_INVISIBLE 37
245#define TB_CAP__COUNT 38
246/* END codegen h */
247
248/* Some hard-coded caps */
249#define TB_HARDCAP_ENTER_MOUSE "\x1b[?1000h\x1b[?1002h\x1b[?1015h\x1b[?1006h"
250#define TB_HARDCAP_EXIT_MOUSE "\x1b[?1006l\x1b[?1015l\x1b[?1002l\x1b[?1000l"
251#define TB_HARDCAP_STRIKEOUT "\x1b[9m"
252#define TB_HARDCAP_UNDERLINE_2 "\x1b[21m"
253#define TB_HARDCAP_OVERLINE "\x1b[53m"
254
255/* Colors (numeric) and attributes (bitwise) (`tb_cell.fg`, `tb_cell.bg`) */
256#define TB_DEFAULT 0x0000
257#define TB_BLACK 0x0001
258#define TB_RED 0x0002
259#define TB_GREEN 0x0003
260#define TB_YELLOW 0x0004
261#define TB_BLUE 0x0005
262#define TB_MAGENTA 0x0006
263#define TB_CYAN 0x0007
264#define TB_WHITE 0x0008
265
266#if TB_OPT_ATTR_W == 16
267#define TB_BOLD 0x0100
268#define TB_UNDERLINE 0x0200
269#define TB_REVERSE 0x0400
270#define TB_ITALIC 0x0800
271#define TB_BLINK 0x1000
272#define TB_HI_BLACK 0x2000
273#define TB_BRIGHT 0x4000
274#define TB_DIM 0x8000
275#define TB_256_BLACK TB_HI_BLACK // `TB_256_BLACK` is deprecated
276#else
277// `TB_OPT_ATTR_W` is 32 or 64
278#define TB_BOLD 0x01000000
279#define TB_UNDERLINE 0x02000000
280#define TB_REVERSE 0x04000000
281#define TB_ITALIC 0x08000000
282#define TB_BLINK 0x10000000
283#define TB_HI_BLACK 0x20000000
284#define TB_BRIGHT 0x40000000
285#define TB_DIM 0x80000000
286#define TB_TRUECOLOR_BOLD TB_BOLD // `TB_TRUECOLOR_*` is deprecated
287#define TB_TRUECOLOR_UNDERLINE TB_UNDERLINE
288#define TB_TRUECOLOR_REVERSE TB_REVERSE
289#define TB_TRUECOLOR_ITALIC TB_ITALIC
290#define TB_TRUECOLOR_BLINK TB_BLINK
291#define TB_TRUECOLOR_BLACK TB_HI_BLACK
292#endif
293
294#if TB_OPT_ATTR_W == 64
295#define TB_STRIKEOUT 0x0000000100000000
296#define TB_UNDERLINE_2 0x0000000200000000
297#define TB_OVERLINE 0x0000000400000000
298#define TB_INVISIBLE 0x0000000800000000
299#endif
300
301/* Event types (`tb_event.type`) */
302#define TB_EVENT_KEY 1
303#define TB_EVENT_RESIZE 2
304#define TB_EVENT_MOUSE 3
305
306/* Key modifiers (bitwise) (`tb_event.mod`) */
307#define TB_MOD_ALT 1
308#define TB_MOD_CTRL 2
309#define TB_MOD_SHIFT 4
310#define TB_MOD_MOTION 8
311
312/* Input modes (bitwise) (`tb_set_input_mode`) */
313#define TB_INPUT_CURRENT 0
314#define TB_INPUT_ESC 1
315#define TB_INPUT_ALT 2
316#define TB_INPUT_MOUSE 4
317
318/* Output modes (`tb_set_output_mode`) */
319#define TB_OUTPUT_CURRENT 0
320#define TB_OUTPUT_NORMAL 1
321#define TB_OUTPUT_256 2
322#define TB_OUTPUT_216 3
323#define TB_OUTPUT_GRAYSCALE 4
324#if TB_OPT_ATTR_W >= 32
325#define TB_OUTPUT_TRUECOLOR 5
326#endif
327
328/* Common function return values unless otherwise noted.
329 *
330 * Library behavior is undefined after receiving `TB_ERR_MEM`. Callers may
331 * attempt reinitializing by freeing memory, invoking `tb_shutdown`, then
332 * `tb_init`.
333 */
334#define TB_OK 0
335#define TB_ERR -1
336#define TB_ERR_NEED_MORE -2
337#define TB_ERR_INIT_ALREADY -3
338#define TB_ERR_INIT_OPEN -4
339#define TB_ERR_MEM -5
340#define TB_ERR_NO_EVENT -6
341#define TB_ERR_NO_TERM -7
342#define TB_ERR_NOT_INIT -8
343#define TB_ERR_OUT_OF_BOUNDS -9
344#define TB_ERR_READ -10
345#define TB_ERR_RESIZE_IOCTL -11
346#define TB_ERR_RESIZE_PIPE -12
347#define TB_ERR_RESIZE_SIGACTION -13
348#define TB_ERR_POLL -14
349#define TB_ERR_TCGETATTR -15
350#define TB_ERR_TCSETATTR -16
351#define TB_ERR_UNSUPPORTED_TERM -17
352#define TB_ERR_RESIZE_WRITE -18
353#define TB_ERR_RESIZE_POLL -19
354#define TB_ERR_RESIZE_READ -20
355#define TB_ERR_RESIZE_SSCANF -21
356#define TB_ERR_CAP_COLLISION -22
357
358#define TB_ERR_SELECT TB_ERR_POLL
359#define TB_ERR_RESIZE_SELECT TB_ERR_RESIZE_POLL
360
361/* Deprecated. Function types to be used with `tb_set_func`. */
362#define TB_FUNC_EXTRACT_PRE 0
363#define TB_FUNC_EXTRACT_POST 1
364
365/* Define this to set the size of the buffer used in `tb_printf`
366 * and `tb_sendf`
367 */
368#ifndef TB_OPT_PRINTF_BUF
369#define TB_OPT_PRINTF_BUF 4096
370#endif
371
372/* Define this to set the size of the read buffer used when reading
373 * from the tty
374 */
375#ifndef TB_OPT_READ_BUF
376#define TB_OPT_READ_BUF 64
377#endif
378
379/* Define this for limited back compat with termbox v1 */
380#ifdef TB_OPT_V1_COMPAT
381#define tb_change_cell tb_set_cell
382#define tb_put_cell(x, y, c) tb_set_cell((x), (y), (c)->ch, (c)->fg, (c)->bg)
383#define tb_set_clear_attributes tb_set_clear_attrs
384#define tb_select_input_mode tb_set_input_mode
385#define tb_select_output_mode tb_set_output_mode
386#endif
387
388/* Define these to swap in a different allocator */
389#ifndef tb_malloc
390#define tb_malloc malloc
391#define tb_realloc realloc
392#define tb_free free
393#endif
394
395#if TB_OPT_ATTR_W == 64
396typedef uint64_t uintattr_t;
397#elif TB_OPT_ATTR_W == 32
398typedef uint32_t uintattr_t;
399#else // 16
400typedef uint16_t uintattr_t;
401#endif
402
403/* A cell in a 2d grid representing the terminal screen.
404 *
405 * The terminal screen is represented as 2d array of cells. The structure is
406 * optimized for dealing with single-width (`wcwidth==1`) Unicode codepoints,
407 * however some support for grapheme clusters (e.g., combining diacritical
408 * marks) and wide codepoints (e.g., Hiragana) is provided through `ech`,
409 * `nech`, and `cech` via `tb_set_cell_ex`. `ech` is only valid when `nech>0`,
410 * otherwise `ch` is used.
411 *
412 * For non-single-width codepoints, given `W=wcwidth(ch || ech)`:
413 *
414 * when `W<=0`: termbox forces a single-width cell. Callers should avoid this
415 * if aiming to render text accurately. Callers may use
416 * `tb_set_cell_ex` or `tb_print*` to render `W==0` combining
417 * characters.
418 *
419 * when `W>=2`: termbox zeroes out the following `W-1` cells and skips sending
420 * them to the tty. So, e.g., if the caller sets `x=0,y=0` to a
421 * `W==2` codepoint, the caller's next set should be at `x=2,y=0`.
422 * Anything set at `x=1,y=0` will be ignored. If there are not
423 * enough columns remaining on the line to render `W` cells, spaces
424 * are sent instead.
425 *
426 * See `tb_present` for implementation.
427 */
428struct tb_cell {
429 uint32_t ch; // a Unicode codepoint
430 uintattr_t fg; // bitwise foreground attributes
431 uintattr_t bg; // bitwise background attributes
432#ifdef TB_OPT_EGC
433 uint32_t *ech; // a grapheme cluster of Unicode codepoints, 0-terminated
434 size_t nech; // num elements in ech, 0 means use ch instead of ech
435 size_t cech; // num elements allocated for ech
436#endif
437};
438
439/* An incoming event from the tty.
440 *
441 * Given the event type, the following fields are relevant:
442 *
443 * when `TB_EVENT_KEY`: `key` xor `ch` (one will be zero) and `mod`. Note
444 * there is overlap between `TB_MOD_CTRL` and
445 * `TB_KEY_CTRL_*`. `TB_MOD_CTRL` and `TB_MOD_SHIFT` are
446 * only set as modifiers to `TB_KEY_ARROW_*`.
447 *
448 * when `TB_EVENT_RESIZE`: `w` and `h`
449 *
450 * when `TB_EVENT_MOUSE`: `key` (`TB_KEY_MOUSE_*`), `x`, and `y`
451 */
452struct tb_event {
453 uint8_t type; // one of `TB_EVENT_*` constants
454 uint8_t mod; // bitwise `TB_MOD_*` constants
455 uint16_t key; // one of `TB_KEY_*` constants
456 uint32_t ch; // a Unicode codepoint
457 int32_t w; // resize width
458 int32_t h; // resize height
459 int32_t x; // mouse x
460 int32_t y; // mouse y
461};
462
463/* Initialize the termbox library. This function should be called before any
464 * other functions. `tb_init` is equivalent to `tb_init_file("/dev/tty")`. After
465 * successful initialization, the library must be finalized using `tb_shutdown`.
466 */
467int tb_init(void);
468int tb_init_file(const char *path);
469int tb_init_fd(int ttyfd);
470int tb_init_rwfd(int rfd, int wfd);
471int tb_shutdown(void);
472
473/* Return the size of the internal back buffer (which is the same as terminal's
474 * window size in rows and columns). The internal buffer can be resized after
475 * `tb_clear` or `tb_present` calls. Both dimensions have an unspecified
476 * negative value when called before `tb_init` or after `tb_shutdown`.
477 */
478int tb_width(void);
479int tb_height(void);
480
481/* Clear the internal back buffer using `TB_DEFAULT` or the attributes set by
482 * `tb_set_clear_attrs`.
483 */
484int tb_clear(void);
485int tb_set_clear_attrs(uintattr_t fg, uintattr_t bg);
486
487/* Synchronize the internal back buffer with the terminal by writing to tty. */
488int tb_present(void);
489
490/* Clear the internal front buffer effectively forcing a complete re-render of
491 * the back buffer to the tty. It is not necessary to call this under normal
492 * circumstances.
493 */
494int tb_invalidate(void);
495
496/* Set the position of the cursor. Upper-left cell is (0, 0). */
497int tb_set_cursor(int cx, int cy);
498int tb_hide_cursor(void);
499
500/* Set cell contents in the internal back buffer at the specified position.
501 *
502 * Use `tb_set_cell_ex` for rendering grapheme clusters (e.g., combining
503 * diacritical marks).
504 *
505 * Calling `tb_set_cell(x, y, ch, fg, bg)` is equivalent to
506 * `tb_set_cell_ex(x, y, &ch, 1, fg, bg)`.
507 *
508 * `tb_extend_cell` is a shortcut for appending 1 codepoint to `tb_cell.ech`.
509 *
510 * Non-printable (`iswprint(3)`) codepoints are replaced with `U+FFFD` at render
511 * time.
512 */
513int tb_set_cell(int x, int y, uint32_t ch, uintattr_t fg, uintattr_t bg);
514int tb_set_cell_ex(int x, int y, uint32_t *ch, size_t nch, uintattr_t fg,
515 uintattr_t bg);
516int tb_extend_cell(int x, int y, uint32_t ch);
517
518/* Return a pointer to the cell at the specified position.
519 *
520 * Cell memory may be invalid or freed after subsequent library calls, so
521 * callers must copy any data that they need to persist across calls. Modifying
522 * cell memory results in undefined behavior.
523 *
524 * Callers may use pointer math to access cells relative to the requested one.
525 * The cell grid memory layout is a contiguous array indexable by the expression
526 * `(y * width) + x`.
527 *
528 * If `back` is non-zero, return cell from the internal back buffer. Otherwise,
529 * return cell from the front buffer. Note the front buffer is updated on each
530 * call to `tb_present`, whereas the back buffer is updated immediately by
531 * `tb_set_cell` and other functions that modify cell contents.
532 *
533 * If the position is invalid, `TB_ERR_OUT_OF_BOUNDS` is returned.
534 */
535int tb_get_cell(int x, int y, int back, struct tb_cell **cell);
536
537/* Set the input mode. Termbox has two input modes:
538 *
539 * 1. `TB_INPUT_ESC`
540 * When escape (`\x1b`) is in the buffer and there's no match for an escape
541 * sequence, a key event for `TB_KEY_ESC` is returned.
542 *
543 * 2. `TB_INPUT_ALT`
544 * When escape (`\x1b`) is in the buffer and there's no match for an escape
545 * sequence, the next keyboard event is returned with a `TB_MOD_ALT`
546 * modifier.
547 *
548 * You can also apply `TB_INPUT_MOUSE` via bitwise OR operation to either of the
549 * modes (e.g., `TB_INPUT_ESC | TB_INPUT_MOUSE`) to receive `TB_EVENT_MOUSE`
550 * events. If none of the main two modes were set, but the mouse mode was,
551 * `TB_INPUT_ESC` is used. If for some reason you've decided to use
552 * `TB_INPUT_ESC | TB_INPUT_ALT`, it will behave as if only `TB_INPUT_ESC` was
553 * selected.
554 *
555 * If mode is `TB_INPUT_CURRENT`, return the current input mode.
556 *
557 * The default input mode is `TB_INPUT_ESC`.
558 */
559int tb_set_input_mode(int mode);
560
561/* Set the output mode. Termbox has multiple output modes:
562 *
563 * 1. `TB_OUTPUT_NORMAL` => [0..8]
564 *
565 * This mode provides 8 different colors:
566 * `TB_BLACK`, `TB_RED`, `TB_GREEN`, `TB_YELLOW`,
567 * `TB_BLUE`, `TB_MAGENTA`, `TB_CYAN`, `TB_WHITE`
568 *
569 * Plus `TB_DEFAULT` which skips sending a color code (i.e., uses the
570 * terminal's default color).
571 *
572 * Colors (including `TB_DEFAULT`) may be bitwise OR'd with attributes:
573 * `TB_BOLD`, `TB_UNDERLINE`, `TB_REVERSE`, `TB_ITALIC`, `TB_BLINK`,
574 * `TB_BRIGHT`, `TB_DIM`
575 *
576 * The following style attributes are also available if compiled with
577 * `TB_OPT_ATTR_W` set to 64:
578 * `TB_STRIKEOUT`, `TB_UNDERLINE_2`, `TB_OVERLINE`, `TB_INVISIBLE`
579 *
580 * As in all modes, the value 0 is interpreted as `TB_DEFAULT` for
581 * convenience.
582 *
583 * Some notes: `TB_REVERSE` and `TB_BRIGHT` can be applied as either `fg` or
584 * `bg` attributes for the same effect. The rest of the attributes apply to
585 * `fg` only and are ignored as `bg` attributes.
586 *
587 * Example usage: `tb_set_cell(x, y, '@', TB_BLACK | TB_BOLD, TB_RED)`
588 *
589 * 2. `TB_OUTPUT_256` => [0..255] + `TB_HI_BLACK`
590 *
591 * In this mode you get 256 distinct colors (plus default):
592 * 0x00 (1): `TB_DEFAULT`
593 * `TB_HI_BLACK` (1): `TB_BLACK` in `TB_OUTPUT_NORMAL`
594 * 0x01..0x07 (7): the next 7 colors as in `TB_OUTPUT_NORMAL`
595 * 0x08..0x0f (8): bright versions of the above
596 * 0x10..0xe7 (216): 216 different colors
597 * 0xe8..0xff (24): 24 different shades of gray
598 *
599 * All `TB_*` style attributes except `TB_BRIGHT` may be bitwise OR'd as in
600 * `TB_OUTPUT_NORMAL`.
601 *
602 * Note `TB_HI_BLACK` must be used for black, as 0x00 represents default.
603 *
604 * 3. `TB_OUTPUT_216` => [0..216]
605 *
606 * This mode supports the 216-color range of `TB_OUTPUT_256` only, but you
607 * don't need to provide an offset:
608 * 0x00 (1): `TB_DEFAULT`
609 * 0x01..0xd8 (216): 216 different colors
610 *
611 * 4. `TB_OUTPUT_GRAYSCALE` => [0..24]
612 *
613 * This mode supports the 24-color range of `TB_OUTPUT_256` only, but you
614 * don't need to provide an offset:
615 * 0x00 (1): `TB_DEFAULT`
616 * 0x01..0x18 (24): 24 different shades of gray
617 *
618 * 5. `TB_OUTPUT_TRUECOLOR` => [0x000000..0xffffff] + `TB_HI_BLACK`
619 *
620 * This mode provides 24-bit color on supported terminals. The format is
621 * 0xRRGGBB.
622 *
623 * All `TB_*` style attributes except `TB_BRIGHT` may be bitwise OR'd as in
624 * `TB_OUTPUT_NORMAL`.
625 *
626 * Note `TB_HI_BLACK` must be used for black, as 0x000000 represents default.
627 *
628 * To use the terminal default color (i.e., to not send an escape code), pass
629 * `TB_DEFAULT`. For convenience, the value 0 is interpreted as `TB_DEFAULT` in
630 * all modes.
631 *
632 * Note, cell attributes persist after switching output modes. Any translation
633 * between, for example, `TB_OUTPUT_NORMAL`'s `TB_RED` and
634 * `TB_OUTPUT_TRUECOLOR`'s 0xff0000 must be performed by the caller. Also note
635 * that cells previously rendered in one mode may persist unchanged until the
636 * front buffer is cleared (such as after a resize event) at which point it will
637 * be re-interpreted and flushed according to the current mode. Callers may
638 * invoke `tb_invalidate` if it is desirable to immediately re-interpret and
639 * flush the entire screen according to the current mode.
640 *
641 * Note, not all terminals support all output modes, especially beyond
642 * `TB_OUTPUT_NORMAL`. There is also no very reliable way to determine color
643 * support dynamically. If portability is desired, callers are recommended to
644 * use `TB_OUTPUT_NORMAL` or make output mode end-user configurable. The same
645 * advice applies to style attributes.
646 *
647 * If mode is `TB_OUTPUT_CURRENT`, return the current output mode.
648 *
649 * The default output mode is `TB_OUTPUT_NORMAL`.
650 */
651int tb_set_output_mode(int mode);
652
653/* Wait for an event up to `timeout_ms` milliseconds and populate `event` with
654 * it. If no event is available within the timeout period, `TB_ERR_NO_EVENT`
655 * is returned. On a resize event, the underlying `select(2)` call may be
656 * interrupted, yielding a return code of `TB_ERR_POLL`. In this case, you may
657 * check `errno` via `tb_last_errno`. If it's `EINTR`, you may elect to ignore
658 * that and call `tb_peek_event` again.
659 */
660int tb_peek_event(struct tb_event *event, int timeout_ms);
661
662/* Same as `tb_peek_event` except no timeout. */
663int tb_poll_event(struct tb_event *event);
664
665/* Internal termbox fds that can be used with `poll(2)`, `select(2)`, etc.
666 * externally. Callers must invoke `tb_poll_event` or `tb_peek_event` if
667 * fds become readable.
668 */
669int tb_get_fds(int *ttyfd, int *resizefd);
670
671/* Print and printf functions. Specify param `out_w` to determine width of
672 * printed string. Strings are interpreted as UTF-8.
673 *
674 * Non-printable characters (`iswprint(3)`) and truncated UTF-8 byte sequences
675 * are replaced with U+FFFD.
676 *
677 * Newlines (`\n`) are supported with the caveat that `out_w` will return the
678 * width of the string as if it were on a single line.
679 *
680 * If the starting coordinate is out of bounds, `TB_ERR_OUT_OF_BOUNDS` is
681 * returned. If the starting coordinate is in bounds, but goes out of bounds,
682 * then the out-of-bounds portions of the string are ignored.
683 *
684 * For finer control, use `tb_set_cell`.
685 */
686int tb_print(int x, int y, uintattr_t fg, uintattr_t bg, const char *str);
687int tb_printf(int x, int y, uintattr_t fg, uintattr_t bg, const char *fmt, ...);
688int tb_print_ex(int x, int y, uintattr_t fg, uintattr_t bg, size_t *out_w,
689 const char *str);
690int tb_printf_ex(int x, int y, uintattr_t fg, uintattr_t bg, size_t *out_w,
691 const char *fmt, ...);
692
693/* Send raw bytes to terminal. */
694int tb_send(const char *buf, size_t nbuf);
695int tb_sendf(const char *fmt, ...);
696
697/* Deprecated. Set custom callbacks. `fn_type` is one of `TB_FUNC_*` constants,
698 * `fn` is a compatible function pointer, or NULL to clear.
699 *
700 * `TB_FUNC_EXTRACT_PRE`:
701 * If specified, invoke this function BEFORE termbox tries to extract any
702 * escape sequences from the input buffer.
703 *
704 * `TB_FUNC_EXTRACT_POST`:
705 * If specified, invoke this function AFTER termbox tries (and fails) to
706 * extract any escape sequences from the input buffer.
707 */
708int tb_set_func(int fn_type, int (*fn)(struct tb_event *, size_t *));
709
710/* Return byte length of codepoint given first byte of UTF-8 sequence (1-6). */
711int tb_utf8_char_length(char c);
712
713/* Convert UTF-8 null-terminated byte sequence to UTF-32 codepoint.
714 *
715 * If `c` is an empty C string, return 0. `out` is left unchanged.
716 *
717 * If a null byte is encountered in the middle of the codepoint, return a
718 * negative number indicating how many bytes were processed. `out` is left
719 * unchanged.
720 *
721 * Otherwise, return byte length of codepoint (1-6).
722 */
723int tb_utf8_char_to_unicode(uint32_t *out, const char *c);
724
725/* Convert UTF-32 codepoint to UTF-8 null-terminated byte sequence.
726 *
727 * `out` must be char[7] or greater. Return byte length of codepoint (1-6).
728 */
729int tb_utf8_unicode_to_char(char *out, uint32_t c);
730
731/* Library utility functions */
732int tb_last_errno(void);
733const char *tb_strerror(int err);
734struct tb_cell *tb_cell_buffer(void); // Deprecated
735int tb_has_truecolor(void);
736int tb_has_egc(void);
737int tb_attr_width(void);
738const char *tb_version(void);
739int tb_iswprint(uint32_t ch);
740int tb_wcwidth(uint32_t ch);
741
742/* Deprecation notice!
743 *
744 * The following will be removed in version 3.x (ABI version 3):
745 *
746 * TB_256_BLACK (use TB_HI_BLACK)
747 * TB_OPT_TRUECOLOR (use TB_OPT_ATTR_W)
748 * TB_TRUECOLOR_BOLD (use TB_BOLD)
749 * TB_TRUECOLOR_UNDERLINE (use TB_UNDERLINE)
750 * TB_TRUECOLOR_REVERSE (use TB_REVERSE)
751 * TB_TRUECOLOR_ITALIC (use TB_ITALIC)
752 * TB_TRUECOLOR_BLINK (use TB_BLINK)
753 * TB_TRUECOLOR_BLACK (use TB_HI_BLACK)
754 * tb_cell_buffer
755 * tb_set_func
756 * TB_FUNC_EXTRACT_PRE
757 * TB_FUNC_EXTRACT_POST
758 */
759
760#ifdef __cplusplus
761}
762#endif
763
764#endif // TERMBOX_H_INCL
765
766#ifdef TB_IMPL
767
768#define if_err_return(rv, expr) \
769 if (((rv) = (expr)) != TB_OK) return (rv)
770#define if_err_break(rv, expr) \
771 if (((rv) = (expr)) != TB_OK) break
772#define if_ok_return(rv, expr) \
773 if (((rv) = (expr)) == TB_OK) return (rv)
774#define if_ok_or_need_more_return(rv, expr) \
775 if (((rv) = (expr)) == TB_OK || (rv) == TB_ERR_NEED_MORE) return (rv)
776
777#define send_literal(rv, a) \
778 if_err_return((rv), bytebuf_nputs(&global.out, (a), sizeof(a) - 1))
779
780#define send_num(rv, nbuf, n) \
781 if_err_return((rv), \
782 bytebuf_nputs(&global.out, (nbuf), convert_num((n), (nbuf))))
783
784#define snprintf_or_return(rv, str, sz, fmt, ...) \
785 do { \
786 (rv) = snprintf((str), (sz), (fmt), __VA_ARGS__); \
787 if ((rv) < 0 || (rv) >= (int)(sz)) return TB_ERR; \
788 } while (0)
789
790#define if_not_init_return() \
791 if (!global.initialized) return TB_ERR_NOT_INIT
792
793struct bytebuf {
794 char *buf;
795 size_t len;
796 size_t cap;
797};
798
799struct cellbuf {
800 int width;
801 int height;
802 struct tb_cell *cells;
803};
804
805struct cap_trie {
806 char c;
807 struct cap_trie *children;
808 size_t nchildren;
809 int is_leaf;
810 uint16_t key;
811 uint8_t mod;
812};
813
814struct tb_global {
815 int ttyfd;
816 int rfd;
817 int wfd;
818 int ttyfd_open;
819 int resize_pipefd[2];
820 int width;
821 int height;
822 int cursor_x;
823 int cursor_y;
824 int last_x;
825 int last_y;
826 uintattr_t fg;
827 uintattr_t bg;
828 uintattr_t last_fg;
829 uintattr_t last_bg;
830 int input_mode;
831 int output_mode;
832 char *terminfo;
833 size_t nterminfo;
834 const char *caps[TB_CAP__COUNT];
835 struct cap_trie cap_trie;
836 struct bytebuf in;
837 struct bytebuf out;
838 struct cellbuf back;
839 struct cellbuf front;
840 struct termios orig_tios;
841 int has_orig_tios;
842 int last_errno;
843 int initialized;
844 int (*fn_extract_esc_pre)(struct tb_event *, size_t *);
845 int (*fn_extract_esc_post)(struct tb_event *, size_t *);
846 char errbuf[1024];
847};
848
849static struct tb_global global = {0};
850
851/* BEGIN codegen c */
852/* Produced by ./codegen.sh on Tue, 03 Sep 2024 04:17:48 +0000 */
853
854static const int16_t terminfo_cap_indexes[] = {
855 66, // kf1 (TB_CAP_F1)
856 68, // kf2 (TB_CAP_F2)
857 69, // kf3 (TB_CAP_F3)
858 70, // kf4 (TB_CAP_F4)
859 71, // kf5 (TB_CAP_F5)
860 72, // kf6 (TB_CAP_F6)
861 73, // kf7 (TB_CAP_F7)
862 74, // kf8 (TB_CAP_F8)
863 75, // kf9 (TB_CAP_F9)
864 67, // kf10 (TB_CAP_F10)
865 216, // kf11 (TB_CAP_F11)
866 217, // kf12 (TB_CAP_F12)
867 77, // kich1 (TB_CAP_INSERT)
868 59, // kdch1 (TB_CAP_DELETE)
869 76, // khome (TB_CAP_HOME)
870 164, // kend (TB_CAP_END)
871 82, // kpp (TB_CAP_PGUP)
872 81, // knp (TB_CAP_PGDN)
873 87, // kcuu1 (TB_CAP_ARROW_UP)
874 61, // kcud1 (TB_CAP_ARROW_DOWN)
875 79, // kcub1 (TB_CAP_ARROW_LEFT)
876 83, // kcuf1 (TB_CAP_ARROW_RIGHT)
877 148, // kcbt (TB_CAP_BACK_TAB)
878 28, // smcup (TB_CAP_ENTER_CA)
879 40, // rmcup (TB_CAP_EXIT_CA)
880 16, // cnorm (TB_CAP_SHOW_CURSOR)
881 13, // civis (TB_CAP_HIDE_CURSOR)
882 5, // clear (TB_CAP_CLEAR_SCREEN)
883 39, // sgr0 (TB_CAP_SGR0)
884 36, // smul (TB_CAP_UNDERLINE)
885 27, // bold (TB_CAP_BOLD)
886 26, // blink (TB_CAP_BLINK)
887 311, // sitm (TB_CAP_ITALIC)
888 34, // rev (TB_CAP_REVERSE)
889 89, // smkx (TB_CAP_ENTER_KEYPAD)
890 88, // rmkx (TB_CAP_EXIT_KEYPAD)
891 30, // dim (TB_CAP_DIM)
892 32, // invis (TB_CAP_INVISIBLE)
893};
894
895// xterm
896static const char *xterm_caps[] = {
897 "\033OP", // kf1 (TB_CAP_F1)
898 "\033OQ", // kf2 (TB_CAP_F2)
899 "\033OR", // kf3 (TB_CAP_F3)
900 "\033OS", // kf4 (TB_CAP_F4)
901 "\033[15~", // kf5 (TB_CAP_F5)
902 "\033[17~", // kf6 (TB_CAP_F6)
903 "\033[18~", // kf7 (TB_CAP_F7)
904 "\033[19~", // kf8 (TB_CAP_F8)
905 "\033[20~", // kf9 (TB_CAP_F9)
906 "\033[21~", // kf10 (TB_CAP_F10)
907 "\033[23~", // kf11 (TB_CAP_F11)
908 "\033[24~", // kf12 (TB_CAP_F12)
909 "\033[2~", // kich1 (TB_CAP_INSERT)
910 "\033[3~", // kdch1 (TB_CAP_DELETE)
911 "\033OH", // khome (TB_CAP_HOME)
912 "\033OF", // kend (TB_CAP_END)
913 "\033[5~", // kpp (TB_CAP_PGUP)
914 "\033[6~", // knp (TB_CAP_PGDN)
915 "\033OA", // kcuu1 (TB_CAP_ARROW_UP)
916 "\033OB", // kcud1 (TB_CAP_ARROW_DOWN)
917 "\033OD", // kcub1 (TB_CAP_ARROW_LEFT)
918 "\033OC", // kcuf1 (TB_CAP_ARROW_RIGHT)
919 "\033[Z", // kcbt (TB_CAP_BACK_TAB)
920 "\033[?1049h\033[22;0;0t", // smcup (TB_CAP_ENTER_CA)
921 "\033[?1049l\033[23;0;0t", // rmcup (TB_CAP_EXIT_CA)
922 "\033[?12l\033[?25h", // cnorm (TB_CAP_SHOW_CURSOR)
923 "\033[?25l", // civis (TB_CAP_HIDE_CURSOR)
924 "\033[H\033[2J", // clear (TB_CAP_CLEAR_SCREEN)
925 "\033(B\033[m", // sgr0 (TB_CAP_SGR0)
926 "\033[4m", // smul (TB_CAP_UNDERLINE)
927 "\033[1m", // bold (TB_CAP_BOLD)
928 "\033[5m", // blink (TB_CAP_BLINK)
929 "\033[3m", // sitm (TB_CAP_ITALIC)
930 "\033[7m", // rev (TB_CAP_REVERSE)
931 "\033[?1h\033=", // smkx (TB_CAP_ENTER_KEYPAD)
932 "\033[?1l\033>", // rmkx (TB_CAP_EXIT_KEYPAD)
933 "\033[2m", // dim (TB_CAP_DIM)
934 "\033[8m", // invis (TB_CAP_INVISIBLE)
935};
936
937// linux
938static const char *linux_caps[] = {
939 "\033[[A", // kf1 (TB_CAP_F1)
940 "\033[[B", // kf2 (TB_CAP_F2)
941 "\033[[C", // kf3 (TB_CAP_F3)
942 "\033[[D", // kf4 (TB_CAP_F4)
943 "\033[[E", // kf5 (TB_CAP_F5)
944 "\033[17~", // kf6 (TB_CAP_F6)
945 "\033[18~", // kf7 (TB_CAP_F7)
946 "\033[19~", // kf8 (TB_CAP_F8)
947 "\033[20~", // kf9 (TB_CAP_F9)
948 "\033[21~", // kf10 (TB_CAP_F10)
949 "\033[23~", // kf11 (TB_CAP_F11)
950 "\033[24~", // kf12 (TB_CAP_F12)
951 "\033[2~", // kich1 (TB_CAP_INSERT)
952 "\033[3~", // kdch1 (TB_CAP_DELETE)
953 "\033[1~", // khome (TB_CAP_HOME)
954 "\033[4~", // kend (TB_CAP_END)
955 "\033[5~", // kpp (TB_CAP_PGUP)
956 "\033[6~", // knp (TB_CAP_PGDN)
957 "\033[A", // kcuu1 (TB_CAP_ARROW_UP)
958 "\033[B", // kcud1 (TB_CAP_ARROW_DOWN)
959 "\033[D", // kcub1 (TB_CAP_ARROW_LEFT)
960 "\033[C", // kcuf1 (TB_CAP_ARROW_RIGHT)
961 "\033\011", // kcbt (TB_CAP_BACK_TAB)
962 "", // smcup (TB_CAP_ENTER_CA)
963 "", // rmcup (TB_CAP_EXIT_CA)
964 "\033[?25h\033[?0c", // cnorm (TB_CAP_SHOW_CURSOR)
965 "\033[?25l\033[?1c", // civis (TB_CAP_HIDE_CURSOR)
966 "\033[H\033[J", // clear (TB_CAP_CLEAR_SCREEN)
967 "\033[m\017", // sgr0 (TB_CAP_SGR0)
968 "\033[4m", // smul (TB_CAP_UNDERLINE)
969 "\033[1m", // bold (TB_CAP_BOLD)
970 "\033[5m", // blink (TB_CAP_BLINK)
971 "", // sitm (TB_CAP_ITALIC)
972 "\033[7m", // rev (TB_CAP_REVERSE)
973 "", // smkx (TB_CAP_ENTER_KEYPAD)
974 "", // rmkx (TB_CAP_EXIT_KEYPAD)
975 "\033[2m", // dim (TB_CAP_DIM)
976 "", // invis (TB_CAP_INVISIBLE)
977};
978
979// screen
980static const char *screen_caps[] = {
981 "\033OP", // kf1 (TB_CAP_F1)
982 "\033OQ", // kf2 (TB_CAP_F2)
983 "\033OR", // kf3 (TB_CAP_F3)
984 "\033OS", // kf4 (TB_CAP_F4)
985 "\033[15~", // kf5 (TB_CAP_F5)
986 "\033[17~", // kf6 (TB_CAP_F6)
987 "\033[18~", // kf7 (TB_CAP_F7)
988 "\033[19~", // kf8 (TB_CAP_F8)
989 "\033[20~", // kf9 (TB_CAP_F9)
990 "\033[21~", // kf10 (TB_CAP_F10)
991 "\033[23~", // kf11 (TB_CAP_F11)
992 "\033[24~", // kf12 (TB_CAP_F12)
993 "\033[2~", // kich1 (TB_CAP_INSERT)
994 "\033[3~", // kdch1 (TB_CAP_DELETE)
995 "\033[1~", // khome (TB_CAP_HOME)
996 "\033[4~", // kend (TB_CAP_END)
997 "\033[5~", // kpp (TB_CAP_PGUP)
998 "\033[6~", // knp (TB_CAP_PGDN)
999 "\033OA", // kcuu1 (TB_CAP_ARROW_UP)
1000 "\033OB", // kcud1 (TB_CAP_ARROW_DOWN)
1001 "\033OD", // kcub1 (TB_CAP_ARROW_LEFT)
1002 "\033OC", // kcuf1 (TB_CAP_ARROW_RIGHT)
1003 "\033[Z", // kcbt (TB_CAP_BACK_TAB)
1004 "\033[?1049h", // smcup (TB_CAP_ENTER_CA)
1005 "\033[?1049l", // rmcup (TB_CAP_EXIT_CA)
1006 "\033[34h\033[?25h", // cnorm (TB_CAP_SHOW_CURSOR)
1007 "\033[?25l", // civis (TB_CAP_HIDE_CURSOR)
1008 "\033[H\033[J", // clear (TB_CAP_CLEAR_SCREEN)
1009 "\033[m\017", // sgr0 (TB_CAP_SGR0)
1010 "\033[4m", // smul (TB_CAP_UNDERLINE)
1011 "\033[1m", // bold (TB_CAP_BOLD)
1012 "\033[5m", // blink (TB_CAP_BLINK)
1013 "", // sitm (TB_CAP_ITALIC)
1014 "\033[7m", // rev (TB_CAP_REVERSE)
1015 "\033[?1h\033=", // smkx (TB_CAP_ENTER_KEYPAD)
1016 "\033[?1l\033>", // rmkx (TB_CAP_EXIT_KEYPAD)
1017 "\033[2m", // dim (TB_CAP_DIM)
1018 "", // invis (TB_CAP_INVISIBLE)
1019};
1020
1021// rxvt-256color
1022static const char *rxvt_256color_caps[] = {
1023 "\033[11~", // kf1 (TB_CAP_F1)
1024 "\033[12~", // kf2 (TB_CAP_F2)
1025 "\033[13~", // kf3 (TB_CAP_F3)
1026 "\033[14~", // kf4 (TB_CAP_F4)
1027 "\033[15~", // kf5 (TB_CAP_F5)
1028 "\033[17~", // kf6 (TB_CAP_F6)
1029 "\033[18~", // kf7 (TB_CAP_F7)
1030 "\033[19~", // kf8 (TB_CAP_F8)
1031 "\033[20~", // kf9 (TB_CAP_F9)
1032 "\033[21~", // kf10 (TB_CAP_F10)
1033 "\033[23~", // kf11 (TB_CAP_F11)
1034 "\033[24~", // kf12 (TB_CAP_F12)
1035 "\033[2~", // kich1 (TB_CAP_INSERT)
1036 "\033[3~", // kdch1 (TB_CAP_DELETE)
1037 "\033[7~", // khome (TB_CAP_HOME)
1038 "\033[8~", // kend (TB_CAP_END)
1039 "\033[5~", // kpp (TB_CAP_PGUP)
1040 "\033[6~", // knp (TB_CAP_PGDN)
1041 "\033[A", // kcuu1 (TB_CAP_ARROW_UP)
1042 "\033[B", // kcud1 (TB_CAP_ARROW_DOWN)
1043 "\033[D", // kcub1 (TB_CAP_ARROW_LEFT)
1044 "\033[C", // kcuf1 (TB_CAP_ARROW_RIGHT)
1045 "\033[Z", // kcbt (TB_CAP_BACK_TAB)
1046 "\0337\033[?47h", // smcup (TB_CAP_ENTER_CA)
1047 "\033[2J\033[?47l\0338", // rmcup (TB_CAP_EXIT_CA)
1048 "\033[?25h", // cnorm (TB_CAP_SHOW_CURSOR)
1049 "\033[?25l", // civis (TB_CAP_HIDE_CURSOR)
1050 "\033[H\033[2J", // clear (TB_CAP_CLEAR_SCREEN)
1051 "\033[m\017", // sgr0 (TB_CAP_SGR0)
1052 "\033[4m", // smul (TB_CAP_UNDERLINE)
1053 "\033[1m", // bold (TB_CAP_BOLD)
1054 "\033[5m", // blink (TB_CAP_BLINK)
1055 "", // sitm (TB_CAP_ITALIC)
1056 "\033[7m", // rev (TB_CAP_REVERSE)
1057 "\033=", // smkx (TB_CAP_ENTER_KEYPAD)
1058 "\033>", // rmkx (TB_CAP_EXIT_KEYPAD)
1059 "", // dim (TB_CAP_DIM)
1060 "", // invis (TB_CAP_INVISIBLE)
1061};
1062
1063// rxvt-unicode
1064static const char *rxvt_unicode_caps[] = {
1065 "\033[11~", // kf1 (TB_CAP_F1)
1066 "\033[12~", // kf2 (TB_CAP_F2)
1067 "\033[13~", // kf3 (TB_CAP_F3)
1068 "\033[14~", // kf4 (TB_CAP_F4)
1069 "\033[15~", // kf5 (TB_CAP_F5)
1070 "\033[17~", // kf6 (TB_CAP_F6)
1071 "\033[18~", // kf7 (TB_CAP_F7)
1072 "\033[19~", // kf8 (TB_CAP_F8)
1073 "\033[20~", // kf9 (TB_CAP_F9)
1074 "\033[21~", // kf10 (TB_CAP_F10)
1075 "\033[23~", // kf11 (TB_CAP_F11)
1076 "\033[24~", // kf12 (TB_CAP_F12)
1077 "\033[2~", // kich1 (TB_CAP_INSERT)
1078 "\033[3~", // kdch1 (TB_CAP_DELETE)
1079 "\033[7~", // khome (TB_CAP_HOME)
1080 "\033[8~", // kend (TB_CAP_END)
1081 "\033[5~", // kpp (TB_CAP_PGUP)
1082 "\033[6~", // knp (TB_CAP_PGDN)
1083 "\033[A", // kcuu1 (TB_CAP_ARROW_UP)
1084 "\033[B", // kcud1 (TB_CAP_ARROW_DOWN)
1085 "\033[D", // kcub1 (TB_CAP_ARROW_LEFT)
1086 "\033[C", // kcuf1 (TB_CAP_ARROW_RIGHT)
1087 "\033[Z", // kcbt (TB_CAP_BACK_TAB)
1088 "\033[?1049h", // smcup (TB_CAP_ENTER_CA)
1089 "\033[r\033[?1049l", // rmcup (TB_CAP_EXIT_CA)
1090 "\033[?12l\033[?25h", // cnorm (TB_CAP_SHOW_CURSOR)
1091 "\033[?25l", // civis (TB_CAP_HIDE_CURSOR)
1092 "\033[H\033[2J", // clear (TB_CAP_CLEAR_SCREEN)
1093 "\033[m\033(B", // sgr0 (TB_CAP_SGR0)
1094 "\033[4m", // smul (TB_CAP_UNDERLINE)
1095 "\033[1m", // bold (TB_CAP_BOLD)
1096 "\033[5m", // blink (TB_CAP_BLINK)
1097 "\033[3m", // sitm (TB_CAP_ITALIC)
1098 "\033[7m", // rev (TB_CAP_REVERSE)
1099 "\033=", // smkx (TB_CAP_ENTER_KEYPAD)
1100 "\033>", // rmkx (TB_CAP_EXIT_KEYPAD)
1101 "", // dim (TB_CAP_DIM)
1102 "", // invis (TB_CAP_INVISIBLE)
1103};
1104
1105// Eterm
1106static const char *eterm_caps[] = {
1107 "\033[11~", // kf1 (TB_CAP_F1)
1108 "\033[12~", // kf2 (TB_CAP_F2)
1109 "\033[13~", // kf3 (TB_CAP_F3)
1110 "\033[14~", // kf4 (TB_CAP_F4)
1111 "\033[15~", // kf5 (TB_CAP_F5)
1112 "\033[17~", // kf6 (TB_CAP_F6)
1113 "\033[18~", // kf7 (TB_CAP_F7)
1114 "\033[19~", // kf8 (TB_CAP_F8)
1115 "\033[20~", // kf9 (TB_CAP_F9)
1116 "\033[21~", // kf10 (TB_CAP_F10)
1117 "\033[23~", // kf11 (TB_CAP_F11)
1118 "\033[24~", // kf12 (TB_CAP_F12)
1119 "\033[2~", // kich1 (TB_CAP_INSERT)
1120 "\033[3~", // kdch1 (TB_CAP_DELETE)
1121 "\033[7~", // khome (TB_CAP_HOME)
1122 "\033[8~", // kend (TB_CAP_END)
1123 "\033[5~", // kpp (TB_CAP_PGUP)
1124 "\033[6~", // knp (TB_CAP_PGDN)
1125 "\033[A", // kcuu1 (TB_CAP_ARROW_UP)
1126 "\033[B", // kcud1 (TB_CAP_ARROW_DOWN)
1127 "\033[D", // kcub1 (TB_CAP_ARROW_LEFT)
1128 "\033[C", // kcuf1 (TB_CAP_ARROW_RIGHT)
1129 "", // kcbt (TB_CAP_BACK_TAB)
1130 "\0337\033[?47h", // smcup (TB_CAP_ENTER_CA)
1131 "\033[2J\033[?47l\0338", // rmcup (TB_CAP_EXIT_CA)
1132 "\033[?25h", // cnorm (TB_CAP_SHOW_CURSOR)
1133 "\033[?25l", // civis (TB_CAP_HIDE_CURSOR)
1134 "\033[H\033[2J", // clear (TB_CAP_CLEAR_SCREEN)
1135 "\033[m\017", // sgr0 (TB_CAP_SGR0)
1136 "\033[4m", // smul (TB_CAP_UNDERLINE)
1137 "\033[1m", // bold (TB_CAP_BOLD)
1138 "\033[5m", // blink (TB_CAP_BLINK)
1139 "", // sitm (TB_CAP_ITALIC)
1140 "\033[7m", // rev (TB_CAP_REVERSE)
1141 "", // smkx (TB_CAP_ENTER_KEYPAD)
1142 "", // rmkx (TB_CAP_EXIT_KEYPAD)
1143 "", // dim (TB_CAP_DIM)
1144 "", // invis (TB_CAP_INVISIBLE)
1145};
1146
1147static struct {
1148 const char *name;
1149 const char **caps;
1150 const char *alias;
1151} builtin_terms[] = {
1152 {"xterm", xterm_caps, "" },
1153 {"linux", linux_caps, "" },
1154 {"screen", screen_caps, "tmux"},
1155 {"rxvt-256color", rxvt_256color_caps, "" },
1156 {"rxvt-unicode", rxvt_unicode_caps, "rxvt"},
1157 {"Eterm", eterm_caps, "" },
1158 {NULL, NULL, NULL },
1159};
1160
1161/* END codegen c */
1162
1163static struct {
1164 const char *cap;
1165 const uint16_t key;
1166 const uint8_t mod;
1167} builtin_mod_caps[] = {
1168 // xterm arrows
1169 {"\x1b[1;2A", TB_KEY_ARROW_UP, TB_MOD_SHIFT },
1170 {"\x1b[1;3A", TB_KEY_ARROW_UP, TB_MOD_ALT },
1171 {"\x1b[1;4A", TB_KEY_ARROW_UP, TB_MOD_ALT | TB_MOD_SHIFT },
1172 {"\x1b[1;5A", TB_KEY_ARROW_UP, TB_MOD_CTRL },
1173 {"\x1b[1;6A", TB_KEY_ARROW_UP, TB_MOD_CTRL | TB_MOD_SHIFT },
1174 {"\x1b[1;7A", TB_KEY_ARROW_UP, TB_MOD_CTRL | TB_MOD_ALT },
1175 {"\x1b[1;8A", TB_KEY_ARROW_UP, TB_MOD_CTRL | TB_MOD_ALT | TB_MOD_SHIFT},
1176
1177 {"\x1b[1;2B", TB_KEY_ARROW_DOWN, TB_MOD_SHIFT },
1178 {"\x1b[1;3B", TB_KEY_ARROW_DOWN, TB_MOD_ALT },
1179 {"\x1b[1;4B", TB_KEY_ARROW_DOWN, TB_MOD_ALT | TB_MOD_SHIFT },
1180 {"\x1b[1;5B", TB_KEY_ARROW_DOWN, TB_MOD_CTRL },
1181 {"\x1b[1;6B", TB_KEY_ARROW_DOWN, TB_MOD_CTRL | TB_MOD_SHIFT },
1182 {"\x1b[1;7B", TB_KEY_ARROW_DOWN, TB_MOD_CTRL | TB_MOD_ALT },
1183 {"\x1b[1;8B", TB_KEY_ARROW_DOWN, TB_MOD_CTRL | TB_MOD_ALT | TB_MOD_SHIFT},
1184
1185 {"\x1b[1;2C", TB_KEY_ARROW_RIGHT, TB_MOD_SHIFT },
1186 {"\x1b[1;3C", TB_KEY_ARROW_RIGHT, TB_MOD_ALT },
1187 {"\x1b[1;4C", TB_KEY_ARROW_RIGHT, TB_MOD_ALT | TB_MOD_SHIFT },
1188 {"\x1b[1;5C", TB_KEY_ARROW_RIGHT, TB_MOD_CTRL },
1189 {"\x1b[1;6C", TB_KEY_ARROW_RIGHT, TB_MOD_CTRL | TB_MOD_SHIFT },
1190 {"\x1b[1;7C", TB_KEY_ARROW_RIGHT, TB_MOD_CTRL | TB_MOD_ALT },
1191 {"\x1b[1;8C", TB_KEY_ARROW_RIGHT, TB_MOD_CTRL | TB_MOD_ALT | TB_MOD_SHIFT},
1192
1193 {"\x1b[1;2D", TB_KEY_ARROW_LEFT, TB_MOD_SHIFT },
1194 {"\x1b[1;3D", TB_KEY_ARROW_LEFT, TB_MOD_ALT },
1195 {"\x1b[1;4D", TB_KEY_ARROW_LEFT, TB_MOD_ALT | TB_MOD_SHIFT },
1196 {"\x1b[1;5D", TB_KEY_ARROW_LEFT, TB_MOD_CTRL },
1197 {"\x1b[1;6D", TB_KEY_ARROW_LEFT, TB_MOD_CTRL | TB_MOD_SHIFT },
1198 {"\x1b[1;7D", TB_KEY_ARROW_LEFT, TB_MOD_CTRL | TB_MOD_ALT },
1199 {"\x1b[1;8D", TB_KEY_ARROW_LEFT, TB_MOD_CTRL | TB_MOD_ALT | TB_MOD_SHIFT},
1200
1201 // xterm keys
1202 {"\x1b[1;2H", TB_KEY_HOME, TB_MOD_SHIFT },
1203 {"\x1b[1;3H", TB_KEY_HOME, TB_MOD_ALT },
1204 {"\x1b[1;4H", TB_KEY_HOME, TB_MOD_ALT | TB_MOD_SHIFT },
1205 {"\x1b[1;5H", TB_KEY_HOME, TB_MOD_CTRL },
1206 {"\x1b[1;6H", TB_KEY_HOME, TB_MOD_CTRL | TB_MOD_SHIFT },
1207 {"\x1b[1;7H", TB_KEY_HOME, TB_MOD_CTRL | TB_MOD_ALT },
1208 {"\x1b[1;8H", TB_KEY_HOME, TB_MOD_CTRL | TB_MOD_ALT | TB_MOD_SHIFT},
1209
1210 {"\x1b[1;2F", TB_KEY_END, TB_MOD_SHIFT },
1211 {"\x1b[1;3F", TB_KEY_END, TB_MOD_ALT },
1212 {"\x1b[1;4F", TB_KEY_END, TB_MOD_ALT | TB_MOD_SHIFT },
1213 {"\x1b[1;5F", TB_KEY_END, TB_MOD_CTRL },
1214 {"\x1b[1;6F", TB_KEY_END, TB_MOD_CTRL | TB_MOD_SHIFT },
1215 {"\x1b[1;7F", TB_KEY_END, TB_MOD_CTRL | TB_MOD_ALT },
1216 {"\x1b[1;8F", TB_KEY_END, TB_MOD_CTRL | TB_MOD_ALT | TB_MOD_SHIFT},
1217
1218 {"\x1b[2;2~", TB_KEY_INSERT, TB_MOD_SHIFT },
1219 {"\x1b[2;3~", TB_KEY_INSERT, TB_MOD_ALT },
1220 {"\x1b[2;4~", TB_KEY_INSERT, TB_MOD_ALT | TB_MOD_SHIFT },
1221 {"\x1b[2;5~", TB_KEY_INSERT, TB_MOD_CTRL },
1222 {"\x1b[2;6~", TB_KEY_INSERT, TB_MOD_CTRL | TB_MOD_SHIFT },
1223 {"\x1b[2;7~", TB_KEY_INSERT, TB_MOD_CTRL | TB_MOD_ALT },
1224 {"\x1b[2;8~", TB_KEY_INSERT, TB_MOD_CTRL | TB_MOD_ALT | TB_MOD_SHIFT},
1225
1226 {"\x1b[3;2~", TB_KEY_DELETE, TB_MOD_SHIFT },
1227 {"\x1b[3;3~", TB_KEY_DELETE, TB_MOD_ALT },
1228 {"\x1b[3;4~", TB_KEY_DELETE, TB_MOD_ALT | TB_MOD_SHIFT },
1229 {"\x1b[3;5~", TB_KEY_DELETE, TB_MOD_CTRL },
1230 {"\x1b[3;6~", TB_KEY_DELETE, TB_MOD_CTRL | TB_MOD_SHIFT },
1231 {"\x1b[3;7~", TB_KEY_DELETE, TB_MOD_CTRL | TB_MOD_ALT },
1232 {"\x1b[3;8~", TB_KEY_DELETE, TB_MOD_CTRL | TB_MOD_ALT | TB_MOD_SHIFT},
1233
1234 {"\x1b[5;2~", TB_KEY_PGUP, TB_MOD_SHIFT },
1235 {"\x1b[5;3~", TB_KEY_PGUP, TB_MOD_ALT },
1236 {"\x1b[5;4~", TB_KEY_PGUP, TB_MOD_ALT | TB_MOD_SHIFT },
1237 {"\x1b[5;5~", TB_KEY_PGUP, TB_MOD_CTRL },
1238 {"\x1b[5;6~", TB_KEY_PGUP, TB_MOD_CTRL | TB_MOD_SHIFT },
1239 {"\x1b[5;7~", TB_KEY_PGUP, TB_MOD_CTRL | TB_MOD_ALT },
1240 {"\x1b[5;8~", TB_KEY_PGUP, TB_MOD_CTRL | TB_MOD_ALT | TB_MOD_SHIFT},
1241
1242 {"\x1b[6;2~", TB_KEY_PGDN, TB_MOD_SHIFT },
1243 {"\x1b[6;3~", TB_KEY_PGDN, TB_MOD_ALT },
1244 {"\x1b[6;4~", TB_KEY_PGDN, TB_MOD_ALT | TB_MOD_SHIFT },
1245 {"\x1b[6;5~", TB_KEY_PGDN, TB_MOD_CTRL },
1246 {"\x1b[6;6~", TB_KEY_PGDN, TB_MOD_CTRL | TB_MOD_SHIFT },
1247 {"\x1b[6;7~", TB_KEY_PGDN, TB_MOD_CTRL | TB_MOD_ALT },
1248 {"\x1b[6;8~", TB_KEY_PGDN, TB_MOD_CTRL | TB_MOD_ALT | TB_MOD_SHIFT},
1249
1250 {"\x1b[1;2P", TB_KEY_F1, TB_MOD_SHIFT },
1251 {"\x1b[1;3P", TB_KEY_F1, TB_MOD_ALT },
1252 {"\x1b[1;4P", TB_KEY_F1, TB_MOD_ALT | TB_MOD_SHIFT },
1253 {"\x1b[1;5P", TB_KEY_F1, TB_MOD_CTRL },
1254 {"\x1b[1;6P", TB_KEY_F1, TB_MOD_CTRL | TB_MOD_SHIFT },
1255 {"\x1b[1;7P", TB_KEY_F1, TB_MOD_CTRL | TB_MOD_ALT },
1256 {"\x1b[1;8P", TB_KEY_F1, TB_MOD_CTRL | TB_MOD_ALT | TB_MOD_SHIFT},
1257
1258 {"\x1b[1;2Q", TB_KEY_F2, TB_MOD_SHIFT },
1259 {"\x1b[1;3Q", TB_KEY_F2, TB_MOD_ALT },
1260 {"\x1b[1;4Q", TB_KEY_F2, TB_MOD_ALT | TB_MOD_SHIFT },
1261 {"\x1b[1;5Q", TB_KEY_F2, TB_MOD_CTRL },
1262 {"\x1b[1;6Q", TB_KEY_F2, TB_MOD_CTRL | TB_MOD_SHIFT },
1263 {"\x1b[1;7Q", TB_KEY_F2, TB_MOD_CTRL | TB_MOD_ALT },
1264 {"\x1b[1;8Q", TB_KEY_F2, TB_MOD_CTRL | TB_MOD_ALT | TB_MOD_SHIFT},
1265
1266 {"\x1b[1;2R", TB_KEY_F3, TB_MOD_SHIFT },
1267 {"\x1b[1;3R", TB_KEY_F3, TB_MOD_ALT },
1268 {"\x1b[1;4R", TB_KEY_F3, TB_MOD_ALT | TB_MOD_SHIFT },
1269 {"\x1b[1;5R", TB_KEY_F3, TB_MOD_CTRL },
1270 {"\x1b[1;6R", TB_KEY_F3, TB_MOD_CTRL | TB_MOD_SHIFT },
1271 {"\x1b[1;7R", TB_KEY_F3, TB_MOD_CTRL | TB_MOD_ALT },
1272 {"\x1b[1;8R", TB_KEY_F3, TB_MOD_CTRL | TB_MOD_ALT | TB_MOD_SHIFT},
1273
1274 {"\x1b[1;2S", TB_KEY_F4, TB_MOD_SHIFT },
1275 {"\x1b[1;3S", TB_KEY_F4, TB_MOD_ALT },
1276 {"\x1b[1;4S", TB_KEY_F4, TB_MOD_ALT | TB_MOD_SHIFT },
1277 {"\x1b[1;5S", TB_KEY_F4, TB_MOD_CTRL },
1278 {"\x1b[1;6S", TB_KEY_F4, TB_MOD_CTRL | TB_MOD_SHIFT },
1279 {"\x1b[1;7S", TB_KEY_F4, TB_MOD_CTRL | TB_MOD_ALT },
1280 {"\x1b[1;8S", TB_KEY_F4, TB_MOD_CTRL | TB_MOD_ALT | TB_MOD_SHIFT},
1281
1282 {"\x1b[15;2~", TB_KEY_F5, TB_MOD_SHIFT },
1283 {"\x1b[15;3~", TB_KEY_F5, TB_MOD_ALT },
1284 {"\x1b[15;4~", TB_KEY_F5, TB_MOD_ALT | TB_MOD_SHIFT },
1285 {"\x1b[15;5~", TB_KEY_F5, TB_MOD_CTRL },
1286 {"\x1b[15;6~", TB_KEY_F5, TB_MOD_CTRL | TB_MOD_SHIFT },
1287 {"\x1b[15;7~", TB_KEY_F5, TB_MOD_CTRL | TB_MOD_ALT },
1288 {"\x1b[15;8~", TB_KEY_F5, TB_MOD_CTRL | TB_MOD_ALT | TB_MOD_SHIFT},
1289
1290 {"\x1b[17;2~", TB_KEY_F6, TB_MOD_SHIFT },
1291 {"\x1b[17;3~", TB_KEY_F6, TB_MOD_ALT },
1292 {"\x1b[17;4~", TB_KEY_F6, TB_MOD_ALT | TB_MOD_SHIFT },
1293 {"\x1b[17;5~", TB_KEY_F6, TB_MOD_CTRL },
1294 {"\x1b[17;6~", TB_KEY_F6, TB_MOD_CTRL | TB_MOD_SHIFT },
1295 {"\x1b[17;7~", TB_KEY_F6, TB_MOD_CTRL | TB_MOD_ALT },
1296 {"\x1b[17;8~", TB_KEY_F6, TB_MOD_CTRL | TB_MOD_ALT | TB_MOD_SHIFT},
1297
1298 {"\x1b[18;2~", TB_KEY_F7, TB_MOD_SHIFT },
1299 {"\x1b[18;3~", TB_KEY_F7, TB_MOD_ALT },
1300 {"\x1b[18;4~", TB_KEY_F7, TB_MOD_ALT | TB_MOD_SHIFT },
1301 {"\x1b[18;5~", TB_KEY_F7, TB_MOD_CTRL },
1302 {"\x1b[18;6~", TB_KEY_F7, TB_MOD_CTRL | TB_MOD_SHIFT },
1303 {"\x1b[18;7~", TB_KEY_F7, TB_MOD_CTRL | TB_MOD_ALT },
1304 {"\x1b[18;8~", TB_KEY_F7, TB_MOD_CTRL | TB_MOD_ALT | TB_MOD_SHIFT},
1305
1306 {"\x1b[19;2~", TB_KEY_F8, TB_MOD_SHIFT },
1307 {"\x1b[19;3~", TB_KEY_F8, TB_MOD_ALT },
1308 {"\x1b[19;4~", TB_KEY_F8, TB_MOD_ALT | TB_MOD_SHIFT },
1309 {"\x1b[19;5~", TB_KEY_F8, TB_MOD_CTRL },
1310 {"\x1b[19;6~", TB_KEY_F8, TB_MOD_CTRL | TB_MOD_SHIFT },
1311 {"\x1b[19;7~", TB_KEY_F8, TB_MOD_CTRL | TB_MOD_ALT },
1312 {"\x1b[19;8~", TB_KEY_F8, TB_MOD_CTRL | TB_MOD_ALT | TB_MOD_SHIFT},
1313
1314 {"\x1b[20;2~", TB_KEY_F9, TB_MOD_SHIFT },
1315 {"\x1b[20;3~", TB_KEY_F9, TB_MOD_ALT },
1316 {"\x1b[20;4~", TB_KEY_F9, TB_MOD_ALT | TB_MOD_SHIFT },
1317 {"\x1b[20;5~", TB_KEY_F9, TB_MOD_CTRL },
1318 {"\x1b[20;6~", TB_KEY_F9, TB_MOD_CTRL | TB_MOD_SHIFT },
1319 {"\x1b[20;7~", TB_KEY_F9, TB_MOD_CTRL | TB_MOD_ALT },
1320 {"\x1b[20;8~", TB_KEY_F9, TB_MOD_CTRL | TB_MOD_ALT | TB_MOD_SHIFT},
1321
1322 {"\x1b[21;2~", TB_KEY_F10, TB_MOD_SHIFT },
1323 {"\x1b[21;3~", TB_KEY_F10, TB_MOD_ALT },
1324 {"\x1b[21;4~", TB_KEY_F10, TB_MOD_ALT | TB_MOD_SHIFT },
1325 {"\x1b[21;5~", TB_KEY_F10, TB_MOD_CTRL },
1326 {"\x1b[21;6~", TB_KEY_F10, TB_MOD_CTRL | TB_MOD_SHIFT },
1327 {"\x1b[21;7~", TB_KEY_F10, TB_MOD_CTRL | TB_MOD_ALT },
1328 {"\x1b[21;8~", TB_KEY_F10, TB_MOD_CTRL | TB_MOD_ALT | TB_MOD_SHIFT},
1329
1330 {"\x1b[23;2~", TB_KEY_F11, TB_MOD_SHIFT },
1331 {"\x1b[23;3~", TB_KEY_F11, TB_MOD_ALT },
1332 {"\x1b[23;4~", TB_KEY_F11, TB_MOD_ALT | TB_MOD_SHIFT },
1333 {"\x1b[23;5~", TB_KEY_F11, TB_MOD_CTRL },
1334 {"\x1b[23;6~", TB_KEY_F11, TB_MOD_CTRL | TB_MOD_SHIFT },
1335 {"\x1b[23;7~", TB_KEY_F11, TB_MOD_CTRL | TB_MOD_ALT },
1336 {"\x1b[23;8~", TB_KEY_F11, TB_MOD_CTRL | TB_MOD_ALT | TB_MOD_SHIFT},
1337
1338 {"\x1b[24;2~", TB_KEY_F12, TB_MOD_SHIFT },
1339 {"\x1b[24;3~", TB_KEY_F12, TB_MOD_ALT },
1340 {"\x1b[24;4~", TB_KEY_F12, TB_MOD_ALT | TB_MOD_SHIFT },
1341 {"\x1b[24;5~", TB_KEY_F12, TB_MOD_CTRL },
1342 {"\x1b[24;6~", TB_KEY_F12, TB_MOD_CTRL | TB_MOD_SHIFT },
1343 {"\x1b[24;7~", TB_KEY_F12, TB_MOD_CTRL | TB_MOD_ALT },
1344 {"\x1b[24;8~", TB_KEY_F12, TB_MOD_CTRL | TB_MOD_ALT | TB_MOD_SHIFT},
1345
1346 // rxvt arrows
1347 {"\x1b[a", TB_KEY_ARROW_UP, TB_MOD_SHIFT },
1348 {"\x1b\x1b[A", TB_KEY_ARROW_UP, TB_MOD_ALT },
1349 {"\x1b\x1b[a", TB_KEY_ARROW_UP, TB_MOD_ALT | TB_MOD_SHIFT },
1350 {"\x1bOa", TB_KEY_ARROW_UP, TB_MOD_CTRL },
1351 {"\x1b\x1bOa", TB_KEY_ARROW_UP, TB_MOD_CTRL | TB_MOD_ALT },
1352
1353 {"\x1b[b", TB_KEY_ARROW_DOWN, TB_MOD_SHIFT },
1354 {"\x1b\x1b[B", TB_KEY_ARROW_DOWN, TB_MOD_ALT },
1355 {"\x1b\x1b[b", TB_KEY_ARROW_DOWN, TB_MOD_ALT | TB_MOD_SHIFT },
1356 {"\x1bOb", TB_KEY_ARROW_DOWN, TB_MOD_CTRL },
1357 {"\x1b\x1bOb", TB_KEY_ARROW_DOWN, TB_MOD_CTRL | TB_MOD_ALT },
1358
1359 {"\x1b[c", TB_KEY_ARROW_RIGHT, TB_MOD_SHIFT },
1360 {"\x1b\x1b[C", TB_KEY_ARROW_RIGHT, TB_MOD_ALT },
1361 {"\x1b\x1b[c", TB_KEY_ARROW_RIGHT, TB_MOD_ALT | TB_MOD_SHIFT },
1362 {"\x1bOc", TB_KEY_ARROW_RIGHT, TB_MOD_CTRL },
1363 {"\x1b\x1bOc", TB_KEY_ARROW_RIGHT, TB_MOD_CTRL | TB_MOD_ALT },
1364
1365 {"\x1b[d", TB_KEY_ARROW_LEFT, TB_MOD_SHIFT },
1366 {"\x1b\x1b[D", TB_KEY_ARROW_LEFT, TB_MOD_ALT },
1367 {"\x1b\x1b[d", TB_KEY_ARROW_LEFT, TB_MOD_ALT | TB_MOD_SHIFT },
1368 {"\x1bOd", TB_KEY_ARROW_LEFT, TB_MOD_CTRL },
1369 {"\x1b\x1bOd", TB_KEY_ARROW_LEFT, TB_MOD_CTRL | TB_MOD_ALT },
1370
1371 // rxvt keys
1372 {"\x1b[7$", TB_KEY_HOME, TB_MOD_SHIFT },
1373 {"\x1b\x1b[7~", TB_KEY_HOME, TB_MOD_ALT },
1374 {"\x1b\x1b[7$", TB_KEY_HOME, TB_MOD_ALT | TB_MOD_SHIFT },
1375 {"\x1b[7^", TB_KEY_HOME, TB_MOD_CTRL },
1376 {"\x1b[7@", TB_KEY_HOME, TB_MOD_CTRL | TB_MOD_SHIFT },
1377 {"\x1b\x1b[7^", TB_KEY_HOME, TB_MOD_CTRL | TB_MOD_ALT },
1378 {"\x1b\x1b[7@", TB_KEY_HOME, TB_MOD_CTRL | TB_MOD_ALT | TB_MOD_SHIFT},
1379
1380 {"\x1b\x1b[8~", TB_KEY_END, TB_MOD_ALT },
1381 {"\x1b\x1b[8$", TB_KEY_END, TB_MOD_ALT | TB_MOD_SHIFT },
1382 {"\x1b[8^", TB_KEY_END, TB_MOD_CTRL },
1383 {"\x1b\x1b[8^", TB_KEY_END, TB_MOD_CTRL | TB_MOD_ALT },
1384 {"\x1b\x1b[8@", TB_KEY_END, TB_MOD_CTRL | TB_MOD_ALT | TB_MOD_SHIFT},
1385 {"\x1b[8@", TB_KEY_END, TB_MOD_CTRL | TB_MOD_SHIFT },
1386 {"\x1b[8$", TB_KEY_END, TB_MOD_SHIFT },
1387
1388 {"\x1b\x1b[2~", TB_KEY_INSERT, TB_MOD_ALT },
1389 {"\x1b\x1b[2$", TB_KEY_INSERT, TB_MOD_ALT | TB_MOD_SHIFT },
1390 {"\x1b[2^", TB_KEY_INSERT, TB_MOD_CTRL },
1391 {"\x1b\x1b[2^", TB_KEY_INSERT, TB_MOD_CTRL | TB_MOD_ALT },
1392 {"\x1b\x1b[2@", TB_KEY_INSERT, TB_MOD_CTRL | TB_MOD_ALT | TB_MOD_SHIFT},
1393 {"\x1b[2@", TB_KEY_INSERT, TB_MOD_CTRL | TB_MOD_SHIFT },
1394 {"\x1b[2$", TB_KEY_INSERT, TB_MOD_SHIFT },
1395
1396 {"\x1b\x1b[3~", TB_KEY_DELETE, TB_MOD_ALT },
1397 {"\x1b\x1b[3$", TB_KEY_DELETE, TB_MOD_ALT | TB_MOD_SHIFT },
1398 {"\x1b[3^", TB_KEY_DELETE, TB_MOD_CTRL },
1399 {"\x1b\x1b[3^", TB_KEY_DELETE, TB_MOD_CTRL | TB_MOD_ALT },
1400 {"\x1b\x1b[3@", TB_KEY_DELETE, TB_MOD_CTRL | TB_MOD_ALT | TB_MOD_SHIFT},
1401 {"\x1b[3@", TB_KEY_DELETE, TB_MOD_CTRL | TB_MOD_SHIFT },
1402 {"\x1b[3$", TB_KEY_DELETE, TB_MOD_SHIFT },
1403
1404 {"\x1b\x1b[5~", TB_KEY_PGUP, TB_MOD_ALT },
1405 {"\x1b\x1b[5$", TB_KEY_PGUP, TB_MOD_ALT | TB_MOD_SHIFT },
1406 {"\x1b[5^", TB_KEY_PGUP, TB_MOD_CTRL },
1407 {"\x1b\x1b[5^", TB_KEY_PGUP, TB_MOD_CTRL | TB_MOD_ALT },
1408 {"\x1b\x1b[5@", TB_KEY_PGUP, TB_MOD_CTRL | TB_MOD_ALT | TB_MOD_SHIFT},
1409 {"\x1b[5@", TB_KEY_PGUP, TB_MOD_CTRL | TB_MOD_SHIFT },
1410 {"\x1b[5$", TB_KEY_PGUP, TB_MOD_SHIFT },
1411
1412 {"\x1b\x1b[6~", TB_KEY_PGDN, TB_MOD_ALT },
1413 {"\x1b\x1b[6$", TB_KEY_PGDN, TB_MOD_ALT | TB_MOD_SHIFT },
1414 {"\x1b[6^", TB_KEY_PGDN, TB_MOD_CTRL },
1415 {"\x1b\x1b[6^", TB_KEY_PGDN, TB_MOD_CTRL | TB_MOD_ALT },
1416 {"\x1b\x1b[6@", TB_KEY_PGDN, TB_MOD_CTRL | TB_MOD_ALT | TB_MOD_SHIFT},
1417 {"\x1b[6@", TB_KEY_PGDN, TB_MOD_CTRL | TB_MOD_SHIFT },
1418 {"\x1b[6$", TB_KEY_PGDN, TB_MOD_SHIFT },
1419
1420 {"\x1b\x1b[11~", TB_KEY_F1, TB_MOD_ALT },
1421 {"\x1b\x1b[23~", TB_KEY_F1, TB_MOD_ALT | TB_MOD_SHIFT },
1422 {"\x1b[11^", TB_KEY_F1, TB_MOD_CTRL },
1423 {"\x1b\x1b[11^", TB_KEY_F1, TB_MOD_CTRL | TB_MOD_ALT },
1424 {"\x1b\x1b[23^", TB_KEY_F1, TB_MOD_CTRL | TB_MOD_ALT | TB_MOD_SHIFT},
1425 {"\x1b[23^", TB_KEY_F1, TB_MOD_CTRL | TB_MOD_SHIFT },
1426 {"\x1b[23~", TB_KEY_F1, TB_MOD_SHIFT },
1427
1428 {"\x1b\x1b[12~", TB_KEY_F2, TB_MOD_ALT },
1429 {"\x1b\x1b[24~", TB_KEY_F2, TB_MOD_ALT | TB_MOD_SHIFT },
1430 {"\x1b[12^", TB_KEY_F2, TB_MOD_CTRL },
1431 {"\x1b\x1b[12^", TB_KEY_F2, TB_MOD_CTRL | TB_MOD_ALT },
1432 {"\x1b\x1b[24^", TB_KEY_F2, TB_MOD_CTRL | TB_MOD_ALT | TB_MOD_SHIFT},
1433 {"\x1b[24^", TB_KEY_F2, TB_MOD_CTRL | TB_MOD_SHIFT },
1434 {"\x1b[24~", TB_KEY_F2, TB_MOD_SHIFT },
1435
1436 {"\x1b\x1b[13~", TB_KEY_F3, TB_MOD_ALT },
1437 {"\x1b\x1b[25~", TB_KEY_F3, TB_MOD_ALT | TB_MOD_SHIFT },
1438 {"\x1b[13^", TB_KEY_F3, TB_MOD_CTRL },
1439 {"\x1b\x1b[13^", TB_KEY_F3, TB_MOD_CTRL | TB_MOD_ALT },
1440 {"\x1b\x1b[25^", TB_KEY_F3, TB_MOD_CTRL | TB_MOD_ALT | TB_MOD_SHIFT},
1441 {"\x1b[25^", TB_KEY_F3, TB_MOD_CTRL | TB_MOD_SHIFT },
1442 {"\x1b[25~", TB_KEY_F3, TB_MOD_SHIFT },
1443
1444 {"\x1b\x1b[14~", TB_KEY_F4, TB_MOD_ALT },
1445 {"\x1b\x1b[26~", TB_KEY_F4, TB_MOD_ALT | TB_MOD_SHIFT },
1446 {"\x1b[14^", TB_KEY_F4, TB_MOD_CTRL },
1447 {"\x1b\x1b[14^", TB_KEY_F4, TB_MOD_CTRL | TB_MOD_ALT },
1448 {"\x1b\x1b[26^", TB_KEY_F4, TB_MOD_CTRL | TB_MOD_ALT | TB_MOD_SHIFT},
1449 {"\x1b[26^", TB_KEY_F4, TB_MOD_CTRL | TB_MOD_SHIFT },
1450 {"\x1b[26~", TB_KEY_F4, TB_MOD_SHIFT },
1451
1452 {"\x1b\x1b[15~", TB_KEY_F5, TB_MOD_ALT },
1453 {"\x1b\x1b[28~", TB_KEY_F5, TB_MOD_ALT | TB_MOD_SHIFT },
1454 {"\x1b[15^", TB_KEY_F5, TB_MOD_CTRL },
1455 {"\x1b\x1b[15^", TB_KEY_F5, TB_MOD_CTRL | TB_MOD_ALT },
1456 {"\x1b\x1b[28^", TB_KEY_F5, TB_MOD_CTRL | TB_MOD_ALT | TB_MOD_SHIFT},
1457 {"\x1b[28^", TB_KEY_F5, TB_MOD_CTRL | TB_MOD_SHIFT },
1458 {"\x1b[28~", TB_KEY_F5, TB_MOD_SHIFT },
1459
1460 {"\x1b\x1b[17~", TB_KEY_F6, TB_MOD_ALT },
1461 {"\x1b\x1b[29~", TB_KEY_F6, TB_MOD_ALT | TB_MOD_SHIFT },
1462 {"\x1b[17^", TB_KEY_F6, TB_MOD_CTRL },
1463 {"\x1b\x1b[17^", TB_KEY_F6, TB_MOD_CTRL | TB_MOD_ALT },
1464 {"\x1b\x1b[29^", TB_KEY_F6, TB_MOD_CTRL | TB_MOD_ALT | TB_MOD_SHIFT},
1465 {"\x1b[29^", TB_KEY_F6, TB_MOD_CTRL | TB_MOD_SHIFT },
1466 {"\x1b[29~", TB_KEY_F6, TB_MOD_SHIFT },
1467
1468 {"\x1b\x1b[18~", TB_KEY_F7, TB_MOD_ALT },
1469 {"\x1b\x1b[31~", TB_KEY_F7, TB_MOD_ALT | TB_MOD_SHIFT },
1470 {"\x1b[18^", TB_KEY_F7, TB_MOD_CTRL },
1471 {"\x1b\x1b[18^", TB_KEY_F7, TB_MOD_CTRL | TB_MOD_ALT },
1472 {"\x1b\x1b[31^", TB_KEY_F7, TB_MOD_CTRL | TB_MOD_ALT | TB_MOD_SHIFT},
1473 {"\x1b[31^", TB_KEY_F7, TB_MOD_CTRL | TB_MOD_SHIFT },
1474 {"\x1b[31~", TB_KEY_F7, TB_MOD_SHIFT },
1475
1476 {"\x1b\x1b[19~", TB_KEY_F8, TB_MOD_ALT },
1477 {"\x1b\x1b[32~", TB_KEY_F8, TB_MOD_ALT | TB_MOD_SHIFT },
1478 {"\x1b[19^", TB_KEY_F8, TB_MOD_CTRL },
1479 {"\x1b\x1b[19^", TB_KEY_F8, TB_MOD_CTRL | TB_MOD_ALT },
1480 {"\x1b\x1b[32^", TB_KEY_F8, TB_MOD_CTRL | TB_MOD_ALT | TB_MOD_SHIFT},
1481 {"\x1b[32^", TB_KEY_F8, TB_MOD_CTRL | TB_MOD_SHIFT },
1482 {"\x1b[32~", TB_KEY_F8, TB_MOD_SHIFT },
1483
1484 {"\x1b\x1b[20~", TB_KEY_F9, TB_MOD_ALT },
1485 {"\x1b\x1b[33~", TB_KEY_F9, TB_MOD_ALT | TB_MOD_SHIFT },
1486 {"\x1b[20^", TB_KEY_F9, TB_MOD_CTRL },
1487 {"\x1b\x1b[20^", TB_KEY_F9, TB_MOD_CTRL | TB_MOD_ALT },
1488 {"\x1b\x1b[33^", TB_KEY_F9, TB_MOD_CTRL | TB_MOD_ALT | TB_MOD_SHIFT},
1489 {"\x1b[33^", TB_KEY_F9, TB_MOD_CTRL | TB_MOD_SHIFT },
1490 {"\x1b[33~", TB_KEY_F9, TB_MOD_SHIFT },
1491
1492 {"\x1b\x1b[21~", TB_KEY_F10, TB_MOD_ALT },
1493 {"\x1b\x1b[34~", TB_KEY_F10, TB_MOD_ALT | TB_MOD_SHIFT },
1494 {"\x1b[21^", TB_KEY_F10, TB_MOD_CTRL },
1495 {"\x1b\x1b[21^", TB_KEY_F10, TB_MOD_CTRL | TB_MOD_ALT },
1496 {"\x1b\x1b[34^", TB_KEY_F10, TB_MOD_CTRL | TB_MOD_ALT | TB_MOD_SHIFT},
1497 {"\x1b[34^", TB_KEY_F10, TB_MOD_CTRL | TB_MOD_SHIFT },
1498 {"\x1b[34~", TB_KEY_F10, TB_MOD_SHIFT },
1499
1500 {"\x1b\x1b[23~", TB_KEY_F11, TB_MOD_ALT },
1501 {"\x1b\x1b[23$", TB_KEY_F11, TB_MOD_ALT | TB_MOD_SHIFT },
1502 {"\x1b[23^", TB_KEY_F11, TB_MOD_CTRL },
1503 {"\x1b\x1b[23^", TB_KEY_F11, TB_MOD_CTRL | TB_MOD_ALT },
1504 {"\x1b\x1b[23@", TB_KEY_F11, TB_MOD_CTRL | TB_MOD_ALT | TB_MOD_SHIFT},
1505 {"\x1b[23@", TB_KEY_F11, TB_MOD_CTRL | TB_MOD_SHIFT },
1506 {"\x1b[23$", TB_KEY_F11, TB_MOD_SHIFT },
1507
1508 {"\x1b\x1b[24~", TB_KEY_F12, TB_MOD_ALT },
1509 {"\x1b\x1b[24$", TB_KEY_F12, TB_MOD_ALT | TB_MOD_SHIFT },
1510 {"\x1b[24^", TB_KEY_F12, TB_MOD_CTRL },
1511 {"\x1b\x1b[24^", TB_KEY_F12, TB_MOD_CTRL | TB_MOD_ALT },
1512 {"\x1b\x1b[24@", TB_KEY_F12, TB_MOD_CTRL | TB_MOD_ALT | TB_MOD_SHIFT},
1513 {"\x1b[24@", TB_KEY_F12, TB_MOD_CTRL | TB_MOD_SHIFT },
1514 {"\x1b[24$", TB_KEY_F12, TB_MOD_SHIFT },
1515
1516 // linux console/putty arrows
1517 {"\x1b[A", TB_KEY_ARROW_UP, TB_MOD_SHIFT },
1518 {"\x1b[B", TB_KEY_ARROW_DOWN, TB_MOD_SHIFT },
1519 {"\x1b[C", TB_KEY_ARROW_RIGHT, TB_MOD_SHIFT },
1520 {"\x1b[D", TB_KEY_ARROW_LEFT, TB_MOD_SHIFT },
1521
1522 // more putty arrows
1523 {"\x1bOA", TB_KEY_ARROW_UP, TB_MOD_CTRL },
1524 {"\x1b\x1bOA", TB_KEY_ARROW_UP, TB_MOD_CTRL | TB_MOD_ALT },
1525 {"\x1bOB", TB_KEY_ARROW_DOWN, TB_MOD_CTRL },
1526 {"\x1b\x1bOB", TB_KEY_ARROW_DOWN, TB_MOD_CTRL | TB_MOD_ALT },
1527 {"\x1bOC", TB_KEY_ARROW_RIGHT, TB_MOD_CTRL },
1528 {"\x1b\x1bOC", TB_KEY_ARROW_RIGHT, TB_MOD_CTRL | TB_MOD_ALT },
1529 {"\x1bOD", TB_KEY_ARROW_LEFT, TB_MOD_CTRL },
1530 {"\x1b\x1bOD", TB_KEY_ARROW_LEFT, TB_MOD_CTRL | TB_MOD_ALT },
1531
1532 {NULL, 0, 0 },
1533};
1534
1535static const unsigned char utf8_length[256] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1536 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1537 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1538 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1539 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1540 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1541 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1542 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1543 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
1544 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
1545 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 1, 1};
1546
1547static const unsigned char utf8_mask[6] = {0x7f, 0x1f, 0x0f, 0x07, 0x03, 0x01};
1548
1549#ifndef TB_OPT_LIBC_WCHAR
1550static struct {
1551 uint32_t range_start;
1552 uint32_t range_end;
1553 int width; // -1 means iswprint==0, otherwise wcwidth value (0, 1, or 2)
1554} wcwidth_table[] = {
1555 // clang-format off
1556 {0x000001, 0x00001f, -1}, {0x000020, 0x00007e, 1}, {0x00007f, 0x00009f, -1},
1557 {0x0000a0, 0x0002ff, 1}, {0x000300, 0x00036f, 0}, {0x000370, 0x000377, 1},
1558 {0x000378, 0x000379, -1}, {0x00037a, 0x00037f, 1}, {0x000380, 0x000383, -1},
1559 {0x000384, 0x00038a, 1}, {0x00038b, 0x00038b, -1}, {0x00038c, 0x00038c, 1},
1560 {0x00038d, 0x00038d, -1}, {0x00038e, 0x0003a1, 1}, {0x0003a2, 0x0003a2, -1},
1561 {0x0003a3, 0x000482, 1}, {0x000483, 0x000489, 0}, {0x00048a, 0x00052f, 1},
1562 {0x000530, 0x000530, -1}, {0x000531, 0x000556, 1}, {0x000557, 0x000558, -1},
1563 {0x000559, 0x00058a, 1}, {0x00058b, 0x00058c, -1}, {0x00058d, 0x00058f, 1},
1564 {0x000590, 0x000590, -1}, {0x000591, 0x0005bd, 0}, {0x0005be, 0x0005be, 1},
1565 {0x0005bf, 0x0005bf, 0}, {0x0005c0, 0x0005c0, 1}, {0x0005c1, 0x0005c2, 0},
1566 {0x0005c3, 0x0005c3, 1}, {0x0005c4, 0x0005c5, 0}, {0x0005c6, 0x0005c6, 1},
1567 {0x0005c7, 0x0005c7, 0}, {0x0005c8, 0x0005cf, -1}, {0x0005d0, 0x0005ea, 1},
1568 {0x0005eb, 0x0005ee, -1}, {0x0005ef, 0x0005f4, 1}, {0x0005f5, 0x0005ff, -1},
1569 {0x000600, 0x00060f, 1}, {0x000610, 0x00061a, 0}, {0x00061b, 0x00061b, 1},
1570 {0x00061c, 0x00061c, 0}, {0x00061d, 0x00064a, 1}, {0x00064b, 0x00065f, 0},
1571 {0x000660, 0x00066f, 1}, {0x000670, 0x000670, 0}, {0x000671, 0x0006d5, 1},
1572 {0x0006d6, 0x0006dc, 0}, {0x0006dd, 0x0006de, 1}, {0x0006df, 0x0006e4, 0},
1573 {0x0006e5, 0x0006e6, 1}, {0x0006e7, 0x0006e8, 0}, {0x0006e9, 0x0006e9, 1},
1574 {0x0006ea, 0x0006ed, 0}, {0x0006ee, 0x00070d, 1}, {0x00070e, 0x00070e, -1},
1575 {0x00070f, 0x000710, 1}, {0x000711, 0x000711, 0}, {0x000712, 0x00072f, 1},
1576 {0x000730, 0x00074a, 0}, {0x00074b, 0x00074c, -1}, {0x00074d, 0x0007a5, 1},
1577 {0x0007a6, 0x0007b0, 0}, {0x0007b1, 0x0007b1, 1}, {0x0007b2, 0x0007bf, -1},
1578 {0x0007c0, 0x0007ea, 1}, {0x0007eb, 0x0007f3, 0}, {0x0007f4, 0x0007fa, 1},
1579 {0x0007fb, 0x0007fc, -1}, {0x0007fd, 0x0007fd, 0}, {0x0007fe, 0x000815, 1},
1580 {0x000816, 0x000819, 0}, {0x00081a, 0x00081a, 1}, {0x00081b, 0x000823, 0},
1581 {0x000824, 0x000824, 1}, {0x000825, 0x000827, 0}, {0x000828, 0x000828, 1},
1582 {0x000829, 0x00082d, 0}, {0x00082e, 0x00082f, -1}, {0x000830, 0x00083e, 1},
1583 {0x00083f, 0x00083f, -1}, {0x000840, 0x000858, 1}, {0x000859, 0x00085b, 0},
1584 {0x00085c, 0x00085d, -1}, {0x00085e, 0x00085e, 1}, {0x00085f, 0x00085f, -1},
1585 {0x000860, 0x00086a, 1}, {0x00086b, 0x00086f, -1}, {0x000870, 0x00088e, 1},
1586 {0x00088f, 0x00088f, -1}, {0x000890, 0x000891, 1}, {0x000892, 0x000896, -1},
1587 {0x000897, 0x00089f, 0}, {0x0008a0, 0x0008c9, 1}, {0x0008ca, 0x0008e1, 0},
1588 {0x0008e2, 0x0008e2, 1}, {0x0008e3, 0x000902, 0}, {0x000903, 0x000939, 1},
1589 {0x00093a, 0x00093a, 0}, {0x00093b, 0x00093b, 1}, {0x00093c, 0x00093c, 0},
1590 {0x00093d, 0x000940, 1}, {0x000941, 0x000948, 0}, {0x000949, 0x00094c, 1},
1591 {0x00094d, 0x00094d, 0}, {0x00094e, 0x000950, 1}, {0x000951, 0x000957, 0},
1592 {0x000958, 0x000961, 1}, {0x000962, 0x000963, 0}, {0x000964, 0x000980, 1},
1593 {0x000981, 0x000981, 0}, {0x000982, 0x000983, 1}, {0x000984, 0x000984, -1},
1594 {0x000985, 0x00098c, 1}, {0x00098d, 0x00098e, -1}, {0x00098f, 0x000990, 1},
1595 {0x000991, 0x000992, -1}, {0x000993, 0x0009a8, 1}, {0x0009a9, 0x0009a9, -1},
1596 {0x0009aa, 0x0009b0, 1}, {0x0009b1, 0x0009b1, -1}, {0x0009b2, 0x0009b2, 1},
1597 {0x0009b3, 0x0009b5, -1}, {0x0009b6, 0x0009b9, 1}, {0x0009ba, 0x0009bb, -1},
1598 {0x0009bc, 0x0009bc, 0}, {0x0009bd, 0x0009c0, 1}, {0x0009c1, 0x0009c4, 0},
1599 {0x0009c5, 0x0009c6, -1}, {0x0009c7, 0x0009c8, 1}, {0x0009c9, 0x0009ca, -1},
1600 {0x0009cb, 0x0009cc, 1}, {0x0009cd, 0x0009cd, 0}, {0x0009ce, 0x0009ce, 1},
1601 {0x0009cf, 0x0009d6, -1}, {0x0009d7, 0x0009d7, 1}, {0x0009d8, 0x0009db, -1},
1602 {0x0009dc, 0x0009dd, 1}, {0x0009de, 0x0009de, -1}, {0x0009df, 0x0009e1, 1},
1603 {0x0009e2, 0x0009e3, 0}, {0x0009e4, 0x0009e5, -1}, {0x0009e6, 0x0009fd, 1},
1604 {0x0009fe, 0x0009fe, 0}, {0x0009ff, 0x000a00, -1}, {0x000a01, 0x000a02, 0},
1605 {0x000a03, 0x000a03, 1}, {0x000a04, 0x000a04, -1}, {0x000a05, 0x000a0a, 1},
1606 {0x000a0b, 0x000a0e, -1}, {0x000a0f, 0x000a10, 1}, {0x000a11, 0x000a12, -1},
1607 {0x000a13, 0x000a28, 1}, {0x000a29, 0x000a29, -1}, {0x000a2a, 0x000a30, 1},
1608 {0x000a31, 0x000a31, -1}, {0x000a32, 0x000a33, 1}, {0x000a34, 0x000a34, -1},
1609 {0x000a35, 0x000a36, 1}, {0x000a37, 0x000a37, -1}, {0x000a38, 0x000a39, 1},
1610 {0x000a3a, 0x000a3b, -1}, {0x000a3c, 0x000a3c, 0}, {0x000a3d, 0x000a3d, -1},
1611 {0x000a3e, 0x000a40, 1}, {0x000a41, 0x000a42, 0}, {0x000a43, 0x000a46, -1},
1612 {0x000a47, 0x000a48, 0}, {0x000a49, 0x000a4a, -1}, {0x000a4b, 0x000a4d, 0},
1613 {0x000a4e, 0x000a50, -1}, {0x000a51, 0x000a51, 0}, {0x000a52, 0x000a58, -1},
1614 {0x000a59, 0x000a5c, 1}, {0x000a5d, 0x000a5d, -1}, {0x000a5e, 0x000a5e, 1},
1615 {0x000a5f, 0x000a65, -1}, {0x000a66, 0x000a6f, 1}, {0x000a70, 0x000a71, 0},
1616 {0x000a72, 0x000a74, 1}, {0x000a75, 0x000a75, 0}, {0x000a76, 0x000a76, 1},
1617 {0x000a77, 0x000a80, -1}, {0x000a81, 0x000a82, 0}, {0x000a83, 0x000a83, 1},
1618 {0x000a84, 0x000a84, -1}, {0x000a85, 0x000a8d, 1}, {0x000a8e, 0x000a8e, -1},
1619 {0x000a8f, 0x000a91, 1}, {0x000a92, 0x000a92, -1}, {0x000a93, 0x000aa8, 1},
1620 {0x000aa9, 0x000aa9, -1}, {0x000aaa, 0x000ab0, 1}, {0x000ab1, 0x000ab1, -1},
1621 {0x000ab2, 0x000ab3, 1}, {0x000ab4, 0x000ab4, -1}, {0x000ab5, 0x000ab9, 1},
1622 {0x000aba, 0x000abb, -1}, {0x000abc, 0x000abc, 0}, {0x000abd, 0x000ac0, 1},
1623 {0x000ac1, 0x000ac5, 0}, {0x000ac6, 0x000ac6, -1}, {0x000ac7, 0x000ac8, 0},
1624 {0x000ac9, 0x000ac9, 1}, {0x000aca, 0x000aca, -1}, {0x000acb, 0x000acc, 1},
1625 {0x000acd, 0x000acd, 0}, {0x000ace, 0x000acf, -1}, {0x000ad0, 0x000ad0, 1},
1626 {0x000ad1, 0x000adf, -1}, {0x000ae0, 0x000ae1, 1}, {0x000ae2, 0x000ae3, 0},
1627 {0x000ae4, 0x000ae5, -1}, {0x000ae6, 0x000af1, 1}, {0x000af2, 0x000af8, -1},
1628 {0x000af9, 0x000af9, 1}, {0x000afa, 0x000aff, 0}, {0x000b00, 0x000b00, -1},
1629 {0x000b01, 0x000b01, 0}, {0x000b02, 0x000b03, 1}, {0x000b04, 0x000b04, -1},
1630 {0x000b05, 0x000b0c, 1}, {0x000b0d, 0x000b0e, -1}, {0x000b0f, 0x000b10, 1},
1631 {0x000b11, 0x000b12, -1}, {0x000b13, 0x000b28, 1}, {0x000b29, 0x000b29, -1},
1632 {0x000b2a, 0x000b30, 1}, {0x000b31, 0x000b31, -1}, {0x000b32, 0x000b33, 1},
1633 {0x000b34, 0x000b34, -1}, {0x000b35, 0x000b39, 1}, {0x000b3a, 0x000b3b, -1},
1634 {0x000b3c, 0x000b3c, 0}, {0x000b3d, 0x000b3e, 1}, {0x000b3f, 0x000b3f, 0},
1635 {0x000b40, 0x000b40, 1}, {0x000b41, 0x000b44, 0}, {0x000b45, 0x000b46, -1},
1636 {0x000b47, 0x000b48, 1}, {0x000b49, 0x000b4a, -1}, {0x000b4b, 0x000b4c, 1},
1637 {0x000b4d, 0x000b4d, 0}, {0x000b4e, 0x000b54, -1}, {0x000b55, 0x000b56, 0},
1638 {0x000b57, 0x000b57, 1}, {0x000b58, 0x000b5b, -1}, {0x000b5c, 0x000b5d, 1},
1639 {0x000b5e, 0x000b5e, -1}, {0x000b5f, 0x000b61, 1}, {0x000b62, 0x000b63, 0},
1640 {0x000b64, 0x000b65, -1}, {0x000b66, 0x000b77, 1}, {0x000b78, 0x000b81, -1},
1641 {0x000b82, 0x000b82, 0}, {0x000b83, 0x000b83, 1}, {0x000b84, 0x000b84, -1},
1642 {0x000b85, 0x000b8a, 1}, {0x000b8b, 0x000b8d, -1}, {0x000b8e, 0x000b90, 1},
1643 {0x000b91, 0x000b91, -1}, {0x000b92, 0x000b95, 1}, {0x000b96, 0x000b98, -1},
1644 {0x000b99, 0x000b9a, 1}, {0x000b9b, 0x000b9b, -1}, {0x000b9c, 0x000b9c, 1},
1645 {0x000b9d, 0x000b9d, -1}, {0x000b9e, 0x000b9f, 1}, {0x000ba0, 0x000ba2, -1},
1646 {0x000ba3, 0x000ba4, 1}, {0x000ba5, 0x000ba7, -1}, {0x000ba8, 0x000baa, 1},
1647 {0x000bab, 0x000bad, -1}, {0x000bae, 0x000bb9, 1}, {0x000bba, 0x000bbd, -1},
1648 {0x000bbe, 0x000bbf, 1}, {0x000bc0, 0x000bc0, 0}, {0x000bc1, 0x000bc2, 1},
1649 {0x000bc3, 0x000bc5, -1}, {0x000bc6, 0x000bc8, 1}, {0x000bc9, 0x000bc9, -1},
1650 {0x000bca, 0x000bcc, 1}, {0x000bcd, 0x000bcd, 0}, {0x000bce, 0x000bcf, -1},
1651 {0x000bd0, 0x000bd0, 1}, {0x000bd1, 0x000bd6, -1}, {0x000bd7, 0x000bd7, 1},
1652 {0x000bd8, 0x000be5, -1}, {0x000be6, 0x000bfa, 1}, {0x000bfb, 0x000bff, -1},
1653 {0x000c00, 0x000c00, 0}, {0x000c01, 0x000c03, 1}, {0x000c04, 0x000c04, 0},
1654 {0x000c05, 0x000c0c, 1}, {0x000c0d, 0x000c0d, -1}, {0x000c0e, 0x000c10, 1},
1655 {0x000c11, 0x000c11, -1}, {0x000c12, 0x000c28, 1}, {0x000c29, 0x000c29, -1},
1656 {0x000c2a, 0x000c39, 1}, {0x000c3a, 0x000c3b, -1}, {0x000c3c, 0x000c3c, 0},
1657 {0x000c3d, 0x000c3d, 1}, {0x000c3e, 0x000c40, 0}, {0x000c41, 0x000c44, 1},
1658 {0x000c45, 0x000c45, -1}, {0x000c46, 0x000c48, 0}, {0x000c49, 0x000c49, -1},
1659 {0x000c4a, 0x000c4d, 0}, {0x000c4e, 0x000c54, -1}, {0x000c55, 0x000c56, 0},
1660 {0x000c57, 0x000c57, -1}, {0x000c58, 0x000c5a, 1}, {0x000c5b, 0x000c5c, -1},
1661 {0x000c5d, 0x000c5d, 1}, {0x000c5e, 0x000c5f, -1}, {0x000c60, 0x000c61, 1},
1662 {0x000c62, 0x000c63, 0}, {0x000c64, 0x000c65, -1}, {0x000c66, 0x000c6f, 1},
1663 {0x000c70, 0x000c76, -1}, {0x000c77, 0x000c80, 1}, {0x000c81, 0x000c81, 0},
1664 {0x000c82, 0x000c8c, 1}, {0x000c8d, 0x000c8d, -1}, {0x000c8e, 0x000c90, 1},
1665 {0x000c91, 0x000c91, -1}, {0x000c92, 0x000ca8, 1}, {0x000ca9, 0x000ca9, -1},
1666 {0x000caa, 0x000cb3, 1}, {0x000cb4, 0x000cb4, -1}, {0x000cb5, 0x000cb9, 1},
1667 {0x000cba, 0x000cbb, -1}, {0x000cbc, 0x000cbc, 0}, {0x000cbd, 0x000cbe, 1},
1668 {0x000cbf, 0x000cbf, 0}, {0x000cc0, 0x000cc4, 1}, {0x000cc5, 0x000cc5, -1},
1669 {0x000cc6, 0x000cc6, 0}, {0x000cc7, 0x000cc8, 1}, {0x000cc9, 0x000cc9, -1},
1670 {0x000cca, 0x000ccb, 1}, {0x000ccc, 0x000ccd, 0}, {0x000cce, 0x000cd4, -1},
1671 {0x000cd5, 0x000cd6, 1}, {0x000cd7, 0x000cdc, -1}, {0x000cdd, 0x000cde, 1},
1672 {0x000cdf, 0x000cdf, -1}, {0x000ce0, 0x000ce1, 1}, {0x000ce2, 0x000ce3, 0},
1673 {0x000ce4, 0x000ce5, -1}, {0x000ce6, 0x000cef, 1}, {0x000cf0, 0x000cf0, -1},
1674 {0x000cf1, 0x000cf3, 1}, {0x000cf4, 0x000cff, -1}, {0x000d00, 0x000d01, 0},
1675 {0x000d02, 0x000d0c, 1}, {0x000d0d, 0x000d0d, -1}, {0x000d0e, 0x000d10, 1},
1676 {0x000d11, 0x000d11, -1}, {0x000d12, 0x000d3a, 1}, {0x000d3b, 0x000d3c, 0},
1677 {0x000d3d, 0x000d40, 1}, {0x000d41, 0x000d44, 0}, {0x000d45, 0x000d45, -1},
1678 {0x000d46, 0x000d48, 1}, {0x000d49, 0x000d49, -1}, {0x000d4a, 0x000d4c, 1},
1679 {0x000d4d, 0x000d4d, 0}, {0x000d4e, 0x000d4f, 1}, {0x000d50, 0x000d53, -1},
1680 {0x000d54, 0x000d61, 1}, {0x000d62, 0x000d63, 0}, {0x000d64, 0x000d65, -1},
1681 {0x000d66, 0x000d7f, 1}, {0x000d80, 0x000d80, -1}, {0x000d81, 0x000d81, 0},
1682 {0x000d82, 0x000d83, 1}, {0x000d84, 0x000d84, -1}, {0x000d85, 0x000d96, 1},
1683 {0x000d97, 0x000d99, -1}, {0x000d9a, 0x000db1, 1}, {0x000db2, 0x000db2, -1},
1684 {0x000db3, 0x000dbb, 1}, {0x000dbc, 0x000dbc, -1}, {0x000dbd, 0x000dbd, 1},
1685 {0x000dbe, 0x000dbf, -1}, {0x000dc0, 0x000dc6, 1}, {0x000dc7, 0x000dc9, -1},
1686 {0x000dca, 0x000dca, 0}, {0x000dcb, 0x000dce, -1}, {0x000dcf, 0x000dd1, 1},
1687 {0x000dd2, 0x000dd4, 0}, {0x000dd5, 0x000dd5, -1}, {0x000dd6, 0x000dd6, 0},
1688 {0x000dd7, 0x000dd7, -1}, {0x000dd8, 0x000ddf, 1}, {0x000de0, 0x000de5, -1},
1689 {0x000de6, 0x000def, 1}, {0x000df0, 0x000df1, -1}, {0x000df2, 0x000df4, 1},
1690 {0x000df5, 0x000e00, -1}, {0x000e01, 0x000e30, 1}, {0x000e31, 0x000e31, 0},
1691 {0x000e32, 0x000e33, 1}, {0x000e34, 0x000e3a, 0}, {0x000e3b, 0x000e3e, -1},
1692 {0x000e3f, 0x000e46, 1}, {0x000e47, 0x000e4e, 0}, {0x000e4f, 0x000e5b, 1},
1693 {0x000e5c, 0x000e80, -1}, {0x000e81, 0x000e82, 1}, {0x000e83, 0x000e83, -1},
1694 {0x000e84, 0x000e84, 1}, {0x000e85, 0x000e85, -1}, {0x000e86, 0x000e8a, 1},
1695 {0x000e8b, 0x000e8b, -1}, {0x000e8c, 0x000ea3, 1}, {0x000ea4, 0x000ea4, -1},
1696 {0x000ea5, 0x000ea5, 1}, {0x000ea6, 0x000ea6, -1}, {0x000ea7, 0x000eb0, 1},
1697 {0x000eb1, 0x000eb1, 0}, {0x000eb2, 0x000eb3, 1}, {0x000eb4, 0x000ebc, 0},
1698 {0x000ebd, 0x000ebd, 1}, {0x000ebe, 0x000ebf, -1}, {0x000ec0, 0x000ec4, 1},
1699 {0x000ec5, 0x000ec5, -1}, {0x000ec6, 0x000ec6, 1}, {0x000ec7, 0x000ec7, -1},
1700 {0x000ec8, 0x000ece, 0}, {0x000ecf, 0x000ecf, -1}, {0x000ed0, 0x000ed9, 1},
1701 {0x000eda, 0x000edb, -1}, {0x000edc, 0x000edf, 1}, {0x000ee0, 0x000eff, -1},
1702 {0x000f00, 0x000f17, 1}, {0x000f18, 0x000f19, 0}, {0x000f1a, 0x000f34, 1},
1703 {0x000f35, 0x000f35, 0}, {0x000f36, 0x000f36, 1}, {0x000f37, 0x000f37, 0},
1704 {0x000f38, 0x000f38, 1}, {0x000f39, 0x000f39, 0}, {0x000f3a, 0x000f47, 1},
1705 {0x000f48, 0x000f48, -1}, {0x000f49, 0x000f6c, 1}, {0x000f6d, 0x000f70, -1},
1706 {0x000f71, 0x000f7e, 0}, {0x000f7f, 0x000f7f, 1}, {0x000f80, 0x000f84, 0},
1707 {0x000f85, 0x000f85, 1}, {0x000f86, 0x000f87, 0}, {0x000f88, 0x000f8c, 1},
1708 {0x000f8d, 0x000f97, 0}, {0x000f98, 0x000f98, -1}, {0x000f99, 0x000fbc, 0},
1709 {0x000fbd, 0x000fbd, -1}, {0x000fbe, 0x000fc5, 1}, {0x000fc6, 0x000fc6, 0},
1710 {0x000fc7, 0x000fcc, 1}, {0x000fcd, 0x000fcd, -1}, {0x000fce, 0x000fda, 1},
1711 {0x000fdb, 0x000fff, -1}, {0x001000, 0x00102c, 1}, {0x00102d, 0x001030, 0},
1712 {0x001031, 0x001031, 1}, {0x001032, 0x001037, 0}, {0x001038, 0x001038, 1},
1713 {0x001039, 0x00103a, 0}, {0x00103b, 0x00103c, 1}, {0x00103d, 0x00103e, 0},
1714 {0x00103f, 0x001057, 1}, {0x001058, 0x001059, 0}, {0x00105a, 0x00105d, 1},
1715 {0x00105e, 0x001060, 0}, {0x001061, 0x001070, 1}, {0x001071, 0x001074, 0},
1716 {0x001075, 0x001081, 1}, {0x001082, 0x001082, 0}, {0x001083, 0x001084, 1},
1717 {0x001085, 0x001086, 0}, {0x001087, 0x00108c, 1}, {0x00108d, 0x00108d, 0},
1718 {0x00108e, 0x00109c, 1}, {0x00109d, 0x00109d, 0}, {0x00109e, 0x0010c5, 1},
1719 {0x0010c6, 0x0010c6, -1}, {0x0010c7, 0x0010c7, 1}, {0x0010c8, 0x0010cc, -1},
1720 {0x0010cd, 0x0010cd, 1}, {0x0010ce, 0x0010cf, -1}, {0x0010d0, 0x0010ff, 1},
1721 {0x001100, 0x00115f, 2}, {0x001160, 0x0011ff, 0}, {0x001200, 0x001248, 1},
1722 {0x001249, 0x001249, -1}, {0x00124a, 0x00124d, 1}, {0x00124e, 0x00124f, -1},
1723 {0x001250, 0x001256, 1}, {0x001257, 0x001257, -1}, {0x001258, 0x001258, 1},
1724 {0x001259, 0x001259, -1}, {0x00125a, 0x00125d, 1}, {0x00125e, 0x00125f, -1},
1725 {0x001260, 0x001288, 1}, {0x001289, 0x001289, -1}, {0x00128a, 0x00128d, 1},
1726 {0x00128e, 0x00128f, -1}, {0x001290, 0x0012b0, 1}, {0x0012b1, 0x0012b1, -1},
1727 {0x0012b2, 0x0012b5, 1}, {0x0012b6, 0x0012b7, -1}, {0x0012b8, 0x0012be, 1},
1728 {0x0012bf, 0x0012bf, -1}, {0x0012c0, 0x0012c0, 1}, {0x0012c1, 0x0012c1, -1},
1729 {0x0012c2, 0x0012c5, 1}, {0x0012c6, 0x0012c7, -1}, {0x0012c8, 0x0012d6, 1},
1730 {0x0012d7, 0x0012d7, -1}, {0x0012d8, 0x001310, 1}, {0x001311, 0x001311, -1},
1731 {0x001312, 0x001315, 1}, {0x001316, 0x001317, -1}, {0x001318, 0x00135a, 1},
1732 {0x00135b, 0x00135c, -1}, {0x00135d, 0x00135f, 0}, {0x001360, 0x00137c, 1},
1733 {0x00137d, 0x00137f, -1}, {0x001380, 0x001399, 1}, {0x00139a, 0x00139f, -1},
1734 {0x0013a0, 0x0013f5, 1}, {0x0013f6, 0x0013f7, -1}, {0x0013f8, 0x0013fd, 1},
1735 {0x0013fe, 0x0013ff, -1}, {0x001400, 0x00169c, 1}, {0x00169d, 0x00169f, -1},
1736 {0x0016a0, 0x0016f8, 1}, {0x0016f9, 0x0016ff, -1}, {0x001700, 0x001711, 1},
1737 {0x001712, 0x001714, 0}, {0x001715, 0x001715, 1}, {0x001716, 0x00171e, -1},
1738 {0x00171f, 0x001731, 1}, {0x001732, 0x001733, 0}, {0x001734, 0x001736, 1},
1739 {0x001737, 0x00173f, -1}, {0x001740, 0x001751, 1}, {0x001752, 0x001753, 0},
1740 {0x001754, 0x00175f, -1}, {0x001760, 0x00176c, 1}, {0x00176d, 0x00176d, -1},
1741 {0x00176e, 0x001770, 1}, {0x001771, 0x001771, -1}, {0x001772, 0x001773, 0},
1742 {0x001774, 0x00177f, -1}, {0x001780, 0x0017b3, 1}, {0x0017b4, 0x0017b5, 0},
1743 {0x0017b6, 0x0017b6, 1}, {0x0017b7, 0x0017bd, 0}, {0x0017be, 0x0017c5, 1},
1744 {0x0017c6, 0x0017c6, 0}, {0x0017c7, 0x0017c8, 1}, {0x0017c9, 0x0017d3, 0},
1745 {0x0017d4, 0x0017dc, 1}, {0x0017dd, 0x0017dd, 0}, {0x0017de, 0x0017df, -1},
1746 {0x0017e0, 0x0017e9, 1}, {0x0017ea, 0x0017ef, -1}, {0x0017f0, 0x0017f9, 1},
1747 {0x0017fa, 0x0017ff, -1}, {0x001800, 0x00180a, 1}, {0x00180b, 0x00180f, 0},
1748 {0x001810, 0x001819, 1}, {0x00181a, 0x00181f, -1}, {0x001820, 0x001878, 1},
1749 {0x001879, 0x00187f, -1}, {0x001880, 0x001884, 1}, {0x001885, 0x001886, 0},
1750 {0x001887, 0x0018a8, 1}, {0x0018a9, 0x0018a9, 0}, {0x0018aa, 0x0018aa, 1},
1751 {0x0018ab, 0x0018af, -1}, {0x0018b0, 0x0018f5, 1}, {0x0018f6, 0x0018ff, -1},
1752 {0x001900, 0x00191e, 1}, {0x00191f, 0x00191f, -1}, {0x001920, 0x001922, 0},
1753 {0x001923, 0x001926, 1}, {0x001927, 0x001928, 0}, {0x001929, 0x00192b, 1},
1754 {0x00192c, 0x00192f, -1}, {0x001930, 0x001931, 1}, {0x001932, 0x001932, 0},
1755 {0x001933, 0x001938, 1}, {0x001939, 0x00193b, 0}, {0x00193c, 0x00193f, -1},
1756 {0x001940, 0x001940, 1}, {0x001941, 0x001943, -1}, {0x001944, 0x00196d, 1},
1757 {0x00196e, 0x00196f, -1}, {0x001970, 0x001974, 1}, {0x001975, 0x00197f, -1},
1758 {0x001980, 0x0019ab, 1}, {0x0019ac, 0x0019af, -1}, {0x0019b0, 0x0019c9, 1},
1759 {0x0019ca, 0x0019cf, -1}, {0x0019d0, 0x0019da, 1}, {0x0019db, 0x0019dd, -1},
1760 {0x0019de, 0x001a16, 1}, {0x001a17, 0x001a18, 0}, {0x001a19, 0x001a1a, 1},
1761 {0x001a1b, 0x001a1b, 0}, {0x001a1c, 0x001a1d, -1}, {0x001a1e, 0x001a55, 1},
1762 {0x001a56, 0x001a56, 0}, {0x001a57, 0x001a57, 1}, {0x001a58, 0x001a5e, 0},
1763 {0x001a5f, 0x001a5f, -1}, {0x001a60, 0x001a60, 0}, {0x001a61, 0x001a61, 1},
1764 {0x001a62, 0x001a62, 0}, {0x001a63, 0x001a64, 1}, {0x001a65, 0x001a6c, 0},
1765 {0x001a6d, 0x001a72, 1}, {0x001a73, 0x001a7c, 0}, {0x001a7d, 0x001a7e, -1},
1766 {0x001a7f, 0x001a7f, 0}, {0x001a80, 0x001a89, 1}, {0x001a8a, 0x001a8f, -1},
1767 {0x001a90, 0x001a99, 1}, {0x001a9a, 0x001a9f, -1}, {0x001aa0, 0x001aad, 1},
1768 {0x001aae, 0x001aaf, -1}, {0x001ab0, 0x001ace, 0}, {0x001acf, 0x001aff, -1},
1769 {0x001b00, 0x001b03, 0}, {0x001b04, 0x001b33, 1}, {0x001b34, 0x001b34, 0},
1770 {0x001b35, 0x001b35, 1}, {0x001b36, 0x001b3a, 0}, {0x001b3b, 0x001b3b, 1},
1771 {0x001b3c, 0x001b3c, 0}, {0x001b3d, 0x001b41, 1}, {0x001b42, 0x001b42, 0},
1772 {0x001b43, 0x001b4c, 1}, {0x001b4d, 0x001b4d, -1}, {0x001b4e, 0x001b6a, 1},
1773 {0x001b6b, 0x001b73, 0}, {0x001b74, 0x001b7f, 1}, {0x001b80, 0x001b81, 0},
1774 {0x001b82, 0x001ba1, 1}, {0x001ba2, 0x001ba5, 0}, {0x001ba6, 0x001ba7, 1},
1775 {0x001ba8, 0x001ba9, 0}, {0x001baa, 0x001baa, 1}, {0x001bab, 0x001bad, 0},
1776 {0x001bae, 0x001be5, 1}, {0x001be6, 0x001be6, 0}, {0x001be7, 0x001be7, 1},
1777 {0x001be8, 0x001be9, 0}, {0x001bea, 0x001bec, 1}, {0x001bed, 0x001bed, 0},
1778 {0x001bee, 0x001bee, 1}, {0x001bef, 0x001bf1, 0}, {0x001bf2, 0x001bf3, 1},
1779 {0x001bf4, 0x001bfb, -1}, {0x001bfc, 0x001c2b, 1}, {0x001c2c, 0x001c33, 0},
1780 {0x001c34, 0x001c35, 1}, {0x001c36, 0x001c37, 0}, {0x001c38, 0x001c3a, -1},
1781 {0x001c3b, 0x001c49, 1}, {0x001c4a, 0x001c4c, -1}, {0x001c4d, 0x001c8a, 1},
1782 {0x001c8b, 0x001c8f, -1}, {0x001c90, 0x001cba, 1}, {0x001cbb, 0x001cbc, -1},
1783 {0x001cbd, 0x001cc7, 1}, {0x001cc8, 0x001ccf, -1}, {0x001cd0, 0x001cd2, 0},
1784 {0x001cd3, 0x001cd3, 1}, {0x001cd4, 0x001ce0, 0}, {0x001ce1, 0x001ce1, 1},
1785 {0x001ce2, 0x001ce8, 0}, {0x001ce9, 0x001cec, 1}, {0x001ced, 0x001ced, 0},
1786 {0x001cee, 0x001cf3, 1}, {0x001cf4, 0x001cf4, 0}, {0x001cf5, 0x001cf7, 1},
1787 {0x001cf8, 0x001cf9, 0}, {0x001cfa, 0x001cfa, 1}, {0x001cfb, 0x001cff, -1},
1788 {0x001d00, 0x001dbf, 1}, {0x001dc0, 0x001dff, 0}, {0x001e00, 0x001f15, 1},
1789 {0x001f16, 0x001f17, -1}, {0x001f18, 0x001f1d, 1}, {0x001f1e, 0x001f1f, -1},
1790 {0x001f20, 0x001f45, 1}, {0x001f46, 0x001f47, -1}, {0x001f48, 0x001f4d, 1},
1791 {0x001f4e, 0x001f4f, -1}, {0x001f50, 0x001f57, 1}, {0x001f58, 0x001f58, -1},
1792 {0x001f59, 0x001f59, 1}, {0x001f5a, 0x001f5a, -1}, {0x001f5b, 0x001f5b, 1},
1793 {0x001f5c, 0x001f5c, -1}, {0x001f5d, 0x001f5d, 1}, {0x001f5e, 0x001f5e, -1},
1794 {0x001f5f, 0x001f7d, 1}, {0x001f7e, 0x001f7f, -1}, {0x001f80, 0x001fb4, 1},
1795 {0x001fb5, 0x001fb5, -1}, {0x001fb6, 0x001fc4, 1}, {0x001fc5, 0x001fc5, -1},
1796 {0x001fc6, 0x001fd3, 1}, {0x001fd4, 0x001fd5, -1}, {0x001fd6, 0x001fdb, 1},
1797 {0x001fdc, 0x001fdc, -1}, {0x001fdd, 0x001fef, 1}, {0x001ff0, 0x001ff1, -1},
1798 {0x001ff2, 0x001ff4, 1}, {0x001ff5, 0x001ff5, -1}, {0x001ff6, 0x001ffe, 1},
1799 {0x001fff, 0x001fff, -1}, {0x002000, 0x00200a, 1}, {0x00200b, 0x00200f, 0},
1800 {0x002010, 0x002027, 1}, {0x002028, 0x002029, -1}, {0x00202a, 0x00202e, 0},
1801 {0x00202f, 0x00205f, 1}, {0x002060, 0x002064, 0}, {0x002065, 0x002065, -1},
1802 {0x002066, 0x00206f, 0}, {0x002070, 0x002071, 1}, {0x002072, 0x002073, -1},
1803 {0x002074, 0x00208e, 1}, {0x00208f, 0x00208f, -1}, {0x002090, 0x00209c, 1},
1804 {0x00209d, 0x00209f, -1}, {0x0020a0, 0x0020c0, 1}, {0x0020c1, 0x0020cf, -1},
1805 {0x0020d0, 0x0020f0, 0}, {0x0020f1, 0x0020ff, -1}, {0x002100, 0x00218b, 1},
1806 {0x00218c, 0x00218f, -1}, {0x002190, 0x002319, 1}, {0x00231a, 0x00231b, 2},
1807 {0x00231c, 0x002328, 1}, {0x002329, 0x00232a, 2}, {0x00232b, 0x0023e8, 1},
1808 {0x0023e9, 0x0023ec, 2}, {0x0023ed, 0x0023ef, 1}, {0x0023f0, 0x0023f0, 2},
1809 {0x0023f1, 0x0023f2, 1}, {0x0023f3, 0x0023f3, 2}, {0x0023f4, 0x002429, 1},
1810 {0x00242a, 0x00243f, -1}, {0x002440, 0x00244a, 1}, {0x00244b, 0x00245f, -1},
1811 {0x002460, 0x0025fc, 1}, {0x0025fd, 0x0025fe, 2}, {0x0025ff, 0x002613, 1},
1812 {0x002614, 0x002615, 2}, {0x002616, 0x00262f, 1}, {0x002630, 0x002637, 2},
1813 {0x002638, 0x002647, 1}, {0x002648, 0x002653, 2}, {0x002654, 0x00267e, 1},
1814 {0x00267f, 0x00267f, 2}, {0x002680, 0x002689, 1}, {0x00268a, 0x00268f, 2},
1815 {0x002690, 0x002692, 1}, {0x002693, 0x002693, 2}, {0x002694, 0x0026a0, 1},
1816 {0x0026a1, 0x0026a1, 2}, {0x0026a2, 0x0026a9, 1}, {0x0026aa, 0x0026ab, 2},
1817 {0x0026ac, 0x0026bc, 1}, {0x0026bd, 0x0026be, 2}, {0x0026bf, 0x0026c3, 1},
1818 {0x0026c4, 0x0026c5, 2}, {0x0026c6, 0x0026cd, 1}, {0x0026ce, 0x0026ce, 2},
1819 {0x0026cf, 0x0026d3, 1}, {0x0026d4, 0x0026d4, 2}, {0x0026d5, 0x0026e9, 1},
1820 {0x0026ea, 0x0026ea, 2}, {0x0026eb, 0x0026f1, 1}, {0x0026f2, 0x0026f3, 2},
1821 {0x0026f4, 0x0026f4, 1}, {0x0026f5, 0x0026f5, 2}, {0x0026f6, 0x0026f9, 1},
1822 {0x0026fa, 0x0026fa, 2}, {0x0026fb, 0x0026fc, 1}, {0x0026fd, 0x0026fd, 2},
1823 {0x0026fe, 0x002704, 1}, {0x002705, 0x002705, 2}, {0x002706, 0x002709, 1},
1824 {0x00270a, 0x00270b, 2}, {0x00270c, 0x002727, 1}, {0x002728, 0x002728, 2},
1825 {0x002729, 0x00274b, 1}, {0x00274c, 0x00274c, 2}, {0x00274d, 0x00274d, 1},
1826 {0x00274e, 0x00274e, 2}, {0x00274f, 0x002752, 1}, {0x002753, 0x002755, 2},
1827 {0x002756, 0x002756, 1}, {0x002757, 0x002757, 2}, {0x002758, 0x002794, 1},
1828 {0x002795, 0x002797, 2}, {0x002798, 0x0027af, 1}, {0x0027b0, 0x0027b0, 2},
1829 {0x0027b1, 0x0027be, 1}, {0x0027bf, 0x0027bf, 2}, {0x0027c0, 0x002b1a, 1},
1830 {0x002b1b, 0x002b1c, 2}, {0x002b1d, 0x002b4f, 1}, {0x002b50, 0x002b50, 2},
1831 {0x002b51, 0x002b54, 1}, {0x002b55, 0x002b55, 2}, {0x002b56, 0x002b73, 1},
1832 {0x002b74, 0x002b75, -1}, {0x002b76, 0x002b95, 1}, {0x002b96, 0x002b96, -1},
1833 {0x002b97, 0x002cee, 1}, {0x002cef, 0x002cf1, 0}, {0x002cf2, 0x002cf3, 1},
1834 {0x002cf4, 0x002cf8, -1}, {0x002cf9, 0x002d25, 1}, {0x002d26, 0x002d26, -1},
1835 {0x002d27, 0x002d27, 1}, {0x002d28, 0x002d2c, -1}, {0x002d2d, 0x002d2d, 1},
1836 {0x002d2e, 0x002d2f, -1}, {0x002d30, 0x002d67, 1}, {0x002d68, 0x002d6e, -1},
1837 {0x002d6f, 0x002d70, 1}, {0x002d71, 0x002d7e, -1}, {0x002d7f, 0x002d7f, 0},
1838 {0x002d80, 0x002d96, 1}, {0x002d97, 0x002d9f, -1}, {0x002da0, 0x002da6, 1},
1839 {0x002da7, 0x002da7, -1}, {0x002da8, 0x002dae, 1}, {0x002daf, 0x002daf, -1},
1840 {0x002db0, 0x002db6, 1}, {0x002db7, 0x002db7, -1}, {0x002db8, 0x002dbe, 1},
1841 {0x002dbf, 0x002dbf, -1}, {0x002dc0, 0x002dc6, 1}, {0x002dc7, 0x002dc7, -1},
1842 {0x002dc8, 0x002dce, 1}, {0x002dcf, 0x002dcf, -1}, {0x002dd0, 0x002dd6, 1},
1843 {0x002dd7, 0x002dd7, -1}, {0x002dd8, 0x002dde, 1}, {0x002ddf, 0x002ddf, -1},
1844 {0x002de0, 0x002dff, 0}, {0x002e00, 0x002e5d, 1}, {0x002e5e, 0x002e7f, -1},
1845 {0x002e80, 0x002e99, 2}, {0x002e9a, 0x002e9a, -1}, {0x002e9b, 0x002ef3, 2},
1846 {0x002ef4, 0x002eff, -1}, {0x002f00, 0x002fd5, 2}, {0x002fd6, 0x002fef, -1},
1847 {0x002ff0, 0x003029, 2}, {0x00302a, 0x00302d, 0}, {0x00302e, 0x00303e, 2},
1848 {0x00303f, 0x00303f, 1}, {0x003040, 0x003040, -1}, {0x003041, 0x003096, 2},
1849 {0x003097, 0x003098, -1}, {0x003099, 0x00309a, 0}, {0x00309b, 0x0030ff, 2},
1850 {0x003100, 0x003104, -1}, {0x003105, 0x00312f, 2}, {0x003130, 0x003130, -1},
1851 {0x003131, 0x003163, 2}, {0x003164, 0x003164, 0}, {0x003165, 0x00318e, 2},
1852 {0x00318f, 0x00318f, -1}, {0x003190, 0x0031e5, 2}, {0x0031e6, 0x0031ee, -1},
1853 {0x0031ef, 0x00321e, 2}, {0x00321f, 0x00321f, -1}, {0x003220, 0x00a48c, 2},
1854 {0x00a48d, 0x00a48f, -1}, {0x00a490, 0x00a4c6, 2}, {0x00a4c7, 0x00a4cf, -1},
1855 {0x00a4d0, 0x00a62b, 1}, {0x00a62c, 0x00a63f, -1}, {0x00a640, 0x00a66e, 1},
1856 {0x00a66f, 0x00a672, 0}, {0x00a673, 0x00a673, 1}, {0x00a674, 0x00a67d, 0},
1857 {0x00a67e, 0x00a69d, 1}, {0x00a69e, 0x00a69f, 0}, {0x00a6a0, 0x00a6ef, 1},
1858 {0x00a6f0, 0x00a6f1, 0}, {0x00a6f2, 0x00a6f7, 1}, {0x00a6f8, 0x00a6ff, -1},
1859 {0x00a700, 0x00a7cd, 1}, {0x00a7ce, 0x00a7cf, -1}, {0x00a7d0, 0x00a7d1, 1},
1860 {0x00a7d2, 0x00a7d2, -1}, {0x00a7d3, 0x00a7d3, 1}, {0x00a7d4, 0x00a7d4, -1},
1861 {0x00a7d5, 0x00a7dc, 1}, {0x00a7dd, 0x00a7f1, -1}, {0x00a7f2, 0x00a801, 1},
1862 {0x00a802, 0x00a802, 0}, {0x00a803, 0x00a805, 1}, {0x00a806, 0x00a806, 0},
1863 {0x00a807, 0x00a80a, 1}, {0x00a80b, 0x00a80b, 0}, {0x00a80c, 0x00a824, 1},
1864 {0x00a825, 0x00a826, 0}, {0x00a827, 0x00a82b, 1}, {0x00a82c, 0x00a82c, 0},
1865 {0x00a82d, 0x00a82f, -1}, {0x00a830, 0x00a839, 1}, {0x00a83a, 0x00a83f, -1},
1866 {0x00a840, 0x00a877, 1}, {0x00a878, 0x00a87f, -1}, {0x00a880, 0x00a8c3, 1},
1867 {0x00a8c4, 0x00a8c5, 0}, {0x00a8c6, 0x00a8cd, -1}, {0x00a8ce, 0x00a8d9, 1},
1868 {0x00a8da, 0x00a8df, -1}, {0x00a8e0, 0x00a8f1, 0}, {0x00a8f2, 0x00a8fe, 1},
1869 {0x00a8ff, 0x00a8ff, 0}, {0x00a900, 0x00a925, 1}, {0x00a926, 0x00a92d, 0},
1870 {0x00a92e, 0x00a946, 1}, {0x00a947, 0x00a951, 0}, {0x00a952, 0x00a953, 1},
1871 {0x00a954, 0x00a95e, -1}, {0x00a95f, 0x00a95f, 1}, {0x00a960, 0x00a97c, 2},
1872 {0x00a97d, 0x00a97f, -1}, {0x00a980, 0x00a982, 0}, {0x00a983, 0x00a9b2, 1},
1873 {0x00a9b3, 0x00a9b3, 0}, {0x00a9b4, 0x00a9b5, 1}, {0x00a9b6, 0x00a9b9, 0},
1874 {0x00a9ba, 0x00a9bb, 1}, {0x00a9bc, 0x00a9bd, 0}, {0x00a9be, 0x00a9cd, 1},
1875 {0x00a9ce, 0x00a9ce, -1}, {0x00a9cf, 0x00a9d9, 1}, {0x00a9da, 0x00a9dd, -1},
1876 {0x00a9de, 0x00a9e4, 1}, {0x00a9e5, 0x00a9e5, 0}, {0x00a9e6, 0x00a9fe, 1},
1877 {0x00a9ff, 0x00a9ff, -1}, {0x00aa00, 0x00aa28, 1}, {0x00aa29, 0x00aa2e, 0},
1878 {0x00aa2f, 0x00aa30, 1}, {0x00aa31, 0x00aa32, 0}, {0x00aa33, 0x00aa34, 1},
1879 {0x00aa35, 0x00aa36, 0}, {0x00aa37, 0x00aa3f, -1}, {0x00aa40, 0x00aa42, 1},
1880 {0x00aa43, 0x00aa43, 0}, {0x00aa44, 0x00aa4b, 1}, {0x00aa4c, 0x00aa4c, 0},
1881 {0x00aa4d, 0x00aa4d, 1}, {0x00aa4e, 0x00aa4f, -1}, {0x00aa50, 0x00aa59, 1},
1882 {0x00aa5a, 0x00aa5b, -1}, {0x00aa5c, 0x00aa7b, 1}, {0x00aa7c, 0x00aa7c, 0},
1883 {0x00aa7d, 0x00aaaf, 1}, {0x00aab0, 0x00aab0, 0}, {0x00aab1, 0x00aab1, 1},
1884 {0x00aab2, 0x00aab4, 0}, {0x00aab5, 0x00aab6, 1}, {0x00aab7, 0x00aab8, 0},
1885 {0x00aab9, 0x00aabd, 1}, {0x00aabe, 0x00aabf, 0}, {0x00aac0, 0x00aac0, 1},
1886 {0x00aac1, 0x00aac1, 0}, {0x00aac2, 0x00aac2, 1}, {0x00aac3, 0x00aada, -1},
1887 {0x00aadb, 0x00aaeb, 1}, {0x00aaec, 0x00aaed, 0}, {0x00aaee, 0x00aaf5, 1},
1888 {0x00aaf6, 0x00aaf6, 0}, {0x00aaf7, 0x00ab00, -1}, {0x00ab01, 0x00ab06, 1},
1889 {0x00ab07, 0x00ab08, -1}, {0x00ab09, 0x00ab0e, 1}, {0x00ab0f, 0x00ab10, -1},
1890 {0x00ab11, 0x00ab16, 1}, {0x00ab17, 0x00ab1f, -1}, {0x00ab20, 0x00ab26, 1},
1891 {0x00ab27, 0x00ab27, -1}, {0x00ab28, 0x00ab2e, 1}, {0x00ab2f, 0x00ab2f, -1},
1892 {0x00ab30, 0x00ab6b, 1}, {0x00ab6c, 0x00ab6f, -1}, {0x00ab70, 0x00abe4, 1},
1893 {0x00abe5, 0x00abe5, 0}, {0x00abe6, 0x00abe7, 1}, {0x00abe8, 0x00abe8, 0},
1894 {0x00abe9, 0x00abec, 1}, {0x00abed, 0x00abed, 0}, {0x00abee, 0x00abef, -1},
1895 {0x00abf0, 0x00abf9, 1}, {0x00abfa, 0x00abff, -1}, {0x00ac00, 0x00d7a3, 2},
1896 {0x00d7a4, 0x00d7af, -1}, {0x00d7b0, 0x00d7c6, 0}, {0x00d7c7, 0x00d7ca, -1},
1897 {0x00d7cb, 0x00d7fb, 0}, {0x00d7fc, 0x00dfff, -1}, {0x00e000, 0x00f8ff, 1},
1898 {0x00f900, 0x00fa6d, 2}, {0x00fa6e, 0x00fa6f, -1}, {0x00fa70, 0x00fad9, 2},
1899 {0x00fada, 0x00faff, -1}, {0x00fb00, 0x00fb06, 1}, {0x00fb07, 0x00fb12, -1},
1900 {0x00fb13, 0x00fb17, 1}, {0x00fb18, 0x00fb1c, -1}, {0x00fb1d, 0x00fb1d, 1},
1901 {0x00fb1e, 0x00fb1e, 0}, {0x00fb1f, 0x00fb36, 1}, {0x00fb37, 0x00fb37, -1},
1902 {0x00fb38, 0x00fb3c, 1}, {0x00fb3d, 0x00fb3d, -1}, {0x00fb3e, 0x00fb3e, 1},
1903 {0x00fb3f, 0x00fb3f, -1}, {0x00fb40, 0x00fb41, 1}, {0x00fb42, 0x00fb42, -1},
1904 {0x00fb43, 0x00fb44, 1}, {0x00fb45, 0x00fb45, -1}, {0x00fb46, 0x00fbc2, 1},
1905 {0x00fbc3, 0x00fbd2, -1}, {0x00fbd3, 0x00fd8f, 1}, {0x00fd90, 0x00fd91, -1},
1906 {0x00fd92, 0x00fdc7, 1}, {0x00fdc8, 0x00fdce, -1}, {0x00fdcf, 0x00fdcf, 1},
1907 {0x00fdd0, 0x00fdef, -1}, {0x00fdf0, 0x00fdff, 1}, {0x00fe00, 0x00fe0f, 0},
1908 {0x00fe10, 0x00fe19, 2}, {0x00fe1a, 0x00fe1f, -1}, {0x00fe20, 0x00fe2f, 0},
1909 {0x00fe30, 0x00fe52, 2}, {0x00fe53, 0x00fe53, -1}, {0x00fe54, 0x00fe66, 2},
1910 {0x00fe67, 0x00fe67, -1}, {0x00fe68, 0x00fe6b, 2}, {0x00fe6c, 0x00fe6f, -1},
1911 {0x00fe70, 0x00fe74, 1}, {0x00fe75, 0x00fe75, -1}, {0x00fe76, 0x00fefc, 1},
1912 {0x00fefd, 0x00fefe, -1}, {0x00feff, 0x00feff, 0}, {0x00ff00, 0x00ff00, -1},
1913 {0x00ff01, 0x00ff60, 2}, {0x00ff61, 0x00ff9f, 1}, {0x00ffa0, 0x00ffa0, 0},
1914 {0x00ffa1, 0x00ffbe, 1}, {0x00ffbf, 0x00ffc1, -1}, {0x00ffc2, 0x00ffc7, 1},
1915 {0x00ffc8, 0x00ffc9, -1}, {0x00ffca, 0x00ffcf, 1}, {0x00ffd0, 0x00ffd1, -1},
1916 {0x00ffd2, 0x00ffd7, 1}, {0x00ffd8, 0x00ffd9, -1}, {0x00ffda, 0x00ffdc, 1},
1917 {0x00ffdd, 0x00ffdf, -1}, {0x00ffe0, 0x00ffe6, 2}, {0x00ffe7, 0x00ffe7, -1},
1918 {0x00ffe8, 0x00ffee, 1}, {0x00ffef, 0x00fff8, -1}, {0x00fff9, 0x00fffd, 1},
1919 {0x00fffe, 0x00ffff, -1}, {0x010000, 0x01000b, 1}, {0x01000c, 0x01000c, -1},
1920 {0x01000d, 0x010026, 1}, {0x010027, 0x010027, -1}, {0x010028, 0x01003a, 1},
1921 {0x01003b, 0x01003b, -1}, {0x01003c, 0x01003d, 1}, {0x01003e, 0x01003e, -1},
1922 {0x01003f, 0x01004d, 1}, {0x01004e, 0x01004f, -1}, {0x010050, 0x01005d, 1},
1923 {0x01005e, 0x01007f, -1}, {0x010080, 0x0100fa, 1}, {0x0100fb, 0x0100ff, -1},
1924 {0x010100, 0x010102, 1}, {0x010103, 0x010106, -1}, {0x010107, 0x010133, 1},
1925 {0x010134, 0x010136, -1}, {0x010137, 0x01018e, 1}, {0x01018f, 0x01018f, -1},
1926 {0x010190, 0x01019c, 1}, {0x01019d, 0x01019f, -1}, {0x0101a0, 0x0101a0, 1},
1927 {0x0101a1, 0x0101cf, -1}, {0x0101d0, 0x0101fc, 1}, {0x0101fd, 0x0101fd, 0},
1928 {0x0101fe, 0x01027f, -1}, {0x010280, 0x01029c, 1}, {0x01029d, 0x01029f, -1},
1929 {0x0102a0, 0x0102d0, 1}, {0x0102d1, 0x0102df, -1}, {0x0102e0, 0x0102e0, 0},
1930 {0x0102e1, 0x0102fb, 1}, {0x0102fc, 0x0102ff, -1}, {0x010300, 0x010323, 1},
1931 {0x010324, 0x01032c, -1}, {0x01032d, 0x01034a, 1}, {0x01034b, 0x01034f, -1},
1932 {0x010350, 0x010375, 1}, {0x010376, 0x01037a, 0}, {0x01037b, 0x01037f, -1},
1933 {0x010380, 0x01039d, 1}, {0x01039e, 0x01039e, -1}, {0x01039f, 0x0103c3, 1},
1934 {0x0103c4, 0x0103c7, -1}, {0x0103c8, 0x0103d5, 1}, {0x0103d6, 0x0103ff, -1},
1935 {0x010400, 0x01049d, 1}, {0x01049e, 0x01049f, -1}, {0x0104a0, 0x0104a9, 1},
1936 {0x0104aa, 0x0104af, -1}, {0x0104b0, 0x0104d3, 1}, {0x0104d4, 0x0104d7, -1},
1937 {0x0104d8, 0x0104fb, 1}, {0x0104fc, 0x0104ff, -1}, {0x010500, 0x010527, 1},
1938 {0x010528, 0x01052f, -1}, {0x010530, 0x010563, 1}, {0x010564, 0x01056e, -1},
1939 {0x01056f, 0x01057a, 1}, {0x01057b, 0x01057b, -1}, {0x01057c, 0x01058a, 1},
1940 {0x01058b, 0x01058b, -1}, {0x01058c, 0x010592, 1}, {0x010593, 0x010593, -1},
1941 {0x010594, 0x010595, 1}, {0x010596, 0x010596, -1}, {0x010597, 0x0105a1, 1},
1942 {0x0105a2, 0x0105a2, -1}, {0x0105a3, 0x0105b1, 1}, {0x0105b2, 0x0105b2, -1},
1943 {0x0105b3, 0x0105b9, 1}, {0x0105ba, 0x0105ba, -1}, {0x0105bb, 0x0105bc, 1},
1944 {0x0105bd, 0x0105bf, -1}, {0x0105c0, 0x0105f3, 1}, {0x0105f4, 0x0105ff, -1},
1945 {0x010600, 0x010736, 1}, {0x010737, 0x01073f, -1}, {0x010740, 0x010755, 1},
1946 {0x010756, 0x01075f, -1}, {0x010760, 0x010767, 1}, {0x010768, 0x01077f, -1},
1947 {0x010780, 0x010785, 1}, {0x010786, 0x010786, -1}, {0x010787, 0x0107b0, 1},
1948 {0x0107b1, 0x0107b1, -1}, {0x0107b2, 0x0107ba, 1}, {0x0107bb, 0x0107ff, -1},
1949 {0x010800, 0x010805, 1}, {0x010806, 0x010807, -1}, {0x010808, 0x010808, 1},
1950 {0x010809, 0x010809, -1}, {0x01080a, 0x010835, 1}, {0x010836, 0x010836, -1},
1951 {0x010837, 0x010838, 1}, {0x010839, 0x01083b, -1}, {0x01083c, 0x01083c, 1},
1952 {0x01083d, 0x01083e, -1}, {0x01083f, 0x010855, 1}, {0x010856, 0x010856, -1},
1953 {0x010857, 0x01089e, 1}, {0x01089f, 0x0108a6, -1}, {0x0108a7, 0x0108af, 1},
1954 {0x0108b0, 0x0108df, -1}, {0x0108e0, 0x0108f2, 1}, {0x0108f3, 0x0108f3, -1},
1955 {0x0108f4, 0x0108f5, 1}, {0x0108f6, 0x0108fa, -1}, {0x0108fb, 0x01091b, 1},
1956 {0x01091c, 0x01091e, -1}, {0x01091f, 0x010939, 1}, {0x01093a, 0x01093e, -1},
1957 {0x01093f, 0x01093f, 1}, {0x010940, 0x01097f, -1}, {0x010980, 0x0109b7, 1},
1958 {0x0109b8, 0x0109bb, -1}, {0x0109bc, 0x0109cf, 1}, {0x0109d0, 0x0109d1, -1},
1959 {0x0109d2, 0x010a00, 1}, {0x010a01, 0x010a03, 0}, {0x010a04, 0x010a04, -1},
1960 {0x010a05, 0x010a06, 0}, {0x010a07, 0x010a0b, -1}, {0x010a0c, 0x010a0f, 0},
1961 {0x010a10, 0x010a13, 1}, {0x010a14, 0x010a14, -1}, {0x010a15, 0x010a17, 1},
1962 {0x010a18, 0x010a18, -1}, {0x010a19, 0x010a35, 1}, {0x010a36, 0x010a37, -1},
1963 {0x010a38, 0x010a3a, 0}, {0x010a3b, 0x010a3e, -1}, {0x010a3f, 0x010a3f, 0},
1964 {0x010a40, 0x010a48, 1}, {0x010a49, 0x010a4f, -1}, {0x010a50, 0x010a58, 1},
1965 {0x010a59, 0x010a5f, -1}, {0x010a60, 0x010a9f, 1}, {0x010aa0, 0x010abf, -1},
1966 {0x010ac0, 0x010ae4, 1}, {0x010ae5, 0x010ae6, 0}, {0x010ae7, 0x010aea, -1},
1967 {0x010aeb, 0x010af6, 1}, {0x010af7, 0x010aff, -1}, {0x010b00, 0x010b35, 1},
1968 {0x010b36, 0x010b38, -1}, {0x010b39, 0x010b55, 1}, {0x010b56, 0x010b57, -1},
1969 {0x010b58, 0x010b72, 1}, {0x010b73, 0x010b77, -1}, {0x010b78, 0x010b91, 1},
1970 {0x010b92, 0x010b98, -1}, {0x010b99, 0x010b9c, 1}, {0x010b9d, 0x010ba8, -1},
1971 {0x010ba9, 0x010baf, 1}, {0x010bb0, 0x010bff, -1}, {0x010c00, 0x010c48, 1},
1972 {0x010c49, 0x010c7f, -1}, {0x010c80, 0x010cb2, 1}, {0x010cb3, 0x010cbf, -1},
1973 {0x010cc0, 0x010cf2, 1}, {0x010cf3, 0x010cf9, -1}, {0x010cfa, 0x010d23, 1},
1974 {0x010d24, 0x010d27, 0}, {0x010d28, 0x010d2f, -1}, {0x010d30, 0x010d39, 1},
1975 {0x010d3a, 0x010d3f, -1}, {0x010d40, 0x010d65, 1}, {0x010d66, 0x010d68, -1},
1976 {0x010d69, 0x010d6d, 0}, {0x010d6e, 0x010d85, 1}, {0x010d86, 0x010d8d, -1},
1977 {0x010d8e, 0x010d8f, 1}, {0x010d90, 0x010e5f, -1}, {0x010e60, 0x010e7e, 1},
1978 {0x010e7f, 0x010e7f, -1}, {0x010e80, 0x010ea9, 1}, {0x010eaa, 0x010eaa, -1},
1979 {0x010eab, 0x010eac, 0}, {0x010ead, 0x010ead, 1}, {0x010eae, 0x010eaf, -1},
1980 {0x010eb0, 0x010eb1, 1}, {0x010eb2, 0x010ec1, -1}, {0x010ec2, 0x010ec4, 1},
1981 {0x010ec5, 0x010efb, -1}, {0x010efc, 0x010eff, 0}, {0x010f00, 0x010f27, 1},
1982 {0x010f28, 0x010f2f, -1}, {0x010f30, 0x010f45, 1}, {0x010f46, 0x010f50, 0},
1983 {0x010f51, 0x010f59, 1}, {0x010f5a, 0x010f6f, -1}, {0x010f70, 0x010f81, 1},
1984 {0x010f82, 0x010f85, 0}, {0x010f86, 0x010f89, 1}, {0x010f8a, 0x010faf, -1},
1985 {0x010fb0, 0x010fcb, 1}, {0x010fcc, 0x010fdf, -1}, {0x010fe0, 0x010ff6, 1},
1986 {0x010ff7, 0x010fff, -1}, {0x011000, 0x011000, 1}, {0x011001, 0x011001, 0},
1987 {0x011002, 0x011037, 1}, {0x011038, 0x011046, 0}, {0x011047, 0x01104d, 1},
1988 {0x01104e, 0x011051, -1}, {0x011052, 0x01106f, 1}, {0x011070, 0x011070, 0},
1989 {0x011071, 0x011072, 1}, {0x011073, 0x011074, 0}, {0x011075, 0x011075, 1},
1990 {0x011076, 0x01107e, -1}, {0x01107f, 0x011081, 0}, {0x011082, 0x0110b2, 1},
1991 {0x0110b3, 0x0110b6, 0}, {0x0110b7, 0x0110b8, 1}, {0x0110b9, 0x0110ba, 0},
1992 {0x0110bb, 0x0110c1, 1}, {0x0110c2, 0x0110c2, 0}, {0x0110c3, 0x0110cc, -1},
1993 {0x0110cd, 0x0110cd, 1}, {0x0110ce, 0x0110cf, -1}, {0x0110d0, 0x0110e8, 1},
1994 {0x0110e9, 0x0110ef, -1}, {0x0110f0, 0x0110f9, 1}, {0x0110fa, 0x0110ff, -1},
1995 {0x011100, 0x011102, 0}, {0x011103, 0x011126, 1}, {0x011127, 0x01112b, 0},
1996 {0x01112c, 0x01112c, 1}, {0x01112d, 0x011134, 0}, {0x011135, 0x011135, -1},
1997 {0x011136, 0x011147, 1}, {0x011148, 0x01114f, -1}, {0x011150, 0x011172, 1},
1998 {0x011173, 0x011173, 0}, {0x011174, 0x011176, 1}, {0x011177, 0x01117f, -1},
1999 {0x011180, 0x011181, 0}, {0x011182, 0x0111b5, 1}, {0x0111b6, 0x0111be, 0},
2000 {0x0111bf, 0x0111c8, 1}, {0x0111c9, 0x0111cc, 0}, {0x0111cd, 0x0111ce, 1},
2001 {0x0111cf, 0x0111cf, 0}, {0x0111d0, 0x0111df, 1}, {0x0111e0, 0x0111e0, -1},
2002 {0x0111e1, 0x0111f4, 1}, {0x0111f5, 0x0111ff, -1}, {0x011200, 0x011211, 1},
2003 {0x011212, 0x011212, -1}, {0x011213, 0x01122e, 1}, {0x01122f, 0x011231, 0},
2004 {0x011232, 0x011233, 1}, {0x011234, 0x011234, 0}, {0x011235, 0x011235, 1},
2005 {0x011236, 0x011237, 0}, {0x011238, 0x01123d, 1}, {0x01123e, 0x01123e, 0},
2006 {0x01123f, 0x011240, 1}, {0x011241, 0x011241, 0}, {0x011242, 0x01127f, -1},
2007 {0x011280, 0x011286, 1}, {0x011287, 0x011287, -1}, {0x011288, 0x011288, 1},
2008 {0x011289, 0x011289, -1}, {0x01128a, 0x01128d, 1}, {0x01128e, 0x01128e, -1},
2009 {0x01128f, 0x01129d, 1}, {0x01129e, 0x01129e, -1}, {0x01129f, 0x0112a9, 1},
2010 {0x0112aa, 0x0112af, -1}, {0x0112b0, 0x0112de, 1}, {0x0112df, 0x0112df, 0},
2011 {0x0112e0, 0x0112e2, 1}, {0x0112e3, 0x0112ea, 0}, {0x0112eb, 0x0112ef, -1},
2012 {0x0112f0, 0x0112f9, 1}, {0x0112fa, 0x0112ff, -1}, {0x011300, 0x011301, 0},
2013 {0x011302, 0x011303, 1}, {0x011304, 0x011304, -1}, {0x011305, 0x01130c, 1},
2014 {0x01130d, 0x01130e, -1}, {0x01130f, 0x011310, 1}, {0x011311, 0x011312, -1},
2015 {0x011313, 0x011328, 1}, {0x011329, 0x011329, -1}, {0x01132a, 0x011330, 1},
2016 {0x011331, 0x011331, -1}, {0x011332, 0x011333, 1}, {0x011334, 0x011334, -1},
2017 {0x011335, 0x011339, 1}, {0x01133a, 0x01133a, -1}, {0x01133b, 0x01133c, 0},
2018 {0x01133d, 0x01133f, 1}, {0x011340, 0x011340, 0}, {0x011341, 0x011344, 1},
2019 {0x011345, 0x011346, -1}, {0x011347, 0x011348, 1}, {0x011349, 0x01134a, -1},
2020 {0x01134b, 0x01134d, 1}, {0x01134e, 0x01134f, -1}, {0x011350, 0x011350, 1},
2021 {0x011351, 0x011356, -1}, {0x011357, 0x011357, 1}, {0x011358, 0x01135c, -1},
2022 {0x01135d, 0x011363, 1}, {0x011364, 0x011365, -1}, {0x011366, 0x01136c, 0},
2023 {0x01136d, 0x01136f, -1}, {0x011370, 0x011374, 0}, {0x011375, 0x01137f, -1},
2024 {0x011380, 0x011389, 1}, {0x01138a, 0x01138a, -1}, {0x01138b, 0x01138b, 1},
2025 {0x01138c, 0x01138d, -1}, {0x01138e, 0x01138e, 1}, {0x01138f, 0x01138f, -1},
2026 {0x011390, 0x0113b5, 1}, {0x0113b6, 0x0113b6, -1}, {0x0113b7, 0x0113ba, 1},
2027 {0x0113bb, 0x0113c0, 0}, {0x0113c1, 0x0113c1, -1}, {0x0113c2, 0x0113c2, 1},
2028 {0x0113c3, 0x0113c4, -1}, {0x0113c5, 0x0113c5, 1}, {0x0113c6, 0x0113c6, -1},
2029 {0x0113c7, 0x0113ca, 1}, {0x0113cb, 0x0113cb, -1}, {0x0113cc, 0x0113cd, 1},
2030 {0x0113ce, 0x0113ce, 0}, {0x0113cf, 0x0113cf, 1}, {0x0113d0, 0x0113d0, 0},
2031 {0x0113d1, 0x0113d1, 1}, {0x0113d2, 0x0113d2, 0}, {0x0113d3, 0x0113d5, 1},
2032 {0x0113d6, 0x0113d6, -1}, {0x0113d7, 0x0113d8, 1}, {0x0113d9, 0x0113e0, -1},
2033 {0x0113e1, 0x0113e2, 0}, {0x0113e3, 0x0113ff, -1}, {0x011400, 0x011437, 1},
2034 {0x011438, 0x01143f, 0}, {0x011440, 0x011441, 1}, {0x011442, 0x011444, 0},
2035 {0x011445, 0x011445, 1}, {0x011446, 0x011446, 0}, {0x011447, 0x01145b, 1},
2036 {0x01145c, 0x01145c, -1}, {0x01145d, 0x01145d, 1}, {0x01145e, 0x01145e, 0},
2037 {0x01145f, 0x011461, 1}, {0x011462, 0x01147f, -1}, {0x011480, 0x0114b2, 1},
2038 {0x0114b3, 0x0114b8, 0}, {0x0114b9, 0x0114b9, 1}, {0x0114ba, 0x0114ba, 0},
2039 {0x0114bb, 0x0114be, 1}, {0x0114bf, 0x0114c0, 0}, {0x0114c1, 0x0114c1, 1},
2040 {0x0114c2, 0x0114c3, 0}, {0x0114c4, 0x0114c7, 1}, {0x0114c8, 0x0114cf, -1},
2041 {0x0114d0, 0x0114d9, 1}, {0x0114da, 0x01157f, -1}, {0x011580, 0x0115b1, 1},
2042 {0x0115b2, 0x0115b5, 0}, {0x0115b6, 0x0115b7, -1}, {0x0115b8, 0x0115bb, 1},
2043 {0x0115bc, 0x0115bd, 0}, {0x0115be, 0x0115be, 1}, {0x0115bf, 0x0115c0, 0},
2044 {0x0115c1, 0x0115db, 1}, {0x0115dc, 0x0115dd, 0}, {0x0115de, 0x0115ff, -1},
2045 {0x011600, 0x011632, 1}, {0x011633, 0x01163a, 0}, {0x01163b, 0x01163c, 1},
2046 {0x01163d, 0x01163d, 0}, {0x01163e, 0x01163e, 1}, {0x01163f, 0x011640, 0},
2047 {0x011641, 0x011644, 1}, {0x011645, 0x01164f, -1}, {0x011650, 0x011659, 1},
2048 {0x01165a, 0x01165f, -1}, {0x011660, 0x01166c, 1}, {0x01166d, 0x01167f, -1},
2049 {0x011680, 0x0116aa, 1}, {0x0116ab, 0x0116ab, 0}, {0x0116ac, 0x0116ac, 1},
2050 {0x0116ad, 0x0116ad, 0}, {0x0116ae, 0x0116af, 1}, {0x0116b0, 0x0116b5, 0},
2051 {0x0116b6, 0x0116b6, 1}, {0x0116b7, 0x0116b7, 0}, {0x0116b8, 0x0116b9, 1},
2052 {0x0116ba, 0x0116bf, -1}, {0x0116c0, 0x0116c9, 1}, {0x0116ca, 0x0116cf, -1},
2053 {0x0116d0, 0x0116e3, 1}, {0x0116e4, 0x0116ff, -1}, {0x011700, 0x01171a, 1},
2054 {0x01171b, 0x01171c, -1}, {0x01171d, 0x01171d, 0}, {0x01171e, 0x01171e, 1},
2055 {0x01171f, 0x01171f, 0}, {0x011720, 0x011721, 1}, {0x011722, 0x011725, 0},
2056 {0x011726, 0x011726, 1}, {0x011727, 0x01172b, 0}, {0x01172c, 0x01172f, -1},
2057 {0x011730, 0x011746, 1}, {0x011747, 0x0117ff, -1}, {0x011800, 0x01182e, 1},
2058 {0x01182f, 0x011837, 0}, {0x011838, 0x011838, 1}, {0x011839, 0x01183a, 0},
2059 {0x01183b, 0x01183b, 1}, {0x01183c, 0x01189f, -1}, {0x0118a0, 0x0118f2, 1},
2060 {0x0118f3, 0x0118fe, -1}, {0x0118ff, 0x011906, 1}, {0x011907, 0x011908, -1},
2061 {0x011909, 0x011909, 1}, {0x01190a, 0x01190b, -1}, {0x01190c, 0x011913, 1},
2062 {0x011914, 0x011914, -1}, {0x011915, 0x011916, 1}, {0x011917, 0x011917, -1},
2063 {0x011918, 0x011935, 1}, {0x011936, 0x011936, -1}, {0x011937, 0x011938, 1},
2064 {0x011939, 0x01193a, -1}, {0x01193b, 0x01193c, 0}, {0x01193d, 0x01193d, 1},
2065 {0x01193e, 0x01193e, 0}, {0x01193f, 0x011942, 1}, {0x011943, 0x011943, 0},
2066 {0x011944, 0x011946, 1}, {0x011947, 0x01194f, -1}, {0x011950, 0x011959, 1},
2067 {0x01195a, 0x01199f, -1}, {0x0119a0, 0x0119a7, 1}, {0x0119a8, 0x0119a9, -1},
2068 {0x0119aa, 0x0119d3, 1}, {0x0119d4, 0x0119d7, 0}, {0x0119d8, 0x0119d9, -1},
2069 {0x0119da, 0x0119db, 0}, {0x0119dc, 0x0119df, 1}, {0x0119e0, 0x0119e0, 0},
2070 {0x0119e1, 0x0119e4, 1}, {0x0119e5, 0x0119ff, -1}, {0x011a00, 0x011a00, 1},
2071 {0x011a01, 0x011a0a, 0}, {0x011a0b, 0x011a32, 1}, {0x011a33, 0x011a38, 0},
2072 {0x011a39, 0x011a3a, 1}, {0x011a3b, 0x011a3e, 0}, {0x011a3f, 0x011a46, 1},
2073 {0x011a47, 0x011a47, 0}, {0x011a48, 0x011a4f, -1}, {0x011a50, 0x011a50, 1},
2074 {0x011a51, 0x011a56, 0}, {0x011a57, 0x011a58, 1}, {0x011a59, 0x011a5b, 0},
2075 {0x011a5c, 0x011a89, 1}, {0x011a8a, 0x011a96, 0}, {0x011a97, 0x011a97, 1},
2076 {0x011a98, 0x011a99, 0}, {0x011a9a, 0x011aa2, 1}, {0x011aa3, 0x011aaf, -1},
2077 {0x011ab0, 0x011af8, 1}, {0x011af9, 0x011aff, -1}, {0x011b00, 0x011b09, 1},
2078 {0x011b0a, 0x011bbf, -1}, {0x011bc0, 0x011be1, 1}, {0x011be2, 0x011bef, -1},
2079 {0x011bf0, 0x011bf9, 1}, {0x011bfa, 0x011bff, -1}, {0x011c00, 0x011c08, 1},
2080 {0x011c09, 0x011c09, -1}, {0x011c0a, 0x011c2f, 1}, {0x011c30, 0x011c36, 0},
2081 {0x011c37, 0x011c37, -1}, {0x011c38, 0x011c3d, 0}, {0x011c3e, 0x011c3e, 1},
2082 {0x011c3f, 0x011c3f, 0}, {0x011c40, 0x011c45, 1}, {0x011c46, 0x011c4f, -1},
2083 {0x011c50, 0x011c6c, 1}, {0x011c6d, 0x011c6f, -1}, {0x011c70, 0x011c8f, 1},
2084 {0x011c90, 0x011c91, -1}, {0x011c92, 0x011ca7, 0}, {0x011ca8, 0x011ca8, -1},
2085 {0x011ca9, 0x011ca9, 1}, {0x011caa, 0x011cb0, 0}, {0x011cb1, 0x011cb1, 1},
2086 {0x011cb2, 0x011cb3, 0}, {0x011cb4, 0x011cb4, 1}, {0x011cb5, 0x011cb6, 0},
2087 {0x011cb7, 0x011cff, -1}, {0x011d00, 0x011d06, 1}, {0x011d07, 0x011d07, -1},
2088 {0x011d08, 0x011d09, 1}, {0x011d0a, 0x011d0a, -1}, {0x011d0b, 0x011d30, 1},
2089 {0x011d31, 0x011d36, 0}, {0x011d37, 0x011d39, -1}, {0x011d3a, 0x011d3a, 0},
2090 {0x011d3b, 0x011d3b, -1}, {0x011d3c, 0x011d3d, 0}, {0x011d3e, 0x011d3e, -1},
2091 {0x011d3f, 0x011d45, 0}, {0x011d46, 0x011d46, 1}, {0x011d47, 0x011d47, 0},
2092 {0x011d48, 0x011d4f, -1}, {0x011d50, 0x011d59, 1}, {0x011d5a, 0x011d5f, -1},
2093 {0x011d60, 0x011d65, 1}, {0x011d66, 0x011d66, -1}, {0x011d67, 0x011d68, 1},
2094 {0x011d69, 0x011d69, -1}, {0x011d6a, 0x011d8e, 1}, {0x011d8f, 0x011d8f, -1},
2095 {0x011d90, 0x011d91, 0}, {0x011d92, 0x011d92, -1}, {0x011d93, 0x011d94, 1},
2096 {0x011d95, 0x011d95, 0}, {0x011d96, 0x011d96, 1}, {0x011d97, 0x011d97, 0},
2097 {0x011d98, 0x011d98, 1}, {0x011d99, 0x011d9f, -1}, {0x011da0, 0x011da9, 1},
2098 {0x011daa, 0x011edf, -1}, {0x011ee0, 0x011ef2, 1}, {0x011ef3, 0x011ef4, 0},
2099 {0x011ef5, 0x011ef8, 1}, {0x011ef9, 0x011eff, -1}, {0x011f00, 0x011f01, 0},
2100 {0x011f02, 0x011f10, 1}, {0x011f11, 0x011f11, -1}, {0x011f12, 0x011f35, 1},
2101 {0x011f36, 0x011f3a, 0}, {0x011f3b, 0x011f3d, -1}, {0x011f3e, 0x011f3f, 1},
2102 {0x011f40, 0x011f40, 0}, {0x011f41, 0x011f41, 1}, {0x011f42, 0x011f42, 0},
2103 {0x011f43, 0x011f59, 1}, {0x011f5a, 0x011f5a, 0}, {0x011f5b, 0x011faf, -1},
2104 {0x011fb0, 0x011fb0, 1}, {0x011fb1, 0x011fbf, -1}, {0x011fc0, 0x011ff1, 1},
2105 {0x011ff2, 0x011ffe, -1}, {0x011fff, 0x012399, 1}, {0x01239a, 0x0123ff, -1},
2106 {0x012400, 0x01246e, 1}, {0x01246f, 0x01246f, -1}, {0x012470, 0x012474, 1},
2107 {0x012475, 0x01247f, -1}, {0x012480, 0x012543, 1}, {0x012544, 0x012f8f, -1},
2108 {0x012f90, 0x012ff2, 1}, {0x012ff3, 0x012fff, -1}, {0x013000, 0x01343f, 1},
2109 {0x013440, 0x013440, 0}, {0x013441, 0x013446, 1}, {0x013447, 0x013455, 0},
2110 {0x013456, 0x01345f, -1}, {0x013460, 0x0143fa, 1}, {0x0143fb, 0x0143ff, -1},
2111 {0x014400, 0x014646, 1}, {0x014647, 0x0160ff, -1}, {0x016100, 0x01611d, 1},
2112 {0x01611e, 0x016129, 0}, {0x01612a, 0x01612c, 1}, {0x01612d, 0x01612f, 0},
2113 {0x016130, 0x016139, 1}, {0x01613a, 0x0167ff, -1}, {0x016800, 0x016a38, 1},
2114 {0x016a39, 0x016a3f, -1}, {0x016a40, 0x016a5e, 1}, {0x016a5f, 0x016a5f, -1},
2115 {0x016a60, 0x016a69, 1}, {0x016a6a, 0x016a6d, -1}, {0x016a6e, 0x016abe, 1},
2116 {0x016abf, 0x016abf, -1}, {0x016ac0, 0x016ac9, 1}, {0x016aca, 0x016acf, -1},
2117 {0x016ad0, 0x016aed, 1}, {0x016aee, 0x016aef, -1}, {0x016af0, 0x016af4, 0},
2118 {0x016af5, 0x016af5, 1}, {0x016af6, 0x016aff, -1}, {0x016b00, 0x016b2f, 1},
2119 {0x016b30, 0x016b36, 0}, {0x016b37, 0x016b45, 1}, {0x016b46, 0x016b4f, -1},
2120 {0x016b50, 0x016b59, 1}, {0x016b5a, 0x016b5a, -1}, {0x016b5b, 0x016b61, 1},
2121 {0x016b62, 0x016b62, -1}, {0x016b63, 0x016b77, 1}, {0x016b78, 0x016b7c, -1},
2122 {0x016b7d, 0x016b8f, 1}, {0x016b90, 0x016d3f, -1}, {0x016d40, 0x016d79, 1},
2123 {0x016d7a, 0x016e3f, -1}, {0x016e40, 0x016e9a, 1}, {0x016e9b, 0x016eff, -1},
2124 {0x016f00, 0x016f4a, 1}, {0x016f4b, 0x016f4e, -1}, {0x016f4f, 0x016f4f, 0},
2125 {0x016f50, 0x016f87, 1}, {0x016f88, 0x016f8e, -1}, {0x016f8f, 0x016f92, 0},
2126 {0x016f93, 0x016f9f, 1}, {0x016fa0, 0x016fdf, -1}, {0x016fe0, 0x016fe3, 2},
2127 {0x016fe4, 0x016fe4, 0}, {0x016fe5, 0x016fef, -1}, {0x016ff0, 0x016ff1, 2},
2128 {0x016ff2, 0x016fff, -1}, {0x017000, 0x0187f7, 2}, {0x0187f8, 0x0187ff, -1},
2129 {0x018800, 0x018cd5, 2}, {0x018cd6, 0x018cfe, -1}, {0x018cff, 0x018d08, 2},
2130 {0x018d09, 0x01afef, -1}, {0x01aff0, 0x01aff3, 2}, {0x01aff4, 0x01aff4, -1},
2131 {0x01aff5, 0x01affb, 2}, {0x01affc, 0x01affc, -1}, {0x01affd, 0x01affe, 2},
2132 {0x01afff, 0x01afff, -1}, {0x01b000, 0x01b122, 2}, {0x01b123, 0x01b131, -1},
2133 {0x01b132, 0x01b132, 2}, {0x01b133, 0x01b14f, -1}, {0x01b150, 0x01b152, 2},
2134 {0x01b153, 0x01b154, -1}, {0x01b155, 0x01b155, 2}, {0x01b156, 0x01b163, -1},
2135 {0x01b164, 0x01b167, 2}, {0x01b168, 0x01b16f, -1}, {0x01b170, 0x01b2fb, 2},
2136 {0x01b2fc, 0x01bbff, -1}, {0x01bc00, 0x01bc6a, 1}, {0x01bc6b, 0x01bc6f, -1},
2137 {0x01bc70, 0x01bc7c, 1}, {0x01bc7d, 0x01bc7f, -1}, {0x01bc80, 0x01bc88, 1},
2138 {0x01bc89, 0x01bc8f, -1}, {0x01bc90, 0x01bc99, 1}, {0x01bc9a, 0x01bc9b, -1},
2139 {0x01bc9c, 0x01bc9c, 1}, {0x01bc9d, 0x01bc9e, 0}, {0x01bc9f, 0x01bc9f, 1},
2140 {0x01bca0, 0x01bca3, 0}, {0x01bca4, 0x01cbff, -1}, {0x01cc00, 0x01ccf9, 1},
2141 {0x01ccfa, 0x01ccff, -1}, {0x01cd00, 0x01ceb3, 1}, {0x01ceb4, 0x01ceff, -1},
2142 {0x01cf00, 0x01cf2d, 0}, {0x01cf2e, 0x01cf2f, -1}, {0x01cf30, 0x01cf46, 0},
2143 {0x01cf47, 0x01cf4f, -1}, {0x01cf50, 0x01cfc3, 1}, {0x01cfc4, 0x01cfff, -1},
2144 {0x01d000, 0x01d0f5, 1}, {0x01d0f6, 0x01d0ff, -1}, {0x01d100, 0x01d126, 1},
2145 {0x01d127, 0x01d128, -1}, {0x01d129, 0x01d166, 1}, {0x01d167, 0x01d169, 0},
2146 {0x01d16a, 0x01d172, 1}, {0x01d173, 0x01d182, 0}, {0x01d183, 0x01d184, 1},
2147 {0x01d185, 0x01d18b, 0}, {0x01d18c, 0x01d1a9, 1}, {0x01d1aa, 0x01d1ad, 0},
2148 {0x01d1ae, 0x01d1ea, 1}, {0x01d1eb, 0x01d1ff, -1}, {0x01d200, 0x01d241, 1},
2149 {0x01d242, 0x01d244, 0}, {0x01d245, 0x01d245, 1}, {0x01d246, 0x01d2bf, -1},
2150 {0x01d2c0, 0x01d2d3, 1}, {0x01d2d4, 0x01d2df, -1}, {0x01d2e0, 0x01d2f3, 1},
2151 {0x01d2f4, 0x01d2ff, -1}, {0x01d300, 0x01d356, 2}, {0x01d357, 0x01d35f, -1},
2152 {0x01d360, 0x01d376, 2}, {0x01d377, 0x01d378, 1}, {0x01d379, 0x01d3ff, -1},
2153 {0x01d400, 0x01d454, 1}, {0x01d455, 0x01d455, -1}, {0x01d456, 0x01d49c, 1},
2154 {0x01d49d, 0x01d49d, -1}, {0x01d49e, 0x01d49f, 1}, {0x01d4a0, 0x01d4a1, -1},
2155 {0x01d4a2, 0x01d4a2, 1}, {0x01d4a3, 0x01d4a4, -1}, {0x01d4a5, 0x01d4a6, 1},
2156 {0x01d4a7, 0x01d4a8, -1}, {0x01d4a9, 0x01d4ac, 1}, {0x01d4ad, 0x01d4ad, -1},
2157 {0x01d4ae, 0x01d4b9, 1}, {0x01d4ba, 0x01d4ba, -1}, {0x01d4bb, 0x01d4bb, 1},
2158 {0x01d4bc, 0x01d4bc, -1}, {0x01d4bd, 0x01d4c3, 1}, {0x01d4c4, 0x01d4c4, -1},
2159 {0x01d4c5, 0x01d505, 1}, {0x01d506, 0x01d506, -1}, {0x01d507, 0x01d50a, 1},
2160 {0x01d50b, 0x01d50c, -1}, {0x01d50d, 0x01d514, 1}, {0x01d515, 0x01d515, -1},
2161 {0x01d516, 0x01d51c, 1}, {0x01d51d, 0x01d51d, -1}, {0x01d51e, 0x01d539, 1},
2162 {0x01d53a, 0x01d53a, -1}, {0x01d53b, 0x01d53e, 1}, {0x01d53f, 0x01d53f, -1},
2163 {0x01d540, 0x01d544, 1}, {0x01d545, 0x01d545, -1}, {0x01d546, 0x01d546, 1},
2164 {0x01d547, 0x01d549, -1}, {0x01d54a, 0x01d550, 1}, {0x01d551, 0x01d551, -1},
2165 {0x01d552, 0x01d6a5, 1}, {0x01d6a6, 0x01d6a7, -1}, {0x01d6a8, 0x01d7cb, 1},
2166 {0x01d7cc, 0x01d7cd, -1}, {0x01d7ce, 0x01d9ff, 1}, {0x01da00, 0x01da36, 0},
2167 {0x01da37, 0x01da3a, 1}, {0x01da3b, 0x01da6c, 0}, {0x01da6d, 0x01da74, 1},
2168 {0x01da75, 0x01da75, 0}, {0x01da76, 0x01da83, 1}, {0x01da84, 0x01da84, 0},
2169 {0x01da85, 0x01da8b, 1}, {0x01da8c, 0x01da9a, -1}, {0x01da9b, 0x01da9f, 0},
2170 {0x01daa0, 0x01daa0, -1}, {0x01daa1, 0x01daaf, 0}, {0x01dab0, 0x01deff, -1},
2171 {0x01df00, 0x01df1e, 1}, {0x01df1f, 0x01df24, -1}, {0x01df25, 0x01df2a, 1},
2172 {0x01df2b, 0x01dfff, -1}, {0x01e000, 0x01e006, 0}, {0x01e007, 0x01e007, -1},
2173 {0x01e008, 0x01e018, 0}, {0x01e019, 0x01e01a, -1}, {0x01e01b, 0x01e021, 0},
2174 {0x01e022, 0x01e022, -1}, {0x01e023, 0x01e024, 0}, {0x01e025, 0x01e025, -1},
2175 {0x01e026, 0x01e02a, 0}, {0x01e02b, 0x01e02f, -1}, {0x01e030, 0x01e06d, 1},
2176 {0x01e06e, 0x01e08e, -1}, {0x01e08f, 0x01e08f, 0}, {0x01e090, 0x01e0ff, -1},
2177 {0x01e100, 0x01e12c, 1}, {0x01e12d, 0x01e12f, -1}, {0x01e130, 0x01e136, 0},
2178 {0x01e137, 0x01e13d, 1}, {0x01e13e, 0x01e13f, -1}, {0x01e140, 0x01e149, 1},
2179 {0x01e14a, 0x01e14d, -1}, {0x01e14e, 0x01e14f, 1}, {0x01e150, 0x01e28f, -1},
2180 {0x01e290, 0x01e2ad, 1}, {0x01e2ae, 0x01e2ae, 0}, {0x01e2af, 0x01e2bf, -1},
2181 {0x01e2c0, 0x01e2eb, 1}, {0x01e2ec, 0x01e2ef, 0}, {0x01e2f0, 0x01e2f9, 1},
2182 {0x01e2fa, 0x01e2fe, -1}, {0x01e2ff, 0x01e2ff, 1}, {0x01e300, 0x01e4cf, -1},
2183 {0x01e4d0, 0x01e4eb, 1}, {0x01e4ec, 0x01e4ef, 0}, {0x01e4f0, 0x01e4f9, 1},
2184 {0x01e4fa, 0x01e5cf, -1}, {0x01e5d0, 0x01e5ed, 1}, {0x01e5ee, 0x01e5ef, 0},
2185 {0x01e5f0, 0x01e5fa, 1}, {0x01e5fb, 0x01e5fe, -1}, {0x01e5ff, 0x01e5ff, 1},
2186 {0x01e600, 0x01e7df, -1}, {0x01e7e0, 0x01e7e6, 1}, {0x01e7e7, 0x01e7e7, -1},
2187 {0x01e7e8, 0x01e7eb, 1}, {0x01e7ec, 0x01e7ec, -1}, {0x01e7ed, 0x01e7ee, 1},
2188 {0x01e7ef, 0x01e7ef, -1}, {0x01e7f0, 0x01e7fe, 1}, {0x01e7ff, 0x01e7ff, -1},
2189 {0x01e800, 0x01e8c4, 1}, {0x01e8c5, 0x01e8c6, -1}, {0x01e8c7, 0x01e8cf, 1},
2190 {0x01e8d0, 0x01e8d6, 0}, {0x01e8d7, 0x01e8ff, -1}, {0x01e900, 0x01e943, 1},
2191 {0x01e944, 0x01e94a, 0}, {0x01e94b, 0x01e94b, 1}, {0x01e94c, 0x01e94f, -1},
2192 {0x01e950, 0x01e959, 1}, {0x01e95a, 0x01e95d, -1}, {0x01e95e, 0x01e95f, 1},
2193 {0x01e960, 0x01ec70, -1}, {0x01ec71, 0x01ecb4, 1}, {0x01ecb5, 0x01ed00, -1},
2194 {0x01ed01, 0x01ed3d, 1}, {0x01ed3e, 0x01edff, -1}, {0x01ee00, 0x01ee03, 1},
2195 {0x01ee04, 0x01ee04, -1}, {0x01ee05, 0x01ee1f, 1}, {0x01ee20, 0x01ee20, -1},
2196 {0x01ee21, 0x01ee22, 1}, {0x01ee23, 0x01ee23, -1}, {0x01ee24, 0x01ee24, 1},
2197 {0x01ee25, 0x01ee26, -1}, {0x01ee27, 0x01ee27, 1}, {0x01ee28, 0x01ee28, -1},
2198 {0x01ee29, 0x01ee32, 1}, {0x01ee33, 0x01ee33, -1}, {0x01ee34, 0x01ee37, 1},
2199 {0x01ee38, 0x01ee38, -1}, {0x01ee39, 0x01ee39, 1}, {0x01ee3a, 0x01ee3a, -1},
2200 {0x01ee3b, 0x01ee3b, 1}, {0x01ee3c, 0x01ee41, -1}, {0x01ee42, 0x01ee42, 1},
2201 {0x01ee43, 0x01ee46, -1}, {0x01ee47, 0x01ee47, 1}, {0x01ee48, 0x01ee48, -1},
2202 {0x01ee49, 0x01ee49, 1}, {0x01ee4a, 0x01ee4a, -1}, {0x01ee4b, 0x01ee4b, 1},
2203 {0x01ee4c, 0x01ee4c, -1}, {0x01ee4d, 0x01ee4f, 1}, {0x01ee50, 0x01ee50, -1},
2204 {0x01ee51, 0x01ee52, 1}, {0x01ee53, 0x01ee53, -1}, {0x01ee54, 0x01ee54, 1},
2205 {0x01ee55, 0x01ee56, -1}, {0x01ee57, 0x01ee57, 1}, {0x01ee58, 0x01ee58, -1},
2206 {0x01ee59, 0x01ee59, 1}, {0x01ee5a, 0x01ee5a, -1}, {0x01ee5b, 0x01ee5b, 1},
2207 {0x01ee5c, 0x01ee5c, -1}, {0x01ee5d, 0x01ee5d, 1}, {0x01ee5e, 0x01ee5e, -1},
2208 {0x01ee5f, 0x01ee5f, 1}, {0x01ee60, 0x01ee60, -1}, {0x01ee61, 0x01ee62, 1},
2209 {0x01ee63, 0x01ee63, -1}, {0x01ee64, 0x01ee64, 1}, {0x01ee65, 0x01ee66, -1},
2210 {0x01ee67, 0x01ee6a, 1}, {0x01ee6b, 0x01ee6b, -1}, {0x01ee6c, 0x01ee72, 1},
2211 {0x01ee73, 0x01ee73, -1}, {0x01ee74, 0x01ee77, 1}, {0x01ee78, 0x01ee78, -1},
2212 {0x01ee79, 0x01ee7c, 1}, {0x01ee7d, 0x01ee7d, -1}, {0x01ee7e, 0x01ee7e, 1},
2213 {0x01ee7f, 0x01ee7f, -1}, {0x01ee80, 0x01ee89, 1}, {0x01ee8a, 0x01ee8a, -1},
2214 {0x01ee8b, 0x01ee9b, 1}, {0x01ee9c, 0x01eea0, -1}, {0x01eea1, 0x01eea3, 1},
2215 {0x01eea4, 0x01eea4, -1}, {0x01eea5, 0x01eea9, 1}, {0x01eeaa, 0x01eeaa, -1},
2216 {0x01eeab, 0x01eebb, 1}, {0x01eebc, 0x01eeef, -1}, {0x01eef0, 0x01eef1, 1},
2217 {0x01eef2, 0x01efff, -1}, {0x01f000, 0x01f003, 1}, {0x01f004, 0x01f004, 2},
2218 {0x01f005, 0x01f02b, 1}, {0x01f02c, 0x01f02f, -1}, {0x01f030, 0x01f093, 1},
2219 {0x01f094, 0x01f09f, -1}, {0x01f0a0, 0x01f0ae, 1}, {0x01f0af, 0x01f0b0, -1},
2220 {0x01f0b1, 0x01f0bf, 1}, {0x01f0c0, 0x01f0c0, -1}, {0x01f0c1, 0x01f0ce, 1},
2221 {0x01f0cf, 0x01f0cf, 2}, {0x01f0d0, 0x01f0d0, -1}, {0x01f0d1, 0x01f0f5, 1},
2222 {0x01f0f6, 0x01f0ff, -1}, {0x01f100, 0x01f18d, 1}, {0x01f18e, 0x01f18e, 2},
2223 {0x01f18f, 0x01f190, 1}, {0x01f191, 0x01f19a, 2}, {0x01f19b, 0x01f1ad, 1},
2224 {0x01f1ae, 0x01f1e5, -1}, {0x01f1e6, 0x01f1ff, 1}, {0x01f200, 0x01f202, 2},
2225 {0x01f203, 0x01f20f, -1}, {0x01f210, 0x01f23b, 2}, {0x01f23c, 0x01f23f, -1},
2226 {0x01f240, 0x01f248, 2}, {0x01f249, 0x01f24f, -1}, {0x01f250, 0x01f251, 2},
2227 {0x01f252, 0x01f25f, -1}, {0x01f260, 0x01f265, 2}, {0x01f266, 0x01f2ff, -1},
2228 {0x01f300, 0x01f320, 2}, {0x01f321, 0x01f32c, 1}, {0x01f32d, 0x01f335, 2},
2229 {0x01f336, 0x01f336, 1}, {0x01f337, 0x01f37c, 2}, {0x01f37d, 0x01f37d, 1},
2230 {0x01f37e, 0x01f393, 2}, {0x01f394, 0x01f39f, 1}, {0x01f3a0, 0x01f3ca, 2},
2231 {0x01f3cb, 0x01f3ce, 1}, {0x01f3cf, 0x01f3d3, 2}, {0x01f3d4, 0x01f3df, 1},
2232 {0x01f3e0, 0x01f3f0, 2}, {0x01f3f1, 0x01f3f3, 1}, {0x01f3f4, 0x01f3f4, 2},
2233 {0x01f3f5, 0x01f3f7, 1}, {0x01f3f8, 0x01f43e, 2}, {0x01f43f, 0x01f43f, 1},
2234 {0x01f440, 0x01f440, 2}, {0x01f441, 0x01f441, 1}, {0x01f442, 0x01f4fc, 2},
2235 {0x01f4fd, 0x01f4fe, 1}, {0x01f4ff, 0x01f53d, 2}, {0x01f53e, 0x01f54a, 1},
2236 {0x01f54b, 0x01f54e, 2}, {0x01f54f, 0x01f54f, 1}, {0x01f550, 0x01f567, 2},
2237 {0x01f568, 0x01f579, 1}, {0x01f57a, 0x01f57a, 2}, {0x01f57b, 0x01f594, 1},
2238 {0x01f595, 0x01f596, 2}, {0x01f597, 0x01f5a3, 1}, {0x01f5a4, 0x01f5a4, 2},
2239 {0x01f5a5, 0x01f5fa, 1}, {0x01f5fb, 0x01f64f, 2}, {0x01f650, 0x01f67f, 1},
2240 {0x01f680, 0x01f6c5, 2}, {0x01f6c6, 0x01f6cb, 1}, {0x01f6cc, 0x01f6cc, 2},
2241 {0x01f6cd, 0x01f6cf, 1}, {0x01f6d0, 0x01f6d2, 2}, {0x01f6d3, 0x01f6d4, 1},
2242 {0x01f6d5, 0x01f6d7, 2}, {0x01f6d8, 0x01f6db, -1}, {0x01f6dc, 0x01f6df, 2},
2243 {0x01f6e0, 0x01f6ea, 1}, {0x01f6eb, 0x01f6ec, 2}, {0x01f6ed, 0x01f6ef, -1},
2244 {0x01f6f0, 0x01f6f3, 1}, {0x01f6f4, 0x01f6fc, 2}, {0x01f6fd, 0x01f6ff, -1},
2245 {0x01f700, 0x01f776, 1}, {0x01f777, 0x01f77a, -1}, {0x01f77b, 0x01f7d9, 1},
2246 {0x01f7da, 0x01f7df, -1}, {0x01f7e0, 0x01f7eb, 2}, {0x01f7ec, 0x01f7ef, -1},
2247 {0x01f7f0, 0x01f7f0, 2}, {0x01f7f1, 0x01f7ff, -1}, {0x01f800, 0x01f80b, 1},
2248 {0x01f80c, 0x01f80f, -1}, {0x01f810, 0x01f847, 1}, {0x01f848, 0x01f84f, -1},
2249 {0x01f850, 0x01f859, 1}, {0x01f85a, 0x01f85f, -1}, {0x01f860, 0x01f887, 1},
2250 {0x01f888, 0x01f88f, -1}, {0x01f890, 0x01f8ad, 1}, {0x01f8ae, 0x01f8af, -1},
2251 {0x01f8b0, 0x01f8bb, 1}, {0x01f8bc, 0x01f8bf, -1}, {0x01f8c0, 0x01f8c1, 1},
2252 {0x01f8c2, 0x01f8ff, -1}, {0x01f900, 0x01f90b, 1}, {0x01f90c, 0x01f93a, 2},
2253 {0x01f93b, 0x01f93b, 1}, {0x01f93c, 0x01f945, 2}, {0x01f946, 0x01f946, 1},
2254 {0x01f947, 0x01f9ff, 2}, {0x01fa00, 0x01fa53, 1}, {0x01fa54, 0x01fa5f, -1},
2255 {0x01fa60, 0x01fa6d, 1}, {0x01fa6e, 0x01fa6f, -1}, {0x01fa70, 0x01fa7c, 2},
2256 {0x01fa7d, 0x01fa7f, -1}, {0x01fa80, 0x01fa89, 2}, {0x01fa8a, 0x01fa8e, -1},
2257 {0x01fa8f, 0x01fac6, 2}, {0x01fac7, 0x01facd, -1}, {0x01face, 0x01fadc, 2},
2258 {0x01fadd, 0x01fade, -1}, {0x01fadf, 0x01fae9, 2}, {0x01faea, 0x01faef, -1},
2259 {0x01faf0, 0x01faf8, 2}, {0x01faf9, 0x01faff, -1}, {0x01fb00, 0x01fb92, 1},
2260 {0x01fb93, 0x01fb93, -1}, {0x01fb94, 0x01fbf9, 1}, {0x01fbfa, 0x01ffff, -1},
2261 {0x020000, 0x02a6df, 2}, {0x02a6e0, 0x02a6ff, -1}, {0x02a700, 0x02b739, 2},
2262 {0x02b73a, 0x02b73f, -1}, {0x02b740, 0x02b81d, 2}, {0x02b81e, 0x02b81f, -1},
2263 {0x02b820, 0x02cea1, 2}, {0x02cea2, 0x02ceaf, -1}, {0x02ceb0, 0x02ebe0, 2},
2264 {0x02ebe1, 0x02ebef, -1}, {0x02ebf0, 0x02ee5d, 2}, {0x02ee5e, 0x02f7ff, -1},
2265 {0x02f800, 0x02fa1d, 2}, {0x02fa1e, 0x02ffff, -1}, {0x030000, 0x03134a, 2},
2266 {0x03134b, 0x03134f, -1}, {0x031350, 0x0323af, 2}, {0x0323b0, 0x0e0000, -1},
2267 {0x0e0001, 0x0e0001, 0}, {0x0e0002, 0x0e001f, -1}, {0x0e0020, 0x0e007f, 0},
2268 {0x0e0080, 0x0e00ff, -1}, {0x0e0100, 0x0e01ef, 0}, {0x0e01f0, 0x0effff, -1},
2269 {0x0f0000, 0x0ffffd, 1}, {0x0ffffe, 0x0fffff, -1}, {0x100000, 0x10fffd, 1},
2270 {0x10fffe, 0x10ffff, -1},
2271 // clang-format on
2272};
2273#define WCWIDTH_TABLE_LENGTH 2143
2274#endif // ifndef TB_OPT_LIBC_WCHAR
2275
2276static int tb_reset(void);
2277static int tb_printf_inner(int x, int y, uintattr_t fg, uintattr_t bg,
2278 size_t *out_w, const char *fmt, va_list vl);
2279static int init_term_attrs(void);
2280static int init_term_caps(void);
2281static int init_cap_trie(void);
2282static int cap_trie_add(const char *cap, uint16_t key, uint8_t mod);
2283static int cap_trie_find(const char *buf, size_t nbuf, struct cap_trie **last,
2284 size_t *depth);
2285static int cap_trie_deinit(struct cap_trie *node);
2286static int init_resize_handler(void);
2287static int send_init_escape_codes(void);
2288static int send_clear(void);
2289static int update_term_size(void);
2290static int update_term_size_via_esc(void);
2291static int init_cellbuf(void);
2292static int tb_deinit(void);
2293static int load_terminfo(void);
2294static int load_terminfo_from_path(const char *path, const char *term);
2295static int read_terminfo_path(const char *path);
2296static int parse_terminfo_caps(void);
2297static int load_builtin_caps(void);
2298static const char *get_terminfo_string(int16_t offsets_pos, int16_t offsets_len,
2299 int16_t table_pos, int16_t table_size, int16_t index);
2300static int get_terminfo_int16(int offset, int16_t *val);
2301static int wait_event(struct tb_event *event, int timeout);
2302static int extract_event(struct tb_event *event);
2303static int extract_esc(struct tb_event *event);
2304static int extract_esc_user(struct tb_event *event, int is_post);
2305static int extract_esc_cap(struct tb_event *event);
2306static int extract_esc_mouse(struct tb_event *event);
2307static int resize_cellbufs(void);
2308static void handle_resize(int sig);
2309static int send_attr(uintattr_t fg, uintattr_t bg);
2310static int send_sgr(uint32_t fg, uint32_t bg, int fg_is_default,
2311 int bg_is_default);
2312static int send_cursor_if(int x, int y);
2313static int send_char(int x, int y, uint32_t ch);
2314static int send_cluster(int x, int y, uint32_t *ch, size_t nch);
2315static int convert_num(uint32_t num, char *buf);
2316static int cell_cmp(struct tb_cell *a, struct tb_cell *b);
2317static int cell_copy(struct tb_cell *dst, struct tb_cell *src);
2318static int cell_set(struct tb_cell *cell, uint32_t *ch, size_t nch,
2319 uintattr_t fg, uintattr_t bg);
2320static int cell_reserve_ech(struct tb_cell *cell, size_t n);
2321static int cell_free(struct tb_cell *cell);
2322static int cellbuf_init(struct cellbuf *c, int w, int h);
2323static int cellbuf_free(struct cellbuf *c);
2324static int cellbuf_clear(struct cellbuf *c);
2325static int cellbuf_get(struct cellbuf *c, int x, int y, struct tb_cell **out);
2326static int cellbuf_in_bounds(struct cellbuf *c, int x, int y);
2327static int cellbuf_resize(struct cellbuf *c, int w, int h);
2328static int bytebuf_puts(struct bytebuf *b, const char *str);
2329static int bytebuf_nputs(struct bytebuf *b, const char *str, size_t nstr);
2330static int bytebuf_shift(struct bytebuf *b, size_t n);
2331static int bytebuf_flush(struct bytebuf *b, int fd);
2332static int bytebuf_reserve(struct bytebuf *b, size_t sz);
2333static int bytebuf_free(struct bytebuf *b);
2334static int tb_iswprint_ex(uint32_t ch, int *width);
2335static int tb_cluster_width(uint32_t *ch, size_t nch);
2336
2337int tb_init(void) {
2338 return tb_init_file("/dev/tty");
2339}
2340
2341int tb_init_file(const char *path) {
2342 if (global.initialized) return TB_ERR_INIT_ALREADY;
2343 int ttyfd = open(path, O_RDWR);
2344 if (ttyfd < 0) {
2345 global.last_errno = errno;
2346 return TB_ERR_INIT_OPEN;
2347 }
2348 global.ttyfd_open = 1;
2349 return tb_init_fd(ttyfd);
2350}
2351
2352int tb_init_fd(int ttyfd) {
2353 return tb_init_rwfd(ttyfd, ttyfd);
2354}
2355
2356int tb_init_rwfd(int rfd, int wfd) {
2357 int rv;
2358
2359 tb_reset();
2360 global.ttyfd = isatty(rfd) ? rfd : (isatty(wfd) ? wfd : -1);
2361 global.rfd = rfd;
2362 global.wfd = wfd;
2363
2364 do {
2365 if_err_break(rv, init_term_attrs());
2366 if_err_break(rv, init_term_caps());
2367 if_err_break(rv, init_cap_trie());
2368 if_err_break(rv, init_resize_handler());
2369 if_err_break(rv, send_init_escape_codes());
2370 if_err_break(rv, send_clear());
2371 if_err_break(rv, update_term_size());
2372 if_err_break(rv, init_cellbuf());
2373 global.initialized = 1;
2374 } while (0);
2375
2376 if (rv != TB_OK) tb_deinit();
2377
2378 return rv;
2379}
2380
2381int tb_shutdown(void) {
2382 if_not_init_return();
2383 tb_deinit();
2384 return TB_OK;
2385}
2386
2387int tb_width(void) {
2388 if_not_init_return();
2389 return global.width;
2390}
2391
2392int tb_height(void) {
2393 if_not_init_return();
2394 return global.height;
2395}
2396
2397int tb_clear(void) {
2398 if_not_init_return();
2399 return cellbuf_clear(&global.back);
2400}
2401
2402int tb_set_clear_attrs(uintattr_t fg, uintattr_t bg) {
2403 if_not_init_return();
2404 global.fg = fg;
2405 global.bg = bg;
2406 return TB_OK;
2407}
2408
2409int tb_present(void) {
2410 if_not_init_return();
2411
2412 int rv;
2413
2414 // TODO: Assert global.back.(width,height) == global.front.(width,height)
2415
2416 global.last_x = -1;
2417 global.last_y = -1;
2418
2419 int x, y, i;
2420 for (y = 0; y < global.front.height; y++) {
2421 for (x = 0; x < global.front.width;) {
2422 struct tb_cell *back, *front;
2423 if_err_return(rv, cellbuf_get(&global.back, x, y, &back));
2424 if_err_return(rv, cellbuf_get(&global.front, x, y, &front));
2425
2426 int w;
2427 {
2428#ifdef TB_OPT_EGC
2429 if (back->nech > 0)
2430 w = tb_cluster_width(back->ech, back->nech);
2431 else
2432#endif
2433 w = tb_wcwidth((wchar_t)back->ch);
2434 }
2435 if (w < 1) w = 1; // wcwidth returns -1 for invalid codepoints
2436
2437 if (cell_cmp(back, front) != 0) {
2438 cell_copy(front, back);
2439
2440 send_attr(back->fg, back->bg);
2441 if (w > 1 && x >= global.front.width - (w - 1)) {
2442 // Not enough room for wide char, send spaces
2443 for (i = x; i < global.front.width; i++) {
2444 send_char(i, y, ' ');
2445 }
2446 } else {
2447 {
2448#ifdef TB_OPT_EGC
2449 if (back->nech > 0)
2450 send_cluster(x, y, back->ech, back->nech);
2451 else
2452#endif
2453 send_char(x, y, back->ch);
2454 }
2455
2456 // When wcwidth>1, we need to advance the cursor by more
2457 // than 1, thereby skipping some cells. Set these skipped
2458 // cells to an invalid codepoint in the front buffer, so
2459 // that if this cell is later replaced by a wcwidth==1 char,
2460 // we'll get a cell_cmp diff for the skipped cells and
2461 // properly re-render.
2462 for (i = 1; i < w; i++) {
2463 struct tb_cell *front_wide;
2464 uint32_t invalid = -1;
2465 if_err_return(rv,
2466 cellbuf_get(&global.front, x + i, y, &front_wide));
2467 if_err_return(rv,
2468 cell_set(front_wide, &invalid, 1, -1, -1));
2469 }
2470 }
2471 }
2472 x += w;
2473 }
2474 }
2475
2476 if_err_return(rv, send_cursor_if(global.cursor_x, global.cursor_y));
2477 if_err_return(rv, bytebuf_flush(&global.out, global.wfd));
2478
2479 return TB_OK;
2480}
2481
2482int tb_invalidate(void) {
2483 int rv;
2484 if_not_init_return();
2485 if_err_return(rv, resize_cellbufs());
2486 return TB_OK;
2487}
2488
2489int tb_set_cursor(int cx, int cy) {
2490 if_not_init_return();
2491 int rv;
2492 if (cx < 0) cx = 0;
2493 if (cy < 0) cy = 0;
2494 if (global.cursor_x == -1) {
2495 if_err_return(rv,
2496 bytebuf_puts(&global.out, global.caps[TB_CAP_SHOW_CURSOR]));
2497 }
2498 if_err_return(rv, send_cursor_if(cx, cy));
2499 global.cursor_x = cx;
2500 global.cursor_y = cy;
2501 return TB_OK;
2502}
2503
2504int tb_hide_cursor(void) {
2505 if_not_init_return();
2506 int rv;
2507 if (global.cursor_x >= 0) {
2508 if_err_return(rv,
2509 bytebuf_puts(&global.out, global.caps[TB_CAP_HIDE_CURSOR]));
2510 }
2511 global.cursor_x = -1;
2512 global.cursor_y = -1;
2513 return TB_OK;
2514}
2515
2516int tb_set_cell(int x, int y, uint32_t ch, uintattr_t fg, uintattr_t bg) {
2517 return tb_set_cell_ex(x, y, &ch, 1, fg, bg);
2518}
2519
2520int tb_set_cell_ex(int x, int y, uint32_t *ch, size_t nch, uintattr_t fg,
2521 uintattr_t bg) {
2522 if_not_init_return();
2523 int rv;
2524 struct tb_cell *cell;
2525 if_err_return(rv, cellbuf_get(&global.back, x, y, &cell));
2526 if_err_return(rv, cell_set(cell, ch, nch, fg, bg));
2527 return TB_OK;
2528}
2529
2530int tb_get_cell(int x, int y, int back, struct tb_cell **cell) {
2531 if_not_init_return();
2532 return cellbuf_get(back ? &global.back : &global.front, x, y, cell);
2533}
2534
2535int tb_extend_cell(int x, int y, uint32_t ch) {
2536 if_not_init_return();
2537#ifdef TB_OPT_EGC
2538 // TODO: iswprint ch?
2539 int rv;
2540 struct tb_cell *cell;
2541 size_t nech;
2542 if_err_return(rv, cellbuf_get(&global.back, x, y, &cell));
2543 if (cell->nech > 0) { // append to ech
2544 nech = cell->nech + 1;
2545 if_err_return(rv, cell_reserve_ech(cell, nech + 1));
2546 cell->ech[nech - 1] = ch;
2547 } else { // make new ech
2548 nech = 2;
2549 if_err_return(rv, cell_reserve_ech(cell, nech + 1));
2550 cell->ech[0] = cell->ch;
2551 cell->ech[1] = ch;
2552 }
2553 cell->ech[nech] = '\0';
2554 cell->nech = nech;
2555 return TB_OK;
2556#else
2557 (void)x;
2558 (void)y;
2559 (void)ch;
2560 return TB_ERR;
2561#endif
2562}
2563
2564int tb_set_input_mode(int mode) {
2565 if_not_init_return();
2566
2567 if (mode == TB_INPUT_CURRENT) return global.input_mode;
2568
2569 int esc_or_alt = TB_INPUT_ESC | TB_INPUT_ALT;
2570 if ((mode & esc_or_alt) == 0) {
2571 // neither specified; flip on ESC
2572 mode |= TB_INPUT_ESC;
2573 } else if ((mode & esc_or_alt) == esc_or_alt) {
2574 // both specified; flip off ALT
2575 mode &= ~TB_INPUT_ALT;
2576 }
2577
2578 if (mode & TB_INPUT_MOUSE) {
2579 bytebuf_puts(&global.out, TB_HARDCAP_ENTER_MOUSE);
2580 bytebuf_flush(&global.out, global.wfd);
2581 } else {
2582 bytebuf_puts(&global.out, TB_HARDCAP_EXIT_MOUSE);
2583 bytebuf_flush(&global.out, global.wfd);
2584 }
2585
2586 global.input_mode = mode;
2587 return TB_OK;
2588}
2589
2590int tb_set_output_mode(int mode) {
2591 if_not_init_return();
2592 switch (mode) {
2593 case TB_OUTPUT_CURRENT:
2594 return global.output_mode;
2595 case TB_OUTPUT_NORMAL:
2596 case TB_OUTPUT_256:
2597 case TB_OUTPUT_216:
2598 case TB_OUTPUT_GRAYSCALE:
2599#if TB_OPT_ATTR_W >= 32
2600 case TB_OUTPUT_TRUECOLOR:
2601#endif
2602 global.last_fg = ~global.fg;
2603 global.last_bg = ~global.bg;
2604 global.output_mode = mode;
2605 return TB_OK;
2606 }
2607 return TB_ERR;
2608}
2609
2610int tb_peek_event(struct tb_event *event, int timeout_ms) {
2611 if_not_init_return();
2612 return wait_event(event, timeout_ms);
2613}
2614
2615int tb_poll_event(struct tb_event *event) {
2616 if_not_init_return();
2617 return wait_event(event, -1);
2618}
2619
2620int tb_get_fds(int *ttyfd, int *resizefd) {
2621 if_not_init_return();
2622
2623 *ttyfd = global.rfd;
2624 *resizefd = global.resize_pipefd[0];
2625
2626 return TB_OK;
2627}
2628
2629int tb_print(int x, int y, uintattr_t fg, uintattr_t bg, const char *str) {
2630 return tb_print_ex(x, y, fg, bg, NULL, str);
2631}
2632
2633int tb_print_ex(int x, int y, uintattr_t fg, uintattr_t bg, size_t *out_w,
2634 const char *str) {
2635 int rv, w, ix, x_prev;
2636 uint32_t uni;
2637
2638 if_not_init_return();
2639
2640 if (!cellbuf_in_bounds(&global.back, x, y)) {
2641 return TB_ERR_OUT_OF_BOUNDS;
2642 }
2643
2644 ix = x;
2645 x_prev = x;
2646 if (out_w) *out_w = 0;
2647
2648 while (*str) {
2649 rv = tb_utf8_char_to_unicode(&uni, str);
2650
2651 if (rv < 0) {
2652 uni = 0xfffd; // replace invalid UTF-8 char with U+FFFD
2653 str += rv * -1;
2654 } else if (rv > 0) {
2655 str += rv;
2656 } else {
2657 break; // shouldn't get here
2658 }
2659
2660 if (uni == '\n') { // TODO: \r, \t, \v, \f, etc?
2661 x = ix;
2662 x_prev = x;
2663 y += 1;
2664 continue;
2665 } else if (!tb_iswprint_ex(uni, &w)) {
2666 uni = 0xfffd; // replace non-printable with U+FFFD
2667 w = 1;
2668 }
2669
2670 if (w < 0) {
2671 return TB_ERR; // shouldn't happen if iswprint
2672 } else if (w == 0) { // combining character
2673 if (cellbuf_in_bounds(&global.back, x_prev, y)) {
2674 if_err_return(rv, tb_extend_cell(x_prev, y, uni));
2675 }
2676 } else {
2677 if (cellbuf_in_bounds(&global.back, x, y)) {
2678 if_err_return(rv, tb_set_cell(x, y, uni, fg, bg));
2679 }
2680 x_prev = x;
2681 x += w;
2682 if (out_w) *out_w += w;
2683 }
2684 }
2685
2686 return TB_OK;
2687}
2688
2689int tb_printf(int x, int y, uintattr_t fg, uintattr_t bg, const char *fmt,
2690 ...) {
2691 int rv;
2692 va_list vl;
2693 va_start(vl, fmt);
2694 rv = tb_printf_inner(x, y, fg, bg, NULL, fmt, vl);
2695 va_end(vl);
2696 return rv;
2697}
2698
2699int tb_printf_ex(int x, int y, uintattr_t fg, uintattr_t bg, size_t *out_w,
2700 const char *fmt, ...) {
2701 int rv;
2702 va_list vl;
2703 va_start(vl, fmt);
2704 rv = tb_printf_inner(x, y, fg, bg, out_w, fmt, vl);
2705 va_end(vl);
2706 return rv;
2707}
2708
2709int tb_send(const char *buf, size_t nbuf) {
2710 return bytebuf_nputs(&global.out, buf, nbuf);
2711}
2712
2713int tb_sendf(const char *fmt, ...) {
2714 int rv;
2715 char buf[TB_OPT_PRINTF_BUF];
2716 va_list vl;
2717 va_start(vl, fmt);
2718 rv = vsnprintf(buf, sizeof(buf), fmt, vl);
2719 va_end(vl);
2720 if (rv < 0 || rv >= (int)sizeof(buf)) {
2721 return TB_ERR;
2722 }
2723 return tb_send(buf, (size_t)rv);
2724}
2725
2726int tb_set_func(int fn_type, int (*fn)(struct tb_event *, size_t *)) {
2727 switch (fn_type) {
2728 case TB_FUNC_EXTRACT_PRE:
2729 global.fn_extract_esc_pre = fn;
2730 return TB_OK;
2731 case TB_FUNC_EXTRACT_POST:
2732 global.fn_extract_esc_post = fn;
2733 return TB_OK;
2734 }
2735 return TB_ERR;
2736}
2737
2738struct tb_cell *tb_cell_buffer(void) {
2739 if (!global.initialized) return NULL;
2740 return global.back.cells;
2741}
2742
2743int tb_utf8_char_length(char c) {
2744 return utf8_length[(unsigned char)c];
2745}
2746
2747int tb_utf8_char_to_unicode(uint32_t *out, const char *c) {
2748 if (*c == '\0') return 0;
2749
2750 int i;
2751 unsigned char len = tb_utf8_char_length(*c);
2752 unsigned char mask = utf8_mask[len - 1];
2753 uint32_t result = c[0] & mask;
2754 for (i = 1; i < len && c[i] != '\0'; ++i) {
2755 result <<= 6;
2756 result |= c[i] & 0x3f;
2757 }
2758
2759 if (i != len) return i * -1;
2760
2761 *out = result;
2762 return (int)len;
2763}
2764
2765int tb_utf8_unicode_to_char(char *out, uint32_t c) {
2766 int len = 0;
2767 int first;
2768 int i;
2769
2770 if (c < 0x80) {
2771 first = 0;
2772 len = 1;
2773 } else if (c < 0x800) {
2774 first = 0xc0;
2775 len = 2;
2776 } else if (c < 0x10000) {
2777 first = 0xe0;
2778 len = 3;
2779 } else if (c < 0x200000) {
2780 first = 0xf0;
2781 len = 4;
2782 } else if (c < 0x4000000) {
2783 first = 0xf8;
2784 len = 5;
2785 } else {
2786 first = 0xfc;
2787 len = 6;
2788 }
2789
2790 for (i = len - 1; i > 0; --i) {
2791 out[i] = (c & 0x3f) | 0x80;
2792 c >>= 6;
2793 }
2794 out[0] = c | first;
2795 out[len] = '\0';
2796
2797 return len;
2798}
2799
2800int tb_last_errno(void) {
2801 return global.last_errno;
2802}
2803
2804const char *tb_strerror(int err) {
2805 switch (err) {
2806 case TB_OK:
2807 return "Success";
2808 case TB_ERR_NEED_MORE:
2809 return "Not enough input";
2810 case TB_ERR_INIT_ALREADY:
2811 return "Termbox initialized already";
2812 case TB_ERR_MEM:
2813 return "Out of memory";
2814 case TB_ERR_NO_EVENT:
2815 return "No event";
2816 case TB_ERR_NO_TERM:
2817 return "No TERM in environment";
2818 case TB_ERR_NOT_INIT:
2819 return "Termbox not initialized";
2820 case TB_ERR_OUT_OF_BOUNDS:
2821 return "Out of bounds";
2822 case TB_ERR_UNSUPPORTED_TERM:
2823 return "Unsupported terminal";
2824 case TB_ERR_CAP_COLLISION:
2825 return "Termcaps collision";
2826 case TB_ERR_RESIZE_SSCANF:
2827 return "Terminal width/height not received by sscanf() after "
2828 "resize";
2829 case TB_ERR:
2830 case TB_ERR_INIT_OPEN:
2831 case TB_ERR_READ:
2832 case TB_ERR_RESIZE_IOCTL:
2833 case TB_ERR_RESIZE_PIPE:
2834 case TB_ERR_RESIZE_SIGACTION:
2835 case TB_ERR_POLL:
2836 case TB_ERR_TCGETATTR:
2837 case TB_ERR_TCSETATTR:
2838 case TB_ERR_RESIZE_WRITE:
2839 case TB_ERR_RESIZE_POLL:
2840 case TB_ERR_RESIZE_READ:
2841 default:
2842 strerror_r(global.last_errno, global.errbuf, sizeof(global.errbuf));
2843 return (const char *)global.errbuf;
2844 }
2845}
2846
2847int tb_has_truecolor(void) {
2848#if TB_OPT_ATTR_W >= 32
2849 return 1;
2850#else
2851 return 0;
2852#endif
2853}
2854
2855int tb_has_egc(void) {
2856#ifdef TB_OPT_EGC
2857 return 1;
2858#else
2859 return 0;
2860#endif
2861}
2862
2863int tb_attr_width(void) {
2864 return TB_OPT_ATTR_W;
2865}
2866
2867const char *tb_version(void) {
2868 return TB_VERSION_STR;
2869}
2870
2871static int tb_reset(void) {
2872 int ttyfd_open = global.ttyfd_open;
2873 memset(&global, 0, sizeof(global));
2874 global.ttyfd = -1;
2875 global.rfd = -1;
2876 global.wfd = -1;
2877 global.ttyfd_open = ttyfd_open;
2878 global.resize_pipefd[0] = -1;
2879 global.resize_pipefd[1] = -1;
2880 global.width = -1;
2881 global.height = -1;
2882 global.cursor_x = -1;
2883 global.cursor_y = -1;
2884 global.last_x = -1;
2885 global.last_y = -1;
2886 global.fg = TB_DEFAULT;
2887 global.bg = TB_DEFAULT;
2888 global.last_fg = ~global.fg;
2889 global.last_bg = ~global.bg;
2890 global.input_mode = TB_INPUT_ESC;
2891 global.output_mode = TB_OUTPUT_NORMAL;
2892 return TB_OK;
2893}
2894
2895static int init_term_attrs(void) {
2896 if (global.ttyfd < 0) return TB_OK;
2897
2898 if (tcgetattr(global.ttyfd, &global.orig_tios) != 0) {
2899 global.last_errno = errno;
2900 return TB_ERR_TCGETATTR;
2901 }
2902
2903 struct termios tios;
2904 memcpy(&tios, &global.orig_tios, sizeof(tios));
2905 global.has_orig_tios = 1;
2906
2907 cfmakeraw(&tios);
2908 tios.c_cc[VMIN] = 1;
2909 tios.c_cc[VTIME] = 0;
2910
2911 if (tcsetattr(global.ttyfd, TCSAFLUSH, &tios) != 0) {
2912 global.last_errno = errno;
2913 return TB_ERR_TCSETATTR;
2914 }
2915
2916 return TB_OK;
2917}
2918
2919int tb_printf_inner(int x, int y, uintattr_t fg, uintattr_t bg, size_t *out_w,
2920 const char *fmt, va_list vl) {
2921 int rv;
2922 char buf[TB_OPT_PRINTF_BUF];
2923 rv = vsnprintf(buf, sizeof(buf), fmt, vl);
2924 if (rv < 0 || rv >= (int)sizeof(buf)) {
2925 return TB_ERR;
2926 }
2927 return tb_print_ex(x, y, fg, bg, out_w, buf);
2928}
2929
2930static int init_term_caps(void) {
2931 if (load_terminfo() == TB_OK) {
2932 return parse_terminfo_caps();
2933 }
2934 return load_builtin_caps();
2935}
2936
2937static int init_cap_trie(void) {
2938 int rv, i;
2939
2940 // Add caps from terminfo or built-in
2941 //
2942 // Collisions are expected as some terminfo entries have dupes. (For
2943 // example, att605-pc collides on TB_CAP_F4 and TB_CAP_DELETE.) First cap
2944 // in TB_CAP_* index order will win.
2945 //
2946 // TODO: Reorder TB_CAP_* so more critical caps come first.
2947 for (i = 0; i < TB_CAP__COUNT_KEYS; i++) {
2948 rv = cap_trie_add(global.caps[i], tb_key_i(i), 0);
2949 if (rv != TB_OK && rv != TB_ERR_CAP_COLLISION) return rv;
2950 }
2951
2952 // Add built-in mod caps
2953 //
2954 // Collisions are OK here as well. This can happen if global.caps collides
2955 // with builtin_mod_caps. It is desirable to give precedence to global.caps
2956 // here.
2957 for (i = 0; builtin_mod_caps[i].cap != NULL; i++) {
2958 rv = cap_trie_add(builtin_mod_caps[i].cap, builtin_mod_caps[i].key,
2959 builtin_mod_caps[i].mod);
2960 if (rv != TB_OK && rv != TB_ERR_CAP_COLLISION) return rv;
2961 }
2962
2963 return TB_OK;
2964}
2965
2966static int cap_trie_add(const char *cap, uint16_t key, uint8_t mod) {
2967 struct cap_trie *next, *node = &global.cap_trie;
2968 size_t i, j;
2969
2970 if (!cap || strlen(cap) <= 0) return TB_OK; // Nothing to do for empty caps
2971
2972 for (i = 0; cap[i] != '\0'; i++) {
2973 char c = cap[i];
2974 next = NULL;
2975
2976 // Check if c is already a child of node
2977 for (j = 0; j < node->nchildren; j++) {
2978 if (node->children[j].c == c) {
2979 next = &node->children[j];
2980 break;
2981 }
2982 }
2983 if (!next) {
2984 // We need to add a new child to node
2985 node->nchildren += 1;
2986 node->children = (struct cap_trie *)tb_realloc(node->children,
2987 sizeof(*node) * node->nchildren);
2988 if (!node->children) {
2989 return TB_ERR_MEM;
2990 }
2991 next = &node->children[node->nchildren - 1];
2992 memset(next, 0, sizeof(*next));
2993 next->c = c;
2994 }
2995
2996 // Continue
2997 node = next;
2998 }
2999
3000 if (node->is_leaf) {
3001 // Already a leaf here
3002 return TB_ERR_CAP_COLLISION;
3003 }
3004
3005 node->is_leaf = 1;
3006 node->key = key;
3007 node->mod = mod;
3008 return TB_OK;
3009}
3010
3011static int cap_trie_find(const char *buf, size_t nbuf, struct cap_trie **last,
3012 size_t *depth) {
3013 struct cap_trie *next, *node = &global.cap_trie;
3014 size_t i, j;
3015 *last = node;
3016 *depth = 0;
3017 for (i = 0; i < nbuf; i++) {
3018 char c = buf[i];
3019 next = NULL;
3020
3021 // Find c in node.children
3022 for (j = 0; j < node->nchildren; j++) {
3023 if (node->children[j].c == c) {
3024 next = &node->children[j];
3025 break;
3026 }
3027 }
3028 if (!next) {
3029 // Not found
3030 return TB_OK;
3031 }
3032 node = next;
3033 *last = node;
3034 *depth += 1;
3035 if (node->is_leaf && node->nchildren < 1) {
3036 break;
3037 }
3038 }
3039 return TB_OK;
3040}
3041
3042static int cap_trie_deinit(struct cap_trie *node) {
3043 size_t j;
3044 for (j = 0; j < node->nchildren; j++) {
3045 cap_trie_deinit(&node->children[j]);
3046 }
3047 if (node->children) tb_free(node->children);
3048 memset(node, 0, sizeof(*node));
3049 return TB_OK;
3050}
3051
3052static int init_resize_handler(void) {
3053 if (pipe(global.resize_pipefd) != 0) {
3054 global.last_errno = errno;
3055 return TB_ERR_RESIZE_PIPE;
3056 }
3057
3058 struct sigaction sa;
3059 memset(&sa, 0, sizeof(sa));
3060 sa.sa_handler = handle_resize;
3061 if (sigaction(SIGWINCH, &sa, NULL) != 0) {
3062 global.last_errno = errno;
3063 return TB_ERR_RESIZE_SIGACTION;
3064 }
3065
3066 return TB_OK;
3067}
3068
3069static int send_init_escape_codes(void) {
3070 int rv;
3071 if_err_return(rv, bytebuf_puts(&global.out, global.caps[TB_CAP_ENTER_CA]));
3072 if_err_return(rv,
3073 bytebuf_puts(&global.out, global.caps[TB_CAP_ENTER_KEYPAD]));
3074 if_err_return(rv,
3075 bytebuf_puts(&global.out, global.caps[TB_CAP_HIDE_CURSOR]));
3076 return TB_OK;
3077}
3078
3079static int send_clear(void) {
3080 int rv;
3081
3082 if_err_return(rv, send_attr(global.fg, global.bg));
3083 if_err_return(rv,
3084 bytebuf_puts(&global.out, global.caps[TB_CAP_CLEAR_SCREEN]));
3085
3086 if_err_return(rv, send_cursor_if(global.cursor_x, global.cursor_y));
3087 if_err_return(rv, bytebuf_flush(&global.out, global.wfd));
3088
3089 global.last_x = -1;
3090 global.last_y = -1;
3091
3092 return TB_OK;
3093}
3094
3095static int update_term_size(void) {
3096 int rv, ioctl_errno;
3097
3098 if (global.ttyfd < 0) return TB_OK;
3099
3100 struct winsize sz;
3101 memset(&sz, 0, sizeof(sz));
3102
3103 // Try ioctl TIOCGWINSZ
3104 if (ioctl(global.ttyfd, TIOCGWINSZ, &sz) == 0) {
3105 global.width = sz.ws_col;
3106 global.height = sz.ws_row;
3107 return TB_OK;
3108 }
3109 ioctl_errno = errno;
3110
3111 // Try >cursor(9999,9999), >u7, <u6
3112 if_ok_return(rv, update_term_size_via_esc());
3113
3114 global.last_errno = ioctl_errno;
3115 return TB_ERR_RESIZE_IOCTL;
3116}
3117
3118static int update_term_size_via_esc(void) {
3119#ifndef TB_RESIZE_FALLBACK_MS
3120#define TB_RESIZE_FALLBACK_MS 1000
3121#endif
3122
3123 char move_and_report[] = "\x1b[9999;9999H\x1b[6n";
3124 ssize_t write_rv =
3125 write(global.wfd, move_and_report, strlen(move_and_report));
3126 if (write_rv != (ssize_t)strlen(move_and_report)) {
3127 return TB_ERR_RESIZE_WRITE;
3128 }
3129
3130 fd_set fds;
3131 FD_ZERO(&fds);
3132 FD_SET(global.rfd, &fds);
3133
3134 struct timeval timeout;
3135 timeout.tv_sec = 0;
3136 timeout.tv_usec = TB_RESIZE_FALLBACK_MS * 1000;
3137
3138 int select_rv = select(global.rfd + 1, &fds, NULL, NULL, &timeout);
3139
3140 if (select_rv != 1) {
3141 global.last_errno = errno;
3142 return TB_ERR_RESIZE_POLL;
3143 }
3144
3145 char buf[TB_OPT_READ_BUF];
3146 ssize_t read_rv = read(global.rfd, buf, sizeof(buf) - 1);
3147 if (read_rv < 1) {
3148 global.last_errno = errno;
3149 return TB_ERR_RESIZE_READ;
3150 }
3151 buf[read_rv] = '\0';
3152
3153 int rw, rh;
3154 if (sscanf(buf, "\x1b[%d;%dR", &rh, &rw) != 2) {
3155 return TB_ERR_RESIZE_SSCANF;
3156 }
3157
3158 global.width = rw;
3159 global.height = rh;
3160 return TB_OK;
3161}
3162
3163static int init_cellbuf(void) {
3164 int rv;
3165 if_err_return(rv, cellbuf_init(&global.back, global.width, global.height));
3166 if_err_return(rv, cellbuf_init(&global.front, global.width, global.height));
3167 if_err_return(rv, cellbuf_clear(&global.back));
3168 if_err_return(rv, cellbuf_clear(&global.front));
3169 return TB_OK;
3170}
3171
3172static int tb_deinit(void) {
3173 if (global.caps[0] != NULL && global.wfd >= 0) {
3174 bytebuf_puts(&global.out, global.caps[TB_CAP_SHOW_CURSOR]);
3175 bytebuf_puts(&global.out, global.caps[TB_CAP_SGR0]);
3176 bytebuf_puts(&global.out, global.caps[TB_CAP_CLEAR_SCREEN]);
3177 bytebuf_puts(&global.out, global.caps[TB_CAP_EXIT_CA]);
3178 bytebuf_puts(&global.out, global.caps[TB_CAP_EXIT_KEYPAD]);
3179 bytebuf_puts(&global.out, TB_HARDCAP_EXIT_MOUSE);
3180 bytebuf_flush(&global.out, global.wfd);
3181 }
3182 if (global.ttyfd >= 0) {
3183 if (global.has_orig_tios) {
3184 tcsetattr(global.ttyfd, TCSAFLUSH, &global.orig_tios);
3185 }
3186 if (global.ttyfd_open) {
3187 close(global.ttyfd);
3188 global.ttyfd_open = 0;
3189 }
3190 }
3191
3192 struct sigaction sa;
3193 memset(&sa, 0, sizeof(sa));
3194 sa.sa_handler = SIG_DFL;
3195 sigaction(SIGWINCH, &sa, NULL);
3196 if (global.resize_pipefd[0] >= 0) close(global.resize_pipefd[0]);
3197 if (global.resize_pipefd[1] >= 0) close(global.resize_pipefd[1]);
3198
3199 cellbuf_free(&global.back);
3200 cellbuf_free(&global.front);
3201 bytebuf_free(&global.in);
3202 bytebuf_free(&global.out);
3203
3204 if (global.terminfo) tb_free(global.terminfo);
3205
3206 cap_trie_deinit(&global.cap_trie);
3207
3208 tb_reset();
3209 return TB_OK;
3210}
3211
3212static int load_terminfo(void) {
3213 int rv;
3214 char tmp[TB_PATH_MAX];
3215
3216 // See terminfo(5) "Fetching Compiled Descriptions" for a description of
3217 // this behavior. Some of these paths are compile-time ncurses options, so
3218 // best guesses are used here.
3219 const char *term = getenv("TERM");
3220 if (!term) return TB_ERR;
3221
3222 // If TERMINFO is set, try that directory first
3223 const char *terminfo = getenv("TERMINFO");
3224 if (terminfo) if_ok_return(rv, load_terminfo_from_path(terminfo, term));
3225
3226 // Next try ~/.terminfo
3227 const char *home = getenv("HOME");
3228 if (home) {
3229 snprintf_or_return(rv, tmp, sizeof(tmp), "%s/.terminfo", home);
3230 if_ok_return(rv, load_terminfo_from_path(tmp, term));
3231 }
3232
3233 // Next try TERMINFO_DIRS
3234 //
3235 // Note, empty entries are supposed to be interpretted as the "compiled-in
3236 // default", which is of course system-dependent. Previously /etc/terminfo
3237 // was used here. Let's skip empty entries altogether rather than give
3238 // precedence to a guess, and check common paths after this loop.
3239 const char *dirs = getenv("TERMINFO_DIRS");
3240 if (dirs) {
3241 snprintf_or_return(rv, tmp, sizeof(tmp), "%s", dirs);
3242 char *dir = strtok(tmp, ":");
3243 while (dir) {
3244 const char *cdir = dir;
3245 if (*cdir != '\0') {
3246 if_ok_return(rv, load_terminfo_from_path(cdir, term));
3247 }
3248 dir = strtok(NULL, ":");
3249 }
3250 }
3251
3252#ifdef TB_TERMINFO_DIR
3253 if_ok_return(rv, load_terminfo_from_path(TB_TERMINFO_DIR, term));
3254#endif
3255 if_ok_return(rv, load_terminfo_from_path("/usr/local/etc/terminfo", term));
3256 if_ok_return(rv,
3257 load_terminfo_from_path("/usr/local/share/terminfo", term));
3258 if_ok_return(rv, load_terminfo_from_path("/usr/local/lib/terminfo", term));
3259 if_ok_return(rv, load_terminfo_from_path("/etc/terminfo", term));
3260 if_ok_return(rv, load_terminfo_from_path("/usr/share/terminfo", term));
3261 if_ok_return(rv, load_terminfo_from_path("/usr/lib/terminfo", term));
3262 if_ok_return(rv, load_terminfo_from_path("/usr/share/lib/terminfo", term));
3263 if_ok_return(rv, load_terminfo_from_path("/lib/terminfo", term));
3264
3265 return TB_ERR;
3266}
3267
3268static int load_terminfo_from_path(const char *path, const char *term) {
3269 int rv;
3270 char tmp[TB_PATH_MAX];
3271
3272 // Look for term at this terminfo location, e.g., <terminfo>/x/xterm
3273 snprintf_or_return(rv, tmp, sizeof(tmp), "%s/%c/%s", path, term[0], term);
3274 if_ok_return(rv, read_terminfo_path(tmp));
3275
3276#ifdef __APPLE__
3277 // Try the Darwin equivalent path, e.g., <terminfo>/78/xterm
3278 snprintf_or_return(rv, tmp, sizeof(tmp), "%s/%x/%s", path, term[0], term);
3279 return read_terminfo_path(tmp);
3280#endif
3281
3282 return TB_ERR;
3283}
3284
3285static int read_terminfo_path(const char *path) {
3286 FILE *fp = fopen(path, "rb");
3287 if (!fp) return TB_ERR;
3288
3289 struct stat st;
3290 if (fstat(fileno(fp), &st) != 0) {
3291 fclose(fp);
3292 return TB_ERR;
3293 }
3294
3295 size_t fsize = st.st_size;
3296 char *data = (char *)tb_malloc(fsize);
3297 if (!data) {
3298 fclose(fp);
3299 return TB_ERR;
3300 }
3301
3302 if (fread(data, 1, fsize, fp) != fsize) {
3303 fclose(fp);
3304 tb_free(data);
3305 return TB_ERR;
3306 }
3307
3308 global.terminfo = data;
3309 global.nterminfo = fsize;
3310
3311 fclose(fp);
3312 return TB_OK;
3313}
3314
3315static int parse_terminfo_caps(void) {
3316 // See term(5) "LEGACY STORAGE FORMAT" and "EXTENDED STORAGE FORMAT" for a
3317 // description of this behavior.
3318
3319 // Ensure there's at least a header's worth of data
3320 if (global.nterminfo < 6 * (int)sizeof(int16_t)) return TB_ERR;
3321
3322 int16_t magic_number, nbytes_names, nbytes_bools, num_ints, num_offsets,
3323 nbytes_strings;
3324 size_t nbytes_header = 6 * sizeof(int16_t);
3325 // header[0] the magic number (octal 0432 or 01036)
3326 // header[1] the size, in bytes, of the names section
3327 // header[2] the number of bytes in the boolean section
3328 // header[3] the number of short integers in the numbers section
3329 // header[4] the number of offsets (short integers) in the strings section
3330 // header[5] the size, in bytes, of the string table
3331 get_terminfo_int16(0 * sizeof(int16_t), &magic_number);
3332 get_terminfo_int16(1 * sizeof(int16_t), &nbytes_names);
3333 get_terminfo_int16(2 * sizeof(int16_t), &nbytes_bools);
3334 get_terminfo_int16(3 * sizeof(int16_t), &num_ints);
3335 get_terminfo_int16(4 * sizeof(int16_t), &num_offsets);
3336 get_terminfo_int16(5 * sizeof(int16_t), &nbytes_strings);
3337
3338 // Legacy ints are 16-bit, extended ints are 32-bit
3339 const int bytes_per_int = magic_number == 01036 ? 4 // 32-bit
3340 : 2; // 16-bit
3341
3342 // > Between the boolean section and the number section, a null byte will be
3343 // > inserted, if necessary, to ensure that the number section begins on an
3344 // > even byte
3345 const int align_offset = (nbytes_names + nbytes_bools) % 2 != 0 ? 1 : 0;
3346
3347 const int pos_str_offsets =
3348 nbytes_header // header (12 bytes)
3349 + nbytes_names // length of names section
3350 + nbytes_bools // length of boolean section
3351 + align_offset +
3352 (num_ints * bytes_per_int); // length of numbers section
3353
3354 const int pos_str_table =
3355 pos_str_offsets +
3356 (num_offsets * sizeof(int16_t)); // length of string offsets table
3357
3358 // Load caps
3359 int i;
3360 for (i = 0; i < TB_CAP__COUNT; i++) {
3361 const char *cap = get_terminfo_string(pos_str_offsets, num_offsets,
3362 pos_str_table, nbytes_strings, terminfo_cap_indexes[i]);
3363 if (!cap) {
3364 // Something is not right
3365 return TB_ERR;
3366 }
3367 global.caps[i] = cap;
3368 }
3369
3370 return TB_OK;
3371}
3372
3373static int load_builtin_caps(void) {
3374 int i, j;
3375 const char *term = getenv("TERM");
3376
3377 if (!term) return TB_ERR_NO_TERM;
3378
3379 // Check for exact TERM match
3380 for (i = 0; builtin_terms[i].name != NULL; i++) {
3381 if (strcmp(term, builtin_terms[i].name) == 0) {
3382 for (j = 0; j < TB_CAP__COUNT; j++) {
3383 global.caps[j] = builtin_terms[i].caps[j];
3384 }
3385 return TB_OK;
3386 }
3387 }
3388
3389 // Check for partial TERM or alias match
3390 for (i = 0; builtin_terms[i].name != NULL; i++) {
3391 if (strstr(term, builtin_terms[i].name) != NULL ||
3392 (*(builtin_terms[i].alias) != '\0' &&
3393 strstr(term, builtin_terms[i].alias) != NULL))
3394 {
3395 for (j = 0; j < TB_CAP__COUNT; j++) {
3396 global.caps[j] = builtin_terms[i].caps[j];
3397 }
3398 return TB_OK;
3399 }
3400 }
3401
3402 return TB_ERR_UNSUPPORTED_TERM;
3403}
3404
3405static const char *get_terminfo_string(int16_t offsets_pos, int16_t offsets_len,
3406 int16_t table_pos, int16_t table_size, int16_t index) {
3407 if (index >= offsets_len) {
3408 // An index beyond the offset table indicates absent
3409 // See `convert_strings` in tinfo `read_entry.c`
3410 return "";
3411 }
3412
3413 int16_t table_offset;
3414 int table_offset_offset = (int)offsets_pos + (index * (int)sizeof(int16_t));
3415 if (get_terminfo_int16(table_offset_offset, &table_offset) != TB_OK) {
3416 // offset beyond end of terminfo entry
3417 // Truncated/corrupt terminfo entry?
3418 return NULL;
3419 }
3420
3421 if (table_offset < 0 || table_offset >= table_size) {
3422 // A negative offset indicates absent
3423 // An offset beyond the string table indicates absent
3424 // See `convert_strings` in tinfo `read_entry.c`
3425 return "";
3426 }
3427
3428 int str_offset = (int)table_pos + (int)table_offset;
3429 if (str_offset >= (int)global.nterminfo) {
3430 // string beyond end of terminfo entry
3431 // Truncated/corrupt terminfo entry?
3432 return NULL;
3433 }
3434
3435 return (const char *)(global.terminfo + str_offset);
3436}
3437
3438static int get_terminfo_int16(int offset, int16_t *val) {
3439 if (offset < 0 || offset + sizeof(int16_t) > global.nterminfo) {
3440 *val = -1;
3441 return TB_ERR;
3442 }
3443 memcpy(val, global.terminfo + offset, sizeof(int16_t));
3444 return TB_OK;
3445}
3446
3447static int wait_event(struct tb_event *event, int timeout) {
3448 int rv;
3449 char buf[TB_OPT_READ_BUF];
3450
3451 memset(event, 0, sizeof(*event));
3452 if_ok_return(rv, extract_event(event));
3453
3454 fd_set fds;
3455 struct timeval tv;
3456 tv.tv_sec = timeout / 1000;
3457 tv.tv_usec = (timeout - (tv.tv_sec * 1000)) * 1000;
3458
3459 do {
3460 FD_ZERO(&fds);
3461 FD_SET(global.rfd, &fds);
3462 FD_SET(global.resize_pipefd[0], &fds);
3463
3464 int maxfd = global.resize_pipefd[0] > global.rfd
3465 ? global.resize_pipefd[0]
3466 : global.rfd;
3467
3468 int select_rv =
3469 select(maxfd + 1, &fds, NULL, NULL, (timeout < 0) ? NULL : &tv);
3470
3471 if (select_rv < 0) {
3472 // Let EINTR/EAGAIN bubble up
3473 global.last_errno = errno;
3474 return TB_ERR_POLL;
3475 } else if (select_rv == 0) {
3476 return TB_ERR_NO_EVENT;
3477 }
3478
3479 int tty_has_events = (FD_ISSET(global.rfd, &fds));
3480 int resize_has_events = (FD_ISSET(global.resize_pipefd[0], &fds));
3481
3482 if (tty_has_events) {
3483 ssize_t read_rv = read(global.rfd, buf, sizeof(buf));
3484 if (read_rv < 0) {
3485 global.last_errno = errno;
3486 return TB_ERR_READ;
3487 } else if (read_rv > 0) {
3488 bytebuf_nputs(&global.in, buf, read_rv);
3489 }
3490 }
3491
3492 if (resize_has_events) {
3493 int ignore = 0;
3494 read(global.resize_pipefd[0], &ignore, sizeof(ignore));
3495 // TODO: Harden against errors encountered mid-resize
3496 if_err_return(rv, update_term_size());
3497 if_err_return(rv, resize_cellbufs());
3498 event->type = TB_EVENT_RESIZE;
3499 event->w = global.width;
3500 event->h = global.height;
3501 return TB_OK;
3502 }
3503
3504 memset(event, 0, sizeof(*event));
3505 if_ok_return(rv, extract_event(event));
3506 } while (timeout == -1);
3507
3508 return rv;
3509}
3510
3511static int extract_event(struct tb_event *event) {
3512 int rv;
3513 struct bytebuf *in = &global.in;
3514
3515 if (in->len == 0) return TB_ERR;
3516
3517 if (in->buf[0] == '\x1b') {
3518 // Escape sequence?
3519 // In TB_INPUT_ESC, skip if the buffer is a single escape char
3520 if (!((global.input_mode & TB_INPUT_ESC) && in->len == 1)) {
3521 if_ok_or_need_more_return(rv, extract_esc(event));
3522 }
3523
3524 // Escape key?
3525 if (global.input_mode & TB_INPUT_ESC) {
3526 event->type = TB_EVENT_KEY;
3527 event->ch = 0;
3528 event->key = TB_KEY_ESC;
3529 event->mod = 0;
3530 bytebuf_shift(in, 1);
3531 return TB_OK;
3532 }
3533
3534 // Recurse for alt key
3535 event->mod |= TB_MOD_ALT;
3536 bytebuf_shift(in, 1);
3537 return extract_event(event);
3538 }
3539
3540 // ASCII control key?
3541 int is_ctrl =
3542 (uint16_t)in->buf[0] < TB_KEY_SPACE || in->buf[0] == TB_KEY_BACKSPACE2;
3543 if (is_ctrl) {
3544 event->type = TB_EVENT_KEY;
3545 event->ch = 0;
3546 event->key = (uint16_t)in->buf[0];
3547 event->mod |= TB_MOD_CTRL;
3548 bytebuf_shift(in, 1);
3549 return TB_OK;
3550 }
3551
3552 // UTF-8?
3553 if (in->len >= (size_t)tb_utf8_char_length(in->buf[0])) {
3554 event->type = TB_EVENT_KEY;
3555 tb_utf8_char_to_unicode(&event->ch, in->buf);
3556 event->key = 0;
3557 bytebuf_shift(in, tb_utf8_char_length(in->buf[0]));
3558 return TB_OK;
3559 }
3560
3561 // Need more input
3562 return TB_ERR;
3563}
3564
3565static int extract_esc(struct tb_event *event) {
3566 int rv;
3567 if_ok_or_need_more_return(rv, extract_esc_user(event, 0));
3568 if_ok_or_need_more_return(rv, extract_esc_cap(event));
3569 if_ok_or_need_more_return(rv, extract_esc_mouse(event));
3570 if_ok_or_need_more_return(rv, extract_esc_user(event, 1));
3571 return TB_ERR;
3572}
3573
3574static int extract_esc_user(struct tb_event *event, int is_post) {
3575 int rv;
3576 size_t consumed = 0;
3577 struct bytebuf *in = &global.in;
3578 int (*fn)(struct tb_event *, size_t *);
3579
3580 fn = is_post ? global.fn_extract_esc_post : global.fn_extract_esc_pre;
3581
3582 if (!fn) return TB_ERR;
3583
3584 rv = fn(event, &consumed);
3585 if (rv == TB_OK) bytebuf_shift(in, consumed);
3586
3587 if_ok_or_need_more_return(rv, rv);
3588 return TB_ERR;
3589}
3590
3591static int extract_esc_cap(struct tb_event *event) {
3592 int rv;
3593 struct bytebuf *in = &global.in;
3594 struct cap_trie *node;
3595 size_t depth;
3596
3597 if_err_return(rv, cap_trie_find(in->buf, in->len, &node, &depth));
3598 if (node->is_leaf) {
3599 // Found a leaf node
3600 event->type = TB_EVENT_KEY;
3601 event->ch = 0;
3602 event->key = node->key;
3603 event->mod = node->mod;
3604 bytebuf_shift(in, depth);
3605 return TB_OK;
3606 } else if (node->nchildren > 0 && in->len <= depth) {
3607 // Found a branch node (not enough input)
3608 return TB_ERR_NEED_MORE;
3609 }
3610
3611 return TB_ERR;
3612}
3613
3614static int extract_esc_mouse(struct tb_event *event) {
3615 struct bytebuf *in = &global.in;
3616 size_t buf_shift = 0;
3617
3618 // Bail if not enough to determine type
3619 if (in->len < 2) {
3620 return TB_ERR_NEED_MORE;
3621 } else if (in->buf[1] != '[') {
3622 return TB_ERR;
3623 } else if (in->len < 3) {
3624 return TB_ERR_NEED_MORE;
3625 }
3626
3627 // Discern type of mouse event from 3rd byte
3628 int type = 0;
3629 enum { TYPE_VT200 = 0, TYPE_1006, TYPE_1015, TYPE_MAX };
3630 if (in->buf[2] == 'M') {
3631 // X10 mouse encoding, the simplest one
3632 // \x1b [ M Cb Cx Cy
3633 type = TYPE_VT200;
3634 } else if (in->buf[2] == '<') {
3635 // xterm 1006 extended mode or urxvt 1015 extended mode
3636 // xterm: \x1b [ < Cb ; Cx ; Cy (M or m)
3637 type = TYPE_1006;
3638 } else {
3639 // urxvt: \x1b [ Cb ; Cx ; Cy M
3640 type = TYPE_1015;
3641 }
3642
3643 switch (type) {
3644 case TYPE_VT200: {
3645 // In this mode, we need 6 bytes
3646 if (in->len < 6) return TB_ERR_NEED_MORE;
3647
3648 int b = in->buf[3] - 0x20;
3649
3650 switch (b & 3) {
3651 case 0:
3652 event->key = ((b & 64) != 0) ? TB_KEY_MOUSE_WHEEL_UP
3653 : TB_KEY_MOUSE_LEFT;
3654 break;
3655 case 1:
3656 event->key = ((b & 64) != 0) ? TB_KEY_MOUSE_WHEEL_DOWN
3657 : TB_KEY_MOUSE_MIDDLE;
3658 break;
3659 case 2:
3660 event->key = TB_KEY_MOUSE_RIGHT;
3661 break;
3662 case 3:
3663 event->key = TB_KEY_MOUSE_RELEASE;
3664 break;
3665 default:
3666 return TB_ERR;
3667 }
3668
3669 if ((b & 32) != 0) event->mod |= TB_MOD_MOTION;
3670
3671 // the coord is 1,1 for upper left
3672 event->x = ((uint8_t)in->buf[4]) - 0x21;
3673 event->y = ((uint8_t)in->buf[5]) - 0x21;
3674
3675 // Eat 6 bytes
3676 buf_shift = 6;
3677 break;
3678 }
3679
3680 case TYPE_1006:
3681 // fallthrough
3682
3683 case TYPE_1015: {
3684 int num[3] = {-1, -1, -1};
3685 int num_i = 0;
3686 int cur_num = -1;
3687 char trail = ' ';
3688
3689 size_t i = 2;
3690 if (type == TYPE_1006) ++i; // skip '<'
3691
3692 // Parse %d;%d;%d[mM] into `num`
3693 while (i < in->len && num_i < 3) {
3694 char c = in->buf[i];
3695 if (c >= '0' && c <= '9') {
3696 // Digit
3697 if (cur_num == -1) cur_num = 0;
3698 cur_num *= 10;
3699 cur_num += (int)(c - '0');
3700 } else if (cur_num != -1 &&
3701 ((num_i < 2 && c == ';') ||
3702 (num_i == 2 && (c == 'm' || c == 'M'))))
3703 {
3704 // We're at a semi-colon, 'm', or 'M'
3705 // and we have a number
3706 num[num_i] = cur_num;
3707 ++num_i;
3708 cur_num = -1;
3709 trail = c;
3710 } else {
3711 // Something else; not a mouse event
3712 return TB_ERR;
3713 }
3714 ++i;
3715 }
3716
3717 // If we didn't get to the 3rd number, we need more
3718 if (num[2] == -1) return TB_ERR_NEED_MORE;
3719
3720 // We have a valid mouse event, eat `i` bytes from the buffer
3721 buf_shift = i;
3722
3723 if (type == TYPE_1015) num[0] -= 0x20;
3724
3725 switch (num[0] & 3) {
3726 case 0:
3727 event->key = ((num[0] & 64) != 0) ? TB_KEY_MOUSE_WHEEL_UP
3728 : TB_KEY_MOUSE_LEFT;
3729 break;
3730 case 1:
3731 event->key = ((num[0] & 64) != 0) ? TB_KEY_MOUSE_WHEEL_DOWN
3732 : TB_KEY_MOUSE_MIDDLE;
3733 break;
3734 case 2:
3735 event->key = TB_KEY_MOUSE_RIGHT;
3736 break;
3737 case 3:
3738 event->key = TB_KEY_MOUSE_RELEASE;
3739 break;
3740 default:
3741 return TB_ERR;
3742 }
3743
3744 // on xterm mouse release is signaled by lowercase m
3745 if (trail == 'm') event->key = TB_KEY_MOUSE_RELEASE;
3746
3747 if ((num[0] & 32) != 0) event->mod |= TB_MOD_MOTION;
3748
3749 event->x = (num[1] - 1 < 0) ? 0 : num[1] - 1;
3750 event->y = (num[2] - 1 < 0) ? 0 : num[2] - 1;
3751
3752 break;
3753 }
3754 }
3755
3756 if (buf_shift > 0) bytebuf_shift(in, buf_shift);
3757
3758 event->type = TB_EVENT_MOUSE;
3759
3760 return TB_OK;
3761}
3762
3763static int resize_cellbufs(void) {
3764 int rv;
3765 if_err_return(rv,
3766 cellbuf_resize(&global.back, global.width, global.height));
3767 if_err_return(rv,
3768 cellbuf_resize(&global.front, global.width, global.height));
3769 if_err_return(rv, cellbuf_clear(&global.front));
3770 if_err_return(rv, send_clear());
3771 return TB_OK;
3772}
3773
3774static void handle_resize(int sig) {
3775 int errno_copy = errno;
3776 write(global.resize_pipefd[1], &sig, sizeof(sig));
3777 errno = errno_copy;
3778}
3779
3780static int send_attr(uintattr_t fg, uintattr_t bg) {
3781 int rv;
3782
3783 if (fg == global.last_fg && bg == global.last_bg) {
3784 return TB_OK;
3785 }
3786
3787 if_err_return(rv, bytebuf_puts(&global.out, global.caps[TB_CAP_SGR0]));
3788
3789 uint32_t cfg, cbg;
3790 switch (global.output_mode) {
3791 default:
3792 case TB_OUTPUT_NORMAL:
3793 // The minus 1 below is because our colors are 1-indexed starting
3794 // from black. Black is represented by a 30, 40, 90, or 100 for fg,
3795 // bg, bright fg, or bright bg respectively. Red is 31, 41, 91,
3796 // 101, etc.
3797 cfg = (fg & TB_BRIGHT ? 90 : 30) + (fg & 0x0f) - 1;
3798 cbg = (bg & TB_BRIGHT ? 100 : 40) + (bg & 0x0f) - 1;
3799 break;
3800
3801 case TB_OUTPUT_256:
3802 cfg = fg & 0xff;
3803 cbg = bg & 0xff;
3804 if (fg & TB_HI_BLACK) cfg = 0;
3805 if (bg & TB_HI_BLACK) cbg = 0;
3806 break;
3807
3808 case TB_OUTPUT_216:
3809 cfg = fg & 0xff;
3810 cbg = bg & 0xff;
3811 if (cfg > 216) cfg = 216;
3812 if (cbg > 216) cbg = 216;
3813 cfg += 0x0f;
3814 cbg += 0x0f;
3815 break;
3816
3817 case TB_OUTPUT_GRAYSCALE:
3818 cfg = fg & 0xff;
3819 cbg = bg & 0xff;
3820 if (cfg > 24) cfg = 24;
3821 if (cbg > 24) cbg = 24;
3822 cfg += 0xe7;
3823 cbg += 0xe7;
3824 break;
3825
3826#if TB_OPT_ATTR_W >= 32
3827 case TB_OUTPUT_TRUECOLOR:
3828 cfg = fg & 0xffffff;
3829 cbg = bg & 0xffffff;
3830 if (fg & TB_HI_BLACK) cfg = 0;
3831 if (bg & TB_HI_BLACK) cbg = 0;
3832 break;
3833#endif
3834 }
3835
3836 if (fg & TB_BOLD)
3837 if_err_return(rv, bytebuf_puts(&global.out, global.caps[TB_CAP_BOLD]));
3838
3839 if (fg & TB_BLINK)
3840 if_err_return(rv, bytebuf_puts(&global.out, global.caps[TB_CAP_BLINK]));
3841
3842 if (fg & TB_UNDERLINE)
3843 if_err_return(rv,
3844 bytebuf_puts(&global.out, global.caps[TB_CAP_UNDERLINE]));
3845
3846 if (fg & TB_ITALIC)
3847 if_err_return(rv,
3848 bytebuf_puts(&global.out, global.caps[TB_CAP_ITALIC]));
3849
3850 if (fg & TB_DIM)
3851 if_err_return(rv, bytebuf_puts(&global.out, global.caps[TB_CAP_DIM]));
3852
3853#if TB_OPT_ATTR_W == 64
3854 if (fg & TB_STRIKEOUT)
3855 if_err_return(rv, bytebuf_puts(&global.out, TB_HARDCAP_STRIKEOUT));
3856
3857 if (fg & TB_UNDERLINE_2)
3858 if_err_return(rv, bytebuf_puts(&global.out, TB_HARDCAP_UNDERLINE_2));
3859
3860 if (fg & TB_OVERLINE)
3861 if_err_return(rv, bytebuf_puts(&global.out, TB_HARDCAP_OVERLINE));
3862
3863 if (fg & TB_INVISIBLE)
3864 if_err_return(rv,
3865 bytebuf_puts(&global.out, global.caps[TB_CAP_INVISIBLE]));
3866#endif
3867
3868 if ((fg & TB_REVERSE) || (bg & TB_REVERSE))
3869 if_err_return(rv,
3870 bytebuf_puts(&global.out, global.caps[TB_CAP_REVERSE]));
3871
3872 int fg_is_default = (fg & 0xff) == 0;
3873 int bg_is_default = (bg & 0xff) == 0;
3874 if (global.output_mode == TB_OUTPUT_256) {
3875 if (fg & TB_HI_BLACK) fg_is_default = 0;
3876 if (bg & TB_HI_BLACK) bg_is_default = 0;
3877 }
3878#if TB_OPT_ATTR_W >= 32
3879 if (global.output_mode == TB_OUTPUT_TRUECOLOR) {
3880 fg_is_default = ((fg & 0xffffff) == 0) && ((fg & TB_HI_BLACK) == 0);
3881 bg_is_default = ((bg & 0xffffff) == 0) && ((bg & TB_HI_BLACK) == 0);
3882 }
3883#endif
3884
3885 if_err_return(rv, send_sgr(cfg, cbg, fg_is_default, bg_is_default));
3886
3887 global.last_fg = fg;
3888 global.last_bg = bg;
3889
3890 return TB_OK;
3891}
3892
3893static int send_sgr(uint32_t cfg, uint32_t cbg, int fg_is_default,
3894 int bg_is_default) {
3895 int rv;
3896 char nbuf[32];
3897
3898 if (fg_is_default && bg_is_default) {
3899 return TB_OK;
3900 }
3901
3902 switch (global.output_mode) {
3903 default:
3904 case TB_OUTPUT_NORMAL:
3905 send_literal(rv, "\x1b[");
3906 if (!fg_is_default) {
3907 send_num(rv, nbuf, cfg);
3908 if (!bg_is_default) {
3909 send_literal(rv, ";");
3910 }
3911 }
3912 if (!bg_is_default) {
3913 send_num(rv, nbuf, cbg);
3914 }
3915 send_literal(rv, "m");
3916 break;
3917
3918 case TB_OUTPUT_256:
3919 case TB_OUTPUT_216:
3920 case TB_OUTPUT_GRAYSCALE:
3921 send_literal(rv, "\x1b[");
3922 if (!fg_is_default) {
3923 send_literal(rv, "38;5;");
3924 send_num(rv, nbuf, cfg);
3925 if (!bg_is_default) {
3926 send_literal(rv, ";");
3927 }
3928 }
3929 if (!bg_is_default) {
3930 send_literal(rv, "48;5;");
3931 send_num(rv, nbuf, cbg);
3932 }
3933 send_literal(rv, "m");
3934 break;
3935
3936#if TB_OPT_ATTR_W >= 32
3937 case TB_OUTPUT_TRUECOLOR:
3938 send_literal(rv, "\x1b[");
3939 if (!fg_is_default) {
3940 send_literal(rv, "38;2;");
3941 send_num(rv, nbuf, (cfg >> 16) & 0xff);
3942 send_literal(rv, ";");
3943 send_num(rv, nbuf, (cfg >> 8) & 0xff);
3944 send_literal(rv, ";");
3945 send_num(rv, nbuf, cfg & 0xff);
3946 if (!bg_is_default) {
3947 send_literal(rv, ";");
3948 }
3949 }
3950 if (!bg_is_default) {
3951 send_literal(rv, "48;2;");
3952 send_num(rv, nbuf, (cbg >> 16) & 0xff);
3953 send_literal(rv, ";");
3954 send_num(rv, nbuf, (cbg >> 8) & 0xff);
3955 send_literal(rv, ";");
3956 send_num(rv, nbuf, cbg & 0xff);
3957 }
3958 send_literal(rv, "m");
3959 break;
3960#endif
3961 }
3962 return TB_OK;
3963}
3964
3965static int send_cursor_if(int x, int y) {
3966 int rv;
3967 char nbuf[32];
3968 if (x < 0 || y < 0) {
3969 return TB_OK;
3970 }
3971 send_literal(rv, "\x1b[");
3972 send_num(rv, nbuf, y + 1);
3973 send_literal(rv, ";");
3974 send_num(rv, nbuf, x + 1);
3975 send_literal(rv, "H");
3976 return TB_OK;
3977}
3978
3979static int send_char(int x, int y, uint32_t ch) {
3980 return send_cluster(x, y, &ch, 1);
3981}
3982
3983static int send_cluster(int x, int y, uint32_t *ch, size_t nch) {
3984 int rv;
3985 char chu8[8];
3986
3987 if (global.last_x != x - 1 || global.last_y != y) {
3988 if_err_return(rv, send_cursor_if(x, y));
3989 }
3990 global.last_x = x;
3991 global.last_y = y;
3992
3993 int i;
3994 for (i = 0; i < (int)nch; i++) {
3995 uint32_t ch32 = *(ch + i);
3996 if (!tb_iswprint(ch32)) {
3997 ch32 = 0xfffd; // replace non-printable codepoints with U+FFFD
3998 }
3999 int chu8_len = tb_utf8_unicode_to_char(chu8, ch32);
4000 if_err_return(rv, bytebuf_nputs(&global.out, chu8, (size_t)chu8_len));
4001 }
4002
4003 return TB_OK;
4004}
4005
4006static int convert_num(uint32_t num, char *buf) {
4007 int i, l = 0;
4008 char ch;
4009 do {
4010 buf[l++] = (char)('0' + (num % 10));
4011 num /= 10;
4012 } while (num);
4013 for (i = 0; i < l / 2; i++) {
4014 ch = buf[i];
4015 buf[i] = buf[l - 1 - i];
4016 buf[l - 1 - i] = ch;
4017 }
4018 return l;
4019}
4020
4021static int cell_cmp(struct tb_cell *a, struct tb_cell *b) {
4022 if (a->ch != b->ch || a->fg != b->fg || a->bg != b->bg) {
4023 return 1;
4024 }
4025#ifdef TB_OPT_EGC
4026 if (a->nech != b->nech) {
4027 return 1;
4028 } else if (a->nech > 0) { // a->nech == b->nech
4029 return memcmp(a->ech, b->ech, a->nech);
4030 }
4031#endif
4032 return 0;
4033}
4034
4035static int cell_copy(struct tb_cell *dst, struct tb_cell *src) {
4036#ifdef TB_OPT_EGC
4037 if (src->nech > 0) {
4038 return cell_set(dst, src->ech, src->nech, src->fg, src->bg);
4039 }
4040#endif
4041 return cell_set(dst, &src->ch, 1, src->fg, src->bg);
4042}
4043
4044static int cell_set(struct tb_cell *cell, uint32_t *ch, size_t nch,
4045 uintattr_t fg, uintattr_t bg) {
4046 // TODO: iswprint ch?
4047 cell->ch = ch ? *ch : 0;
4048 cell->fg = fg;
4049 cell->bg = bg;
4050#ifdef TB_OPT_EGC
4051 if (nch <= 1) {
4052 cell->nech = 0;
4053 } else {
4054 int rv;
4055 if_err_return(rv, cell_reserve_ech(cell, nch + 1));
4056 memcpy(cell->ech, ch, sizeof(*ch) * nch);
4057 cell->ech[nch] = '\0';
4058 cell->nech = nch;
4059 }
4060#else
4061 (void)nch;
4062 (void)cell_reserve_ech;
4063#endif
4064 return TB_OK;
4065}
4066
4067static int cell_reserve_ech(struct tb_cell *cell, size_t n) {
4068#ifdef TB_OPT_EGC
4069 if (cell->cech >= n) return TB_OK;
4070 cell->ech = (uint32_t *)tb_realloc(cell->ech, n * sizeof(cell->ch));
4071 if (!cell->ech) return TB_ERR_MEM;
4072 cell->cech = n;
4073 return TB_OK;
4074#else
4075 (void)cell;
4076 (void)n;
4077 return TB_ERR;
4078#endif
4079}
4080
4081static int cell_free(struct tb_cell *cell) {
4082#ifdef TB_OPT_EGC
4083 if (cell->ech) tb_free(cell->ech);
4084#endif
4085 memset(cell, 0, sizeof(*cell));
4086 return TB_OK;
4087}
4088
4089static int cellbuf_init(struct cellbuf *c, int w, int h) {
4090 c->cells = (struct tb_cell *)tb_malloc(sizeof(struct tb_cell) * w * h);
4091 if (!c->cells) return TB_ERR_MEM;
4092 memset(c->cells, 0, sizeof(struct tb_cell) * w * h);
4093 c->width = w;
4094 c->height = h;
4095 return TB_OK;
4096}
4097
4098static int cellbuf_free(struct cellbuf *c) {
4099 if (c->cells) {
4100 int i;
4101 for (i = 0; i < c->width * c->height; i++) {
4102 cell_free(&c->cells[i]);
4103 }
4104 tb_free(c->cells);
4105 }
4106 memset(c, 0, sizeof(*c));
4107 return TB_OK;
4108}
4109
4110static int cellbuf_clear(struct cellbuf *c) {
4111 int rv, i;
4112 uint32_t space = (uint32_t)' ';
4113 for (i = 0; i < c->width * c->height; i++) {
4114 if_err_return(rv,
4115 cell_set(&c->cells[i], &space, 1, global.fg, global.bg));
4116 }
4117 return TB_OK;
4118}
4119
4120static int cellbuf_get(struct cellbuf *c, int x, int y,
4121 struct tb_cell **out) {
4122 if (!cellbuf_in_bounds(c, x, y)) {
4123 *out = NULL;
4124 return TB_ERR_OUT_OF_BOUNDS;
4125 }
4126 *out = &c->cells[(y * c->width) + x];
4127 return TB_OK;
4128}
4129
4130static int cellbuf_in_bounds(struct cellbuf *c, int x, int y) {
4131 if (x < 0 || x >= c->width || y < 0 || y >= c->height) {
4132 return 0;
4133 }
4134 return 1;
4135}
4136
4137static int cellbuf_resize(struct cellbuf *c, int w, int h) {
4138 int rv;
4139
4140 int ow = c->width;
4141 int oh = c->height;
4142
4143 if (ow == w && oh == h) {
4144 return TB_OK;
4145 }
4146
4147 w = w < 1 ? 1 : w;
4148 h = h < 1 ? 1 : h;
4149
4150 int minw = (w < ow) ? w : ow;
4151 int minh = (h < oh) ? h : oh;
4152
4153 struct tb_cell *prev = c->cells;
4154
4155 if_err_return(rv, cellbuf_init(c, w, h));
4156 if_err_return(rv, cellbuf_clear(c));
4157
4158 int x, y;
4159 for (x = 0; x < minw; x++) {
4160 for (y = 0; y < minh; y++) {
4161 struct tb_cell *src, *dst;
4162 src = &prev[(y * ow) + x];
4163 if_err_return(rv, cellbuf_get(c, x, y, &dst));
4164 if_err_return(rv, cell_copy(dst, src));
4165 }
4166 }
4167
4168 tb_free(prev);
4169
4170 return TB_OK;
4171}
4172
4173static int bytebuf_puts(struct bytebuf *b, const char *str) {
4174 if (!str || strlen(str) <= 0) return TB_OK; // Nothing to do for empty caps
4175 return bytebuf_nputs(b, str, (size_t)strlen(str));
4176}
4177
4178static int bytebuf_nputs(struct bytebuf *b, const char *str, size_t nstr) {
4179 int rv;
4180 if_err_return(rv, bytebuf_reserve(b, b->len + nstr + 1));
4181 memcpy(b->buf + b->len, str, nstr);
4182 b->len += nstr;
4183 b->buf[b->len] = '\0';
4184 return TB_OK;
4185}
4186
4187static int bytebuf_shift(struct bytebuf *b, size_t n) {
4188 if (n > b->len) n = b->len;
4189 size_t nmove = b->len - n;
4190 memmove(b->buf, b->buf + n, nmove);
4191 b->len -= n;
4192 return TB_OK;
4193}
4194
4195static int bytebuf_flush(struct bytebuf *b, int fd) {
4196 if (b->len <= 0) return TB_OK;
4197 ssize_t write_rv = write(fd, b->buf, b->len);
4198 if (write_rv < 0 || (size_t)write_rv != b->len) {
4199 // Note, errno will be 0 on partial write
4200 global.last_errno = errno;
4201 return TB_ERR;
4202 }
4203 b->len = 0;
4204 return TB_OK;
4205}
4206
4207static int bytebuf_reserve(struct bytebuf *b, size_t sz) {
4208 if (b->cap >= sz) return TB_OK;
4209
4210 size_t newcap = b->cap > 0 ? b->cap : 1;
4211 while (newcap < sz) {
4212 newcap *= 2;
4213 }
4214
4215 char *newbuf;
4216 if (b->buf) {
4217 newbuf = (char *)tb_realloc(b->buf, newcap);
4218 } else {
4219 newbuf = (char *)tb_malloc(newcap);
4220 }
4221 if (!newbuf) return TB_ERR_MEM;
4222
4223 b->buf = newbuf;
4224 b->cap = newcap;
4225 return TB_OK;
4226}
4227
4228static int bytebuf_free(struct bytebuf *b) {
4229 if (b->buf) tb_free(b->buf);
4230 memset(b, 0, sizeof(*b));
4231 return TB_OK;
4232}
4233
4234int tb_iswprint(uint32_t ch) {
4235#ifdef TB_OPT_LIBC_WCHAR
4236 return iswprint((wint_t)ch);
4237#else
4238 return tb_iswprint_ex(ch, NULL);
4239#endif
4240}
4241
4242int tb_wcwidth(uint32_t ch) {
4243 int w;
4244#ifdef TB_OPT_LIBC_WCHAR
4245 w = wcwidth((wchar_t)ch);
4246#else
4247 tb_iswprint_ex(ch, &w);
4248#endif
4249 return w;
4250}
4251
4252static int tb_cluster_width(uint32_t *ch, size_t nch) {
4253 int wmax = -1;
4254 int vs15 = 0, vs16 = 0, ri = 0, zwj = 0;
4255 size_t i = 0;
4256 for (i = 0; i < nch; i++) {
4257 uint32_t c = ch[i];
4258 switch (c) {
4259 case 0xfe0e: ++vs15; break;
4260 case 0xfe0f: ++vs16; break;
4261 case 0x200d: ++zwj; break;
4262 default: if (c >= 0x1f1e6 && c <= 0x1f1ff) ++ri;
4263 }
4264 int w = tb_wcwidth(c);
4265 if (w > wmax) wmax = w;
4266 }
4267 if (wmax >= 1) {
4268 if (vs15) return 1;
4269 else if (vs16 || zwj || ri >= 2) return 2;
4270 }
4271 return wmax;
4272}
4273
4274static int tb_iswprint_ex(uint32_t ch, int *w) {
4275#ifdef TB_OPT_LIBC_WCHAR
4276 if (w) *w = wcwidth((wint_t)ch);
4277 return iswprint(ch);
4278#else
4279 // Fast path for 1-byte codepoints
4280 if ((ch >= 0x20 && ch <= 0x7e) || (ch >= 0xa0 && ch <= 0xff)) {
4281 if (w) *w = 1;
4282 return 1;
4283 } else if (ch <= 0xff) {
4284 if (w) *w = ch == 0 ? 0 : -1;
4285 return 0;
4286 }
4287
4288 int lo = 0, hi = WCWIDTH_TABLE_LENGTH - 1;
4289 while (lo <= hi) {
4290 int i = (lo + hi) / 2;
4291 if (ch < wcwidth_table[i].range_start) {
4292 hi = i - 1;
4293 } else if (ch > wcwidth_table[i].range_end) {
4294 lo = i + 1;
4295 } else {
4296 if (w) *w = wcwidth_table[i].width;
4297 return wcwidth_table[i].width >= 0 ? 1 : 0;
4298 }
4299 }
4300 if (w) *w = -1; // Invalid codepoint
4301 return 0;
4302#endif
4303}
4304
4305#endif // TB_IMPL