чување e3e70e393bb7f227e0093bbf3a0dfc3399854546
родитељ d96590dd836da784c4949774f054b1c359caf705
Аутор: Страхиња Радић <contact@strahinja.org>
Датум: Fri, 4 Aug 2023 16:36:23 +0200
Update termbox.h; clarify license terms (GPL v3+)
Signed-off-by: Страхиња Радић <contact@strahinja.org>
Diffstat:
измењених датотека: 9, додавања: 495(+), брисања: 267(-)
diff --git a/README b/README
@@ -63,18 +63,13 @@ License
-------
sled - Simple text editor
-Copyright (C) 2022, 2023 Страхиња Радић
+Copyright (C) 2022-2023 Страхиња Радић
This program is free software: you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
----
-
-This program includes code from the termbox2 TUI library,
-
- https://github.com/termbox/termbox2
-
-The file LICENSE.termbox applies to the portion of this program which is from
-the termbox2 library. Currently, this includes only the file termbox.h.
+File termbox.h is based on termbox2 TUI library, (c) 2021 termbox developers,
+which is released under the terms of Expat license, see the file
+LICENSE.termbox.
diff --git a/config.def.h b/config.def.h
@@ -1,4 +1,6 @@
-/* See the file LICENSE for copyright and license details. */
+/* This program is licensed under the terms of GNU GPL v3 or (at your option)
+ * any later version.
+ * See the file LICENSE for exact copyright and license details. */
/* Comment out to not create backups */
#define CREATE_BACKUPS
diff --git a/draw.c b/draw.c
@@ -1,4 +1,6 @@
-/* See the file LICENSE for copyright and license details. */
+/* This program is licensed under the terms of GNU GPL v3 or (at your option)
+ * any later version.
+ * See the file LICENSE for exact copyright and license details. */
#define _POSIX_C_SOURCE 200809L
#define _DEFAULT_SOURCE
diff --git a/draw.h b/draw.h
@@ -1,4 +1,6 @@
-/* See the file LICENSE for copyright and license details. */
+/* This program is licensed under the terms of GNU GPL v3 or (at your option)
+ * any later version.
+ * See the file LICENSE for exact copyright and license details. */
#include <stddef.h>
#include <termios.h>
#include <unistd.h>
diff --git a/sled.1.in b/sled.1.in
@@ -45,11 +45,13 @@ sled \- Simple text editor
.LP
sled Copyright \(co 2022\-2023 Strahinya Radich.
.br
-This program is licensed under GNU GPL v3 or later. See the file
+This program is licensed under GNU GPL v3 or later.
+See the file
.I LICENSE
-in the sled repository for details. For licensing details about the portion of
-the code taken from the termbox2 library (\fItermbox.h\fR), see the file
-.IR "LICENSE.termbox" .
+in the sled repository for details.
+File \fItermbox.h\fR is based on termbox2 TUI library, (c) 2021 termbox
+developers, which is released under the terms of Expat license, see the file
+.IR LICENSE.termbox .
.
.SH DESCRIPTION
.
diff --git a/sled.c b/sled.c
@@ -1,4 +1,6 @@
-/* See the file LICENSE for copyright and license details. */
+/* This program is licensed under the terms of GNU GPL v3 or (at your option)
+ * any later version.
+ * See the file LICENSE for exact copyright and license details. */
#define _POSIX_C_SOURCE 200809L
#define _DEFAULT_SOURCE
@@ -1069,7 +1071,6 @@ erase_forward(struct DrawState* state)
else if (state->coord.row < state->rows_count - 1)
{
struct BufferLine* current = state->buffer + state->coord.row;
- /* TODO: realloc? */
if (state->coord.row == state->rows_count - 1
|| current->length
+ state->buffer[state->coord.row + 1].length
diff --git a/termbox.h b/termbox.h
@@ -1,8 +1,17 @@
+/* This program is licensed under the terms of GNU GPL v3 or (at your option)
+ * any later version.
+ * See the file LICENSE for exact copyright and license details. */
+
/*
+This file is based on the termbox2 TUI library, (c) 2021 termbox developers.
+
+License notice from the original termbox2.h from the termbox2 repository
+follows:
+
MIT License
Copyright (c) 2010-2020 nsf <no.smile.face@gmail.com>
- 2015-2021 Adam Saponara <as@php.net>
+ 2015-2023 Adam Saponara <as@php.net>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -52,10 +61,66 @@ SOFTWARE.
#include <unistd.h>
#include <wchar.h>
+#ifdef PATH_MAX
+#define TB_PATH_MAX PATH_MAX
+#else
+#define TB_PATH_MAX 4096
+#endif
+
#ifdef __cplusplus
extern "C" {
#endif
+// __ffi_start
+
+#define TB_VERSION_STR "2.4.0-dev"
+
+/* The following compile-time options are supported:
+ *
+ * TB_OPT_ATTR_W: Integer width of fg and bg attributes. Valid values
+ * (assuming system support) are 16, 32, and 64. (See
+ * uintattr_t). 32 or 64 enables output mode
+ * TB_OUTPUT_TRUECOLOR. 64 enables additional style
+ * attributes. (See tb_set_output_mode.) Larger values
+ * consume more memory in exchange for more features.
+ * Defaults to 16.
+ *
+ * TB_OPT_EGC: If set, enable extended grapheme cluster support
+ * (tb_extend_cell, tb_set_cell_ex). Consumes more memory.
+ * Defaults off.
+ *
+ * TB_OPT_PRINTF_BUF: Write buffer size for printf operations. Represents the
+ * largest string that can be sent in one call to tb_print*
+ * and tb_send* functions. Defaults to 4096.
+ *
+ * TB_OPT_READ_BUF: Read buffer size for tty reads. Defaults to 64.
+ *
+ * TB_OPT_TRUECOLOR: Deprecated. Sets TB_OPT_ATTR_W to 32 if not already set.
+ */
+
+#if defined(TB_LIB_OPTS) || 0 // __tb_lib_opts
+// Ensure consistent compile-time options when using as a shared library
+#undef TB_OPT_ATTR_W
+#undef TB_OPT_EGC
+#undef TB_OPT_PRINTF_BUF
+#undef TB_OPT_READ_BUF
+#define TB_OPT_ATTR_W 64
+#define TB_OPT_EGC
+#endif
+
+// Ensure sane TB_OPT_ATTR_W (16, 32, or 64)
+#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 == 64
+#else
+#undef TB_OPT_ATTR_W
+#if defined TB_OPT_TRUECOLOR // Back-compat for old flag
+#define TB_OPT_ATTR_W 32
+#else
+#define TB_OPT_ATTR_W 16
+#endif
+#endif
+
/* ASCII key constants (tb_event.key) */
#define TB_KEY_CTRL_TILDE 0x00
#define TB_KEY_CTRL_2 0x00 /* clash with 'CTRL_TILDE' */
@@ -106,7 +171,7 @@ extern "C" {
#define tb_key_i(i) 0xffff - (i)
/* Terminal-dependent key constants (tb_event.key) and terminfo capabilities */
/* BEGIN codegen h */
-/* Produced by ./codegen.sh on Sun, 19 Sep 2021 01:02:02 +0000 */
+/* Produced by ./codegen.sh on Thu, 13 Jul 2023 05:46:13 +0000 */
#define TB_KEY_F1 (0xffff - 0)
#define TB_KEY_F2 (0xffff - 1)
#define TB_KEY_F3 (0xffff - 2)
@@ -174,12 +239,17 @@ extern "C" {
#define TB_CAP_REVERSE 33
#define TB_CAP_ENTER_KEYPAD 34
#define TB_CAP_EXIT_KEYPAD 35
-#define TB_CAP__COUNT 36
+#define TB_CAP_DIM 36
+#define TB_CAP_INVISIBLE 37
+#define TB_CAP__COUNT 38
/* END codegen h */
/* Some hard-coded caps */
#define TB_HARDCAP_ENTER_MOUSE "\x1b[?1000h\x1b[?1002h\x1b[?1015h\x1b[?1006h"
#define TB_HARDCAP_EXIT_MOUSE "\x1b[?1006l\x1b[?1015l\x1b[?1002l\x1b[?1000l"
+#define TB_HARDCAP_STRIKEOUT "\x1b[9m"
+#define TB_HARDCAP_UNDERLINE_2 "\x1b[21m"
+#define TB_HARDCAP_OVERLINE "\x1b[53m"
/* Colors (numeric) and attributes (bitwise) (tb_cell.fg, tb_cell.bg) */
#define TB_DEFAULT 0x0000
@@ -191,17 +261,39 @@ extern "C" {
#define TB_MAGENTA 0x0006
#define TB_CYAN 0x0007
#define TB_WHITE 0x0008
-#define TB_BOLD 0x0100
-#define TB_UNDERLINE 0x0200
-#define TB_REVERSE 0x0400
-#define TB_ITALIC 0x0800
-#define TB_BLINK 0x1000
-#ifdef TB_OPT_TRUECOLOR
-#define TB_TRUECOLOR_BOLD 0x01000000
-#define TB_TRUECOLOR_UNDERLINE 0x02000000
-#define TB_TRUECOLOR_REVERSE 0x04000000
-#define TB_TRUECOLOR_ITALIC 0x08000000
-#define TB_TRUECOLOR_BLINK 0x10000000
+
+#if TB_OPT_ATTR_W == 16
+#define TB_BOLD 0x0100
+#define TB_UNDERLINE 0x0200
+#define TB_REVERSE 0x0400
+#define TB_ITALIC 0x0800
+#define TB_BLINK 0x1000
+#define TB_HI_BLACK 0x2000
+#define TB_BRIGHT 0x4000
+#define TB_DIM 0x8000
+#define TB_256_BLACK TB_HI_BLACK // TB_256_BLACK is deprecated
+#else // 32 or 64
+#define TB_BOLD 0x01000000
+#define TB_UNDERLINE 0x02000000
+#define TB_REVERSE 0x04000000
+#define TB_ITALIC 0x08000000
+#define TB_BLINK 0x10000000
+#define TB_HI_BLACK 0x20000000
+#define TB_BRIGHT 0x40000000
+#define TB_DIM 0x80000000
+#define TB_TRUECOLOR_BOLD TB_BOLD // TB_TRUECOLOR_* is deprecated
+#define TB_TRUECOLOR_UNDERLINE TB_UNDERLINE
+#define TB_TRUECOLOR_REVERSE TB_REVERSE
+#define TB_TRUECOLOR_ITALIC TB_ITALIC
+#define TB_TRUECOLOR_BLINK TB_BLINK
+#define TB_TRUECOLOR_BLACK TB_HI_BLACK
+#endif
+
+#if TB_OPT_ATTR_W == 64
+#define TB_STRIKEOUT 0x0000000100000000
+#define TB_UNDERLINE_2 0x0000000200000000
+#define TB_OVERLINE 0x0000000400000000
+#define TB_INVISIBLE 0x0000000800000000
#endif
/* Event types (tb_event.type) */
@@ -227,11 +319,16 @@ extern "C" {
#define TB_OUTPUT_256 2
#define TB_OUTPUT_216 3
#define TB_OUTPUT_GRAYSCALE 4
-#ifdef TB_OPT_TRUECOLOR
+#if TB_OPT_ATTR_W >= 32
#define TB_OUTPUT_TRUECOLOR 5
#endif
-/* 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
+ * attempt reinitializing by freeing memory, invoking tb_shutdown, then
+ * tb_init.
+ */
#define TB_OK 0
#define TB_ERR -1
#define TB_ERR_NEED_MORE -2
@@ -293,11 +390,11 @@ extern "C" {
#define tb_free free
#endif
-// __ffi_start
-
-#ifdef TB_OPT_TRUECOLOR
+#if TB_OPT_ATTR_W == 64
+typedef uint64_t uintattr_t;
+#elif TB_OPT_ATTR_W == 32
typedef uint32_t uintattr_t;
-#else
+#else // 16
typedef uint16_t uintattr_t;
#endif
@@ -324,8 +421,8 @@ typedef uint16_t uintattr_t;
*/
struct tb_cell {
uint32_t ch; /* a Unicode character */
- uintattr_t fg; /* bit-wise foreground attributes */
- uintattr_t bg; /* bit-wise background attributes */
+ uintattr_t fg; /* bitwise foreground attributes */
+ uintattr_t bg; /* bitwise background attributes */
#ifdef TB_OPT_EGC
uint32_t *ech; /* a grapheme cluster of Unicode code points */
size_t nech; /* length in bytes of ech, 0 means use ch instead of ech */
@@ -348,7 +445,7 @@ struct tb_cell {
*/
struct tb_event {
uint8_t type; /* one of TB_EVENT_* constants */
- uint8_t mod; /* bit-wise TB_MOD_* constants */
+ uint8_t mod; /* bitwise TB_MOD_* constants */
uint16_t key; /* one of TB_KEY_* constants */
uint32_t ch; /* a Unicode code point */
int32_t w; /* resize width */
@@ -362,11 +459,11 @@ struct tb_event {
* successful initialization, the library must be finalized using the
* tb_shutdown() function.
*/
-int tb_init();
+int tb_init(void);
int tb_init_file(const char *path);
int tb_init_fd(int ttyfd);
int tb_init_rwfd(int rfd, int wfd);
-int tb_shutdown();
+int tb_shutdown(void);
/* Returns 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
@@ -374,27 +471,37 @@ int tb_shutdown();
* unspecified negative value when called before tb_init() or after
* tb_shutdown().
*/
-int tb_width();
-int tb_height();
+int tb_width(void);
+int tb_height(void);
/* Clears the internal back buffer using TB_DEFAULT color or the
* color/attributes set by tb_set_clear_attrs() function.
*/
-int tb_clear();
+int tb_clear(void);
int tb_set_clear_attrs(uintattr_t fg, uintattr_t bg);
/* Synchronizes the internal back buffer with the terminal by writing to tty. */
-int tb_present();
+int tb_present(void);
+
+/* Clears 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
+ * circumstances. */
+int tb_invalidate(void);
/* Sets the position of the cursor. Upper-left character is (0, 0). */
int tb_set_cursor(int cx, int cy);
-int tb_hide_cursor();
+int tb_hide_cursor(void);
-/* Set cell contents in the internal back buffer at the specified position. Use
- * tb_set_cell_ex() for rendering grapheme clusters (e.g., combining diacritical
- * marks). Function tb_set_cell(x, y, ch, fg, bg) is equivalent to
- * tb_set_cell_ex(x, y, &ch, 1, fg, bg). tb_extend_cell() is a shortcut for
- * appending 1 code point to cell->ech.
+/* Set cell contents in the internal back buffer at the specified position.
+ *
+ * Use tb_set_cell_ex() for rendering grapheme clusters (e.g., combining
+ * diacritical marks).
+ *
+ * Function tb_set_cell(x, y, ch, fg, bg) is equivalent to
+ * tb_set_cell_ex(x, y, &ch, 1, fg, bg).
+ *
+ * Function tb_extend_cell() is a shortcut for appending 1 code point to
+ * cell->ech.
*/
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,
@@ -402,9 +509,11 @@ int tb_set_cell_ex(int x, int y, uint32_t *ch, size_t nch, uintattr_t fg,
int tb_extend_cell(int x, int y, uint32_t ch);
/* Sets the input mode. Termbox has two input modes:
+ *
* 1. TB_INPUT_ESC
* 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.
+ *
* 2. TB_INPUT_ALT
* 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.
@@ -422,47 +531,96 @@ int tb_extend_cell(int x, int y, uint32_t ch);
*/
int tb_set_input_mode(int mode);
-/* Sets the termbox output mode. Termbox has three output modes:
- * 1. TB_OUTPUT_NORMAL => [1..8]
+/* Sets the termbox output mode. Termbox has multiple output modes:
+ *
+ * 1. TB_OUTPUT_NORMAL => [0..8]
+ *
* This mode provides 8 different colors:
* TB_BLACK, TB_RED, TB_GREEN, TB_YELLOW,
* TB_BLUE, TB_MAGENTA, TB_CYAN, TB_WHITE
- * Colors may be bitwise OR'd with attributes:
- * TB_BOLD, TB_UNDERLINE, TB_REVERSE, TB_ITALIC, TB_BLINK
+ *
+ * Plus TB_DEFAULT which skips sending a color code (i.e., uses the
+ * terminal's default color).
+ *
+ * Colors (including TB_DEFAULT) may be bitwise OR'd with attributes:
+ * TB_BOLD, TB_UNDERLINE, TB_REVERSE, TB_ITALIC, TB_BLINK, TB_BRIGHT,
+ * TB_DIM
+ *
+ * The following style attributes are also available if compiled with
+ * TB_OPT_ATTR_W set to 64:
+ * TB_STRIKEOUT, TB_UNDERLINE_2, TB_OVERLINE, TB_INVISIBLE
+ *
+ * As in all modes, the value 0 is interpreted as TB_DEFAULT for
+ * convenience.
*
* Some notes: TB_REVERSE can be applied as either fg or bg attributes for
- * the same effect. TB_BOLD, TB_UNDERLINE, TB_ITALIC, TB_BLINK apply as fg
- * attributes only, and are ignored as bg attributes.
+ * the same effect. TB_BRIGHT can be applied to either fg or bg. The rest of
+ * the attributes apply to fg only and are ignored as bg attributes.
*
* Example usage:
* tb_set_cell(x, y, '@', TB_BLACK | TB_BOLD, TB_RED);
*
- * 2. TB_OUTPUT_256 => [0..255]
- * In this mode you get 256 distinct colors:
- * 0x00 - 0x07: the 8 colors as in TB_OUTPUT_NORMAL
- * 0x08 - 0x0f: bright versions of the above
- * 0x10 - 0xe7: 216 different colors
- * 0xe8 - 0xff: 24 different shades of grey
+ * 2. TB_OUTPUT_256 => [0..255] + TB_HI_BLACK
*
- * Example usage:
- * tb_set_cell(x, y, '@', 184, 240);
- * tb_set_cell(x, y, '@', 0xb8, 0xf0);
+ * In this mode you get 256 distinct colors (plus default):
+ * 0x00 (1): TB_DEFAULT
+ * TB_HI_BLACK (1): TB_BLACK in TB_OUTPUT_NORMAL
+ * 0x01..0x07 (7): the next 7 colors as in TB_OUTPUT_NORMAL
+ * 0x08..0x0f (8): bright versions of the above
+ * 0x10..0xe7 (216): 216 different colors
+ * 0xe8..0xff (24): 24 different shades of gray
+ *
+ * All TB_* style attributes except TB_BRIGHT may be bitwise OR'd as in
+ * TB_OUTPUT_NORMAL.
*
- * 3. TB_OUTPUT_216 => [0..215]
- * This mode supports the 3rd range of TB_OUTPUT_256 only, but you don't
- * need to provide an offset.
+ * Note TB_HI_BLACK must be used for black, as 0x00 represents default.
*
- * 4. TB_OUTPUT_GRAYSCALE => [0..23]
- * This mode supports the 4th range of TB_OUTPUT_256 only, but you don't
- * need to provide an offset.
+ * 3. TB_OUTPUT_216 => [0..216]
+ *
+ * This mode supports the 216-color range of TB_OUTPUT_256 only, but you
+ * don't need to provide an offset:
+ * 0x00 (1): TB_DEFAULT
+ * 0x01..0xd8 (216): 216 different colors
+ *
+ * 4. TB_OUTPUT_GRAYSCALE => [0..24]
+ *
+ * This mode supports the 24-color range of TB_OUTPUT_256 only, but you
+ * don't need to provide an offset:
+ * 0x00 (1): TB_DEFAULT
+ * 0x01..0x18 (24): 24 different shades of gray
+ *
+ * 5. TB_OUTPUT_TRUECOLOR => [0x000000..0xffffff] + TB_HI_BLACK
*
- * 5. TB_OUTPUT_TRUECOLOR => [0x000000..0xffffff]
* This mode provides 24-bit color on supported terminals. The format is
- * 0xRRGGBB. Colors may be bitwise OR'd with `TB_TRUECOLOR_*` attributes.
+ * 0xRRGGBB.
+ *
+ * All TB_* style attributes except TB_BRIGHT may be bitwise OR'd as in
+ * TB_OUTPUT_NORMAL.
+ *
+ * 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
+ * TB_DEFAULT. For convenience, the value 0 is interpreted as TB_DEFAULT in
+ * all modes.
+ *
+ * Note, cell attributes persist after switching output modes. Any translation
+ * between, for example, TB_OUTPUT_NORMAL's TB_RED and TB_OUTPUT_TRUECOLOR's
+ * 0xff0000 must be performed by the caller. Also note that cells previously
+ * rendered in one mode may persist unchanged until the front buffer is cleared
+ * (such as after a resize event) at which point it will be re-interpreted and
+ * flushed according to the current mode. Callers may invoke tb_invalidate if
+ * it is desirable to immediately re-interpret and flush the entire screen
+ * according to the current mode.
+ *
+ * Note, not all terminals support all output modes, especially beyond
+ * TB_OUTPUT_NORMAL. There is also no very reliable way to determine color
+ * support dynamically. If portability is desired, callers are recommended to
+ * use TB_OUTPUT_NORMAL or make output mode end-user configurable. The same
+ * advice applies to style attributes.
*/
int tb_set_output_mode(int mode);
@@ -513,11 +671,13 @@ int tb_set_func(int fn_type, int (*fn)(struct tb_event *, size_t *));
int tb_utf8_char_length(char c);
int tb_utf8_char_to_unicode(uint32_t *out, const char *c);
int tb_utf8_unicode_to_char(char *out, uint32_t c);
-int tb_last_errno();
+int tb_last_errno(void);
const char *tb_strerror(int err);
-struct tb_cell *tb_cell_buffer();
-int tb_has_truecolor();
-int tb_has_egc();
+struct tb_cell *tb_cell_buffer(void);
+int tb_has_truecolor(void);
+int tb_has_egc(void);
+int tb_attr_width(void);
+const char *tb_version(void);
#ifdef __cplusplus
}
@@ -528,17 +688,13 @@ int tb_has_egc();
#ifdef TB_IMPL
#define if_err_return(rv, expr) \
- if (((rv) = (expr)) != TB_OK) \
- return (rv)
+ if (((rv) = (expr)) != TB_OK) return (rv)
#define if_err_break(rv, expr) \
- if (((rv) = (expr)) != TB_OK) \
- break
+ if (((rv) = (expr)) != TB_OK) break
#define if_ok_return(rv, expr) \
- if (((rv) = (expr)) == TB_OK) \
- return (rv)
+ if (((rv) = (expr)) == TB_OK) return (rv)
#define if_ok_or_need_more_return(rv, expr) \
- if (((rv) = (expr)) == TB_OK || (rv) == TB_ERR_NEED_MORE) \
- return (rv)
+ if (((rv) = (expr)) == TB_OK || (rv) == TB_ERR_NEED_MORE) return (rv)
#define send_literal(rv, a) \
if_err_return((rv), bytebuf_nputs(&global.out, (a), sizeof(a) - 1))
@@ -550,13 +706,11 @@ int tb_has_egc();
#define snprintf_or_return(rv, str, sz, fmt, ...) \
do { \
(rv) = snprintf((str), (sz), (fmt), __VA_ARGS__); \
- if ((rv) < 0 || (rv) >= (int)(sz)) \
- return TB_ERR; \
+ if ((rv) < 0 || (rv) >= (int)(sz)) return TB_ERR; \
} while (0)
#define if_not_init_return() \
- if (!global.initialized) \
- return TB_ERR_NOT_INIT
+ if (!global.initialized) return TB_ERR_NOT_INIT
struct bytebuf_t {
char *buf;
@@ -609,15 +763,15 @@ struct tb_global_t {
int has_orig_tios;
int last_errno;
int initialized;
- int need_resize;
int (*fn_extract_esc_pre)(struct tb_event *, size_t *);
int (*fn_extract_esc_post)(struct tb_event *, size_t *);
+ char errbuf[1024];
};
static struct tb_global_t global = {0};
/* BEGIN codegen c */
-/* Produced by ./codegen.sh on Sun, 19 Sep 2021 01:02:03 +0000 */
+/* Produced by ./codegen.sh on Thu, 13 Jul 2023 05:46:13 +0000 */
static const int16_t terminfo_cap_indexes[] = {
66, // kf1 (TB_CAP_F1)
@@ -656,6 +810,8 @@ static const int16_t terminfo_cap_indexes[] = {
34, // rev (TB_CAP_REVERSE)
89, // smkx (TB_CAP_ENTER_KEYPAD)
88, // rmkx (TB_CAP_EXIT_KEYPAD)
+ 30, // dim (TB_CAP_DIM)
+ 32, // invis (TB_CAP_INVISIBLE)
};
// xterm
@@ -696,6 +852,8 @@ static const char *xterm_caps[] = {
"\033[7m", // rev (TB_CAP_REVERSE)
"\033[?1h\033=", // smkx (TB_CAP_ENTER_KEYPAD)
"\033[?1l\033>", // rmkx (TB_CAP_EXIT_KEYPAD)
+ "\033[2m", // dim (TB_CAP_DIM)
+ "\033[8m", // invis (TB_CAP_INVISIBLE)
};
// linux
@@ -722,7 +880,7 @@ static const char *linux_caps[] = {
"\033[B", // kcud1 (TB_CAP_ARROW_DOWN)
"\033[D", // kcub1 (TB_CAP_ARROW_LEFT)
"\033[C", // kcuf1 (TB_CAP_ARROW_RIGHT)
- "\033[Z", // kcbt (TB_CAP_BACK_TAB)
+ "\033\011", // kcbt (TB_CAP_BACK_TAB)
"", // smcup (TB_CAP_ENTER_CA)
"", // rmcup (TB_CAP_EXIT_CA)
"\033[?25h\033[?0c", // cnorm (TB_CAP_SHOW_CURSOR)
@@ -736,6 +894,8 @@ static const char *linux_caps[] = {
"\033[7m", // rev (TB_CAP_REVERSE)
"", // smkx (TB_CAP_ENTER_KEYPAD)
"", // rmkx (TB_CAP_EXIT_KEYPAD)
+ "\033[2m", // dim (TB_CAP_DIM)
+ "", // invis (TB_CAP_INVISIBLE)
};
// screen
@@ -776,6 +936,8 @@ static const char *screen_caps[] = {
"\033[7m", // rev (TB_CAP_REVERSE)
"\033[?1h\033=", // smkx (TB_CAP_ENTER_KEYPAD)
"\033[?1l\033>", // rmkx (TB_CAP_EXIT_KEYPAD)
+ "\033[2m", // dim (TB_CAP_DIM)
+ "", // invis (TB_CAP_INVISIBLE)
};
// rxvt-256color
@@ -816,6 +978,8 @@ static const char *rxvt_256color_caps[] = {
"\033[7m", // rev (TB_CAP_REVERSE)
"\033=", // smkx (TB_CAP_ENTER_KEYPAD)
"\033>", // rmkx (TB_CAP_EXIT_KEYPAD)
+ "", // dim (TB_CAP_DIM)
+ "", // invis (TB_CAP_INVISIBLE)
};
// rxvt-unicode
@@ -856,6 +1020,8 @@ static const char *rxvt_unicode_caps[] = {
"\033[7m", // rev (TB_CAP_REVERSE)
"\033=", // smkx (TB_CAP_ENTER_KEYPAD)
"\033>", // rmkx (TB_CAP_EXIT_KEYPAD)
+ "", // dim (TB_CAP_DIM)
+ "", // invis (TB_CAP_INVISIBLE)
};
// Eterm
@@ -896,6 +1062,8 @@ static const char *eterm_caps[] = {
"\033[7m", // rev (TB_CAP_REVERSE)
"", // smkx (TB_CAP_ENTER_KEYPAD)
"", // rmkx (TB_CAP_EXIT_KEYPAD)
+ "", // dim (TB_CAP_DIM)
+ "", // invis (TB_CAP_INVISIBLE)
};
static struct {
@@ -1300,40 +1468,42 @@ static const unsigned char utf8_length[256] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
static const unsigned char utf8_mask[6] = {0x7f, 0x1f, 0x0f, 0x07, 0x03, 0x01};
-static int tb_reset();
+static int tb_reset(void);
static int tb_printf_inner(int x, int y, uintattr_t fg, uintattr_t bg,
size_t *out_w, const char *fmt, va_list vl);
-static int init_term_attrs();
-static int init_term_caps();
-static int init_cap_trie();
+static int init_term_attrs(void);
+static int init_term_caps(void);
+static int init_cap_trie(void);
static int cap_trie_add(const char *cap, uint16_t key, uint8_t mod);
static int cap_trie_find(const char *buf, size_t nbuf, struct cap_trie_t **last,
size_t *depth);
static int cap_trie_deinit(struct cap_trie_t *node);
-static int init_resize_handler();
-static int send_init_escape_codes();
-static int send_clear();
-static int update_term_size();
-static int update_term_size_via_esc();
-static int init_cellbuf();
-static int tb_deinit();
-static int load_terminfo();
+static int init_resize_handler(void);
+static int send_init_escape_codes(void);
+static int send_clear(void);
+static int update_term_size(void);
+static int update_term_size_via_esc(void);
+static int init_cellbuf(void);
+static int tb_deinit(void);
+static int load_terminfo(void);
static int load_terminfo_from_path(const char *path, const char *term);
static int read_terminfo_path(const char *path);
-static int parse_terminfo_caps();
-static int load_builtin_caps();
+static int parse_terminfo_caps(void);
+static int load_builtin_caps(void);
static const char *get_terminfo_string(int16_t str_offsets_pos,
- int16_t str_table_pos, int16_t str_table_len, int16_t str_index);
+ int16_t str_offsets_len, int16_t str_table_pos, int16_t str_table_len,
+ int16_t str_index);
static int wait_event(struct tb_event *event, int timeout);
static int extract_event(struct tb_event *event);
static int extract_esc(struct tb_event *event);
static int extract_esc_user(struct tb_event *event, int is_post);
static int extract_esc_cap(struct tb_event *event);
static int extract_esc_mouse(struct tb_event *event);
-static int resize_if_needed();
+static int resize_cellbufs(void);
static void handle_resize(int sig);
static int send_attr(uintattr_t fg, uintattr_t bg);
-static int send_sgr(uintattr_t fg, uintattr_t bg);
+static int send_sgr(uint32_t fg, uint32_t bg, int fg_is_default,
+ int bg_is_default);
static int send_cursor_if(int x, int y);
static int send_char(int x, int y, uint32_t ch);
static int send_cluster(int x, int y, uint32_t *ch, size_t nch);
@@ -1356,7 +1526,7 @@ static int bytebuf_flush(struct bytebuf_t *b, int fd);
static int bytebuf_reserve(struct bytebuf_t *b, size_t sz);
static int bytebuf_free(struct bytebuf_t *b);
-int tb_init() {
+int tb_init(void) {
return tb_init_file("/dev/tty");
}
@@ -1404,26 +1574,24 @@ int tb_init_rwfd(int rfd, int wfd) {
return rv;
}
-int tb_shutdown() {
+int tb_shutdown(void) {
if_not_init_return();
tb_deinit();
return TB_OK;
}
-int tb_width() {
+int tb_width(void) {
if_not_init_return();
return global.width;
}
-int tb_height() {
+int tb_height(void) {
if_not_init_return();
return global.height;
}
-int tb_clear() {
- int rv;
+int tb_clear(void) {
if_not_init_return();
- if_err_return(rv, resize_if_needed());
return cellbuf_clear(&global.back);
}
@@ -1434,11 +1602,10 @@ int tb_set_clear_attrs(uintattr_t fg, uintattr_t bg) {
return TB_OK;
}
-int tb_present() {
+int tb_present(void) {
if_not_init_return();
int rv;
- if_err_return(rv, resize_if_needed());
// TODO Assert global.back.(width,height) == global.front.(width,height)
@@ -1459,7 +1626,8 @@ int tb_present() {
w = wcswidth((wchar_t *)back->ech, back->nech);
else
#endif
- w = wcwidth(back->ch);
+ /* wcwidth() simply returns -1 on overflow of wchar_t */
+ w = wcwidth((wchar_t)back->ch);
}
if (w < 1) {
w = 1;
@@ -1501,13 +1669,18 @@ int tb_present() {
return TB_OK;
}
+int tb_invalidate(void) {
+ int rv;
+ if_not_init_return();
+ if_err_return(rv, resize_cellbufs());
+ return TB_OK;
+}
+
int tb_set_cursor(int cx, int cy) {
if_not_init_return();
int rv;
- if (cx < 0)
- cx = 0;
- if (cy < 0)
- cy = 0;
+ if (cx < 0) cx = 0;
+ if (cy < 0) cy = 0;
if (global.cursor_x == -1) {
if_err_return(rv,
bytebuf_puts(&global.out, global.caps[TB_CAP_SHOW_CURSOR]));
@@ -1518,7 +1691,7 @@ int tb_set_cursor(int cx, int cy) {
return TB_OK;
}
-int tb_hide_cursor() {
+int tb_hide_cursor(void) {
if_not_init_return();
int rv;
if (global.cursor_x >= 0) {
@@ -1609,9 +1782,11 @@ int tb_set_output_mode(int mode) {
case TB_OUTPUT_256:
case TB_OUTPUT_216:
case TB_OUTPUT_GRAYSCALE:
-#ifdef TB_OPT_TRUECOLOR
+#if TB_OPT_ATTR_W >= 32
case TB_OUTPUT_TRUECOLOR:
#endif
+ global.last_fg = ~global.fg;
+ global.last_bg = ~global.bg;
global.output_mode = mode;
return TB_OK;
}
@@ -1651,7 +1826,7 @@ int tb_print_ex(int x, int y, uintattr_t fg, uintattr_t bg, size_t *out_w,
}
while (*str) {
str += tb_utf8_char_to_unicode(&uni, str);
- w = wcwidth(uni);
+ w = wcwidth((wchar_t)uni);
if (w < 0) {
w = 1;
}
@@ -1717,9 +1892,8 @@ int tb_set_func(int fn_type, int (*fn)(struct tb_event *, size_t *)) {
return TB_ERR;
}
-struct tb_cell *tb_cell_buffer() {
- if (!global.initialized)
- return NULL;
+struct tb_cell *tb_cell_buffer(void) {
+ if (!global.initialized) return NULL;
return global.back.cells;
}
@@ -1779,7 +1953,7 @@ int tb_utf8_unicode_to_char(char *out, uint32_t c) {
return len;
}
-int tb_last_errno() {
+int tb_last_errno(void) {
return global.last_errno;
}
@@ -1821,19 +1995,20 @@ const char *tb_strerror(int err) {
case TB_ERR_RESIZE_POLL:
case TB_ERR_RESIZE_READ:
default:
- return strerror(global.last_errno);
+ strerror_r(global.last_errno, global.errbuf, sizeof(global.errbuf));
+ return (const char *)global.errbuf;
}
}
-int tb_has_truecolor() {
-#ifdef TB_OPT_TRUECOLOR
+int tb_has_truecolor(void) {
+#if TB_OPT_ATTR_W >= 32
return 1;
#else
return 0;
#endif
}
-int tb_has_egc() {
+int tb_has_egc(void) {
#ifdef TB_OPT_EGC
return 1;
#else
@@ -1841,7 +2016,15 @@ int tb_has_egc() {
#endif
}
-static int tb_reset() {
+int tb_attr_width(void) {
+ return TB_OPT_ATTR_W;
+}
+
+const char *tb_version(void) {
+ return TB_VERSION_STR;
+}
+
+static int tb_reset(void) {
int ttyfd_open = global.ttyfd_open;
memset(&global, 0, sizeof(global));
global.ttyfd = -1;
@@ -1865,7 +2048,7 @@ static int tb_reset() {
return TB_OK;
}
-static int init_term_attrs() {
+static int init_term_attrs(void) {
if (global.ttyfd < 0) {
return TB_OK;
}
@@ -1902,31 +2085,37 @@ int tb_printf_inner(int x, int y, uintattr_t fg, uintattr_t bg, size_t *out_w,
return tb_print_ex(x, y, fg, bg, out_w, buf);
}
-static int init_term_caps() {
+static int init_term_caps(void) {
if (load_terminfo() == TB_OK) {
return parse_terminfo_caps();
}
return load_builtin_caps();
}
-static int init_cap_trie() {
+static int init_cap_trie(void) {
int rv, i;
// Add caps from terminfo or built-in
+ //
+ // Collisions are expected as some terminfo entries have dupes. (For
+ // example, att605-pc collides on TB_CAP_F4 and TB_CAP_DELETE.) First cap
+ // in TB_CAP_* index order will win.
+ //
+ // TODO Reorder TB_CAP_* so more critical caps come first.
for (i = 0; i < TB_CAP__COUNT_KEYS; i++) {
- if_err_return(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;
}
// Add built-in mod caps
+ //
+ // Collisions are OK here as well. This can happen if global.caps collides
+ // with builtin_mod_caps. It is desirable to give precedence to global.caps
+ // here.
for (i = 0; builtin_mod_caps[i].cap != NULL; i++) {
rv = cap_trie_add(builtin_mod_caps[i].cap, builtin_mod_caps[i].key,
builtin_mod_caps[i].mod);
- // Collisions are OK. This can happen if global.caps collides with
- // builtin_mod_caps. It is desirable to give precedence to global.caps
- // here.
- if (rv != TB_OK && rv != TB_ERR_CAP_COLLISION) {
- return rv;
- }
+ if (rv != TB_OK && rv != TB_ERR_CAP_COLLISION) return rv;
}
return TB_OK;
@@ -1935,6 +2124,9 @@ static int init_cap_trie() {
static int cap_trie_add(const char *cap, uint16_t key, uint8_t mod) {
struct cap_trie_t *next, *node = &global.cap_trie;
size_t i, j;
+
+ if (!cap || strlen(cap) <= 0) return TB_OK; // Nothing to do for empty caps
+
for (i = 0; cap[i] != '\0'; i++) {
char c = cap[i];
next = NULL;
@@ -2017,7 +2209,7 @@ static int cap_trie_deinit(struct cap_trie_t *node) {
return TB_OK;
}
-static int init_resize_handler() {
+static int init_resize_handler(void) {
if (pipe(global.resize_pipefd) != 0) {
global.last_errno = errno;
return TB_ERR_RESIZE_PIPE;
@@ -2034,7 +2226,7 @@ static int init_resize_handler() {
return TB_OK;
}
-static int send_init_escape_codes() {
+static int send_init_escape_codes(void) {
int rv;
if_err_return(rv, bytebuf_puts(&global.out, global.caps[TB_CAP_ENTER_CA]));
if_err_return(rv,
@@ -2044,7 +2236,7 @@ static int send_init_escape_codes() {
return TB_OK;
}
-static int send_clear() {
+static int send_clear(void) {
int rv;
if_err_return(rv, send_attr(global.fg, global.bg));
@@ -2060,8 +2252,8 @@ static int send_clear() {
return TB_OK;
}
-static int update_term_size() {
- int rv;
+static int update_term_size(void) {
+ int rv, ioctl_errno;
if (global.ttyfd < 0) {
return TB_OK;
@@ -2070,22 +2262,22 @@ static int update_term_size() {
struct winsize sz;
memset(&sz, 0, sizeof(sz));
+ // Try ioctl TIOCGWINSZ
if (ioctl(global.ttyfd, TIOCGWINSZ, &sz) == 0) {
global.width = sz.ws_col;
global.height = sz.ws_row;
return TB_OK;
}
+ ioctl_errno = errno;
- // If TB_RESIZE_FALLBACK deinfed, try >cursor(9999,9999), >u7, <u6
- //#ifdef TB_RESIZE_FALLBACK
+ // Try >cursor(9999,9999), >u7, <u6
if_ok_return(rv, update_term_size_via_esc());
- //#endif
- global.last_errno = errno;
+ global.last_errno = ioctl_errno;
return TB_ERR_RESIZE_IOCTL;
}
-static int update_term_size_via_esc() {
+static int update_term_size_via_esc(void) {
#ifndef TB_RESIZE_FALLBACK_MS
#define TB_RESIZE_FALLBACK_MS 1000
#endif
@@ -2130,7 +2322,7 @@ static int update_term_size_via_esc() {
return TB_OK;
}
-static int init_cellbuf() {
+static int init_cellbuf(void) {
int rv;
if_err_return(rv, cellbuf_init(&global.back, global.width, global.height));
if_err_return(rv, cellbuf_init(&global.front, global.width, global.height));
@@ -2139,7 +2331,7 @@ static int init_cellbuf() {
return TB_OK;
}
-static int tb_deinit() {
+static int tb_deinit(void) {
if (global.caps[0] != NULL && global.wfd >= 0) {
bytebuf_puts(&global.out, global.caps[TB_CAP_SHOW_CURSOR]);
bytebuf_puts(&global.out, global.caps[TB_CAP_SGR0]);
@@ -2160,18 +2352,15 @@ static int tb_deinit() {
}
sigaction(SIGWINCH, &(struct sigaction){.sa_handler = SIG_DFL}, NULL);
- 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[0] >= 0) close(global.resize_pipefd[0]);
+ if (global.resize_pipefd[1] >= 0) close(global.resize_pipefd[1]);
cellbuf_free(&global.back);
cellbuf_free(&global.front);
bytebuf_free(&global.in);
bytebuf_free(&global.out);
- if (global.terminfo)
- tb_free(global.terminfo);
+ if (global.terminfo) tb_free(global.terminfo);
cap_trie_deinit(&global.cap_trie);
@@ -2179,9 +2368,9 @@ static int tb_deinit() {
return TB_OK;
}
-static int load_terminfo() {
+static int load_terminfo(void) {
int rv;
- char tmp[PATH_MAX];
+ char tmp[TB_PATH_MAX];
// See terminfo(5) "Fetching Compiled Descriptions" for a description of
// this behavior. Some of these paths are compile-time ncurses options, so
@@ -2241,7 +2430,7 @@ static int load_terminfo() {
static int load_terminfo_from_path(const char *path, const char *term) {
int rv;
- char tmp[PATH_MAX];
+ char tmp[TB_PATH_MAX];
// Look for term at this terminfo location, e.g., <terminfo>/x/xterm
snprintf_or_return(rv, tmp, sizeof(tmp), "%s/%c/%s", path, term[0], term);
@@ -2288,7 +2477,7 @@ static int read_terminfo_path(const char *path) {
return TB_OK;
}
-static int parse_terminfo_caps() {
+static int parse_terminfo_caps(void) {
// See term(5) "LEGACY STORAGE FORMAT" and "EXTENDED STORAGE FORMAT" for a
// description of this behavior.
@@ -2328,8 +2517,8 @@ static int parse_terminfo_caps() {
// Load caps
int i;
for (i = 0; i < TB_CAP__COUNT; i++) {
- const char *cap = get_terminfo_string(pos_str_offsets, pos_str_table,
- header[5], terminfo_cap_indexes[i]);
+ const char *cap = get_terminfo_string(pos_str_offsets, header[4],
+ pos_str_table, header[5], terminfo_cap_indexes[i]);
if (!cap) {
// Something is not right
return TB_ERR;
@@ -2340,7 +2529,7 @@ static int parse_terminfo_caps() {
return TB_OK;
}
-static int load_builtin_caps() {
+static int load_builtin_caps(void) {
int i, j;
const char *term = getenv("TERM");
@@ -2375,16 +2564,30 @@ static int load_builtin_caps() {
}
static const char *get_terminfo_string(int16_t str_offsets_pos,
- int16_t str_table_pos, int16_t str_table_len, int16_t str_index) {
+ int16_t str_offsets_len, int16_t str_table_pos, int16_t str_table_len,
+ int16_t str_index) {
+ const int str_byte_index = (int)str_index * (int)sizeof(int16_t);
+ if (str_byte_index >= (int)str_offsets_len * (int)sizeof(int16_t)) {
+ // An offset beyond the table indicates absent
+ // See `convert_strings` in tinfo `read_entry.c`
+ return "";
+ }
const int16_t *str_offset =
- (int16_t *)(global.terminfo + (int)str_offsets_pos +
- ((int)str_index * (int)sizeof(int16_t)));
- if (*str_offset >= str_table_len) {
- // Invalid string offset
+ (int16_t *)(global.terminfo + (int)str_offsets_pos + str_byte_index);
+ if ((char *)str_offset >= global.terminfo + global.nterminfo) {
+ // str_offset points beyond end of entry
+ // Truncated/corrupt terminfo entry?
return NULL;
}
+ if (*str_offset < 0 || *str_offset >= str_table_len) {
+ // A negative offset indicates absent
+ // An offset beyond the table indicates absent
+ // See `convert_strings` in tinfo `read_entry.c`
+ return "";
+ }
if (((size_t)((int)str_table_pos + (int)*str_offset)) >= global.nterminfo) {
- // Truncated/corrupt terminfo?
+ // string points beyond end of entry
+ // Truncated/corrupt terminfo entry?
return NULL;
}
return (
@@ -2439,11 +2642,12 @@ static int wait_event(struct tb_event *event, int timeout) {
if (resize_has_events) {
int ignore = 0;
read(global.resize_pipefd[0], &ignore, sizeof(ignore));
+ // TODO Harden against errors encountered mid-resize
if_err_return(rv, update_term_size());
+ if_err_return(rv, resize_cellbufs());
event->type = TB_EVENT_RESIZE;
event->w = global.width;
event->h = global.height;
- global.need_resize = 1;
return TB_OK;
}
@@ -2677,10 +2881,10 @@ static int extract_esc_mouse(struct tb_event *event) {
} else {
int start = (type == TYPE_1015 ? 2 : 3);
- int n1 = strtoul(&in->buf[start], NULL, 10);
- int n2 =
+ unsigned n1 = strtoul(&in->buf[start], NULL, 10);
+ unsigned n2 =
strtoul(&in->buf[indices[FIRST_SEMICOLON] + 1], NULL, 10);
- int n3 =
+ unsigned n3 =
strtoul(&in->buf[indices[LAST_SEMICOLON] + 1], NULL, 10);
if (type == TYPE_1015) {
@@ -2744,19 +2948,14 @@ static int extract_esc_mouse(struct tb_event *event) {
return ret;
}
-static int resize_if_needed() {
+static int resize_cellbufs(void) {
int rv;
- if (!global.need_resize) {
- return TB_OK;
- }
- if_err_return(rv, update_term_size()); // TODO is this needed?
if_err_return(rv,
cellbuf_resize(&global.back, global.width, global.height));
if_err_return(rv,
cellbuf_resize(&global.front, global.width, global.height));
if_err_return(rv, cellbuf_clear(&global.front));
if_err_return(rv, send_clear());
- global.need_resize = 0;
return TB_OK;
}
@@ -2775,86 +2974,103 @@ static int send_attr(uintattr_t fg, uintattr_t bg) {
if_err_return(rv, bytebuf_puts(&global.out, global.caps[TB_CAP_SGR0]));
- uintattr_t cfg, cbg;
+ uint32_t cfg, cbg;
switch (global.output_mode) {
default:
case TB_OUTPUT_NORMAL:
- cfg = fg & 0x0f;
- cbg = bg & 0x0f;
+ // The minus 1 below is because our colors are 1-indexed starting
+ // from black. Black is represented by a 30, 40, 90, or 100 for fg,
+ // bg, bright fg, or bright bg respectively. Red is 31, 41, 91,
+ // 101, etc.
+ cfg = (fg & TB_BRIGHT ? 90 : 30) + (fg & 0x0f) - 1;
+ cbg = (bg & TB_BRIGHT ? 100 : 40) + (bg & 0x0f) - 1;
break;
case TB_OUTPUT_256:
cfg = fg & 0xff;
cbg = bg & 0xff;
+ if (fg & TB_HI_BLACK) cfg = 0;
+ if (bg & TB_HI_BLACK) cbg = 0;
break;
case TB_OUTPUT_216:
cfg = fg & 0xff;
- if (cfg > 215)
- cfg = 7;
cbg = bg & 0xff;
- if (cbg > 215)
- cbg = 0;
- cfg += 0x10;
- cbg += 0x10;
+ if (cfg > 216) cfg = 216;
+ if (cbg > 216) cbg = 216;
+ cfg += 0x0f;
+ cbg += 0x0f;
break;
case TB_OUTPUT_GRAYSCALE:
cfg = fg & 0xff;
- if (cfg > 23)
- cfg = 23;
cbg = bg & 0xff;
- if (cbg > 23)
- cbg = 0;
- cfg += 0xe8;
- cbg += 0xe8;
+ if (cfg > 24) cfg = 24;
+ if (cbg > 24) cbg = 24;
+ cfg += 0xe7;
+ cbg += 0xe7;
break;
-#ifdef TB_OPT_TRUECOLOR
+#if TB_OPT_ATTR_W >= 32
case TB_OUTPUT_TRUECOLOR:
- cfg = fg;
- cbg = bg;
+ cfg = fg & 0xffffff;
+ cbg = bg & 0xffffff;
+ if (fg & TB_HI_BLACK) cfg = 0;
+ if (bg & TB_HI_BLACK) cbg = 0;
break;
#endif
}
- uintattr_t attr_bold, attr_blink, attr_italic, attr_underline, attr_reverse;
-#ifdef TB_OPT_TRUECOLOR
- if (global.output_mode == TB_OUTPUT_TRUECOLOR) {
- attr_bold = TB_TRUECOLOR_BOLD;
- attr_blink = TB_TRUECOLOR_BLINK;
- attr_italic = TB_TRUECOLOR_ITALIC;
- attr_underline = TB_TRUECOLOR_UNDERLINE;
- attr_reverse = TB_TRUECOLOR_REVERSE;
- } else
-#endif
- {
- attr_bold = TB_BOLD;
- attr_blink = TB_BLINK;
- attr_italic = TB_ITALIC;
- attr_underline = TB_UNDERLINE;
- attr_reverse = TB_REVERSE;
- }
-
- if (fg & attr_bold)
+ if (fg & TB_BOLD)
if_err_return(rv, bytebuf_puts(&global.out, global.caps[TB_CAP_BOLD]));
- if (fg & attr_blink)
+ if (fg & TB_BLINK)
if_err_return(rv, bytebuf_puts(&global.out, global.caps[TB_CAP_BLINK]));
- if (fg & attr_underline)
+ if (fg & TB_UNDERLINE)
if_err_return(rv,
bytebuf_puts(&global.out, global.caps[TB_CAP_UNDERLINE]));
- if (fg & attr_italic)
+ if (fg & TB_ITALIC)
if_err_return(rv,
bytebuf_puts(&global.out, global.caps[TB_CAP_ITALIC]));
- if ((fg & attr_reverse) || (bg & attr_reverse))
+ if (fg & TB_DIM)
+ if_err_return(rv, bytebuf_puts(&global.out, global.caps[TB_CAP_DIM]));
+
+#if TB_OPT_ATTR_W == 64
+ if (fg & TB_STRIKEOUT)
+ if_err_return(rv, bytebuf_puts(&global.out, TB_HARDCAP_STRIKEOUT));
+
+ if (fg & TB_UNDERLINE_2)
+ if_err_return(rv, bytebuf_puts(&global.out, TB_HARDCAP_UNDERLINE_2));
+
+ if (fg & TB_OVERLINE)
+ if_err_return(rv, bytebuf_puts(&global.out, TB_HARDCAP_OVERLINE));
+
+ if (fg & TB_INVISIBLE)
+ if_err_return(rv,
+ bytebuf_puts(&global.out, global.caps[TB_CAP_INVISIBLE]));
+#endif
+
+ if ((fg & TB_REVERSE) || (bg & TB_REVERSE))
if_err_return(rv,
bytebuf_puts(&global.out, global.caps[TB_CAP_REVERSE]));
- if_err_return(rv, send_sgr(cfg, cbg));
+ int fg_is_default = (fg & 0xff) == 0;
+ int bg_is_default = (bg & 0xff) == 0;
+ if (global.output_mode == TB_OUTPUT_256) {
+ if (fg & TB_HI_BLACK) fg_is_default = 0;
+ if (bg & TB_HI_BLACK) bg_is_default = 0;
+ }
+#if TB_OPT_ATTR_W >= 32
+ if (global.output_mode == TB_OUTPUT_TRUECOLOR) {
+ fg_is_default = ((fg & 0xffffff) == 0) && ((fg & TB_HI_BLACK) == 0);
+ bg_is_default = ((bg & 0xffffff) == 0) && ((bg & TB_HI_BLACK) == 0);
+ }
+#endif
+
+ if_err_return(rv, send_sgr(cfg, cbg, fg_is_default, bg_is_default));
global.last_fg = fg;
global.last_bg = bg;
@@ -2862,16 +3078,12 @@ static int send_attr(uintattr_t fg, uintattr_t bg) {
return TB_OK;
}
-static int send_sgr(uintattr_t fg, uintattr_t bg) {
+static int send_sgr(uint32_t cfg, uint32_t cbg, int fg_is_default,
+ int bg_is_default) {
int rv;
char nbuf[32];
- if (
-#ifdef TB_OPT_TRUECOLOR
- global.output_mode != TB_OUTPUT_TRUECOLOR &&
-#endif
- fg == TB_DEFAULT && bg == TB_DEFAULT)
- {
+ if (fg_is_default && bg_is_default) {
return TB_OK;
}
@@ -2879,16 +3091,14 @@ static int send_sgr(uintattr_t fg, uintattr_t bg) {
default:
case TB_OUTPUT_NORMAL:
send_literal(rv, "\x1b[");
- if (fg != TB_DEFAULT) {
- send_literal(rv, "3");
- send_num(rv, nbuf, fg - 1);
- if (bg != TB_DEFAULT) {
+ if (!fg_is_default) {
+ send_num(rv, nbuf, cfg);
+ if (!bg_is_default) {
send_literal(rv, ";");
}
}
- if (bg != TB_DEFAULT) {
- send_literal(rv, "4");
- send_num(rv, nbuf, bg - 1);
+ if (!bg_is_default) {
+ send_num(rv, nbuf, cbg);
}
send_literal(rv, "m");
break;
@@ -2897,34 +3107,42 @@ static int send_sgr(uintattr_t fg, uintattr_t bg) {
case TB_OUTPUT_216:
case TB_OUTPUT_GRAYSCALE:
send_literal(rv, "\x1b[");
- if (fg != TB_DEFAULT) {
+ if (!fg_is_default) {
send_literal(rv, "38;5;");
- send_num(rv, nbuf, fg);
- if (bg != TB_DEFAULT) {
+ send_num(rv, nbuf, cfg);
+ if (!bg_is_default) {
send_literal(rv, ";");
}
}
- if (bg != TB_DEFAULT) {
+ if (!bg_is_default) {
send_literal(rv, "48;5;");
- send_num(rv, nbuf, bg);
+ send_num(rv, nbuf, cbg);
}
send_literal(rv, "m");
break;
-#ifdef TB_OPT_TRUECOLOR
+#if TB_OPT_ATTR_W >= 32
case TB_OUTPUT_TRUECOLOR:
- send_literal(rv, "\x1b[38;2;");
- send_num(rv, nbuf, (fg >> 16) & 0xff);
- send_literal(rv, ";");
- send_num(rv, nbuf, (fg >> 8) & 0xff);
- send_literal(rv, ";");
- send_num(rv, nbuf, fg & 0xff);
- send_literal(rv, ";48;2;");
- send_num(rv, nbuf, (bg >> 16) & 0xff);
- send_literal(rv, ";");
- send_num(rv, nbuf, (bg >> 8) & 0xff);
- send_literal(rv, ";");
- send_num(rv, nbuf, bg & 0xff);
+ send_literal(rv, "\x1b[");
+ if (!fg_is_default) {
+ send_literal(rv, "38;2;");
+ send_num(rv, nbuf, (cfg >> 16) & 0xff);
+ send_literal(rv, ";");
+ send_num(rv, nbuf, (cfg >> 8) & 0xff);
+ send_literal(rv, ";");
+ send_num(rv, nbuf, cfg & 0xff);
+ if (!bg_is_default) {
+ send_literal(rv, ";");
+ }
+ }
+ if (!bg_is_default) {
+ send_literal(rv, "48;2;");
+ send_num(rv, nbuf, (cbg >> 16) & 0xff);
+ send_literal(rv, ";");
+ send_num(rv, nbuf, (cbg >> 8) & 0xff);
+ send_literal(rv, ";");
+ send_num(rv, nbuf, cbg & 0xff);
+ }
send_literal(rv, "m");
break;
#endif
@@ -2975,9 +3193,10 @@ static int send_cluster(int x, int y, uint32_t *ch, size_t nch) {
static int convert_num(uint32_t num, char *buf) {
int i, l = 0;
- int ch;
+ char ch;
do {
- buf[l++] = '0' + (num % 10);
+ /* '0' = 48; 48 + num%10 < 58 < MAX_8bitCHAR */
+ buf[l++] = (char)('0' + (num % 10));
num /= 10;
} while (num);
for (i = 0; i < l / 2; i++) {
@@ -3140,6 +3359,7 @@ static int cellbuf_resize(struct cellbuf_t *c, int w, int h) {
}
static int bytebuf_puts(struct bytebuf_t *b, const char *str) {
+ if (!str || strlen(str) <= 0) return TB_OK; // Nothing to do for empty caps
return bytebuf_nputs(b, str, (size_t)strlen(str));
}
diff --git a/util.c b/util.c
@@ -1,4 +1,6 @@
-/* See the file LICENSE for copyright and license details. */
+/* This program is licensed under the terms of GNU GPL v3 or (at your option)
+ * any later version.
+ * See the file LICENSE for exact copyright and license details. */
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
diff --git a/version.h.in b/version.h.in
@@ -1,4 +1,6 @@
-/* See the file LICENSE for copyright and license details. */
+/* This program is licensed under the terms of GNU GPL v3 or (at your option)
+ * any later version.
+ * See the file LICENSE for exact copyright and license details. */
#define VERSION "%VERSION%"
#define DATE "%DATE%"