]> Sergey Matveev's repositories - bfs.git/commitdiff
bfstd: Expose xmbrtowc() and use it in eval_status()
authorTavian Barnes <tavianator@tavianator.com>
Fri, 27 Oct 2023 14:58:47 +0000 (10:58 -0400)
committerTavian Barnes <tavianator@tavianator.com>
Fri, 27 Oct 2023 15:15:07 +0000 (11:15 -0400)
src/bfstd.c
src/bfstd.h
src/eval.c

index cdc33f18a718206523e2b3670e6717847538e086..a5a7e54d75ed92fd5330040de2884016a448a644 100644 (file)
@@ -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);
                }
 
index abde24e4ba6e6a82ca9380cafc43b03122576e8b..db558c6b1a7db1e0de5715269619669da7ccf33c 100644 (file)
@@ -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.
index 3d396fa0a938c50fcc48c19a0675faa82452aaf4..62303539f1802e9fcf3e103c2dbeb0c33cd2ef95 100644 (file)
@@ -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);
 }