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