diff options
author | Tavian Barnes <tavianator@tavianator.com> | 2023-10-27 10:58:47 -0400 |
---|---|---|
committer | Tavian Barnes <tavianator@tavianator.com> | 2023-10-27 11:15:07 -0400 |
commit | 14ef89a442f7a027f52fd688b438c5fa627b6af7 (patch) | |
tree | b28e2f7114b067a26af6fffea044615d57ef10c8 | |
parent | 8ced65189cbea5ff0b06482713d647ca57c91f81 (diff) | |
download | bfs-14ef89a442f7a027f52fd688b438c5fa627b6af7.tar.xz |
bfstd: Expose xmbrtowc() and use it in eval_status()
-rw-r--r-- | src/bfstd.c | 26 | ||||
-rw-r--r-- | src/bfstd.h | 19 | ||||
-rw-r--r-- | src/eval.c | 39 |
3 files changed, 46 insertions, 38 deletions
diff --git a/src/bfstd.c b/src/bfstd.c index cdc33f1..a5a7e54 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -586,18 +586,18 @@ int xstrtofflags(const char **str, unsigned long long *set, unsigned long long * #endif } -/** mbrtowc() wrapper. */ -static int xmbrtowc(wchar_t *wc, size_t *i, const char *str, size_t len, mbstate_t *mb) { - size_t mblen = mbrtowc(wc, str + *i, len - *i, mb); +wint_t xmbrtowc(const char *str, size_t *i, size_t len, mbstate_t *mb) { + wchar_t wc; + size_t mblen = mbrtowc(&wc, str + *i, len - *i, mb); switch (mblen) { case -1: // Invalid byte sequence case -2: // Incomplete byte sequence *i += 1; memset(mb, 0, sizeof(*mb)); - return -1; + return WEOF; default: *i += mblen; - return 0; + return wc; } } @@ -609,12 +609,12 @@ size_t xstrwidth(const char *str) { memset(&mb, 0, sizeof(mb)); for (size_t i = 0; i < len;) { - wchar_t wc; - if (xmbrtowc(&wc, &i, str, len, &mb) == 0) { - ret += wcwidth(wc); - } else { + wint_t wc = xmbrtowc(str, &i, len, &mb); + if (wc == WEOF) { // Assume a single-width '?' ++ret; + } else { + ret += wcwidth(wc); } } @@ -729,8 +729,8 @@ multibyte: memset(&mb, 0, sizeof(mb)); for (size_t j = i; i < len; i = j) { - wchar_t wc; - if (xmbrtowc(&wc, &j, str, len, &mb) != 0) { + wint_t wc = xmbrtowc(str, &j, len, &mb); + if (wc == WEOF) { break; } if (!xiswprint(wc, flags)) { @@ -781,8 +781,8 @@ static char *dollar_quote(char *dest, char *end, const char *str, size_t len, en size_t start = i; bool safe = false; - wchar_t wc; - if (xmbrtowc(&wc, &i, str, len, &mb) == 0) { + wint_t wc = xmbrtowc(str, &i, len, &mb); + if (wc != WEOF) { safe = xiswprint(wc, flags); } diff --git a/src/bfstd.h b/src/bfstd.h index abde24e..db558c6 100644 --- a/src/bfstd.h +++ b/src/bfstd.h @@ -316,7 +316,24 @@ char *xconfstr(int name); */ int xstrtofflags(const char **str, unsigned long long *set, unsigned long long *clear); -// #include <wchar.h> +#include <wchar.h> + +/** + * Error-recovering mbrtowc() wrapper. + * + * @param str + * The string to convert. + * @param i + * The current index. + * @param len + * The length of the string. + * @param mb + * The multi-byte decoding state. + * @return + * The wide character at index *i, or WEOF if decoding fails. In either + * case, *i will be advanced to the next multi-byte character. + */ +wint_t xmbrtowc(const char *str, size_t *i, size_t len, mbstate_t *mb); /** * wcswidth() variant that works on narrow strings. @@ -1114,6 +1114,7 @@ static void eval_status(struct bfs_eval *state, struct bfs_bar *bar, struct time const struct BFTW *ftwbuf = state->ftwbuf; + dchar *status = NULL; dchar *rhs = dstrprintf(" (visited: %zu, depth: %2zu)", count, ftwbuf->depth); if (!rhs) { return; @@ -1125,9 +1126,9 @@ static void eval_status(struct bfs_eval *state, struct bfs_bar *bar, struct time rhslen = 0; } - dchar *status = dstralloc(0); + status = dstralloc(0); if (!status) { - goto out_rhs; + goto out; } const char *path = ftwbuf->path; @@ -1139,20 +1140,14 @@ static void eval_status(struct bfs_eval *state, struct bfs_bar *bar, struct time // Try to make sure even wide characters fit in the status bar size_t pathmax = width - rhslen - 3; size_t pathwidth = 0; + size_t lhslen = 0; mbstate_t mb; memset(&mb, 0, sizeof(mb)); - while (pathlen > 0) { - wchar_t wc; - size_t len = mbrtowc(&wc, path, pathlen, &mb); + for (size_t i = lhslen; lhslen < pathlen; lhslen = i) { + wint_t wc = xmbrtowc(path, &i, pathlen, &mb); int cwidth; - if (len == (size_t)-1) { + if (wc == WEOF) { // Invalid byte sequence, assume a single-width '?' - len = 1; - cwidth = 1; - memset(&mb, 0, sizeof(mb)); - } else if (len == (size_t)-2) { - // Incomplete byte sequence, assume a single-width '?' - len = pathlen; cwidth = 1; } else { cwidth = wcwidth(wc); @@ -1164,35 +1159,31 @@ static void eval_status(struct bfs_eval *state, struct bfs_bar *bar, struct time if (pathwidth + cwidth > pathmax) { break; } - - if (dstrncat(&status, path, len) != 0) { - goto out_rhs; - } - - path += len; - pathlen -= len; pathwidth += cwidth; } + if (dstrncat(&status, path, lhslen) != 0) { + goto out; + } if (dstrcat(&status, "...") != 0) { - goto out_rhs; + goto out; } while (pathwidth < pathmax) { if (dstrapp(&status, ' ') != 0) { - goto out_rhs; + goto out; } ++pathwidth; } - if (dstrcat(&status, rhs) != 0) { - goto out_rhs; + if (dstrdcat(&status, rhs) != 0) { + goto out; } bfs_bar_update(bar, status); +out: dstrfree(status); -out_rhs: dstrfree(rhs); } |