diff --git a/include/notcurses/notcurses.h b/include/notcurses/notcurses.h index 802f852a9..89d557f3f 100644 --- a/include/notcurses/notcurses.h +++ b/include/notcurses/notcurses.h @@ -1830,20 +1830,25 @@ ncplane_putegc(struct ncplane* n, const char* gclust, int* sbytes){ // of the plane will not be changed. API int ncplane_putegc_stained(struct ncplane* n, const char* gclust, int* sbytes); -// 0x0--0x10ffff can be UTF-8-encoded with only 4 bytes...but we aren't -// yet actively guarding against higher values getting into wcstombs FIXME -#define WCHAR_MAX_UTF8BYTES 6 +// 0x0--0x10ffff can be UTF-8-encoded with only 4 bytes +#define WCHAR_MAX_UTF8BYTES 4 // ncplane_putegc(), but following a conversion from wchar_t to UTF-8 multibyte. static inline int ncplane_putwegc(struct ncplane* n, const wchar_t* gclust, int* sbytes){ - // maximum of six UTF8-encoded bytes per wchar_t - const size_t mbytes = (wcslen(gclust) * WCHAR_MAX_UTF8BYTES) + 1; + mbstate_t ps; + memset(&ps, 0, sizeof(ps)); + const wchar_t** wset = &gclust; + size_t mbytes = wcsrtombs(NULL, wset, 0, &ps); + if(mbytes == (size_t)-1){ + return -1; + } + ++mbytes; char* mbstr = (char*)malloc(mbytes); // need cast for c++ callers if(mbstr == NULL){ return -1; } - size_t s = wcstombs(mbstr, gclust, mbytes); + size_t s = wcsrtombs(mbstr, wset, mbytes, &ps); if(s == (size_t)-1){ free(mbstr); return -1; @@ -2802,8 +2807,8 @@ API int ncvisual_decode(struct ncvisual* nc) API int ncvisual_decode_loop(struct ncvisual* nc) __attribute__ ((nonnull (1))); -// Rotate the visual 'rads' radians. Only M_PI/2 and -M_PI/2 are -// supported at the moment, but this will change FIXME. +// Rotate the visual 'rads' radians. Only M_PI/2 and -M_PI/2 are supported at +// the moment, but this might change in the future. API int ncvisual_rotate(struct ncvisual* n, double rads) __attribute__ ((nonnull (1))); diff --git a/src/lib/direct.c b/src/lib/direct.c index 9557f080e..e8d1a86ff 100644 --- a/src/lib/direct.c +++ b/src/lib/direct.c @@ -1242,8 +1242,8 @@ int ncdirect_box(ncdirect* n, uint64_t ul, uint64_t ur, if(xlen < 2 || ylen < 2){ return -1; } - char hl[WCHAR_MAX_UTF8BYTES + 1]; - char vl[WCHAR_MAX_UTF8BYTES + 1]; + char hl[MB_CUR_MAX + 1]; + char vl[MB_CUR_MAX + 1]; unsigned edges; edges = !(ctlword & NCBOXMASK_TOP) + !(ctlword & NCBOXMASK_LEFT); if(edges >= box_corner_needs(ctlword)){ diff --git a/src/lib/notcurses.c b/src/lib/notcurses.c index f968d8dc6..68ee171fe 100644 --- a/src/lib/notcurses.c +++ b/src/lib/notcurses.c @@ -2972,13 +2972,19 @@ int ncplane_putstr_stained(struct ncplane* n, const char* gclusters){ } int ncplane_putwstr_stained(ncplane* n, const wchar_t* gclustarr){ - // maximum of six UTF8-encoded bytes per wchar_t - const size_t mbytes = (wcslen(gclustarr) * WCHAR_MAX_UTF8BYTES) + 1; - char* mbstr = malloc(mbytes); // need cast for c++ callers + mbstate_t ps = {}; + const wchar_t** wset = &gclustarr; + size_t mbytes = wcsrtombs(NULL, wset, 0, &ps); + if(mbytes == (size_t)-1){ + logerror("error converting wide string\n"); + return -1; + } + ++mbytes; + char* mbstr = malloc(mbytes); if(mbstr == NULL){ return -1; } - size_t s = wcstombs(mbstr, gclustarr, mbytes); + size_t s = wcsrtombs(mbstr, wset, mbytes, &ps); if(s == (size_t)-1){ free(mbstr); return -1;