#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;
}
}
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);
}
}
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)) {
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);
}
*/
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.
const struct BFTW *ftwbuf = state->ftwbuf;
+ dchar *status = NULL;
dchar *rhs = dstrprintf(" (visited: %zu, depth: %2zu)", count, ftwbuf->depth);
if (!rhs) {
return;
rhslen = 0;
}
- dchar *status = dstralloc(0);
+ status = dstralloc(0);
if (!status) {
- goto out_rhs;
+ goto out;
}
const char *path = ftwbuf->path;
// 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);
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);
}