Update termbox2

Signed-off-by: AnErrupTion <anerruption@disroot.org>
This commit is contained in:
AnErrupTion 2025-03-06 11:42:19 +01:00
parent f54657432a
commit a766dc2b9c
No known key found for this signature in database
1 changed files with 259 additions and 205 deletions

View File

@ -51,6 +51,8 @@ SOFTWARE.
#include <termios.h> #include <termios.h>
#include <unistd.h> #include <unistd.h>
#include <wchar.h> #include <wchar.h>
#include <wctype.h>
#include <locale.h>
#ifdef PATH_MAX #ifdef PATH_MAX
#define TB_PATH_MAX PATH_MAX #define TB_PATH_MAX PATH_MAX
@ -64,7 +66,7 @@ extern "C" {
// __ffi_start // __ffi_start
#define TB_VERSION_STR "2.5.0-dev" #define TB_VERSION_STR "2.5.0"
/* The following compile-time options are supported: /* The following compile-time options are supported:
* *
@ -90,7 +92,7 @@ extern "C" {
*/ */
#if defined(TB_LIB_OPTS) || 0 // __tb_lib_opts #if defined(TB_LIB_OPTS) || 0 // __tb_lib_opts
// Ensure consistent compile-time options when using as a shared library /* Ensure consistent compile-time options when using as a shared library */
#undef TB_OPT_ATTR_W #undef TB_OPT_ATTR_W
#undef TB_OPT_EGC #undef TB_OPT_EGC
#undef TB_OPT_PRINTF_BUF #undef TB_OPT_PRINTF_BUF
@ -99,7 +101,7 @@ extern "C" {
#define TB_OPT_EGC #define TB_OPT_EGC
#endif #endif
// Ensure sane TB_OPT_ATTR_W (16, 32, or 64) /* Ensure sane `TB_OPT_ATTR_W` (16, 32, or 64) */
#if defined TB_OPT_ATTR_W && TB_OPT_ATTR_W == 16 #if defined TB_OPT_ATTR_W && TB_OPT_ATTR_W == 16
#elif defined TB_OPT_ATTR_W && TB_OPT_ATTR_W == 32 #elif defined TB_OPT_ATTR_W && TB_OPT_ATTR_W == 32
#elif defined TB_OPT_ATTR_W && TB_OPT_ATTR_W == 64 #elif defined TB_OPT_ATTR_W && TB_OPT_ATTR_W == 64
@ -112,9 +114,9 @@ extern "C" {
#endif #endif
#endif #endif
/* ASCII key constants (tb_event.key) */ /* ASCII key constants (`tb_event.key`) */
#define TB_KEY_CTRL_TILDE 0x00 #define TB_KEY_CTRL_TILDE 0x00
#define TB_KEY_CTRL_2 0x00 /* clash with 'CTRL_TILDE' */ #define TB_KEY_CTRL_2 0x00 // clash with `CTRL_TILDE`
#define TB_KEY_CTRL_A 0x01 #define TB_KEY_CTRL_A 0x01
#define TB_KEY_CTRL_B 0x02 #define TB_KEY_CTRL_B 0x02
#define TB_KEY_CTRL_C 0x03 #define TB_KEY_CTRL_C 0x03
@ -123,14 +125,14 @@ extern "C" {
#define TB_KEY_CTRL_F 0x06 #define TB_KEY_CTRL_F 0x06
#define TB_KEY_CTRL_G 0x07 #define TB_KEY_CTRL_G 0x07
#define TB_KEY_BACKSPACE 0x08 #define TB_KEY_BACKSPACE 0x08
#define TB_KEY_CTRL_H 0x08 /* clash with 'CTRL_BACKSPACE' */ #define TB_KEY_CTRL_H 0x08 // clash with `CTRL_BACKSPACE`
#define TB_KEY_TAB 0x09 #define TB_KEY_TAB 0x09
#define TB_KEY_CTRL_I 0x09 /* clash with 'TAB' */ #define TB_KEY_CTRL_I 0x09 // clash with `TAB`
#define TB_KEY_CTRL_J 0x0a #define TB_KEY_CTRL_J 0x0a
#define TB_KEY_CTRL_K 0x0b #define TB_KEY_CTRL_K 0x0b
#define TB_KEY_CTRL_L 0x0c #define TB_KEY_CTRL_L 0x0c
#define TB_KEY_ENTER 0x0d #define TB_KEY_ENTER 0x0d
#define TB_KEY_CTRL_M 0x0d /* clash with 'ENTER' */ #define TB_KEY_CTRL_M 0x0d // clash with `ENTER`
#define TB_KEY_CTRL_N 0x0e #define TB_KEY_CTRL_N 0x0e
#define TB_KEY_CTRL_O 0x0f #define TB_KEY_CTRL_O 0x0f
#define TB_KEY_CTRL_P 0x10 #define TB_KEY_CTRL_P 0x10
@ -145,24 +147,24 @@ extern "C" {
#define TB_KEY_CTRL_Y 0x19 #define TB_KEY_CTRL_Y 0x19
#define TB_KEY_CTRL_Z 0x1a #define TB_KEY_CTRL_Z 0x1a
#define TB_KEY_ESC 0x1b #define TB_KEY_ESC 0x1b
#define TB_KEY_CTRL_LSQ_BRACKET 0x1b /* clash with 'ESC' */ #define TB_KEY_CTRL_LSQ_BRACKET 0x1b // clash with 'ESC'
#define TB_KEY_CTRL_3 0x1b /* clash with 'ESC' */ #define TB_KEY_CTRL_3 0x1b // clash with 'ESC'
#define TB_KEY_CTRL_4 0x1c #define TB_KEY_CTRL_4 0x1c
#define TB_KEY_CTRL_BACKSLASH 0x1c /* clash with 'CTRL_4' */ #define TB_KEY_CTRL_BACKSLASH 0x1c // clash with 'CTRL_4'
#define TB_KEY_CTRL_5 0x1d #define TB_KEY_CTRL_5 0x1d
#define TB_KEY_CTRL_RSQ_BRACKET 0x1d /* clash with 'CTRL_5' */ #define TB_KEY_CTRL_RSQ_BRACKET 0x1d // clash with 'CTRL_5'
#define TB_KEY_CTRL_6 0x1e #define TB_KEY_CTRL_6 0x1e
#define TB_KEY_CTRL_7 0x1f #define TB_KEY_CTRL_7 0x1f
#define TB_KEY_CTRL_SLASH 0x1f /* clash with 'CTRL_7' */ #define TB_KEY_CTRL_SLASH 0x1f // clash with 'CTRL_7'
#define TB_KEY_CTRL_UNDERSCORE 0x1f /* clash with 'CTRL_7' */ #define TB_KEY_CTRL_UNDERSCORE 0x1f // clash with 'CTRL_7'
#define TB_KEY_SPACE 0x20 #define TB_KEY_SPACE 0x20
#define TB_KEY_BACKSPACE2 0x7f #define TB_KEY_BACKSPACE2 0x7f
#define TB_KEY_CTRL_8 0x7f /* clash with 'BACKSPACE2' */ #define TB_KEY_CTRL_8 0x7f // clash with 'BACKSPACE2'
#define tb_key_i(i) 0xffff - (i) #define tb_key_i(i) 0xffff - (i)
/* Terminal-dependent key constants (tb_event.key) and terminfo capabilities */ /* Terminal-dependent key constants (`tb_event.key`) and terminfo caps */
/* BEGIN codegen h */ /* BEGIN codegen h */
/* Produced by ./codegen.sh on Thu, 13 Jul 2023 05:46:13 +0000 */ /* Produced by ./codegen.sh on Tue, 03 Sep 2024 04:17:47 +0000 */
#define TB_KEY_F1 (0xffff - 0) #define TB_KEY_F1 (0xffff - 0)
#define TB_KEY_F2 (0xffff - 1) #define TB_KEY_F2 (0xffff - 1)
#define TB_KEY_F3 (0xffff - 2) #define TB_KEY_F3 (0xffff - 2)
@ -242,7 +244,7 @@ extern "C" {
#define TB_HARDCAP_UNDERLINE_2 "\x1b[21m" #define TB_HARDCAP_UNDERLINE_2 "\x1b[21m"
#define TB_HARDCAP_OVERLINE "\x1b[53m" #define TB_HARDCAP_OVERLINE "\x1b[53m"
/* Colors (numeric) and attributes (bitwise) (tb_cell.fg, tb_cell.bg) */ /* Colors (numeric) and attributes (bitwise) (`tb_cell.fg`, `tb_cell.bg`) */
#define TB_DEFAULT 0x0000 #define TB_DEFAULT 0x0000
#define TB_BLACK 0x0001 #define TB_BLACK 0x0001
#define TB_RED 0x0002 #define TB_RED 0x0002
@ -262,8 +264,9 @@ extern "C" {
#define TB_HI_BLACK 0x2000 #define TB_HI_BLACK 0x2000
#define TB_BRIGHT 0x4000 #define TB_BRIGHT 0x4000
#define TB_DIM 0x8000 #define TB_DIM 0x8000
#define TB_256_BLACK TB_HI_BLACK // TB_256_BLACK is deprecated #define TB_256_BLACK TB_HI_BLACK // `TB_256_BLACK` is deprecated
#else // 32 or 64 #else
// `TB_OPT_ATTR_W` is 32 or 64
#define TB_BOLD 0x01000000 #define TB_BOLD 0x01000000
#define TB_UNDERLINE 0x02000000 #define TB_UNDERLINE 0x02000000
#define TB_REVERSE 0x04000000 #define TB_REVERSE 0x04000000
@ -272,7 +275,7 @@ extern "C" {
#define TB_HI_BLACK 0x20000000 #define TB_HI_BLACK 0x20000000
#define TB_BRIGHT 0x40000000 #define TB_BRIGHT 0x40000000
#define TB_DIM 0x80000000 #define TB_DIM 0x80000000
#define TB_TRUECOLOR_BOLD TB_BOLD // TB_TRUECOLOR_* is deprecated #define TB_TRUECOLOR_BOLD TB_BOLD // `TB_TRUECOLOR_*` is deprecated
#define TB_TRUECOLOR_UNDERLINE TB_UNDERLINE #define TB_TRUECOLOR_UNDERLINE TB_UNDERLINE
#define TB_TRUECOLOR_REVERSE TB_REVERSE #define TB_TRUECOLOR_REVERSE TB_REVERSE
#define TB_TRUECOLOR_ITALIC TB_ITALIC #define TB_TRUECOLOR_ITALIC TB_ITALIC
@ -287,24 +290,24 @@ extern "C" {
#define TB_INVISIBLE 0x0000000800000000 #define TB_INVISIBLE 0x0000000800000000
#endif #endif
/* Event types (tb_event.type) */ /* Event types (`tb_event.type`) */
#define TB_EVENT_KEY 1 #define TB_EVENT_KEY 1
#define TB_EVENT_RESIZE 2 #define TB_EVENT_RESIZE 2
#define TB_EVENT_MOUSE 3 #define TB_EVENT_MOUSE 3
/* Key modifiers (bitwise) (tb_event.mod) */ /* Key modifiers (bitwise) (`tb_event.mod`) */
#define TB_MOD_ALT 1 #define TB_MOD_ALT 1
#define TB_MOD_CTRL 2 #define TB_MOD_CTRL 2
#define TB_MOD_SHIFT 4 #define TB_MOD_SHIFT 4
#define TB_MOD_MOTION 8 #define TB_MOD_MOTION 8
/* Input modes (bitwise) (tb_set_input_mode) */ /* Input modes (bitwise) (`tb_set_input_mode`) */
#define TB_INPUT_CURRENT 0 #define TB_INPUT_CURRENT 0
#define TB_INPUT_ESC 1 #define TB_INPUT_ESC 1
#define TB_INPUT_ALT 2 #define TB_INPUT_ALT 2
#define TB_INPUT_MOUSE 4 #define TB_INPUT_MOUSE 4
/* Output modes (tb_set_output_mode) */ /* Output modes (`tb_set_output_mode`) */
#define TB_OUTPUT_CURRENT 0 #define TB_OUTPUT_CURRENT 0
#define TB_OUTPUT_NORMAL 1 #define TB_OUTPUT_NORMAL 1
#define TB_OUTPUT_256 2 #define TB_OUTPUT_256 2
@ -316,9 +319,9 @@ extern "C" {
/* Common function return values unless otherwise noted. /* Common function return values unless otherwise noted.
* *
* Library behavior is undefined after receiving TB_ERR_MEM. Callers may * Library behavior is undefined after receiving `TB_ERR_MEM`. Callers may
* attempt reinitializing by freeing memory, invoking tb_shutdown, then * attempt reinitializing by freeing memory, invoking `tb_shutdown`, then
* tb_init. * `tb_init`.
*/ */
#define TB_OK 0 #define TB_OK 0
#define TB_ERR -1 #define TB_ERR -1
@ -347,12 +350,12 @@ extern "C" {
#define TB_ERR_SELECT TB_ERR_POLL #define TB_ERR_SELECT TB_ERR_POLL
#define TB_ERR_RESIZE_SELECT TB_ERR_RESIZE_POLL #define TB_ERR_RESIZE_SELECT TB_ERR_RESIZE_POLL
/* Deprecated. Function types to be used with tb_set_func(). */ /* Deprecated. Function types to be used with `tb_set_func`. */
#define TB_FUNC_EXTRACT_PRE 0 #define TB_FUNC_EXTRACT_PRE 0
#define TB_FUNC_EXTRACT_POST 1 #define TB_FUNC_EXTRACT_POST 1
/* Define this to set the size of the buffer used in tb_printf() /* Define this to set the size of the buffer used in `tb_printf`
* and tb_sendf() * and `tb_sendf`
*/ */
#ifndef TB_OPT_PRINTF_BUF #ifndef TB_OPT_PRINTF_BUF
#define TB_OPT_PRINTF_BUF 4096 #define TB_OPT_PRINTF_BUF 4096
@ -389,35 +392,39 @@ typedef uint32_t uintattr_t;
typedef uint16_t uintattr_t; typedef uint16_t uintattr_t;
#endif #endif
/* The terminal screen is represented as 2d array of cells. The structure is /* A cell in a 2d grid representing the terminal screen.
* optimized for dealing with single-width (wcwidth()==1) Unicode codepoints, *
* The terminal screen is represented as 2d array of cells. The structure is
* optimized for dealing with single-width (`wcwidth==1`) Unicode codepoints,
* however some support for grapheme clusters (e.g., combining diacritical * however some support for grapheme clusters (e.g., combining diacritical
* marks) and wide codepoints (e.g., Hiragana) is provided through ech, nech, * marks) and wide codepoints (e.g., Hiragana) is provided through `ech`,
* cech via tb_set_cell_ex(). ech is only valid when nech>0, otherwise ch is * `nech`, and `cech` via `tb_set_cell_ex`. `ech` is only valid when `nech>0`,
* used. * otherwise `ch` is used.
* *
* For non-single-width codepoints, given N=wcwidth(ch)/wcswidth(ech): * For non-single-width codepoints, given `N=wcwidth(ch)/wcswidth(ech)`:
* *
* when N==0: termbox forces a single-width cell. Callers should avoid this * when `N==0`: termbox forces a single-width cell. Callers should avoid this
* if aiming to render text accurately. * if aiming to render text accurately. Callers may use
* `tb_set_cell_ex` or `tb_print*` to render `N==0` combining
* characters.
* *
* when N>1: termbox zeroes out the following N-1 cells and skips sending * when `N>1`: termbox zeroes out the following `N-1` cells and skips sending
* them to the tty. So, e.g., if the caller sets x=0,y=0 to an N==2 * them to the tty. So, e.g., if the caller sets `x=0,y=0` to an
* codepoint, the caller's next set should be at x=2,y=0. Anything * `N==2` codepoint, the caller's next set should be at `x=2,y=0`.
* set at x=1,y=0 will be ignored. If there are not enough columns * Anything set at `x=1,y=0` will be ignored. If there are not
* remaining on the line to render N width, spaces are sent * enough columns remaining on the line to render `N` width, spaces
* instead. * are sent instead.
* *
* See tb_present() for implementation. * See `tb_present` for implementation.
*/ */
struct tb_cell { struct tb_cell {
uint32_t ch; /* a Unicode codepoint */ uint32_t ch; // a Unicode codepoint
uintattr_t fg; /* bitwise foreground attributes */ uintattr_t fg; // bitwise foreground attributes
uintattr_t bg; /* bitwise background attributes */ uintattr_t bg; // bitwise background attributes
#ifdef TB_OPT_EGC #ifdef TB_OPT_EGC
uint32_t *ech; /* a grapheme cluster of Unicode codepoints, 0-terminated */ uint32_t *ech; // a grapheme cluster of Unicode codepoints, 0-terminated
size_t nech; /* num elements in ech, 0 means use ch instead of ech */ size_t nech; // num elements in ech, 0 means use ch instead of ech
size_t cech; /* num elements allocated for ech */ size_t cech; // num elements allocated for ech
#endif #endif
}; };
@ -425,30 +432,29 @@ struct tb_cell {
* *
* Given the event type, the following fields are relevant: * Given the event type, the following fields are relevant:
* *
* when TB_EVENT_KEY: (key XOR ch, one will be zero), mod. Note there is * when `TB_EVENT_KEY`: `key` xor `ch` (one will be zero) and `mod`. Note
* overlap between TB_MOD_CTRL and TB_KEY_CTRL_*. * there is overlap between `TB_MOD_CTRL` and
* TB_MOD_CTRL and TB_MOD_SHIFT are only set as * `TB_KEY_CTRL_*`. `TB_MOD_CTRL` and `TB_MOD_SHIFT` are
* modifiers to TB_KEY_ARROW_*. * only set as modifiers to `TB_KEY_ARROW_*`.
* *
* when TB_EVENT_RESIZE: w, h * when `TB_EVENT_RESIZE`: `w` and `h`
* *
* when TB_EVENT_MOUSE: key (TB_KEY_MOUSE_*), x, y * when `TB_EVENT_MOUSE`: `key` (`TB_KEY_MOUSE_*`), `x`, and `y`
*/ */
struct tb_event { struct tb_event {
uint8_t type; /* one of TB_EVENT_* constants */ uint8_t type; // one of `TB_EVENT_*` constants
uint8_t mod; /* bitwise TB_MOD_* constants */ uint8_t mod; // bitwise `TB_MOD_*` constants
uint16_t key; /* one of TB_KEY_* constants */ uint16_t key; // one of `TB_KEY_*` constants
uint32_t ch; /* a Unicode codepoint */ uint32_t ch; // a Unicode codepoint
int32_t w; /* resize width */ int32_t w; // resize width
int32_t h; /* resize height */ int32_t h; // resize height
int32_t x; /* mouse x */ int32_t x; // mouse x
int32_t y; /* mouse y */ int32_t y; // mouse y
}; };
/* Initializes the termbox library. This function should be called before any /* Initialize the termbox library. This function should be called before any
* other functions. tb_init() is equivalent to tb_init_file("/dev/tty"). After * other functions. `tb_init` is equivalent to `tb_init_file("/dev/tty")`. After
* successful initialization, the library must be finalized using the * successful initialization, the library must be finalized using `tb_shutdown`.
* tb_shutdown() function.
*/ */
int tb_init(void); int tb_init(void);
int tb_init_file(const char *path); int tb_init_file(const char *path);
@ -456,184 +462,197 @@ int tb_init_fd(int ttyfd);
int tb_init_rwfd(int rfd, int wfd); int tb_init_rwfd(int rfd, int wfd);
int tb_shutdown(void); int tb_shutdown(void);
/* Returns the size of the internal back buffer (which is the same as terminal's /* Return the size of the internal back buffer (which is the same as terminal's
* window size in rows and columns). The internal buffer can be resized after * window size in rows and columns). The internal buffer can be resized after
* tb_clear() or tb_present() function calls. Both dimensions have an * `tb_clear` or `tb_present` calls. Both dimensions have an unspecified
* unspecified negative value when called before tb_init() or after * negative value when called before `tb_init` or after `tb_shutdown`.
* tb_shutdown().
*/ */
int tb_width(void); int tb_width(void);
int tb_height(void); int tb_height(void);
/* Clears the internal back buffer using TB_DEFAULT color or the /* Clear the internal back buffer using `TB_DEFAULT` or the attributes set by
* color/attributes set by tb_set_clear_attrs() function. * `tb_set_clear_attrs`.
*/ */
int tb_clear(void); int tb_clear(void);
int tb_set_clear_attrs(uintattr_t fg, uintattr_t bg); int tb_set_clear_attrs(uintattr_t fg, uintattr_t bg);
/* Synchronizes the internal back buffer with the terminal by writing to tty. */ /* Synchronize the internal back buffer with the terminal by writing to tty. */
int tb_present(void); int tb_present(void);
/* Clears the internal front buffer effectively forcing a complete re-render of /* Clear the internal front buffer effectively forcing a complete re-render of
* the back buffer to the tty. It is not necessary to call this under normal * the back buffer to the tty. It is not necessary to call this under normal
* circumstances. */ * circumstances. */
int tb_invalidate(void); int tb_invalidate(void);
/* Sets the position of the cursor. Upper-left character is (0, 0). */ /* Set the position of the cursor. Upper-left cell is (0, 0). */
int tb_set_cursor(int cx, int cy); int tb_set_cursor(int cx, int cy);
int tb_hide_cursor(void); int tb_hide_cursor(void);
/* Set cell contents in the internal back buffer at the specified position. /* Set cell contents in the internal back buffer at the specified position.
* *
* Use tb_set_cell_ex() for rendering grapheme clusters (e.g., combining * Use `tb_set_cell_ex` for rendering grapheme clusters (e.g., combining
* diacritical marks). * diacritical marks).
* *
* Function tb_set_cell(x, y, ch, fg, bg) is equivalent to * Calling `tb_set_cell(x, y, ch, fg, bg)` is equivalent to
* tb_set_cell_ex(x, y, &ch, 1, fg, bg). * `tb_set_cell_ex(x, y, &ch, 1, fg, bg)`.
* *
* Function tb_extend_cell() is a shortcut for appending 1 codepoint to * `tb_extend_cell` is a shortcut for appending 1 codepoint to `tb_cell.ech`.
* cell->ech. *
* Non-printable (`iswprint(3)`) codepoints are replaced with `U+FFFD` at render
* time.
*/ */
int tb_set_cell(int x, int y, uint32_t ch, uintattr_t fg, uintattr_t bg); int tb_set_cell(int x, int y, uint32_t ch, uintattr_t fg, uintattr_t bg);
int tb_set_cell_ex(int x, int y, uint32_t *ch, size_t nch, uintattr_t fg, int tb_set_cell_ex(int x, int y, uint32_t *ch, size_t nch, uintattr_t fg,
uintattr_t bg); uintattr_t bg);
int tb_extend_cell(int x, int y, uint32_t ch); int tb_extend_cell(int x, int y, uint32_t ch);
/* Sets the input mode. Termbox has two input modes: /* Set the input mode. Termbox has two input modes:
* *
* 1. TB_INPUT_ESC * 1. `TB_INPUT_ESC`
* When escape (\x1b) is in the buffer and there's no match for an escape * When escape (`\x1b`) is in the buffer and there's no match for an escape
* sequence, a key event for TB_KEY_ESC is returned. * sequence, a key event for `TB_KEY_ESC` is returned.
* *
* 2. TB_INPUT_ALT * 2. `TB_INPUT_ALT`
* When escape (\x1b) is in the buffer and there's no match for an escape * When escape (`\x1b`) is in the buffer and there's no match for an escape
* sequence, the next keyboard event is returned with a TB_MOD_ALT modifier. * sequence, the next keyboard event is returned with a `TB_MOD_ALT`
* modifier.
* *
* You can also apply TB_INPUT_MOUSE via bitwise OR operation to either of the * You can also apply `TB_INPUT_MOUSE` via bitwise OR operation to either of the
* modes (e.g., TB_INPUT_ESC | TB_INPUT_MOUSE) to receive TB_EVENT_MOUSE events. * modes (e.g., `TB_INPUT_ESC | TB_INPUT_MOUSE`) to receive `TB_EVENT_MOUSE`
* If none of the main two modes were set, but the mouse mode was, TB_INPUT_ESC * events. If none of the main two modes were set, but the mouse mode was,
* mode is used. If for some reason you've decided to use * `TB_INPUT_ESC` is used. If for some reason you've decided to use
* (TB_INPUT_ESC | TB_INPUT_ALT) combination, it will behave as if only * `TB_INPUT_ESC | TB_INPUT_ALT`, it will behave as if only `TB_INPUT_ESC` was
* TB_INPUT_ESC was selected. * selected.
* *
* If mode is TB_INPUT_CURRENT, the function returns the current input mode. * If mode is `TB_INPUT_CURRENT`, return the current input mode.
* *
* The default input mode is TB_INPUT_ESC. * The default input mode is `TB_INPUT_ESC`.
*/ */
int tb_set_input_mode(int mode); int tb_set_input_mode(int mode);
/* Sets the termbox output mode. Termbox has multiple output modes: /* Set the output mode. Termbox has multiple output modes:
* *
* 1. TB_OUTPUT_NORMAL => [0..8] * 1. `TB_OUTPUT_NORMAL` => [0..8]
* *
* This mode provides 8 different colors: * This mode provides 8 different colors:
* TB_BLACK, TB_RED, TB_GREEN, TB_YELLOW, * `TB_BLACK`, `TB_RED`, `TB_GREEN`, `TB_YELLOW`,
* TB_BLUE, TB_MAGENTA, TB_CYAN, TB_WHITE * `TB_BLUE`, `TB_MAGENTA`, `TB_CYAN`, `TB_WHITE`
* *
* Plus TB_DEFAULT which skips sending a color code (i.e., uses the * Plus `TB_DEFAULT` which skips sending a color code (i.e., uses the
* terminal's default color). * terminal's default color).
* *
* Colors (including TB_DEFAULT) may be bitwise OR'd with attributes: * Colors (including `TB_DEFAULT`) may be bitwise OR'd with attributes:
* TB_BOLD, TB_UNDERLINE, TB_REVERSE, TB_ITALIC, TB_BLINK, TB_BRIGHT, * `TB_BOLD`, `TB_UNDERLINE`, `TB_REVERSE`, `TB_ITALIC`, `TB_BLINK`,
* TB_DIM * `TB_BRIGHT`, `TB_DIM`
* *
* The following style attributes are also available if compiled with * The following style attributes are also available if compiled with
* TB_OPT_ATTR_W set to 64: * `TB_OPT_ATTR_W` set to 64:
* TB_STRIKEOUT, TB_UNDERLINE_2, TB_OVERLINE, TB_INVISIBLE * `TB_STRIKEOUT`, `TB_UNDERLINE_2`, `TB_OVERLINE`, `TB_INVISIBLE`
* *
* As in all modes, the value 0 is interpreted as TB_DEFAULT for * As in all modes, the value 0 is interpreted as `TB_DEFAULT` for
* convenience. * convenience.
* *
* Some notes: TB_REVERSE can be applied as either fg or bg attributes for * Some notes: `TB_REVERSE` and `TB_BRIGHT` can be applied as either `fg` or
* the same effect. TB_BRIGHT can be applied to either fg or bg. The rest of * `bg` attributes for the same effect. The rest of the attributes apply to
* the attributes apply to fg only and are ignored as bg attributes. * `fg` only and are ignored as `bg` attributes.
* *
* Example usage: * Example usage: `tb_set_cell(x, y, '@', TB_BLACK | TB_BOLD, TB_RED)`
* tb_set_cell(x, y, '@', TB_BLACK | TB_BOLD, TB_RED);
* *
* 2. TB_OUTPUT_256 => [0..255] + TB_HI_BLACK * 2. `TB_OUTPUT_256` => [0..255] + `TB_HI_BLACK`
* *
* In this mode you get 256 distinct colors (plus default): * In this mode you get 256 distinct colors (plus default):
* 0x00 (1): TB_DEFAULT * 0x00 (1): `TB_DEFAULT`
* TB_HI_BLACK (1): TB_BLACK in TB_OUTPUT_NORMAL * `TB_HI_BLACK` (1): `TB_BLACK` in `TB_OUTPUT_NORMAL`
* 0x01..0x07 (7): the next 7 colors as in TB_OUTPUT_NORMAL * 0x01..0x07 (7): the next 7 colors as in `TB_OUTPUT_NORMAL`
* 0x08..0x0f (8): bright versions of the above * 0x08..0x0f (8): bright versions of the above
* 0x10..0xe7 (216): 216 different colors * 0x10..0xe7 (216): 216 different colors
* 0xe8..0xff (24): 24 different shades of gray * 0xe8..0xff (24): 24 different shades of gray
* *
* All TB_* style attributes except TB_BRIGHT may be bitwise OR'd as in * All `TB_*` style attributes except `TB_BRIGHT` may be bitwise OR'd as in
* TB_OUTPUT_NORMAL. * `TB_OUTPUT_NORMAL`.
* *
* Note TB_HI_BLACK must be used for black, as 0x00 represents default. * Note `TB_HI_BLACK` must be used for black, as 0x00 represents default.
* *
* 3. TB_OUTPUT_216 => [0..216] * 3. `TB_OUTPUT_216` => [0..216]
* *
* This mode supports the 216-color range of TB_OUTPUT_256 only, but you * This mode supports the 216-color range of `TB_OUTPUT_256` only, but you
* don't need to provide an offset: * don't need to provide an offset:
* 0x00 (1): TB_DEFAULT * 0x00 (1): `TB_DEFAULT`
* 0x01..0xd8 (216): 216 different colors * 0x01..0xd8 (216): 216 different colors
* *
* 4. TB_OUTPUT_GRAYSCALE => [0..24] * 4. `TB_OUTPUT_GRAYSCALE` => [0..24]
* *
* This mode supports the 24-color range of TB_OUTPUT_256 only, but you * This mode supports the 24-color range of `TB_OUTPUT_256` only, but you
* don't need to provide an offset: * don't need to provide an offset:
* 0x00 (1): TB_DEFAULT * 0x00 (1): `TB_DEFAULT`
* 0x01..0x18 (24): 24 different shades of gray * 0x01..0x18 (24): 24 different shades of gray
* *
* 5. TB_OUTPUT_TRUECOLOR => [0x000000..0xffffff] + TB_HI_BLACK * 5. `TB_OUTPUT_TRUECOLOR` => [0x000000..0xffffff] + `TB_HI_BLACK`
* *
* This mode provides 24-bit color on supported terminals. The format is * This mode provides 24-bit color on supported terminals. The format is
* 0xRRGGBB. * 0xRRGGBB.
* *
* All TB_* style attributes except TB_BRIGHT may be bitwise OR'd as in * All `TB_*` style attributes except `TB_BRIGHT` may be bitwise OR'd as in
* TB_OUTPUT_NORMAL. * `TB_OUTPUT_NORMAL`.
* *
* Note TB_HI_BLACK must be used for black, as 0x000000 represents default. * Note `TB_HI_BLACK` must be used for black, as 0x000000 represents default.
*
* If mode is TB_OUTPUT_CURRENT, the function returns the current output mode.
*
* The default output mode is TB_OUTPUT_NORMAL.
* *
* To use the terminal default color (i.e., to not send an escape code), pass * To use the terminal default color (i.e., to not send an escape code), pass
* TB_DEFAULT. For convenience, the value 0 is interpreted as TB_DEFAULT in * `TB_DEFAULT`. For convenience, the value 0 is interpreted as `TB_DEFAULT` in
* all modes. * all modes.
* *
* Note, cell attributes persist after switching output modes. Any translation * Note, cell attributes persist after switching output modes. Any translation
* between, for example, TB_OUTPUT_NORMAL's TB_RED and TB_OUTPUT_TRUECOLOR's * between, for example, `TB_OUTPUT_NORMAL`'s `TB_RED` and
* 0xff0000 must be performed by the caller. Also note that cells previously * `TB_OUTPUT_TRUECOLOR`'s 0xff0000 must be performed by the caller. Also note
* rendered in one mode may persist unchanged until the front buffer is cleared * that cells previously rendered in one mode may persist unchanged until the
* (such as after a resize event) at which point it will be re-interpreted and * front buffer is cleared (such as after a resize event) at which point it will
* flushed according to the current mode. Callers may invoke tb_invalidate if * be re-interpreted and flushed according to the current mode. Callers may
* it is desirable to immediately re-interpret and flush the entire screen * invoke `tb_invalidate` if it is desirable to immediately re-interpret and
* according to the current mode. * flush the entire screen according to the current mode.
* *
* Note, not all terminals support all output modes, especially beyond * Note, not all terminals support all output modes, especially beyond
* TB_OUTPUT_NORMAL. There is also no very reliable way to determine color * `TB_OUTPUT_NORMAL`. There is also no very reliable way to determine color
* support dynamically. If portability is desired, callers are recommended to * support dynamically. If portability is desired, callers are recommended to
* use TB_OUTPUT_NORMAL or make output mode end-user configurable. The same * use `TB_OUTPUT_NORMAL` or make output mode end-user configurable. The same
* advice applies to style attributes. * advice applies to style attributes.
*
* If mode is `TB_OUTPUT_CURRENT`, return the current output mode.
*
* The default output mode is `TB_OUTPUT_NORMAL`.
*/ */
int tb_set_output_mode(int mode); int tb_set_output_mode(int mode);
/* Wait for an event up to timeout_ms milliseconds and fill the event structure /* Wait for an event up to `timeout_ms` milliseconds and populate `event` with
* with it. If no event is available within the timeout period, TB_ERR_NO_EVENT * it. If no event is available within the timeout period, `TB_ERR_NO_EVENT`
* is returned. On a resize event, the underlying select(2) call may be * is returned. On a resize event, the underlying `select(2)` call may be
* interrupted, yielding a return code of TB_ERR_POLL. In this case, you may * interrupted, yielding a return code of `TB_ERR_POLL`. In this case, you may
* check errno via tb_last_errno(). If it's EINTR, you can safely ignore that * check `errno` via `tb_last_errno`. If it's `EINTR`, you may elect to ignore
* and call tb_peek_event() again. * that and call `tb_peek_event` again.
*/ */
int tb_peek_event(struct tb_event *event, int timeout_ms); int tb_peek_event(struct tb_event *event, int timeout_ms);
/* Same as tb_peek_event except no timeout. */ /* Same as `tb_peek_event` except no timeout. */
int tb_poll_event(struct tb_event *event); int tb_poll_event(struct tb_event *event);
/* Internal termbox FDs that can be used with poll() / select(). Must call /* Internal termbox fds that can be used with `poll(2)`, `select(2)`, etc.
* tb_poll_event() / tb_peek_event() if activity is detected. */ * externally. Callers must invoke `tb_poll_event` or `tb_peek_event` if
* fds become readable. */
int tb_get_fds(int *ttyfd, int *resizefd); int tb_get_fds(int *ttyfd, int *resizefd);
/* Print and printf functions. Specify param out_w to determine width of printed /* Print and printf functions. Specify param `out_w` to determine width of
* string. Incomplete trailing UTF-8 byte sequences are replaced with U+FFFD. * printed string. Strings are interpreted as UTF-8.
* For finer control, use tb_set_cell(). *
* Non-printable characters (`iswprint(3)`) and truncated UTF-8 byte sequences
* are replaced with U+FFFD.
*
* Newlines (`\n`) are supported with the caveat that `out_w` will return the
* width of the string as if it were on a single line.
*
* If the starting coordinate is out of bounds, `TB_ERR_OUT_OF_BOUNDS` is
* returned. If the starting coordinate is in bounds, but goes out of bounds,
* then the out-of-bounds portions of the string are ignored.
*
* For finer control, use `tb_set_cell`.
*/ */
int tb_print(int x, int y, uintattr_t fg, uintattr_t bg, const char *str); int tb_print(int x, int y, uintattr_t fg, uintattr_t bg, const char *str);
int tb_printf(int x, int y, uintattr_t fg, uintattr_t bg, const char *fmt, ...); int tb_printf(int x, int y, uintattr_t fg, uintattr_t bg, const char *fmt, ...);
@ -646,14 +665,14 @@ int tb_printf_ex(int x, int y, uintattr_t fg, uintattr_t bg, size_t *out_w,
int tb_send(const char *buf, size_t nbuf); int tb_send(const char *buf, size_t nbuf);
int tb_sendf(const char *fmt, ...); int tb_sendf(const char *fmt, ...);
/* Deprecated. Set custom functions. fn_type is one of TB_FUNC_* constants, fn /* Deprecated. Set custom callbacks. `fn_type` is one of `TB_FUNC_*` constants,
* is a compatible function pointer, or NULL to clear. * `fn` is a compatible function pointer, or NULL to clear.
* *
* TB_FUNC_EXTRACT_PRE: * `TB_FUNC_EXTRACT_PRE`:
* If specified, invoke this function BEFORE termbox tries to extract any * If specified, invoke this function BEFORE termbox tries to extract any
* escape sequences from the input buffer. * escape sequences from the input buffer.
* *
* TB_FUNC_EXTRACT_POST: * `TB_FUNC_EXTRACT_POST`:
* If specified, invoke this function AFTER termbox tries (and fails) to * If specified, invoke this function AFTER termbox tries (and fails) to
* extract any escape sequences from the input buffer. * extract any escape sequences from the input buffer.
*/ */
@ -711,7 +730,7 @@ const char *tb_version(void);
} }
#endif #endif
#endif /* TERMBOX_H_INCL */ #endif // TERMBOX_H_INCL
#ifdef TB_IMPL #ifdef TB_IMPL
@ -799,7 +818,7 @@ struct tb_global_t {
static struct tb_global_t global = {0}; static struct tb_global_t global = {0};
/* BEGIN codegen c */ /* BEGIN codegen c */
/* Produced by ./codegen.sh on Thu, 13 Jul 2023 05:46:13 +0000 */ /* Produced by ./codegen.sh on Tue, 03 Sep 2024 04:17:48 +0000 */
static const int16_t terminfo_cap_indexes[] = { static const int16_t terminfo_cap_indexes[] = {
66, // kf1 (TB_CAP_F1) 66, // kf1 (TB_CAP_F1)
@ -1546,6 +1565,7 @@ static int cellbuf_init(struct cellbuf_t *c, int w, int h);
static int cellbuf_free(struct cellbuf_t *c); static int cellbuf_free(struct cellbuf_t *c);
static int cellbuf_clear(struct cellbuf_t *c); static int cellbuf_clear(struct cellbuf_t *c);
static int cellbuf_get(struct cellbuf_t *c, int x, int y, struct tb_cell **out); static int cellbuf_get(struct cellbuf_t *c, int x, int y, struct tb_cell **out);
static int cellbuf_in_bounds(struct cellbuf_t *c, int x, int y);
static int cellbuf_resize(struct cellbuf_t *c, int w, int h); static int cellbuf_resize(struct cellbuf_t *c, int w, int h);
static int bytebuf_puts(struct bytebuf_t *b, const char *str); static int bytebuf_puts(struct bytebuf_t *b, const char *str);
static int bytebuf_nputs(struct bytebuf_t *b, const char *str, size_t nstr); static int bytebuf_nputs(struct bytebuf_t *b, const char *str, size_t nstr);
@ -1555,13 +1575,12 @@ static int bytebuf_reserve(struct bytebuf_t *b, size_t sz);
static int bytebuf_free(struct bytebuf_t *b); static int bytebuf_free(struct bytebuf_t *b);
int tb_init(void) { int tb_init(void) {
setlocale(LC_CTYPE, "C.UTF-8"); // Required for iswprint(3) to work properly
return tb_init_file("/dev/tty"); return tb_init_file("/dev/tty");
} }
int tb_init_file(const char *path) { int tb_init_file(const char *path) {
if (global.initialized) { if (global.initialized) return TB_ERR_INIT_ALREADY;
return TB_ERR_INIT_ALREADY;
}
int ttyfd = open(path, O_RDWR); int ttyfd = open(path, O_RDWR);
if (ttyfd < 0) { if (ttyfd < 0) {
global.last_errno = errno; global.last_errno = errno;
@ -1635,7 +1654,7 @@ int tb_present(void) {
int rv; int rv;
// TODO Assert global.back.(width,height) == global.front.(width,height) // TODO: Assert global.back.(width,height) == global.front.(width,height)
global.last_x = -1; global.last_x = -1;
global.last_y = -1; global.last_y = -1;
@ -1654,12 +1673,10 @@ int tb_present(void) {
w = wcswidth((wchar_t *)back->ech, back->nech); w = wcswidth((wchar_t *)back->ech, back->nech);
else else
#endif #endif
/* wcwidth() simply returns -1 on overflow of wchar_t */ // wcwidth simply returns -1 on overflow of wchar_t
w = wcwidth((wchar_t)back->ch); w = wcwidth((wchar_t)back->ch);
} }
if (w < 1) { if (w < 1) w = 1;
w = 1;
}
if (cell_cmp(back, front) != 0) { if (cell_cmp(back, front) != 0) {
cell_copy(front, back); cell_copy(front, back);
@ -1763,11 +1780,11 @@ int tb_extend_cell(int x, int y, uint32_t ch) {
if_err_return(rv, cellbuf_get(&global.back, x, y, &cell)); if_err_return(rv, cellbuf_get(&global.back, x, y, &cell));
if (cell->nech > 0) { // append to ech if (cell->nech > 0) { // append to ech
nech = cell->nech + 1; nech = cell->nech + 1;
if_err_return(rv, cell_reserve_ech(cell, nech)); if_err_return(rv, cell_reserve_ech(cell, nech + 1));
cell->ech[nech - 1] = ch; cell->ech[nech - 1] = ch;
} else { // make new ech } else { // make new ech
nech = 2; nech = 2;
if_err_return(rv, cell_reserve_ech(cell, nech)); if_err_return(rv, cell_reserve_ech(cell, nech + 1));
cell->ech[0] = cell->ch; cell->ech[0] = cell->ch;
cell->ech[1] = ch; cell->ech[1] = ch;
} }
@ -1854,14 +1871,22 @@ int tb_print(int x, int y, uintattr_t fg, uintattr_t bg, const char *str) {
int tb_print_ex(int x, int y, uintattr_t fg, uintattr_t bg, size_t *out_w, int tb_print_ex(int x, int y, uintattr_t fg, uintattr_t bg, size_t *out_w,
const char *str) { const char *str) {
int rv; int rv, w, ix, x_prev;
uint32_t uni; uint32_t uni;
int w, ix = x;
if (out_w) { if_not_init_return();
*out_w = 0;
if (!cellbuf_in_bounds(&global.back, x, y)) {
return TB_ERR_OUT_OF_BOUNDS;
} }
ix = x;
x_prev = x;
if (out_w) *out_w = 0;
while (*str) { while (*str) {
rv = tb_utf8_char_to_unicode(&uni, str); rv = tb_utf8_char_to_unicode(&uni, str);
if (rv < 0) { if (rv < 0) {
uni = 0xfffd; // replace invalid UTF-8 char with U+FFFD uni = 0xfffd; // replace invalid UTF-8 char with U+FFFD
str += rv * -1; str += rv * -1;
@ -1870,18 +1895,33 @@ int tb_print_ex(int x, int y, uintattr_t fg, uintattr_t bg, size_t *out_w,
} else { } else {
break; // shouldn't get here break; // shouldn't get here
} }
w = wcwidth((wchar_t)uni);
if (w < 0) w = 1; if (uni == '\n') { // TODO: \r, \t, \v, \f, etc?
if (w == 0 && x > ix) { x = ix;
if_err_return(rv, tb_extend_cell(x - 1, y, uni)); x_prev = x;
} else { y += 1;
if_err_return(rv, tb_set_cell(x, y, uni, fg, bg)); continue;
} else if (!iswprint((wint_t)uni)) {
uni = 0xfffd; // replace non-printable with U+FFFD
} }
x += w;
if (out_w) { w = wcwidth((wchar_t)uni);
*out_w += w; if (w < 0) {
return TB_ERR; // shouldn't happen if iswprint
} else if (w == 0) { // combining character
if (cellbuf_in_bounds(&global.back, x_prev, y)) {
if_err_return(rv, tb_extend_cell(x_prev, y, uni));
}
} else {
if (cellbuf_in_bounds(&global.back, x, y)) {
if_err_return(rv, tb_set_cell(x, y, uni, fg, bg));
}
x_prev = x;
x += w;
if (out_w) *out_w += w;
} }
} }
return TB_OK; return TB_OK;
} }
@ -2144,7 +2184,7 @@ static int init_cap_trie(void) {
// example, att605-pc collides on TB_CAP_F4 and TB_CAP_DELETE.) First cap // example, att605-pc collides on TB_CAP_F4 and TB_CAP_DELETE.) First cap
// in TB_CAP_* index order will win. // in TB_CAP_* index order will win.
// //
// TODO Reorder TB_CAP_* so more critical caps come first. // TODO: Reorder TB_CAP_* so more critical caps come first.
for (i = 0; i < TB_CAP__COUNT_KEYS; i++) { for (i = 0; i < TB_CAP__COUNT_KEYS; i++) {
rv = cap_trie_add(global.caps[i], tb_key_i(i), 0); rv = cap_trie_add(global.caps[i], tb_key_i(i), 0);
if (rv != TB_OK && rv != TB_ERR_CAP_COLLISION) return rv; if (rv != TB_OK && rv != TB_ERR_CAP_COLLISION) return rv;
@ -2184,8 +2224,8 @@ static int cap_trie_add(const char *cap, uint16_t key, uint8_t mod) {
if (!next) { if (!next) {
// We need to add a new child to node // We need to add a new child to node
node->nchildren += 1; node->nchildren += 1;
node->children = node->children = (struct cap_trie_t *)tb_realloc(node->children,
tb_realloc(node->children, sizeof(*node) * node->nchildren); sizeof(*node) * node->nchildren);
if (!node->children) { if (!node->children) {
return TB_ERR_MEM; return TB_ERR_MEM;
} }
@ -2325,7 +2365,7 @@ static int update_term_size_via_esc(void) {
#define TB_RESIZE_FALLBACK_MS 1000 #define TB_RESIZE_FALLBACK_MS 1000
#endif #endif
char *move_and_report = "\x1b[9999;9999H\x1b[6n"; char move_and_report[] = "\x1b[9999;9999H\x1b[6n";
ssize_t write_rv = ssize_t write_rv =
write(global.wfd, move_and_report, strlen(move_and_report)); write(global.wfd, move_and_report, strlen(move_and_report));
if (write_rv != (ssize_t)strlen(move_and_report)) { if (write_rv != (ssize_t)strlen(move_and_report)) {
@ -2394,7 +2434,10 @@ static int tb_deinit(void) {
} }
} }
sigaction(SIGWINCH, &(struct sigaction){.sa_handler = SIG_DFL}, NULL); struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = SIG_DFL;
sigaction(SIGWINCH, &sa, NULL);
if (global.resize_pipefd[0] >= 0) close(global.resize_pipefd[0]); if (global.resize_pipefd[0] >= 0) close(global.resize_pipefd[0]);
if (global.resize_pipefd[1] >= 0) close(global.resize_pipefd[1]); if (global.resize_pipefd[1] >= 0) close(global.resize_pipefd[1]);
@ -2501,7 +2544,7 @@ static int read_terminfo_path(const char *path) {
} }
size_t fsize = st.st_size; size_t fsize = st.st_size;
char *data = tb_malloc(fsize); char *data = (char *)tb_malloc(fsize);
if (!data) { if (!data) {
fclose(fp); fclose(fp);
return TB_ERR; return TB_ERR;
@ -2685,7 +2728,7 @@ static int wait_event(struct tb_event *event, int timeout) {
if (resize_has_events) { if (resize_has_events) {
int ignore = 0; int ignore = 0;
read(global.resize_pipefd[0], &ignore, sizeof(ignore)); read(global.resize_pipefd[0], &ignore, sizeof(ignore));
// TODO Harden against errors encountered mid-resize // TODO: Harden against errors encountered mid-resize
if_err_return(rv, update_term_size()); if_err_return(rv, update_term_size());
if_err_return(rv, resize_cellbufs()); if_err_return(rv, resize_cellbufs());
event->type = TB_EVENT_RESIZE; event->type = TB_EVENT_RESIZE;
@ -2812,7 +2855,7 @@ static int extract_esc_cap(struct tb_event *event) {
static int extract_esc_mouse(struct tb_event *event) { static int extract_esc_mouse(struct tb_event *event) {
struct bytebuf_t *in = &global.in; struct bytebuf_t *in = &global.in;
enum type { TYPE_VT200 = 0, TYPE_1006, TYPE_1015, TYPE_MAX }; enum { TYPE_VT200 = 0, TYPE_1006, TYPE_1015, TYPE_MAX };
const char *cmp[TYPE_MAX] = {// const char *cmp[TYPE_MAX] = {//
// X10 mouse encoding, the simplest one // X10 mouse encoding, the simplest one
@ -2824,7 +2867,7 @@ static int extract_esc_mouse(struct tb_event *event) {
// urxvt: \x1b [ Cb ; Cx ; Cy M // urxvt: \x1b [ Cb ; Cx ; Cy M
[TYPE_1015] = "\x1b["}; [TYPE_1015] = "\x1b["};
enum type type = 0; int type = 0;
int ret = TB_ERR; int ret = TB_ERR;
// Unrolled at compile-time (probably) // Unrolled at compile-time (probably)
@ -3224,13 +3267,18 @@ static int send_cluster(int x, int y, uint32_t *ch, size_t nch) {
int i; int i;
for (i = 0; i < (int)nch; i++) { for (i = 0; i < (int)nch; i++) {
uint32_t ch32 = *(ch + i); uint32_t ch32 = *(ch + i);
int chu8_len; if (!iswprint((wint_t)ch32)) {
ch32 = 0xfffd; // replace non-printable codepoints with U+FFFD
}
int chu8_len = tb_utf8_unicode_to_char(chu8, ch32);
/*
if (ch32 == 0) { // replace null with space (from termbox 19dbee5) if (ch32 == 0) { // replace null with space (from termbox 19dbee5)
chu8_len = 1; chu8_len = 1;
chu8[0] = ' '; chu8[0] = ' ';
} else { } else {
chu8_len = tb_utf8_unicode_to_char(chu8, ch32); chu8_len = tb_utf8_unicode_to_char(chu8, ch32);
} }
*/
if_err_return(rv, bytebuf_nputs(&global.out, chu8, (size_t)chu8_len)); if_err_return(rv, bytebuf_nputs(&global.out, chu8, (size_t)chu8_len));
} }
@ -3241,7 +3289,6 @@ static int convert_num(uint32_t num, char *buf) {
int i, l = 0; int i, l = 0;
char ch; char ch;
do { do {
/* '0' = 48; 48 + num%10 < 58 < MAX_8bitCHAR */
buf[l++] = (char)('0' + (num % 10)); buf[l++] = (char)('0' + (num % 10));
num /= 10; num /= 10;
} while (num); } while (num);
@ -3287,7 +3334,7 @@ static int cell_set(struct tb_cell *cell, uint32_t *ch, size_t nch,
} else { } else {
int rv; int rv;
if_err_return(rv, cell_reserve_ech(cell, nch + 1)); if_err_return(rv, cell_reserve_ech(cell, nch + 1));
memcpy(cell->ech, ch, sizeof(ch) * nch); memcpy(cell->ech, ch, sizeof(*ch) * nch);
cell->ech[nch] = '\0'; cell->ech[nch] = '\0';
cell->nech = nch; cell->nech = nch;
} }
@ -3303,7 +3350,7 @@ static int cell_reserve_ech(struct tb_cell *cell, size_t n) {
if (cell->cech >= n) { if (cell->cech >= n) {
return TB_OK; return TB_OK;
} }
if (!(cell->ech = tb_realloc(cell->ech, n * sizeof(cell->ch)))) { if (!(cell->ech = (uint32_t*)tb_realloc(cell->ech, n * sizeof(cell->ch)))) {
return TB_ERR_MEM; return TB_ERR_MEM;
} }
cell->cech = n; cell->cech = n;
@ -3326,7 +3373,7 @@ static int cell_free(struct tb_cell *cell) {
} }
static int cellbuf_init(struct cellbuf_t *c, int w, int h) { static int cellbuf_init(struct cellbuf_t *c, int w, int h) {
c->cells = tb_malloc(sizeof(struct tb_cell) * w * h); c->cells = (struct tb_cell *)tb_malloc(sizeof(struct tb_cell) * w * h);
if (!c->cells) { if (!c->cells) {
return TB_ERR_MEM; return TB_ERR_MEM;
} }
@ -3360,7 +3407,7 @@ static int cellbuf_clear(struct cellbuf_t *c) {
static int cellbuf_get(struct cellbuf_t *c, int x, int y, static int cellbuf_get(struct cellbuf_t *c, int x, int y,
struct tb_cell **out) { struct tb_cell **out) {
if (x < 0 || x >= c->width || y < 0 || y >= c->height) { if (!cellbuf_in_bounds(c, x, y)) {
*out = NULL; *out = NULL;
return TB_ERR_OUT_OF_BOUNDS; return TB_ERR_OUT_OF_BOUNDS;
} }
@ -3368,6 +3415,13 @@ static int cellbuf_get(struct cellbuf_t *c, int x, int y,
return TB_OK; return TB_OK;
} }
static int cellbuf_in_bounds(struct cellbuf_t *c, int x, int y) {
if (x < 0 || x >= c->width || y < 0 || y >= c->height) {
return 0;
}
return 1;
}
static int cellbuf_resize(struct cellbuf_t *c, int w, int h) { static int cellbuf_resize(struct cellbuf_t *c, int w, int h) {
int rv; int rv;
@ -3452,9 +3506,9 @@ static int bytebuf_reserve(struct bytebuf_t *b, size_t sz) {
} }
char *newbuf; char *newbuf;
if (b->buf) { if (b->buf) {
newbuf = tb_realloc(b->buf, newcap); newbuf = (char *)tb_realloc(b->buf, newcap);
} else { } else {
newbuf = tb_malloc(newcap); newbuf = (char *)tb_malloc(newcap);
} }
if (!newbuf) { if (!newbuf) {
return TB_ERR_MEM; return TB_ERR_MEM;
@ -3472,4 +3526,4 @@ static int bytebuf_free(struct bytebuf_t *b) {
return TB_OK; return TB_OK;
} }
#endif /* TB_IMPL */ #endif // TB_IMPL