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