summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@tavianator.com>2022-11-06 17:47:23 -0500
committerTavian Barnes <tavianator@tavianator.com>2022-11-06 17:47:23 -0500
commitb4c7112bafe9b85f3a039a8b34fef2c1f2fa3b58 (patch)
tree4dbd16b8dac10609434eb8744f95762c4d178c19
parent096884c4fe1fb922eab2797d4583ca2ae8ae2600 (diff)
downloadbfs-b4c7112bafe9b85f3a039a8b34fef2c1f2fa3b58.tar.xz
bfstd: Rename from util and reorganize it
-rw-r--r--Makefile2
-rw-r--r--src/bar.c2
-rw-r--r--src/bfstd.c (renamed from src/util.c)556
-rw-r--r--src/bfstd.h (renamed from src/util.h)218
-rw-r--r--src/bftw.c2
-rw-r--r--src/color.c2
-rw-r--r--src/diag.c2
-rw-r--r--src/diag.h2
-rw-r--r--src/dir.c2
-rw-r--r--src/eval.c6
-rw-r--r--src/exec.c2
-rw-r--r--src/fsade.c3
-rw-r--r--src/main.c4
-rw-r--r--src/mtab.c2
-rw-r--r--src/opt.c1
-rw-r--r--src/parse.c2
-rw-r--r--src/printf.c2
-rw-r--r--src/stat.c6
-rw-r--r--src/xregex.c3
-rw-r--r--src/xspawn.c2
20 files changed, 419 insertions, 402 deletions
diff --git a/Makefile b/Makefile
index a251234..66126df 100644
--- a/Makefile
+++ b/Makefile
@@ -203,6 +203,7 @@ all: $(BIN)/bfs $(BIN)/tests/mksock $(BIN)/tests/trie $(BIN)/tests/xtimegm
$(BIN)/bfs: \
$(OBJ)/src/bar.o \
+ $(OBJ)/src/bfstd.o \
$(OBJ)/src/bftw.o \
$(OBJ)/src/color.o \
$(OBJ)/src/ctx.o \
@@ -222,7 +223,6 @@ $(BIN)/bfs: \
$(OBJ)/src/stat.o \
$(OBJ)/src/trie.o \
$(OBJ)/src/typo.o \
- $(OBJ)/src/util.o \
$(OBJ)/src/xregex.o \
$(OBJ)/src/xspawn.o \
$(OBJ)/src/xtime.o
diff --git a/src/bar.c b/src/bar.c
index b0e595e..c656b14 100644
--- a/src/bar.c
+++ b/src/bar.c
@@ -15,8 +15,8 @@
****************************************************************************/
#include "bar.h"
+#include "bfstd.h"
#include "dstring.h"
-#include "util.h"
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
diff --git a/src/util.c b/src/bfstd.c
index da54040..043e8e5 100644
--- a/src/util.c
+++ b/src/bfstd.c
@@ -14,7 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *
****************************************************************************/
-#include "util.h"
+#include "bfstd.h"
#include "config.h"
#include "dstring.h"
#include "xregex.h"
@@ -42,75 +42,197 @@
# include <util.h>
#endif
-char *xreadlinkat(int fd, const char *path, size_t size) {
- ssize_t len;
- char *name = NULL;
+bool is_nonexistence_error(int error) {
+ return error == ENOENT || errno == ENOTDIR;
+}
- if (size == 0) {
- size = 64;
+const char *xbasename(const char *path) {
+ const char *i;
+
+ // Skip trailing slashes
+ for (i = path + strlen(path); i > path && i[-1] == '/'; --i);
+
+ // Find the beginning of the name
+ for (; i > path && i[-1] != '/'; --i);
+
+ // Skip leading slashes
+ for (; i[0] == '/' && i[1]; ++i);
+
+ return i;
+}
+
+void close_quietly(int fd) {
+ int error = errno;
+ xclose(fd);
+ errno = error;
+}
+
+int xclose(int fd) {
+ int ret = close(fd);
+ if (ret != 0) {
+ assert(errno != EBADF);
+ }
+ return ret;
+}
+
+FILE *xfopen(const char *path, int flags) {
+ char mode[4];
+
+ switch (flags & O_ACCMODE) {
+ case O_RDONLY:
+ strcpy(mode, "rb");
+ break;
+ case O_WRONLY:
+ strcpy(mode, "wb");
+ break;
+ case O_RDWR:
+ strcpy(mode, "r+b");
+ break;
+ default:
+ assert(!"Invalid access mode");
+ errno = EINVAL;
+ return NULL;
+ }
+
+ if (flags & O_APPEND) {
+ mode[0] = 'a';
+ }
+
+ int fd;
+ if (flags & O_CREAT) {
+ fd = open(path, flags, 0666);
} else {
- ++size; // NUL terminator
+ fd = open(path, flags);
}
- while (true) {
- char *new_name = realloc(name, size);
- if (!new_name) {
- goto error;
+ if (fd < 0) {
+ return NULL;
+ }
+
+ FILE *ret = fdopen(fd, mode);
+ if (!ret) {
+ close_quietly(fd);
+ return NULL;
+ }
+
+ return ret;
+}
+
+char *xgetdelim(FILE *file, char delim) {
+ char *chunk = NULL;
+ size_t n = 0;
+ ssize_t len = getdelim(&chunk, &n, delim, file);
+ if (len >= 0) {
+ if (chunk[len] == delim) {
+ chunk[len] = '\0';
}
- name = new_name;
+ return chunk;
+ } else {
+ free(chunk);
+ if (!ferror(file)) {
+ errno = 0;
+ }
+ return NULL;
+ }
+}
- len = readlinkat(fd, path, name, size);
- if (len < 0) {
- goto error;
- } else if ((size_t)len >= size) {
- size *= 2;
- } else {
+size_t xread(int fd, void *buf, size_t nbytes) {
+ size_t count = 0;
+
+ while (count < nbytes) {
+ ssize_t ret = read(fd, (char *)buf + count, nbytes - count);
+ if (ret < 0) {
+ if (errno == EINTR) {
+ continue;
+ } else {
+ break;
+ }
+ } else if (ret == 0) {
+ // EOF
+ errno = 0;
break;
+ } else {
+ count += ret;
}
}
- name[len] = '\0';
- return name;
+ return count;
+}
-error:
- free(name);
- return NULL;
+size_t xwrite(int fd, const void *buf, size_t nbytes) {
+ size_t count = 0;
+
+ while (count < nbytes) {
+ ssize_t ret = write(fd, (const char *)buf + count, nbytes - count);
+ if (ret < 0) {
+ if (errno == EINTR) {
+ continue;
+ } else {
+ break;
+ }
+ } else if (ret == 0) {
+ // EOF?
+ errno = 0;
+ break;
+ } else {
+ count += ret;
+ }
+ }
+
+ return count;
}
-int dup_cloexec(int fd) {
-#ifdef F_DUPFD_CLOEXEC
- return fcntl(fd, F_DUPFD_CLOEXEC, 0);
-#else
- int ret = dup(fd);
- if (ret < 0) {
+/** Compile and execute a regular expression for xrpmatch(). */
+static int xrpregex(nl_item item, const char *response) {
+ const char *pattern = nl_langinfo(item);
+ if (!pattern) {
return -1;
}
- if (fcntl(ret, F_SETFD, FD_CLOEXEC) == -1) {
- close_quietly(ret);
- return -1;
+ struct bfs_regex *regex;
+ int ret = bfs_regcomp(&regex, pattern, BFS_REGEX_POSIX_EXTENDED, 0);
+ if (ret == 0) {
+ ret = bfs_regexec(regex, response, 0);
}
+ bfs_regfree(regex);
return ret;
-#endif
}
-int pipe_cloexec(int pipefd[2]) {
-#if __linux__ || (BSD && !__APPLE__)
- return pipe2(pipefd, O_CLOEXEC);
-#else
- if (pipe(pipefd) != 0) {
+/** Check if a response is affirmative or negative. */
+static int xrpmatch(const char *response) {
+ int ret = xrpregex(NOEXPR, response);
+ if (ret > 0) {
+ return 0;
+ } else if (ret < 0) {
return -1;
}
- if (fcntl(pipefd[0], F_SETFD, FD_CLOEXEC) == -1 || fcntl(pipefd[1], F_SETFD, FD_CLOEXEC) == -1) {
- close_quietly(pipefd[1]);
- close_quietly(pipefd[0]);
+ ret = xrpregex(YESEXPR, response);
+ if (ret > 0) {
+ return 1;
+ } else if (ret < 0) {
return -1;
}
- return 0;
-#endif
+ // Failsafe: always handle y/n
+ char c = response[0];
+ if (c == 'n' || c == 'N') {
+ return 0;
+ } else if (c == 'y' || c == 'Y') {
+ return 1;
+ } else {
+ return -1;
+ }
+}
+
+int ynprompt(void) {
+ fflush(stderr);
+
+ char *line = xgetdelim(stdin, '\n');
+ int ret = line ? xrpmatch(line) : -1;
+ free(line);
+ return ret;
}
/** Get the single character describing the given file type. */
@@ -195,19 +317,88 @@ void xstrmode(mode_t mode, char str[11]) {
}
}
-const char *xbasename(const char *path) {
- const char *i;
+dev_t xmakedev(int ma, int mi) {
+#ifdef makedev
+ return makedev(ma, mi);
+#else
+ return (ma << 8) | mi;
+#endif
+}
- // Skip trailing slashes
- for (i = path + strlen(path); i > path && i[-1] == '/'; --i);
+int xmajor(dev_t dev) {
+#ifdef major
+ return major(dev);
+#else
+ return dev >> 8;
+#endif
+}
- // Find the beginning of the name
- for (; i > path && i[-1] != '/'; --i);
+int xminor(dev_t dev) {
+#ifdef minor
+ return minor(dev);
+#else
+ return dev & 0xFF;
+#endif
+}
- // Skip leading slashes
- for (; i[0] == '/' && i[1]; ++i);
+int dup_cloexec(int fd) {
+#ifdef F_DUPFD_CLOEXEC
+ return fcntl(fd, F_DUPFD_CLOEXEC, 0);
+#else
+ int ret = dup(fd);
+ if (ret < 0) {
+ return -1;
+ }
- return i;
+ if (fcntl(ret, F_SETFD, FD_CLOEXEC) == -1) {
+ close_quietly(ret);
+ return -1;
+ }
+
+ return ret;
+#endif
+}
+
+int pipe_cloexec(int pipefd[2]) {
+#if __linux__ || (BSD && !__APPLE__)
+ return pipe2(pipefd, O_CLOEXEC);
+#else
+ if (pipe(pipefd) != 0) {
+ return -1;
+ }
+
+ if (fcntl(pipefd[0], F_SETFD, FD_CLOEXEC) == -1 || fcntl(pipefd[1], F_SETFD, FD_CLOEXEC) == -1) {
+ close_quietly(pipefd[1]);
+ close_quietly(pipefd[0]);
+ return -1;
+ }
+
+ return 0;
+#endif
+}
+
+char *xconfstr(int name) {
+#if __ANDROID__
+ errno = ENOTSUP;
+ return NULL;
+#else
+ size_t len = confstr(name, NULL, 0);
+ if (len == 0) {
+ return NULL;
+ }
+
+ char *str = malloc(len);
+ if (!str) {
+ return NULL;
+ }
+
+ if (confstr(name, str, len) != len) {
+ free(str);
+ return NULL;
+ }
+
+ return str;
+#endif // !__ANDROID__
}
int xfaccessat(int fd, const char *path, int amode) {
@@ -224,6 +415,41 @@ int xfaccessat(int fd, const char *path, int amode) {
return ret;
}
+char *xreadlinkat(int fd, const char *path, size_t size) {
+ ssize_t len;
+ char *name = NULL;
+
+ if (size == 0) {
+ size = 64;
+ } else {
+ ++size; // NUL terminator
+ }
+
+ while (true) {
+ char *new_name = realloc(name, size);
+ if (!new_name) {
+ goto error;
+ }
+ name = new_name;
+
+ len = readlinkat(fd, path, name, size);
+ if (len < 0) {
+ goto error;
+ } else if ((size_t)len >= size) {
+ size *= 2;
+ } else {
+ break;
+ }
+ }
+
+ name[len] = '\0';
+ return name;
+
+error:
+ free(name);
+ return NULL;
+}
+
int xstrtofflags(const char **str, unsigned long long *set, unsigned long long *clear) {
#if BSD && !__GNU__
char *str_arg = (char *)*str;
@@ -284,229 +510,3 @@ size_t xstrwidth(const char *str) {
return ret;
}
-
-bool is_nonexistence_error(int error) {
- return error == ENOENT || errno == ENOTDIR;
-}
-
-/** Compile and execute a regular expression for xrpmatch(). */
-static int xrpregex(nl_item item, const char *response) {
- const char *pattern = nl_langinfo(item);
- if (!pattern) {
- return -1;
- }
-
- struct bfs_regex *regex;
- int ret = bfs_regcomp(&regex, pattern, BFS_REGEX_POSIX_EXTENDED, 0);
- if (ret == 0) {
- ret = bfs_regexec(regex, response, 0);
- }
-
- bfs_regfree(regex);
- return ret;
-}
-
-/** Check if a response is affirmative or negative. */
-static int xrpmatch(const char *response) {
- int ret = xrpregex(NOEXPR, response);
- if (ret > 0) {
- return 0;
- } else if (ret < 0) {
- return -1;
- }
-
- ret = xrpregex(YESEXPR, response);
- if (ret > 0) {
- return 1;
- } else if (ret < 0) {
- return -1;
- }
-
- // Failsafe: always handle y/n
- char c = response[0];
- if (c == 'n' || c == 'N') {
- return 0;
- } else if (c == 'y' || c == 'Y') {
- return 1;
- } else {
- return -1;
- }
-}
-
-int ynprompt(void) {
- fflush(stderr);
-
- char *line = xgetdelim(stdin, '\n');
- int ret = line ? xrpmatch(line) : -1;
- free(line);
- return ret;
-}
-
-dev_t bfs_makedev(int ma, int mi) {
-#ifdef makedev
- return makedev(ma, mi);
-#else
- return (ma << 8) | mi;
-#endif
-}
-
-int bfs_major(dev_t dev) {
-#ifdef major
- return major(dev);
-#else
- return dev >> 8;
-#endif
-}
-
-int bfs_minor(dev_t dev) {
-#ifdef minor
- return minor(dev);
-#else
- return dev & 0xFF;
-#endif
-}
-
-size_t xread(int fd, void *buf, size_t nbytes) {
- size_t count = 0;
-
- while (count < nbytes) {
- ssize_t ret = read(fd, (char *)buf + count, nbytes - count);
- if (ret < 0) {
- if (errno == EINTR) {
- continue;
- } else {
- break;
- }
- } else if (ret == 0) {
- // EOF
- errno = 0;
- break;
- } else {
- count += ret;
- }
- }
-
- return count;
-}
-
-size_t xwrite(int fd, const void *buf, size_t nbytes) {
- size_t count = 0;
-
- while (count < nbytes) {
- ssize_t ret = write(fd, (const char *)buf + count, nbytes - count);
- if (ret < 0) {
- if (errno == EINTR) {
- continue;
- } else {
- break;
- }
- } else if (ret == 0) {
- // EOF?
- errno = 0;
- break;
- } else {
- count += ret;
- }
- }
-
- return count;
-}
-
-char *xconfstr(int name) {
-#if __ANDROID__
- errno = ENOTSUP;
- return NULL;
-#else
- size_t len = confstr(name, NULL, 0);
- if (len == 0) {
- return NULL;
- }
-
- char *str = malloc(len);
- if (!str) {
- return NULL;
- }
-
- if (confstr(name, str, len) != len) {
- free(str);
- return NULL;
- }
-
- return str;
-#endif // !__ANDROID__
-}
-
-char *xgetdelim(FILE *file, char delim) {
- char *chunk = NULL;
- size_t n = 0;
- ssize_t len = getdelim(&chunk, &n, delim, file);
- if (len >= 0) {
- if (chunk[len] == delim) {
- chunk[len] = '\0';
- }
- return chunk;
- } else {
- free(chunk);
- if (!ferror(file)) {
- errno = 0;
- }
- return NULL;
- }
-}
-
-FILE *xfopen(const char *path, int flags) {
- char mode[4];
-
- switch (flags & O_ACCMODE) {
- case O_RDONLY:
- strcpy(mode, "rb");
- break;
- case O_WRONLY:
- strcpy(mode, "wb");
- break;
- case O_RDWR:
- strcpy(mode, "r+b");
- break;
- default:
- assert(!"Invalid access mode");
- errno = EINVAL;
- return NULL;
- }
-
- if (flags & O_APPEND) {
- mode[0] = 'a';
- }
-
- int fd;
- if (flags & O_CREAT) {
- fd = open(path, flags, 0666);
- } else {
- fd = open(path, flags);
- }
-
- if (fd < 0) {
- return NULL;
- }
-
- FILE *ret = fdopen(fd, mode);
- if (!ret) {
- close_quietly(fd);
- return NULL;
- }
-
- return ret;
-}
-
-int xclose(int fd) {
- int ret = close(fd);
- if (ret != 0) {
- assert(errno != EBADF);
- }
- return ret;
-}
-
-void close_quietly(int fd) {
- int error = errno;
- xclose(fd);
- errno = error;
-}
diff --git a/src/util.h b/src/bfstd.h
index 2d99152..3ad2116 100644
--- a/src/util.h
+++ b/src/bfstd.h
@@ -15,113 +15,107 @@
****************************************************************************/
/**
- * Assorted utilities that don't belong anywhere else.
+ * Standard library wrappers and polyfills.
*/
-#ifndef BFS_UTIL_H
-#define BFS_UTIL_H
+#ifndef BFS_BFSTD_H
+#define BFS_BFSTD_H
-#include <fcntl.h>
-#include <fnmatch.h>
#include <stdbool.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <sys/types.h>
-// Some portability concerns
+// #include <errno.h>
-#if !defined(FNM_CASEFOLD) && defined(FNM_IGNORECASE)
-# define FNM_CASEFOLD FNM_IGNORECASE
-#endif
+/**
+ * Return whether an error code is due to a path not existing.
+ */
+bool is_nonexistence_error(int error);
+
+#include <fcntl.h>
#ifndef O_DIRECTORY
# define O_DIRECTORY 0
#endif
+#include <fnmatch.h>
+
+#if !defined(FNM_CASEFOLD) && defined(FNM_IGNORECASE)
+# define FNM_CASEFOLD FNM_IGNORECASE
+#endif
+
+// #include <libgen.h>
+
/**
- * readlinkat() wrapper that dynamically allocates the result.
+ * basename() variant that doesn't modify the input.
*
- * @param fd
- * The base directory descriptor.
* @param path
- * The path to the link, relative to fd.
- * @param size
- * An estimate for the size of the link name (pass 0 if unknown).
- * @return The target of the link, allocated with malloc(), or NULL on failure.
+ * The path in question.
+ * @return A pointer into path at the base name offset.
*/
-char *xreadlinkat(int fd, const char *path, size_t size);
+const char *xbasename(const char *path);
-/**
- * Like dup(), but set the FD_CLOEXEC flag.
- *
- * @param fd
- * The file descriptor to duplicate.
- * @return A duplicated file descriptor, or -1 on failure.
- */
-int dup_cloexec(int fd);
+#include <stdio.h>
/**
- * Like pipe(), but set the FD_CLOEXEC flag.
+ * close() variant that preserves errno.
*
- * @param pipefd
- * The array to hold the two file descriptors.
- * @return 0 on success, -1 on failure.
+ * @param fd
+ * The file descriptor to close.
*/
-int pipe_cloexec(int pipefd[2]);
+void close_quietly(int fd);
/**
- * Format a mode like ls -l (e.g. -rw-r--r--).
+ * close() wrapper that asserts the file descriptor is valid.
*
- * @param mode
- * The mode to format.
- * @param str
- * The string to hold the formatted mode.
+ * @param fd
+ * The file descriptor to close.
+ * @return
+ * 0 on success, or -1 on error.
*/
-void xstrmode(mode_t mode, char str[11]);
+int xclose(int fd);
/**
- * basename() variant that doesn't modify the input.
+ * fopen() variant that takes open() style flags.
*
* @param path
- * The path in question.
- * @return A pointer into path at the base name offset.
+ * The path to open.
+ * @param flags
+ * Flags to pass to open().
*/
-const char *xbasename(const char *path);
+FILE *xfopen(const char *path, int flags);
/**
- * Wrapper for faccessat() that handles some portability issues.
+ * Convenience wrapper for getdelim().
+ *
+ * @param file
+ * The file to read.
+ * @param delim
+ * The delimiter character to split on.
+ * @return
+ * The read chunk (without the delimiter), allocated with malloc().
+ * NULL is returned on error (errno != 0) or end of file (errno == 0).
*/
-int xfaccessat(int fd, const char *path, int amode);
+char *xgetdelim(FILE *file, char delim);
/**
- * Portability wrapper for strtofflags().
+ * A safe version of read() that handles interrupted system calls and partial
+ * reads.
*
- * @param str
- * The string to parse. The pointee will be advanced to the first
- * invalid position on error.
- * @param set
- * The flags that are set in the string.
- * @param clear
- * The flags that are cleared in the string.
* @return
- * 0 on success, -1 on failure.
+ * The number of bytes read. A value != nbytes indicates an error
+ * (errno != 0) or end of file (errno == 0).
*/
-int xstrtofflags(const char **str, unsigned long long *set, unsigned long long *clear);
+size_t xread(int fd, void *buf, size_t nbytes);
/**
- * wcswidth() variant that works on narrow strings.
+ * A safe version of write() that handles interrupted system calls and partial
+ * writes.
*
- * @param str
- * The string to measure.
* @return
- * The likely width of that string in a terminal.
+ The number of bytes written. A value != nbytes indicates an error.
*/
-size_t xstrwidth(const char *str);
+size_t xwrite(int fd, const void *buf, size_t nbytes);
-/**
- * Return whether an error code is due to a path not existing.
- */
-bool is_nonexistence_error(int error);
+// #include <stdlib.h>
/**
* Process a yes/no prompt.
@@ -130,39 +124,56 @@ bool is_nonexistence_error(int error);
*/
int ynprompt(void);
+// #include <string.h>
+
+/**
+ * Format a mode like ls -l (e.g. -rw-r--r--).
+ *
+ * @param mode
+ * The mode to format.
+ * @param str
+ * The string to hold the formatted mode.
+ */
+void xstrmode(mode_t mode, char str[11]);
+
+#include <sys/types.h>
+
/**
* Portable version of makedev().
*/
-dev_t bfs_makedev(int ma, int mi);
+dev_t xmakedev(int ma, int mi);
/**
* Portable version of major().
*/
-int bfs_major(dev_t dev);
+int xmajor(dev_t dev);
/**
* Portable version of minor().
*/
-int bfs_minor(dev_t dev);
+int xminor(dev_t dev);
+
+#include <unistd.h>
/**
- * A safe version of read() that handles interrupted system calls and partial
- * reads.
+ * Like dup(), but set the FD_CLOEXEC flag.
*
+ * @param fd
+ * The file descriptor to duplicate.
* @return
- * The number of bytes read. A value != nbytes indicates an error
- * (errno != 0) or end of file (errno == 0).
+ * A duplicated file descriptor, or -1 on failure.
*/
-size_t xread(int fd, void *buf, size_t nbytes);
+int dup_cloexec(int fd);
/**
- * A safe version of write() that handles interrupted system calls and partial
- * writes.
+ * Like pipe(), but set the FD_CLOEXEC flag.
*
+ * @param pipefd
+ * The array to hold the two file descriptors.
* @return
- The number of bytes written. A value != nbytes indicates an error.
+ * 0 on success, -1 on failure.
*/
-size_t xwrite(int fd, const void *buf, size_t nbytes);
+int pipe_cloexec(int pipefd[2]);
/**
* Wrapper for confstr() that allocates with malloc().
@@ -175,44 +186,49 @@ size_t xwrite(int fd, const void *buf, size_t nbytes);
char *xconfstr(int name);
/**
- * Convenience wrapper for getdelim().
- *
- * @param file
- * The file to read.
- * @param delim
- * The delimiter character to split on.
- * @return
- * The read chunk (without the delimiter), allocated with malloc().
- * NULL is returned on error (errno != 0) or end of file (errno == 0).
+ * Wrapper for faccessat() that handles some portability issues.
*/
-char *xgetdelim(FILE *file, char delim);
+int xfaccessat(int fd, const char *path, int amode);
/**
- * fopen() variant that takes open() style flags.
+ * readlinkat() wrapper that dynamically allocates the result.
*
+ * @param fd
+ * The base directory descriptor.
* @param path
- * The path to open.
- * @param flags
- * Flags to pass to open().
+ * The path to the link, relative to fd.
+ * @param size
+ * An estimate for the size of the link name (pass 0 if unknown).
+ * @return
+ * The target of the link, allocated with malloc(), or NULL on failure.
*/
-FILE *xfopen(const char *path, int flags);
+char *xreadlinkat(int fd, const char *path, size_t size);
/**
- * close() wrapper that asserts the file descriptor is valid.
+ * Portability wrapper for strtofflags().
*
- * @param fd
- * The file descriptor to close.
+ * @param str
+ * The string to parse. The pointee will be advanced to the first
+ * invalid position on error.
+ * @param set
+ * The flags that are set in the string.
+ * @param clear
+ * The flags that are cleared in the string.
* @return
- * 0 on success, or -1 on error.
+ * 0 on success, -1 on failure.
*/
-int xclose(int fd);
+int xstrtofflags(const char **str, unsigned long long *set, unsigned long long *clear);
+
+// #include <wchar.h>
/**
- * close() variant that preserves errno.
+ * wcswidth() variant that works on narrow strings.
*
- * @param fd
- * The file descriptor to close.
+ * @param str
+ * The string to measure.
+ * @return
+ * The likely width of that string in a terminal.
*/
-void close_quietly(int fd);
+size_t xstrwidth(const char *str);
-#endif // BFS_UTIL_H
+#endif // BFS_BFSTD_H
diff --git a/src/bftw.c b/src/bftw.c
index 6f97bf6..378a225 100644
--- a/src/bftw.c
+++ b/src/bftw.c
@@ -31,13 +31,13 @@
*/
#include "bftw.h"
+#include "bfstd.h"
#include "dir.h"
#include "darray.h"
#include "dstring.h"
#include "mtab.h"
#include "stat.h"
#include "trie.h"
-#include "util.h"
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
diff --git a/src/color.c b/src/color.c
index 6240b9c..98fe9f2 100644
--- a/src/color.c
+++ b/src/color.c
@@ -15,6 +15,7 @@
****************************************************************************/
#include "color.h"
+#include "bfstd.h"
#include "bftw.h"
#include "dir.h"
#include "dstring.h"
@@ -22,7 +23,6 @@
#include "fsade.h"
#include "stat.h"
#include "trie.h"
-#include "util.h"
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
diff --git a/src/diag.c b/src/diag.c
index 27848f1..a9be5b4 100644
--- a/src/diag.c
+++ b/src/diag.c
@@ -15,10 +15,10 @@
****************************************************************************/
#include "diag.h"
+#include "bfstd.h"
#include "ctx.h"
#include "color.h"
#include "expr.h"
-#include "util.h"
#include <assert.h>
#include <errno.h>
#include <stdarg.h>
diff --git a/src/diag.h b/src/diag.h
index 39129cc..56ad39b 100644
--- a/src/diag.h
+++ b/src/diag.h
@@ -22,7 +22,7 @@
#define BFS_DIAG_H
#include "ctx.h"
-#include "util.h"
+#include "config.h"
#include <stdarg.h>
#include <stdbool.h>
diff --git a/src/dir.c b/src/dir.c
index 1cd2d2c..2081cc5 100644
--- a/src/dir.c
+++ b/src/dir.c
@@ -15,8 +15,8 @@
****************************************************************************/
#include "dir.h"
+#include "bfstd.h"
#include "config.h"
-#include "util.h"
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
diff --git a/src/eval.c b/src/eval.c
index dc79188..5bf3120 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -20,6 +20,7 @@
#include "eval.h"
#include "bar.h"
+#include "bfstd.h"
#include "bftw.h"
#include "color.h"
#include "config.h"
@@ -36,7 +37,6 @@
#include "pwcache.h"
#include "stat.h"
#include "trie.h"
-#include "util.h"
#include "xregex.h"
#include "xtime.h"
#include <assert.h>
@@ -686,8 +686,8 @@ bool eval_fls(const struct bfs_expr *expr, struct bfs_eval *state) {
}
if (ftwbuf->type == BFS_BLK || ftwbuf->type == BFS_CHR) {
- int ma = bfs_major(statbuf->rdev);
- int mi = bfs_minor(statbuf->rdev);
+ int ma = xmajor(statbuf->rdev);
+ int mi = xminor(statbuf->rdev);
if (fprintf(file, " %3d, %3d", ma, mi) < 0) {
goto error;
}
diff --git a/src/exec.c b/src/exec.c
index 0130317..afbdcb7 100644
--- a/src/exec.c
+++ b/src/exec.c
@@ -15,12 +15,12 @@
****************************************************************************/
#include "exec.h"
+#include "bfstd.h"
#include "bftw.h"
#include "ctx.h"
#include "color.h"
#include "diag.h"
#include "dstring.h"
-#include "util.h"
#include "xspawn.h"
#include <assert.h>
#include <errno.h>
diff --git a/src/fsade.c b/src/fsade.c
index 7a7201e..a609b97 100644
--- a/src/fsade.c
+++ b/src/fsade.c
@@ -15,10 +15,11 @@
****************************************************************************/
#include "fsade.h"
+#include "config.h"
+#include "bfstd.h"
#include "bftw.h"
#include "dir.h"
#include "dstring.h"
-#include "util.h"
#include <errno.h>
#include <fcntl.h>
#include <stddef.h>
diff --git a/src/main.c b/src/main.c
index 6f82976..fbddbe5 100644
--- a/src/main.c
+++ b/src/main.c
@@ -34,6 +34,7 @@
*
* - Utilities:
* - bar.[ch] (a terminal status bar)
+ * - bfstd.[ch] (standard library wrappers/polyfills)
* - color.[ch] (for pretty terminal colors)
* - config.h (configuration and feature/platform detection)
* - darray.[ch] (a dynamic array library)
@@ -49,13 +50,12 @@
* - xregex.[ch] (regular expression support)
* - xspawn.[ch] (spawns processes)
* - xtime.[ch] (date/time handling utilities)
- * - util.[ch] (everything else)
*/
+#include "bfstd.h"
#include "ctx.h"
#include "eval.h"
#include "parse.h"
-#include "util.h"
#include <errno.h>
#include <fcntl.h>
#include <locale.h>
diff --git a/src/mtab.c b/src/mtab.c
index e6a92e1..316ec6e 100644
--- a/src/mtab.c
+++ b/src/mtab.c
@@ -15,11 +15,11 @@
****************************************************************************/
#include "mtab.h"
+#include "bfstd.h"
#include "config.h"
#include "darray.h"
#include "stat.h"
#include "trie.h"
-#include "util.h"
#include <errno.h>
#include <fcntl.h>
#include <stdbool.h>
diff --git a/src/opt.c b/src/opt.c
index f8c0ba3..80fdd43 100644
--- a/src/opt.c
+++ b/src/opt.c
@@ -46,7 +46,6 @@
#include "eval.h"
#include "expr.h"
#include "pwcache.h"
-#include "util.h"
#include <assert.h>
#include <limits.h>
#include <stdarg.h>
diff --git a/src/parse.c b/src/parse.c
index 2fe3473..1be7cb7 100644
--- a/src/parse.c
+++ b/src/parse.c
@@ -22,6 +22,7 @@
*/
#include "parse.h"
+#include "bfstd.h"
#include "bftw.h"
#include "color.h"
#include "config.h"
@@ -38,7 +39,6 @@
#include "pwcache.h"
#include "stat.h"
#include "typo.h"
-#include "util.h"
#include "xregex.h"
#include "xspawn.h"
#include "xtime.h"
diff --git a/src/printf.c b/src/printf.c
index 8fdde41..97c203f 100644
--- a/src/printf.c
+++ b/src/printf.c
@@ -15,6 +15,7 @@
****************************************************************************/
#include "printf.h"
+#include "bfstd.h"
#include "bftw.h"
#include "color.h"
#include "ctx.h"
@@ -26,7 +27,6 @@
#include "mtab.h"
#include "pwcache.h"
#include "stat.h"
-#include "util.h"
#include "xtime.h"
#include <assert.h>
#include <errno.h>
diff --git a/src/stat.c b/src/stat.c
index 3134b6a..b59e9b0 100644
--- a/src/stat.c
+++ b/src/stat.c
@@ -15,8 +15,8 @@
****************************************************************************/
#include "stat.h"
+#include "bfstd.h"
#include "config.h"
-#include "util.h"
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
@@ -186,7 +186,7 @@ static int bfs_statx_impl(int at_fd, const char *at_path, int at_flags, struct b
buf->mask = 0;
- buf->dev = bfs_makedev(xbuf.stx_dev_major, xbuf.stx_dev_minor);
+ buf->dev = xmakedev(xbuf.stx_dev_major, xbuf.stx_dev_minor);
buf->mask |= BFS_STAT_DEV;
if (xbuf.stx_mask & STATX_INO) {
@@ -227,7 +227,7 @@ static int bfs_statx_impl(int at_fd, const char *at_path, int at_flags, struct b
buf->mask |= BFS_STAT_BLOCKS;
}
- buf->rdev = bfs_makedev(xbuf.stx_rdev_major, xbuf.stx_rdev_minor);
+ buf->rdev = xmakedev(xbuf.stx_rdev_major, xbuf.stx_rdev_minor);
buf->mask |= BFS_STAT_RDEV;
buf->attrs = xbuf.stx_attributes;
diff --git a/src/xregex.c b/src/xregex.c
index 4fa098d..e8d6b23 100644
--- a/src/xregex.c
+++ b/src/xregex.c
@@ -15,7 +15,8 @@
****************************************************************************/
#include "xregex.h"
-#include "util.h"
+#include "bfstd.h"
+#include "config.h"
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
diff --git a/src/xspawn.c b/src/xspawn.c
index f9d52b0..5d2c320 100644
--- a/src/xspawn.c
+++ b/src/xspawn.c
@@ -15,8 +15,8 @@
****************************************************************************/
#include "xspawn.h"
+#include "bfstd.h"
#include "config.h"
-#include "util.h"
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>