summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@tavianator.com>2022-03-26 19:42:13 -0400
committerTavian Barnes <tavianator@tavianator.com>2022-03-26 19:42:13 -0400
commitc2139e2e03cbcee9a1ae03956b1f06d3a9c269b0 (patch)
treeb6bda303b95d1f783fa9ae885e14c864943a94ea
parent5026a144add526567771a75b414a4d9873054620 (diff)
downloadbfs-c2139e2e03cbcee9a1ae03956b1f06d3a9c269b0.tar.xz
util: New xstrwidth() function
-rw-r--r--util.c36
-rw-r--r--util.h10
2 files changed, 46 insertions, 0 deletions
diff --git a/util.c b/util.c
index f67406c..a62e66c 100644
--- a/util.c
+++ b/util.c
@@ -29,6 +29,7 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
+#include <wchar.h>
#if BFS_HAS_SYS_PARAM
# include <sys/param.h>
@@ -252,6 +253,41 @@ int xstrtofflags(const char **str, unsigned long long *set, unsigned long long *
#endif
}
+size_t xstrwidth(const char *str) {
+ size_t len = strlen(str);
+ size_t ret = 0;
+
+ mbstate_t mb;
+ memset(&mb, 0, sizeof(mb));
+
+ while (len > 0) {
+ wchar_t wc;
+ size_t mblen = mbrtowc(&wc, str, len, &mb);
+ int cwidth;
+ if (mblen == (size_t)-1) {
+ // Invalid byte sequence, assume a single-width '?'
+ mblen = 1;
+ cwidth = 1;
+ memset(&mb, 0, sizeof(mb));
+ } else if (mblen == (size_t)-2) {
+ // Incomplete byte sequence, assume a single-width '?'
+ mblen = len;
+ cwidth = 1;
+ } else {
+ cwidth = wcwidth(wc);
+ if (cwidth < 0) {
+ cwidth = 0;
+ }
+ }
+
+ str += mblen;
+ len -= mblen;
+ ret += cwidth;
+ }
+
+ return ret;
+}
+
bool is_nonexistence_error(int error) {
return error == ENOENT || errno == ENOTDIR;
}
diff --git a/util.h b/util.h
index b780624..b5c7d80 100644
--- a/util.h
+++ b/util.h
@@ -208,6 +208,16 @@ int xfaccessat(int fd, const char *path, int amode);
int xstrtofflags(const char **str, unsigned long long *set, unsigned long long *clear);
/**
+ * wcswidth() variant that works on narrow strings.
+ *
+ * @param str
+ * The string to measure.
+ * @return
+ * The likely width of that string in a terminal.
+ */
+size_t xstrwidth(const char *str);
+
+/**
* Return whether an error code is due to a path not existing.
*/
bool is_nonexistence_error(int error);