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