summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@tavianator.com>2023-10-27 10:58:47 -0400
committerTavian Barnes <tavianator@tavianator.com>2023-10-27 11:15:07 -0400
commit14ef89a442f7a027f52fd688b438c5fa627b6af7 (patch)
treeb28e2f7114b067a26af6fffea044615d57ef10c8
parent8ced65189cbea5ff0b06482713d647ca57c91f81 (diff)
downloadbfs-14ef89a442f7a027f52fd688b438c5fa627b6af7.tar.xz
bfstd: Expose xmbrtowc() and use it in eval_status()
-rw-r--r--src/bfstd.c26
-rw-r--r--src/bfstd.h19
-rw-r--r--src/eval.c39
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.
diff --git a/src/eval.c b/src/eval.c
index 3d396fa..6230353 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -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);
}