add nccell_load_ucs32

This commit is contained in:
nick black 2021-12-09 22:48:50 -05:00 committed by nick black
parent ed7213a8bf
commit ba1c79b66e
4 changed files with 56 additions and 22 deletions

View File

@ -9,6 +9,7 @@ rearrangements of Notcurses.
is automatically enlarged to accommodate output at its right (no scrolling) is automatically enlarged to accommodate output at its right (no scrolling)
or bottom (scrolling enabled) boundaries. or bottom (scrolling enabled) boundaries.
* Added `notcurses_default_background()` and `notcurses_default_foreground()`. * Added `notcurses_default_background()` and `notcurses_default_foreground()`.
* Added `nccell_load_ucs32()`.
* 3.0.0 (2021-12-01) **"In the A"** * 3.0.0 (2021-12-01) **"In the A"**
* Made the ABI/API changes that have been planned/collected during 2.x * Made the ABI/API changes that have been planned/collected during 2.x

View File

@ -2135,6 +2135,20 @@ nccell_load_egc32(struct ncplane* n, nccell* c, uint32_t egc){
return nccell_load(n, c, gcluster); return nccell_load(n, c, gcluster);
} }
// Load a UCS-32 codepoint into the nccell 'c'. Returns the number of bytes
// used, or -1 on error.
static inline int
nccell_load_ucs32(struct ncplane* n, nccell* c, uint32_t u){
unsigned char utf8[WCHAR_MAX_UTF8BYTES];
if(notcurses_ucs32_to_utf8(&u, 1, utf8, sizeof(utf8)) < 0){
return -1;
}
uint32_t utf8asegc;
_Static_assert(WCHAR_MAX_UTF8BYTES == sizeof(utf8asegc));
memcpy(&utf8asegc, utf8, sizeof(utf8));
return nccell_load_egc32(n, c, utf8asegc);
}
// return a pointer to the NUL-terminated EGC referenced by 'c'. this pointer // return a pointer to the NUL-terminated EGC referenced by 'c'. this pointer
// is invalidated by any further operation on the plane 'n', so...watch out! // is invalidated by any further operation on the plane 'n', so...watch out!
const char* nccell_extended_gcluster(const struct ncplane* n, const nccell* c); const char* nccell_extended_gcluster(const struct ncplane* n, const nccell* c);

View File

@ -74,6 +74,8 @@ typedef struct nccell {
**int nccell_load_egc32(struct ncplane* ***n***, nccell* ***c***, uint32_t ***egc***);** **int nccell_load_egc32(struct ncplane* ***n***, nccell* ***c***, uint32_t ***egc***);**
**int nccell_load_ucs32(struct ncplane* ***n***, nccell* ***c***, uint32_t ***u***);**
**char* nccell_extract(const struct ncplane* ***n***, const nccell* ***c***, uint16_t* ***stylemask***, uint64_t* ***channels***);** **char* nccell_extract(const struct ncplane* ***n***, const nccell* ***c***, uint16_t* ***stylemask***, uint64_t* ***channels***);**
**uint32_t nccell_bchannel(const nccell* ***c***);** **uint32_t nccell_bchannel(const nccell* ***c***);**
@ -144,10 +146,12 @@ must be considered associated with **ncplane**s. Indeed, **ncplane_erase**
destroys the backing storage for all a plane's cells, invalidating them. This destroys the backing storage for all a plane's cells, invalidating them. This
association is formed at the time of **nccell_load**, **nccell_prime**, or association is formed at the time of **nccell_load**, **nccell_prime**, or
**nccell_duplicate**. All of these functions first call **nccell_release**, as **nccell_duplicate**. All of these functions first call **nccell_release**, as
do **nccell_load_egc32** and **nccell_load_char**. When done using a **nccell** do **nccell_load_egc32**, **nccell_load_char**, and **nccell_load_ucs32**.
entirely, call **nccell_release**. **ncplane_destroy** will free up the memory When done using a **nccell** entirely, call **nccell_release**.
used by the **nccell**, but the backing egcpool has a maximum size of 16MiB, **ncplane_destroy** will free up the memory used by the **nccell**, but the
and failure to release **nccell**s can eventually block new output. backing egcpool has a maximum size of 16MiB, and failure to release **nccell**s
can eventually block new output. Writing over an **ncplane**'s cells releases
them automatically.
**nccell_extended_gcluster** provides a nul-terminated handle to the EGC. This **nccell_extended_gcluster** provides a nul-terminated handle to the EGC. This
ought be considered invalidated by changes to the **nccell** or **egcpool**. ought be considered invalidated by changes to the **nccell** or **egcpool**.

View File

@ -19,6 +19,7 @@
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#define RESTRICT #define RESTRICT
#define _Static_assert(...)
#else #else
#define RESTRICT restrict #define RESTRICT restrict
#endif #endif
@ -552,6 +553,24 @@ ncchannels_set_bg_default(uint64_t* channels){
return *channels; return *channels;
} }
// 0x0--0x10ffff can be UTF-8-encoded with only 4 bytes
#define WCHAR_MAX_UTF8BYTES 4
// Returns the number of columns occupied by the longest valid prefix of a
// multibyte (UTF-8) string. If an invalid character is encountered, -1 will be
// returned, and the number of valid bytes and columns will be written into
// *|validbytes| and *|validwidth| (assuming them non-NULL). If the entire
// string is valid, *|validbytes| and *|validwidth| reflect the entire string.
API int ncstrwidth(const char* egcs, int* validbytes, int* validwidth);
// input functions like notcurses_get() return ucs32-encoded uint32_t. convert
// a series of uint32_t to utf8. result must be at least 4 bytes per input
// uint32_t (6 bytes per uint32_t will future-proof against Unicode expansion).
// the number of bytes used is returned, or -1 if passed illegal ucs32, or too
// small of a buffer.
API int notcurses_ucs32_to_utf8(const uint32_t* ucs32, unsigned ucs32count,
unsigned char* resultbuf, size_t buflen);
// An nccell corresponds to a single character cell on some plane, which can be // An nccell corresponds to a single character cell on some plane, which can be
// occupied by a single grapheme cluster (some root spacing glyph, along with // occupied by a single grapheme cluster (some root spacing glyph, along with
// possible combining characters, which might span multiple columns). At any // possible combining characters, which might span multiple columns). At any
@ -851,6 +870,20 @@ nccell_load_egc32(struct ncplane* n, nccell* c, uint32_t egc){
return nccell_load(n, c, gcluster); return nccell_load(n, c, gcluster);
} }
// Load a UCS-32 codepoint into the nccell 'c'. Returns the number of bytes
// used, or -1 on error.
static inline int
nccell_load_ucs32(struct ncplane* n, nccell* c, uint32_t u){
unsigned char utf8[WCHAR_MAX_UTF8BYTES];
if(notcurses_ucs32_to_utf8(&u, 1, utf8, sizeof(utf8)) < 0){
return -1;
}
uint32_t utf8asegc;
_Static_assert(WCHAR_MAX_UTF8BYTES == sizeof(utf8asegc));
memcpy(&utf8asegc, utf8, sizeof(utf8));
return nccell_load_egc32(n, c, utf8asegc);
}
// These log levels consciously map cleanly to those of libav; Notcurses itself // These log levels consciously map cleanly to those of libav; Notcurses itself
// does not use this full granularity. The log level does not affect the opening // does not use this full granularity. The log level does not affect the opening
// and closing banners, which can be disabled via the notcurses_option struct's // and closing banners, which can be disabled via the notcurses_option struct's
@ -1885,21 +1918,6 @@ API ALLOC uint32_t* ncplane_as_rgba(const struct ncplane* n, ncblitter_e blit,
unsigned* pxdimy, unsigned* pxdimx) unsigned* pxdimy, unsigned* pxdimx)
__attribute__ ((nonnull (1))); __attribute__ ((nonnull (1)));
// Returns the number of columns occupied by the longest valid prefix of a
// multibyte (UTF-8) string. If an invalid character is encountered, -1 will be
// returned, and the number of valid bytes and columns will be written into
// *|validbytes| and *|validwidth| (assuming them non-NULL). If the entire
// string is valid, *|validbytes| and *|validwidth| reflect the entire string.
API int ncstrwidth(const char* egcs, int* validbytes, int* validwidth);
// input functions like notcurses_get() return ucs32-encoded uint32_t. convert
// a series of uint32_t to utf8. result must be at least 4 bytes per input
// uint32_t (6 bytes per uint32_t will future-proof against Unicode expansion).
// the number of bytes used is returned, or -1 if passed illegal ucs32, or too
// small of a buffer.
API int notcurses_ucs32_to_utf8(const uint32_t* ucs32, unsigned ucs32count,
unsigned char* resultbuf, size_t buflen);
// Return the offset into 'availu' at which 'u' ought be output given the // Return the offset into 'availu' at which 'u' ought be output given the
// requirements of 'align'. Return -INT_MAX on invalid 'align'. Undefined // requirements of 'align'. Return -INT_MAX on invalid 'align'. Undefined
// behavior on negative 'availu' or 'u'. // behavior on negative 'availu' or 'u'.
@ -2013,9 +2031,6 @@ ncplane_putegc(struct ncplane* n, const char* gclust, size_t* sbytes){
API int ncplane_putegc_stained(struct ncplane* n, const char* gclust, size_t* sbytes) API int ncplane_putegc_stained(struct ncplane* n, const char* gclust, size_t* sbytes)
__attribute__ ((nonnull (1, 2))); __attribute__ ((nonnull (1, 2)));
// 0x0--0x10ffff can be UTF-8-encoded with only 4 bytes
#define WCHAR_MAX_UTF8BYTES 4
// generate a heap-allocated UTF-8 encoding of the wide string 'src'. // generate a heap-allocated UTF-8 encoding of the wide string 'src'.
ALLOC static inline char* ALLOC static inline char*
ncwcsrtombs(const wchar_t* src){ ncwcsrtombs(const wchar_t* src){