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