From 1d68b43f1554ee82b3ac5772534a5ecbd57855a7 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Wed, 30 Nov 2022 10:51:45 -0500 Subject: expr: Remove the singleton bfs_{true,false} expressions --- src/color.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/color.c') diff --git a/src/color.c b/src/color.c index 98fe9f2..94fcac8 100644 --- a/src/color.c +++ b/src/color.c @@ -877,6 +877,10 @@ static int cbuff(CFILE *cfile, const char *format, ...); /** Dump a parsed expression tree, for debugging. */ static int print_expr(CFILE *cfile, const struct bfs_expr *expr, bool verbose) { + if (!expr) { + return dstrcat(&cfile->buffer, "(null)"); + } + if (dstrcat(&cfile->buffer, "(") != 0) { return -1; } -- cgit v1.2.3 From d1e532ed839c1b2be093c88006fcf4cd3d11805d Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Mon, 5 Dec 2022 14:18:53 -0500 Subject: expr: Rename bfs_expr_has_children() to _is_parent() --- src/color.c | 2 +- src/diag.c | 2 +- src/eval.c | 4 ++-- src/expr.h | 2 +- src/opt.c | 6 +++--- src/parse.c | 12 ++++++------ 6 files changed, 14 insertions(+), 14 deletions(-) (limited to 'src/color.c') diff --git a/src/color.c b/src/color.c index 94fcac8..8d32c6c 100644 --- a/src/color.c +++ b/src/color.c @@ -888,7 +888,7 @@ static int print_expr(CFILE *cfile, const struct bfs_expr *expr, bool verbose) { const struct bfs_expr *lhs = NULL; const struct bfs_expr *rhs = NULL; - if (bfs_expr_has_children(expr)) { + if (bfs_expr_is_parent(expr)) { lhs = expr->lhs; rhs = expr->rhs; diff --git a/src/diag.c b/src/diag.c index c5e139e..a0c11f2 100644 --- a/src/diag.c +++ b/src/diag.c @@ -125,7 +125,7 @@ static bool highlight_expr_recursive(const struct bfs_ctx *ctx, const struct bfs } } - if (bfs_expr_has_children(expr)) { + if (bfs_expr_is_parent(expr)) { ret |= highlight_expr_recursive(ctx, expr->lhs, args); ret |= highlight_expr_recursive(ctx, expr->rhs, args); } diff --git a/src/eval.c b/src/eval.c index 4c9d807..e3257ce 100644 --- a/src/eval.c +++ b/src/eval.c @@ -387,7 +387,7 @@ static int eval_exec_finish(const struct bfs_expr *expr, const struct bfs_ctx *c } ret = -1; } - } else if (bfs_expr_has_children(expr)) { + } else if (bfs_expr_is_parent(expr)) { if (expr->lhs && eval_exec_finish(expr->lhs, ctx) != 0) { ret = -1; } @@ -1557,7 +1557,7 @@ static bool eval_must_buffer(const struct bfs_expr *expr) { return true; } - if (bfs_expr_has_children(expr)) { + if (bfs_expr_is_parent(expr)) { if (expr->lhs && eval_must_buffer(expr->lhs)) { return true; } diff --git a/src/expr.h b/src/expr.h index e541d8e..a52007a 100644 --- a/src/expr.h +++ b/src/expr.h @@ -210,7 +210,7 @@ struct bfs_expr *bfs_expr_new(bfs_eval_fn *eval, size_t argc, char **argv); /** * @return Whether the expression has child expressions. */ -bool bfs_expr_has_children(const struct bfs_expr *expr); +bool bfs_expr_is_parent(const struct bfs_expr *expr); /** * @return Whether expr is known to always quit. diff --git a/src/opt.c b/src/opt.c index 441c611..56d4102 100644 --- a/src/opt.c +++ b/src/opt.c @@ -847,7 +847,7 @@ static struct bfs_expr *optimize_expr_recursive(struct opt_state *state, struct return ret; } - if (!bfs_expr_has_children(expr) && !expr->pure) { + if (!bfs_expr_is_parent(expr) && !expr->pure) { facts_union(state->facts_when_impure, state->facts_when_impure, &state->facts); } @@ -901,7 +901,7 @@ static struct bfs_expr *optimize_expr_recursive(struct opt_state *state, struct return NULL; } - if (bfs_expr_has_children(expr)) { + if (bfs_expr_is_parent(expr)) { struct bfs_expr *lhs = expr->lhs; struct bfs_expr *rhs = expr->rhs; if (rhs) { @@ -980,7 +980,7 @@ static bool reorder_expr(const struct opt_state *state, struct bfs_expr *expr, f * Whether any subexpression was reordered. */ static bool reorder_expr_recursive(const struct opt_state *state, struct bfs_expr *expr) { - if (!bfs_expr_has_children(expr)) { + if (!bfs_expr_is_parent(expr)) { return false; } diff --git a/src/parse.c b/src/parse.c index a858a4c..320e165 100644 --- a/src/parse.c +++ b/src/parse.c @@ -109,7 +109,7 @@ struct bfs_expr *bfs_expr_new(bfs_eval_fn *eval_fn, size_t argc, char **argv) { } // Prevent bfs_expr_free() from freeing uninitialized pointers on error paths - if (bfs_expr_has_children(expr)) { + if (bfs_expr_is_parent(expr)) { expr->lhs = NULL; expr->rhs = NULL; } else if (eval_fn == eval_exec) { @@ -123,7 +123,7 @@ struct bfs_expr *bfs_expr_new(bfs_eval_fn *eval_fn, size_t argc, char **argv) { return expr; } -bool bfs_expr_has_children(const struct bfs_expr *expr) { +bool bfs_expr_is_parent(const struct bfs_expr *expr) { return expr->eval_fn == eval_and || expr->eval_fn == eval_or || expr->eval_fn == eval_not @@ -140,7 +140,7 @@ void bfs_expr_free(struct bfs_expr *expr) { return; } - if (bfs_expr_has_children(expr)) { + if (bfs_expr_is_parent(expr)) { bfs_expr_free(expr->rhs); bfs_expr_free(expr->lhs); } else if (expr->eval_fn == eval_exec) { @@ -166,7 +166,7 @@ static struct bfs_expr *new_unary_expr(bfs_eval_fn *eval_fn, struct bfs_expr *rh expr->lhs = NULL; expr->rhs = rhs; - assert(bfs_expr_has_children(expr)); + assert(bfs_expr_is_parent(expr)); expr->persistent_fds = rhs->persistent_fds; expr->ephemeral_fds = rhs->ephemeral_fds; @@ -186,7 +186,7 @@ static struct bfs_expr *new_binary_expr(bfs_eval_fn *eval_fn, struct bfs_expr *l expr->lhs = lhs; expr->rhs = rhs; - assert(bfs_expr_has_children(expr)); + assert(bfs_expr_is_parent(expr)); expr->persistent_fds = lhs->persistent_fds + rhs->persistent_fds; if (lhs->ephemeral_fds > rhs->ephemeral_fds) { @@ -3722,7 +3722,7 @@ static void dump_expr_multiline(const struct bfs_ctx *ctx, enum debug_flags flag cfprintf(ctx->cerr, " "); } - if (bfs_expr_has_children(expr)) { + if (bfs_expr_is_parent(expr)) { cfprintf(ctx->cerr, "(${red}%s${rs}\n", expr->argv[0]); if (expr->lhs) { dump_expr_multiline(ctx, flag, expr->lhs, indent + 1, 0); -- cgit v1.2.3 From 0cc598f1628167599131756e909630dc36d33610 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 8 Dec 2022 16:45:06 -0500 Subject: Add BFS_FORMATTER() to vprintf()-type functions too --- src/color.c | 2 ++ src/color.h | 1 + src/diag.h | 3 +++ src/dstring.h | 2 ++ 4 files changed, 8 insertions(+) (limited to 'src/color.c') diff --git a/src/color.c b/src/color.c index 8d32c6c..cc37e96 100644 --- a/src/color.c +++ b/src/color.c @@ -17,6 +17,7 @@ #include "color.h" #include "bfstd.h" #include "bftw.h" +#include "config.h" #include "dir.h" #include "dstring.h" #include "expr.h" @@ -944,6 +945,7 @@ static int print_expr(CFILE *cfile, const struct bfs_expr *expr, bool verbose) { return 0; } +BFS_FORMATTER(2, 0) static int cvbuff(CFILE *cfile, const char *format, va_list args) { const struct colors *colors = cfile->colors; int error = errno; diff --git a/src/color.h b/src/color.h index 1b0cadb..5b350cc 100644 --- a/src/color.h +++ b/src/color.h @@ -115,6 +115,7 @@ int cfprintf(CFILE *cfile, const char *format, ...); /** * cfprintf() variant that takes a va_list. */ +BFS_FORMATTER(2, 0) int cvfprintf(CFILE *cfile, const char *format, va_list args); #endif // BFS_COLOR_H diff --git a/src/diag.h b/src/diag.h index 56ad39b..8d0b19f 100644 --- a/src/diag.h +++ b/src/diag.h @@ -58,16 +58,19 @@ bool bfs_debug(const struct bfs_ctx *ctx, enum debug_flags flag, const char *for /** * bfs_error() variant that takes a va_list. */ +BFS_FORMATTER(2, 0) void bfs_verror(const struct bfs_ctx *ctx, const char *format, va_list args); /** * bfs_warning() variant that takes a va_list. */ +BFS_FORMATTER(2, 0) bool bfs_vwarning(const struct bfs_ctx *ctx, const char *format, va_list args); /** * bfs_debug() variant that takes a va_list. */ +BFS_FORMATTER(3, 0) bool bfs_vdebug(const struct bfs_ctx *ctx, enum debug_flags flag, const char *format, va_list args); /** diff --git a/src/dstring.h b/src/dstring.h index 51f1b2f..df20a04 100644 --- a/src/dstring.h +++ b/src/dstring.h @@ -152,6 +152,7 @@ char *dstrprintf(const char *format, ...); * @return * The created string, or NULL on failure. */ +BFS_FORMATTER(1, 0) char *dstrvprintf(const char *format, va_list args); /** @@ -181,6 +182,7 @@ int dstrcatf(char **str, const char *format, ...); * @return * 0 on success, -1 on failure. */ +BFS_FORMATTER(2, 0) int dstrvcatf(char **str, const char *format, va_list args); /** -- cgit v1.2.3 From 683552c4c9a3dfee4ce603157bb2cf18d64fbcfc Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Fri, 30 Dec 2022 14:49:46 -0500 Subject: bfstd: New wrappers for dirname()/basename() --- Makefile | 13 +++++++++---- src/bfstd.c | 45 ++++++++++++++++++++++++++++++++++++++++----- src/bfstd.h | 28 +++++++++++++++++++++++++--- src/bftw.c | 2 +- src/color.c | 2 +- src/diag.c | 11 ++++++++--- src/eval.c | 10 +--------- src/exec.c | 2 +- src/mtab.c | 5 +++-- src/parse.c | 6 ++++-- tests/bfstd.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ tests/mksock.c | 22 ++++++++-------------- tests/xtouch.c | 1 - 13 files changed, 158 insertions(+), 46 deletions(-) create mode 100644 tests/bfstd.c (limited to 'src/color.c') diff --git a/Makefile b/Makefile index 49a3a87..b39a88a 100644 --- a/Makefile +++ b/Makefile @@ -197,6 +197,7 @@ $(FLAG_GOALS): $(FLAG_PREREQS) all: \ $(BIN)/bfs \ + $(BIN)/tests/bfstd \ $(BIN)/tests/mksock \ $(BIN)/tests/trie \ $(BIN)/tests/xtimegm \ @@ -250,22 +251,26 @@ LIBBFS := \ # The main executable $(BIN)/bfs: $(OBJ)/src/main.o $(LIBBFS) +# Standalone binary tests +STANDALONE_CHECKS := check-bfstd check-trie check-xtimegm + # The different search strategies that we test STRATEGIES := bfs dfs ids eds STRATEGY_CHECKS := $(STRATEGIES:%=check-%) # All the different checks we run -CHECKS := $(STRATEGY_CHECKS) check-trie check-xtimegm +CHECKS := $(STANDALONE_CHECKS) $(STRATEGY_CHECKS) check: $(CHECKS) .PHONY: check $(CHECKS) +$(STANDALONE_CHECKS): check-%: $(BIN)/tests/% + $< + $(STRATEGY_CHECKS): check-%: $(BIN)/bfs $(BIN)/tests/mksock $(BIN)/tests/xtouch ./tests/tests.sh --bfs="$(BIN)/bfs -S $*" $(TEST_FLAGS) -check-trie check-xtimegm: check-%: $(BIN)/tests/% - $< - +$(BIN)/tests/bfstd: $(OBJ)/tests/bfstd.o $(LIBBFS) $(BIN)/tests/mksock: $(OBJ)/tests/mksock.o $(LIBBFS) $(BIN)/tests/trie: $(OBJ)/tests/trie.o $(LIBBFS) $(BIN)/tests/xtimegm: $(OBJ)/tests/xtimegm.o $(LIBBFS) diff --git a/src/bfstd.c b/src/bfstd.c index 1561796..3a37250 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -45,17 +45,52 @@ bool is_nonexistence_error(int error) { return error == ENOENT || errno == ENOTDIR; } -const char *xbasename(const char *path) { - const char *i; +char *xdirname(const char *path) { + size_t i = xbaseoff(path); // Skip trailing slashes - for (i = path + strlen(path); i > path && i[-1] == '/'; --i); + while (i > 0 && path[i - 1] == '/') { + --i; + } + + if (i > 0) { + return strndup(path, i); + } else if (path[i] == '/') { + return strdup("/"); + } else { + return strdup("."); + } +} + +char *xbasename(const char *path) { + size_t i = xbaseoff(path); + size_t len = strcspn(path + i, "/"); + if (len > 0) { + return strndup(path + i, len); + } else if (path[i] == '/') { + return strdup("/"); + } else { + return strdup("."); + } +} + +size_t xbaseoff(const char *path) { + size_t i = strlen(path); + + // Skip trailing slashes + while (i > 0 && path[i - 1] == '/') { + --i; + } // Find the beginning of the name - for (; i > path && i[-1] != '/'; --i); + while (i > 0 && path[i - 1] != '/') { + --i; + } // Skip leading slashes - for (; i[0] == '/' && i[1]; ++i); + while (path[i] == '/' && path[i + 1]) { + ++i; + } return i; } diff --git a/src/bfstd.h b/src/bfstd.h index 6bf6ec8..d46fa02 100644 --- a/src/bfstd.h +++ b/src/bfstd.h @@ -22,6 +22,7 @@ #define BFS_BFSTD_H #include +#include // #include @@ -45,13 +46,34 @@ bool is_nonexistence_error(int error); // #include /** - * basename() variant that doesn't modify the input. + * Re-entrant dirname() variant that always allocates a copy. * * @param path * The path in question. - * @return A pointer into path at the base name offset. + * @return + * The parent directory of the path. + */ +char *xdirname(const char *path); + +/** + * Re-entrant basename() variant that always allocates a copy. + * + * @param path + * The path in question. + * @return + * The final component of the path. + */ +char *xbasename(const char *path); + +/** + * Find the offset of the final component of a path. + * + * @param path + * The path in question. + * @return + * The offset of the basename. */ -const char *xbasename(const char *path); +size_t xbaseoff(const char *path); #include diff --git a/src/bftw.c b/src/bftw.c index 8c88101..5f3ebde 100644 --- a/src/bftw.c +++ b/src/bftw.c @@ -793,7 +793,7 @@ static void bftw_init_ftwbuf(struct bftw_state *state, enum bftw_visit visit) { if (ftwbuf->depth == 0) { // Compute the name offset for root paths like "foo/bar" - ftwbuf->nameoff = xbasename(ftwbuf->path) - ftwbuf->path; + ftwbuf->nameoff = xbaseoff(ftwbuf->path); } if (ftwbuf->error != 0) { diff --git a/src/color.c b/src/color.c index cc37e96..7c16ec5 100644 --- a/src/color.c +++ b/src/color.c @@ -809,7 +809,7 @@ static int print_path_colored(CFILE *cfile, const char *path, const struct BFTW if (path == ftwbuf->path) { nameoff = ftwbuf->nameoff; } else { - nameoff = xbasename(path) - path; + nameoff = xbaseoff(path); } if (print_dirs_colored(cfile, path, ftwbuf, flags, nameoff) != 0) { diff --git a/src/diag.c b/src/diag.c index a0c11f2..b02473a 100644 --- a/src/diag.c +++ b/src/diag.c @@ -84,13 +84,18 @@ bool bfs_vdebug(const struct bfs_ctx *ctx, enum debug_flags flag, const char *fo } } +/** Get the command name without any leading directories. */ +static const char *bfs_cmd(const struct bfs_ctx *ctx) { + return ctx->argv[0] + xbaseoff(ctx->argv[0]); +} + void bfs_error_prefix(const struct bfs_ctx *ctx) { - cfprintf(ctx->cerr, "${bld}%s:${rs} ${err}error:${rs} ", xbasename(ctx->argv[0])); + cfprintf(ctx->cerr, "${bld}%s:${rs} ${err}error:${rs} ", bfs_cmd(ctx)); } bool bfs_warning_prefix(const struct bfs_ctx *ctx) { if (ctx->warn) { - cfprintf(ctx->cerr, "${bld}%s:${rs} ${wrn}warning:${rs} ", xbasename(ctx->argv[0])); + cfprintf(ctx->cerr, "${bld}%s:${rs} ${wrn}warning:${rs} ", bfs_cmd(ctx)); return true; } else { return false; @@ -99,7 +104,7 @@ bool bfs_warning_prefix(const struct bfs_ctx *ctx) { bool bfs_debug_prefix(const struct bfs_ctx *ctx, enum debug_flags flag) { if (ctx->debug & flag) { - cfprintf(ctx->cerr, "${bld}%s:${rs} ${cyn}-D %s${rs}: ", xbasename(ctx->argv[0]), debug_flag_name(flag)); + cfprintf(ctx->cerr, "${bld}%s:${rs} ${cyn}-D %s${rs}: ", bfs_cmd(ctx), debug_flag_name(flag)); return true; } else { return false; diff --git a/src/eval.c b/src/eval.c index 89591b2..32b2e0e 100644 --- a/src/eval.c +++ b/src/eval.c @@ -590,15 +590,7 @@ bool eval_name(const struct bfs_expr *expr, struct bfs_eval *state) { if (ftwbuf->depth == 0) { // Any trailing slashes are not part of the name. This can only // happen for the root path. - const char *slash = strchr(name, '/'); - if (slash && slash > name) { - copy = strndup(name, slash - name); - if (!copy) { - eval_report_error(state); - return false; - } - name = copy; - } + name = copy = xbasename(name); } bool ret = fnmatch(expr->argv[1], name, expr->num) == 0; diff --git a/src/exec.c b/src/exec.c index a1cbde1..8630469 100644 --- a/src/exec.c +++ b/src/exec.c @@ -295,7 +295,7 @@ static int bfs_exec_openwd(struct bfs_exec *execbuf, const struct BFTW *ftwbuf) if (ftwbuf->at_fd != AT_FDCWD) { // Rely on at_fd being the immediate parent - assert(ftwbuf->at_path == xbasename(ftwbuf->at_path)); + assert(xbaseoff(ftwbuf->at_path) == 0); execbuf->wd_fd = ftwbuf->at_fd; if (!(execbuf->flags & BFS_EXEC_MULTI)) { diff --git a/src/mtab.c b/src/mtab.c index 316ec6e..39676e5 100644 --- a/src/mtab.c +++ b/src/mtab.c @@ -86,7 +86,8 @@ static int bfs_mtab_add(struct bfs_mtab *mtab, const char *path, const char *typ goto fail_entry; } - if (!trie_insert_str(&mtab->names, xbasename(path))) { + const char *name = path + xbaseoff(path); + if (!trie_insert_str(&mtab->names, name)) { goto fail; } @@ -223,7 +224,7 @@ const char *bfs_fstype(const struct bfs_mtab *mtab, const struct bfs_stat *statb } bool bfs_might_be_mount(const struct bfs_mtab *mtab, const char *path) { - const char *name = xbasename(path); + const char *name = path + xbaseoff(path); return trie_find_str(&mtab->names, name); } diff --git a/src/parse.c b/src/parse.c index ad32714..51a9d0a 100644 --- a/src/parse.c +++ b/src/parse.c @@ -2888,7 +2888,8 @@ static CFILE *launch_pager(pid_t *pid, CFILE *cout) { NULL, }; - if (strcmp(xbasename(exe), "less") == 0) { + const char *cmd = exe + xbaseoff(exe); + if (strcmp(cmd, "less") == 0) { // We know less supports colors, other pagers may not ret->colors = cout->colors; argv[1] = "-FKRX"; @@ -3931,7 +3932,8 @@ struct bfs_ctx *bfs_parse_cmdline(int argc, char *argv[]) { .now = ctx->now, }; - if (strcmp(xbasename(state.command), "find") == 0) { + const char *cmd = state.command + xbaseoff(state.command); + if (strcmp(cmd, "find") == 0) { // Operate depth-first when invoked as "find" ctx->strategy = BFTW_DFS; } diff --git a/tests/bfstd.c b/tests/bfstd.c new file mode 100644 index 0000000..4a8181b --- /dev/null +++ b/tests/bfstd.c @@ -0,0 +1,57 @@ +/**************************************************************************** + * bfs * + * Copyright (C) 2022 Tavian Barnes * + * * + * Permission to use, copy, modify, and/or distribute this software for any * + * purpose with or without fee is hereby granted. * + * * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * + ****************************************************************************/ + +#include "../src/bfstd.h" +#include +#include +#include + +/** Check the result of xdirname()/xbasename(). */ +static void check_base_dir(const char *path, const char *dir, const char *base) { + char *xdir = xdirname(path); + if (!xdir) { + perror("xdirname()"); + abort(); + } else if (strcmp(xdir, dir) != 0) { + fprintf(stderr, "xdirname(\"%s\") == \"%s\" (!= \"%s\")\n", path, xdir, dir); + abort(); + } + free(xdir); + + char *xbase = xbasename(path); + if (!xbase) { + perror("xbasename()"); + abort(); + } else if (strcmp(xbase, base) != 0) { + fprintf(stderr, "xbasename(\"%s\") == \"%s\" (!= \"%s\")\n", path, xbase, base); + abort(); + } + free(xbase); +} + +int main(void) { + // From man 3p basename + check_base_dir("usr", ".", "usr"); + check_base_dir("usr/", ".", "usr"); + check_base_dir("", ".", "."); + check_base_dir("/", "/", "/"); + // check_base_dir("//", "/" or "//", "/" or "//"); + check_base_dir("///", "/", "/"); + check_base_dir("/usr/", "/", "usr"); + check_base_dir("/usr/lib", "/usr", "lib"); + check_base_dir("//usr//lib//", "//usr", "lib"); + check_base_dir("/home//dwc//test", "/home//dwc", "test"); +} diff --git a/tests/mksock.c b/tests/mksock.c index d1776b3..5068bc8 100644 --- a/tests/mksock.c +++ b/tests/mksock.c @@ -19,8 +19,8 @@ * program does the job. */ +#include "../src/bfstd.h" #include -#include #include #include #include @@ -41,18 +41,13 @@ static void errmsg(const char *cmd, const char *path) { * file name is not. */ static int chdir_parent(const char *path) { - char *copy = strdup(path); - if (!copy) { + char *dir = xdirname(path); + if (!dir) { return -1; } - const char *dir = dirname(copy); int ret = chdir(dir); - - int error = errno; - free(copy); - errno = error; - + free(dir); return ret; } @@ -66,22 +61,21 @@ static int init_sun(struct sockaddr_un *sock, const char *path) { return -1; } - char *copy = strdup(path); - if (!copy) { + char *base = xbasename(path); + if (!base) { return -1; } - const char *base = basename(copy); len = strlen(base); if (len >= sizeof(sock->sun_path)) { - free(copy); + free(base); errno = ENAMETOOLONG; return -1; } sock->sun_family = AF_UNIX; memcpy(sock->sun_path, base, len + 1); - free(copy); + free(base); return 0; } diff --git a/tests/xtouch.c b/tests/xtouch.c index 9a91ec7..262fc33 100644 --- a/tests/xtouch.c +++ b/tests/xtouch.c @@ -14,7 +14,6 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * ****************************************************************************/ -#include "../src/bfstd.h" #include "../src/xtime.h" #include #include -- cgit v1.2.3 From 9463fdd30d392c98de7b5712d30dfbaeada40e99 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Wed, 25 Jan 2023 16:14:11 -0500 Subject: Replace license boilerplate with SPDX tags And while I'm at it, remove years from copyright declarations. Link: https://spdx.dev/about/ Link: https://daniel.haxx.se/blog/2023/01/08/copyright-without-years/ --- LICENSE | 33 +++++++++++++++++++++------------ Makefile | 17 ++--------------- completions/bfs.bash | 21 ++++----------------- src/bar.c | 17 ++--------------- src/bar.h | 17 ++--------------- src/bfstd.c | 17 ++--------------- src/bfstd.h | 17 ++--------------- src/bftw.c | 17 ++--------------- src/bftw.h | 17 ++--------------- src/color.c | 17 ++--------------- src/color.h | 17 ++--------------- src/config.h | 17 ++--------------- src/ctx.c | 17 ++--------------- src/ctx.h | 17 ++--------------- src/darray.c | 17 ++--------------- src/darray.h | 17 ++--------------- src/diag.c | 17 ++--------------- src/diag.h | 17 ++--------------- src/dir.c | 17 ++--------------- src/dir.h | 17 ++--------------- src/dstring.c | 17 ++--------------- src/dstring.h | 17 ++--------------- src/eval.c | 17 ++--------------- src/eval.h | 17 ++--------------- src/exec.c | 17 ++--------------- src/exec.h | 17 ++--------------- src/expr.h | 17 ++--------------- src/fsade.c | 17 ++--------------- src/fsade.h | 17 ++--------------- src/main.c | 17 ++--------------- src/mtab.c | 17 ++--------------- src/mtab.h | 17 ++--------------- src/opt.c | 17 ++--------------- src/opt.h | 17 ++--------------- src/parse.c | 17 ++--------------- src/parse.h | 17 ++--------------- src/printf.c | 17 ++--------------- src/printf.h | 17 ++--------------- src/pwcache.c | 17 ++--------------- src/pwcache.h | 17 ++--------------- src/stat.c | 17 ++--------------- src/stat.h | 17 ++--------------- src/trie.c | 17 ++--------------- src/trie.h | 17 ++--------------- src/typo.c | 17 ++--------------- src/typo.h | 17 ++--------------- src/xregex.c | 17 ++--------------- src/xregex.h | 18 ++---------------- src/xspawn.c | 17 ++--------------- src/xspawn.h | 17 ++--------------- src/xtime.c | 17 ++--------------- src/xtime.h | 17 ++--------------- tests/bfstd.c | 17 ++--------------- tests/find-color.sh | 17 ++--------------- tests/ls-color.sh | 17 ++--------------- tests/mksock.c | 17 ++--------------- tests/tests.sh | 17 ++--------------- tests/trie.c | 17 ++--------------- tests/xtimegm.c | 17 ++--------------- tests/xtouch.c | 17 ++--------------- 60 files changed, 141 insertions(+), 900 deletions(-) (limited to 'src/color.c') diff --git a/LICENSE b/LICENSE index 069b145..290e3d3 100644 --- a/LICENSE +++ b/LICENSE @@ -1,12 +1,21 @@ -Copyright (C) 2015-2021 Tavian Barnes - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +Copyright © 2015-2023 Tavian Barnes and the bfs contributors + +Permission to use, copy, modify, and/or distribute this software for any purpose with or +without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT +SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION +OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE +USE OR PERFORMANCE OF THIS SOFTWARE. + +--- + +bfs is licensed under the Zero Clause BSD License. Individual files contain the following +tag instead of the full license text: + + SPDX-License-Identifier: 0BSD + +This enables machine processing of license information based on the SPDX License +Identifiers that are available here: https://spdx.org/licenses/ diff --git a/Makefile b/Makefile index b39a88a..0247b47 100644 --- a/Makefile +++ b/Makefile @@ -1,18 +1,5 @@ -############################################################################ -# bfs # -# Copyright (C) 2015-2023 Tavian Barnes # -# # -# Permission to use, copy, modify, and/or distribute this software for any # -# purpose with or without fee is hereby granted. # -# # -# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # -# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # -############################################################################ +# Copyright © Tavian Barnes +# SPDX-License-Identifier: 0BSD ifneq ($(wildcard .git),) VERSION := $(shell git describe --always 2>/dev/null) diff --git a/completions/bfs.bash b/completions/bfs.bash index f734ab1..2f52e8d 100644 --- a/completions/bfs.bash +++ b/completions/bfs.bash @@ -1,21 +1,8 @@ -# bash completion script for bfs +# Copyright © Benjamin Mundt +# Copyright © Tavian Barnes +# SPDX-License-Identifier: 0BSD -############################################################################ -# bfs # -# Copyright (C) 2020 Benjamin Mundt # -# Copyright (C) 2021 Tavian Barnes # -# # -# Permission to use, copy, modify, and/or distribute this software for any # -# purpose with or without fee is hereby granted. # -# # -# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # -# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # -############################################################################ +# bash completion script for bfs _bfs() { local cur prev words cword diff --git a/src/bar.c b/src/bar.c index 37d33c8..bd5d381 100644 --- a/src/bar.c +++ b/src/bar.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2020-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD #include "bar.h" #include "bfstd.h" diff --git a/src/bar.h b/src/bar.h index 3e509d6..20d92a9 100644 --- a/src/bar.h +++ b/src/bar.h @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2020 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * A terminal status bar. diff --git a/src/bfstd.c b/src/bfstd.c index 3a37250..437e9c9 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2016-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD #include "bfstd.h" #include "config.h" diff --git a/src/bfstd.h b/src/bfstd.h index 79307cc..0e11b66 100644 --- a/src/bfstd.h +++ b/src/bfstd.h @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2016-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * Standard library wrappers and polyfills. diff --git a/src/bftw.c b/src/bftw.c index 5f3ebde..9feca79 100644 --- a/src/bftw.c +++ b/src/bftw.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2015-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * The bftw() implementation consists of the following components: diff --git a/src/bftw.h b/src/bftw.h index c458e1b..77697ed 100644 --- a/src/bftw.h +++ b/src/bftw.h @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2015-2021 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * A file-walking API based on nftw(). diff --git a/src/color.c b/src/color.c index 7c16ec5..589e631 100644 --- a/src/color.c +++ b/src/color.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2015-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD #include "color.h" #include "bfstd.h" diff --git a/src/color.h b/src/color.h index 5b350cc..737c34b 100644 --- a/src/color.h +++ b/src/color.h @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2015-2021 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * Utilities for colored output on ANSI terminals. diff --git a/src/config.h b/src/config.h index 810f913..5ae9c82 100644 --- a/src/config.h +++ b/src/config.h @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2015-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * Configuration and feature/platform detection. diff --git a/src/ctx.c b/src/ctx.c index 0403299..ff4a2a7 100644 --- a/src/ctx.c +++ b/src/ctx.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2015-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD #include "ctx.h" #include "color.h" diff --git a/src/ctx.h b/src/ctx.h index 6755d02..4c748b7 100644 --- a/src/ctx.h +++ b/src/ctx.h @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2015-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * bfs execution context. diff --git a/src/darray.c b/src/darray.c index 6585d30..42b8397 100644 --- a/src/darray.c +++ b/src/darray.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2019-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD #include "darray.h" #include diff --git a/src/darray.h b/src/darray.h index 4464381..cc6cc42 100644 --- a/src/darray.h +++ b/src/darray.h @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2019-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * A dynamic array library. diff --git a/src/diag.c b/src/diag.c index b02473a..53db98e 100644 --- a/src/diag.c +++ b/src/diag.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2019-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD #include "diag.h" #include "bfstd.h" diff --git a/src/diag.h b/src/diag.h index 8d0b19f..2952e30 100644 --- a/src/diag.h +++ b/src/diag.h @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2019-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * Formatters for diagnostic messages. diff --git a/src/dir.c b/src/dir.c index 2081cc5..3d18eb2 100644 --- a/src/dir.c +++ b/src/dir.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2021-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD #include "dir.h" #include "bfstd.h" diff --git a/src/dir.h b/src/dir.h index 69344c6..01eaaba 100644 --- a/src/dir.h +++ b/src/dir.h @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2021 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * Directories and their contents. diff --git a/src/dstring.c b/src/dstring.c index f344d09..9112e54 100644 --- a/src/dstring.c +++ b/src/dstring.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2016-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD #include "dstring.h" #include diff --git a/src/dstring.h b/src/dstring.h index df20a04..ee3b345 100644 --- a/src/dstring.h +++ b/src/dstring.h @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2016-2020 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * A dynamic string library. diff --git a/src/eval.c b/src/eval.c index d297af1..53ce605 100644 --- a/src/eval.c +++ b/src/eval.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2015-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * Implementation of all the primary expressions. diff --git a/src/eval.h b/src/eval.h index a50dc4e..3d70319 100644 --- a/src/eval.h +++ b/src/eval.h @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2015-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * The evaluation functions that implement primary expressions like -name, diff --git a/src/exec.c b/src/exec.c index 8630469..6bde1c1 100644 --- a/src/exec.c +++ b/src/exec.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2017-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD #include "exec.h" #include "bfstd.h" diff --git a/src/exec.h b/src/exec.h index a3e3c71..9d4192d 100644 --- a/src/exec.h +++ b/src/exec.h @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2017-2020 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * Implementation of -exec/-execdir/-ok/-okdir. diff --git a/src/expr.h b/src/expr.h index a52007a..1628cac 100644 --- a/src/expr.h +++ b/src/expr.h @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2015-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * The expression tree representation. diff --git a/src/fsade.c b/src/fsade.c index 45969d1..a61a6b8 100644 --- a/src/fsade.c +++ b/src/fsade.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2019-2021 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD #include "fsade.h" #include "config.h" diff --git a/src/fsade.h b/src/fsade.h index f45c6fd..9bef892 100644 --- a/src/fsade.h +++ b/src/fsade.h @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2019-2020 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * A facade over (file)system features that are (un)implemented differently diff --git a/src/main.c b/src/main.c index fbddbe5..4f99580 100644 --- a/src/main.c +++ b/src/main.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2015-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * - main(): the entry point for bfs(1), a breadth-first version of find(1) diff --git a/src/mtab.c b/src/mtab.c index 07d7a53..ae6dfd2 100644 --- a/src/mtab.c +++ b/src/mtab.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2017-2020 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD #include "mtab.h" #include "bfstd.h" diff --git a/src/mtab.h b/src/mtab.h index 807539d..5dfdf6c 100644 --- a/src/mtab.h +++ b/src/mtab.h @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2017-2020 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * A facade over platform-specific APIs for enumerating mounted filesystems. diff --git a/src/opt.c b/src/opt.c index e76e216..5505b7b 100644 --- a/src/opt.c +++ b/src/opt.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2017-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * The expression optimizer. Different optimization levels are supported: diff --git a/src/opt.h b/src/opt.h index 5f8180d..28cadb9 100644 --- a/src/opt.h +++ b/src/opt.h @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2020 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * Optimization. diff --git a/src/parse.c b/src/parse.c index f2582e0..30bf56d 100644 --- a/src/parse.c +++ b/src/parse.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2015-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * The command line parser. Expressions are parsed by recursive descent, with a diff --git a/src/parse.h b/src/parse.h index 7e29a03..6895c9f 100644 --- a/src/parse.h +++ b/src/parse.h @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2020 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * bfs command line parsing. diff --git a/src/printf.c b/src/printf.c index 7c0c8db..1b4f2d4 100644 --- a/src/printf.c +++ b/src/printf.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2017-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD #include "printf.h" #include "bfstd.h" diff --git a/src/printf.h b/src/printf.h index a8c5f2a..2bff087 100644 --- a/src/printf.h +++ b/src/printf.h @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2017-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * Implementation of -printf/-fprintf. diff --git a/src/pwcache.c b/src/pwcache.c index 868ec8f..5026dee 100644 --- a/src/pwcache.c +++ b/src/pwcache.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2020-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD #include "pwcache.h" #include "darray.h" diff --git a/src/pwcache.h b/src/pwcache.h index f1ca0bf..b6c0b67 100644 --- a/src/pwcache.h +++ b/src/pwcache.h @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2020 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * A caching wrapper for /etc/{passwd,group}. diff --git a/src/stat.c b/src/stat.c index 94dedef..aaa5eac 100644 --- a/src/stat.c +++ b/src/stat.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2018-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD #include "stat.h" #include "bfstd.h" diff --git a/src/stat.h b/src/stat.h index 44cbfad..7a70146 100644 --- a/src/stat.h +++ b/src/stat.h @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2018-2019 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * A facade over the stat() API that unifies some details that diverge between diff --git a/src/trie.c b/src/trie.c index 08a99b5..77c43cc 100644 --- a/src/trie.c +++ b/src/trie.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2019-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * This is an implementation of a "qp trie," as documented at diff --git a/src/trie.h b/src/trie.h index 2ede6ea..03ee64d 100644 --- a/src/trie.h +++ b/src/trie.h @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2019-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD #ifndef BFS_TRIE_H #define BFS_TRIE_H diff --git a/src/typo.c b/src/typo.c index c16cab4..305711d 100644 --- a/src/typo.c +++ b/src/typo.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2016 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD #include "typo.h" #include diff --git a/src/typo.h b/src/typo.h index 0347aae..13eaa67 100644 --- a/src/typo.h +++ b/src/typo.h @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2016 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD #ifndef BFS_TYPO_H #define BFS_TYPO_H diff --git a/src/xregex.c b/src/xregex.c index 6f0e5a1..5f5480f 100644 --- a/src/xregex.c +++ b/src/xregex.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD #include "xregex.h" #include "config.h" diff --git a/src/xregex.h b/src/xregex.h index b2f56a5..998a2b0 100644 --- a/src/xregex.h +++ b/src/xregex.h @@ -1,19 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2022 Tavian Barnes and bfs * - * contributors * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes and the bfs contributors +// SPDX-License-Identifier: 0BSD #ifndef BFS_XREGEX_H #define BFS_XREGEX_H diff --git a/src/xspawn.c b/src/xspawn.c index f76267b..a30c264 100644 --- a/src/xspawn.c +++ b/src/xspawn.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2018-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD #include "xspawn.h" #include "bfstd.h" diff --git a/src/xspawn.h b/src/xspawn.h index cd6a42e..3dbf5d2 100644 --- a/src/xspawn.h +++ b/src/xspawn.h @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2018-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * A process-spawning library inspired by posix_spawn(). diff --git a/src/xtime.c b/src/xtime.c index 079d42a..82690d0 100644 --- a/src/xtime.c +++ b/src/xtime.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2020-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD #include "xtime.h" #include diff --git a/src/xtime.h b/src/xtime.h index b49cd04..75d1f4e 100644 --- a/src/xtime.h +++ b/src/xtime.h @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2020-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * Date/time handling. diff --git a/tests/bfstd.c b/tests/bfstd.c index 4a8181b..8c61072 100644 --- a/tests/bfstd.c +++ b/tests/bfstd.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD #include "../src/bfstd.h" #include diff --git a/tests/find-color.sh b/tests/find-color.sh index ecdd5af..47de2a2 100755 --- a/tests/find-color.sh +++ b/tests/find-color.sh @@ -1,20 +1,7 @@ #!/usr/bin/env bash -############################################################################ -# bfs # -# Copyright (C) 2019 Tavian Barnes # -# # -# Permission to use, copy, modify, and/or distribute this software for any # -# purpose with or without fee is hereby granted. # -# # -# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # -# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # -############################################################################ +# Copyright © Tavian Barnes +# SPDX-License-Identifier: 0BSD set -e diff --git a/tests/ls-color.sh b/tests/ls-color.sh index c82a58d..6d33f53 100755 --- a/tests/ls-color.sh +++ b/tests/ls-color.sh @@ -1,20 +1,7 @@ #!/usr/bin/env bash -############################################################################ -# bfs # -# Copyright (C) 2019 Tavian Barnes # -# # -# Permission to use, copy, modify, and/or distribute this software for any # -# purpose with or without fee is hereby granted. # -# # -# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # -# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # -############################################################################ +# Copyright © Tavian Barnes +# SPDX-License-Identifier: 0BSD # Prints the "ground truth" coloring of a path using ls diff --git a/tests/mksock.c b/tests/mksock.c index 5068bc8..05edbeb 100644 --- a/tests/mksock.c +++ b/tests/mksock.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2019 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD /** * There's no standard Unix utility that creates a socket file, so this small diff --git a/tests/tests.sh b/tests/tests.sh index e57db4e..98d332c 100755 --- a/tests/tests.sh +++ b/tests/tests.sh @@ -1,20 +1,7 @@ #!/usr/bin/env bash -############################################################################ -# bfs # -# Copyright (C) 2015-2022 Tavian Barnes # -# # -# Permission to use, copy, modify, and/or distribute this software for any # -# purpose with or without fee is hereby granted. # -# # -# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # -# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # -############################################################################ +# Copyright © Tavian Barnes +# SPDX-License-Identifier: 0BSD set -euP umask 022 diff --git a/tests/trie.c b/tests/trie.c index 88e92da..c2af18a 100644 --- a/tests/trie.c +++ b/tests/trie.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2020-2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD #undef NDEBUG diff --git a/tests/xtimegm.c b/tests/xtimegm.c index d774b9e..bab64ba 100644 --- a/tests/xtimegm.c +++ b/tests/xtimegm.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2020 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD #include "../src/xtime.h" #include diff --git a/tests/xtouch.c b/tests/xtouch.c index 9a91ec7..506c73d 100644 --- a/tests/xtouch.c +++ b/tests/xtouch.c @@ -1,18 +1,5 @@ -/**************************************************************************** - * bfs * - * Copyright (C) 2022 Tavian Barnes * - * * - * Permission to use, copy, modify, and/or distribute this software for any * - * purpose with or without fee is hereby granted. * - * * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - ****************************************************************************/ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD #include "../src/bfstd.h" #include "../src/xtime.h" -- cgit v1.2.3 From 59f87eed2b930af2f31fd1d1fb2589f80f426ee0 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 11 May 2023 10:12:35 -0400 Subject: config: Provide and In anticipation of C23, since those headers won't be necessary any more. --- src/bfstd.c | 1 - src/bfstd.h | 2 +- src/bftw.c | 1 - src/color.c | 1 - src/color.h | 1 - src/config.h | 6 +++++- src/ctx.h | 2 +- src/diag.h | 1 - src/dir.c | 2 -- src/eval.h | 2 +- src/exec.c | 1 - src/expr.h | 2 +- src/fsade.h | 1 - src/main.c | 2 +- src/mtab.c | 1 - src/mtab.h | 2 +- src/opt.c | 1 - src/parse.c | 1 - src/printf.c | 1 - src/pwcache.c | 2 +- src/stat.c | 1 - src/trie.c | 1 - src/trie.h | 1 - src/xspawn.c | 1 - src/xtime.c | 2 +- tests/xtimegm.c | 2 +- tests/xtouch.c | 2 +- 27 files changed, 15 insertions(+), 28 deletions(-) (limited to 'src/color.c') diff --git a/src/bfstd.c b/src/bfstd.c index 1dc322b..932f2c4 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/src/bfstd.h b/src/bfstd.h index 028e4e6..e4fd1f1 100644 --- a/src/bfstd.h +++ b/src/bfstd.h @@ -8,7 +8,7 @@ #ifndef BFS_BFSTD_H #define BFS_BFSTD_H -#include +#include "config.h" #include // #include diff --git a/src/bftw.c b/src/bftw.c index 56701a7..14805de 100644 --- a/src/bftw.c +++ b/src/bftw.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include diff --git a/src/color.c b/src/color.c index 589e631..eeadf98 100644 --- a/src/color.c +++ b/src/color.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/src/color.h b/src/color.h index 737c34b..3db2b07 100644 --- a/src/color.h +++ b/src/color.h @@ -10,7 +10,6 @@ #include "config.h" #include -#include #include /** diff --git a/src/config.h b/src/config.h index 229bafb..4408feb 100644 --- a/src/config.h +++ b/src/config.h @@ -8,9 +8,13 @@ #ifndef BFS_CONFIG_H #define BFS_CONFIG_H -#include #include +#if __STDC_VERSION__ < 202311L +# include +# include +#endif + // bfs packaging configuration #ifndef BFS_COMMAND diff --git a/src/ctx.h b/src/ctx.h index 4c748b7..0dc9f08 100644 --- a/src/ctx.h +++ b/src/ctx.h @@ -9,8 +9,8 @@ #define BFS_CTX_H #include "bftw.h" +#include "config.h" #include "trie.h" -#include #include #include #include diff --git a/src/diag.h b/src/diag.h index 2952e30..987d4b4 100644 --- a/src/diag.h +++ b/src/diag.h @@ -11,7 +11,6 @@ #include "ctx.h" #include "config.h" #include -#include struct bfs_expr; diff --git a/src/dir.c b/src/dir.c index eb6e3e0..30db5df 100644 --- a/src/dir.c +++ b/src/dir.c @@ -8,8 +8,6 @@ #include #include #include -#include -#include #include #include #include diff --git a/src/eval.h b/src/eval.h index 3d70319..bdb9440 100644 --- a/src/eval.h +++ b/src/eval.h @@ -9,7 +9,7 @@ #ifndef BFS_EVAL_H #define BFS_EVAL_H -#include +#include "config.h" struct bfs_ctx; struct bfs_expr; diff --git a/src/exec.c b/src/exec.c index 6bde1c1..7f22d36 100644 --- a/src/exec.c +++ b/src/exec.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/src/expr.h b/src/expr.h index 1628cac..356689d 100644 --- a/src/expr.h +++ b/src/expr.h @@ -9,9 +9,9 @@ #define BFS_EXPR_H #include "color.h" +#include "config.h" #include "eval.h" #include "stat.h" -#include #include #include #include diff --git a/src/fsade.h b/src/fsade.h index 557da26..0d9ecaf 100644 --- a/src/fsade.h +++ b/src/fsade.h @@ -10,7 +10,6 @@ #define BFS_FSADE_H #include "config.h" -#include #define BFS_CAN_CHECK_ACL BFS_USE_SYS_ACL_H diff --git a/src/main.c b/src/main.c index 4f99580..24a5035 100644 --- a/src/main.c +++ b/src/main.c @@ -40,13 +40,13 @@ */ #include "bfstd.h" +#include "config.h" #include "ctx.h" #include "eval.h" #include "parse.h" #include #include #include -#include #include #include #include diff --git a/src/mtab.c b/src/mtab.c index 27f1743..1d1ad94 100644 --- a/src/mtab.c +++ b/src/mtab.c @@ -9,7 +9,6 @@ #include "trie.h" #include #include -#include #include #include #include diff --git a/src/mtab.h b/src/mtab.h index 5dfdf6c..ca4372c 100644 --- a/src/mtab.h +++ b/src/mtab.h @@ -8,7 +8,7 @@ #ifndef BFS_MTAB_H #define BFS_MTAB_H -#include +#include "config.h" struct bfs_stat; diff --git a/src/opt.c b/src/opt.c index 731dd10..4ce9425 100644 --- a/src/opt.c +++ b/src/opt.c @@ -39,7 +39,6 @@ #include #include #include -#include #include #include #include diff --git a/src/parse.c b/src/parse.c index 15f38a4..55f1e74 100644 --- a/src/parse.c +++ b/src/parse.c @@ -37,7 +37,6 @@ #include #include #include -#include #include #include #include diff --git a/src/printf.c b/src/printf.c index 454fbee..9ccc216 100644 --- a/src/printf.c +++ b/src/printf.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include diff --git a/src/pwcache.c b/src/pwcache.c index 5026dee..f52e4e1 100644 --- a/src/pwcache.c +++ b/src/pwcache.c @@ -2,12 +2,12 @@ // SPDX-License-Identifier: 0BSD #include "pwcache.h" +#include "config.h" #include "darray.h" #include "trie.h" #include #include #include -#include #include #include #include diff --git a/src/stat.c b/src/stat.c index f3d9046..7973d71 100644 --- a/src/stat.c +++ b/src/stat.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/src/trie.c b/src/trie.c index bfe97e6..e0e00ff 100644 --- a/src/trie.c +++ b/src/trie.c @@ -86,7 +86,6 @@ #include "list.h" #include #include -#include #include #include #include diff --git a/src/trie.h b/src/trie.h index 58974aa..6bd211e 100644 --- a/src/trie.h +++ b/src/trie.h @@ -5,7 +5,6 @@ #define BFS_TRIE_H #include "config.h" -#include #include #include diff --git a/src/xspawn.c b/src/xspawn.c index a6d18a3..00fb76e 100644 --- a/src/xspawn.c +++ b/src/xspawn.c @@ -7,7 +7,6 @@ #include "list.h" #include #include -#include #include #include #include diff --git a/src/xtime.c b/src/xtime.c index 82690d0..406d694 100644 --- a/src/xtime.c +++ b/src/xtime.c @@ -2,9 +2,9 @@ // SPDX-License-Identifier: 0BSD #include "xtime.h" +#include "config.h" #include #include -#include #include #include #include diff --git a/tests/xtimegm.c b/tests/xtimegm.c index bab64ba..b2479b7 100644 --- a/tests/xtimegm.c +++ b/tests/xtimegm.c @@ -2,7 +2,7 @@ // SPDX-License-Identifier: 0BSD #include "../src/xtime.h" -#include +#include "../src/config.h" #include #include #include diff --git a/tests/xtouch.c b/tests/xtouch.c index 7e29547..50416ba 100644 --- a/tests/xtouch.c +++ b/tests/xtouch.c @@ -2,10 +2,10 @@ // SPDX-License-Identifier: 0BSD #include "../src/bfstd.h" +#include "../src/config.h" #include "../src/xtime.h" #include #include -#include #include #include #include -- cgit v1.2.3 From 88581b9d505342e20d03cc4c6557d30c3f66f0f5 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 18 May 2023 13:27:04 -0400 Subject: Use bfs_bug("...") over assert(!"...") --- src/bfstd.c | 3 ++- src/color.c | 3 ++- src/ctx.c | 3 +-- src/dstring.c | 4 ++-- src/eval.c | 6 +++--- src/parse.c | 4 ++-- src/stat.c | 6 +++--- 7 files changed, 15 insertions(+), 14 deletions(-) (limited to 'src/color.c') diff --git a/src/bfstd.c b/src/bfstd.c index 932f2c4..91383a2 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -3,6 +3,7 @@ #include "bfstd.h" #include "config.h" +#include "diag.h" #include "xregex.h" #include #include @@ -95,7 +96,7 @@ FILE *xfopen(const char *path, int flags) { strcpy(mode, "r+b"); break; default: - assert(!"Invalid access mode"); + bfs_bug("Invalid access mode"); errno = EINVAL; return NULL; } diff --git a/src/color.c b/src/color.c index eeadf98..43ea9a4 100644 --- a/src/color.c +++ b/src/color.c @@ -5,6 +5,7 @@ #include "bfstd.h" #include "bftw.h" #include "config.h" +#include "diag.h" #include "dir.h" #include "dstring.h" #include "expr.h" @@ -1085,7 +1086,7 @@ static int cvbuff(CFILE *cfile, const char *format, va_list args) { return 0; invalid: - assert(!"Invalid format string"); + bfs_bug("Invalid format string"); errno = EINVAL; return -1; } diff --git a/src/ctx.c b/src/ctx.c index ff4a2a7..c4b2fb2 100644 --- a/src/ctx.c +++ b/src/ctx.c @@ -11,7 +11,6 @@ #include "stat.h" #include "trie.h" #include "xtime.h" -#include #include #include #include @@ -38,7 +37,7 @@ const char *debug_flag_name(enum debug_flags flag) { break; } - assert(!"Unrecognized debug flag"); + bfs_bug("Unrecognized debug flag"); return "???"; } diff --git a/src/dstring.c b/src/dstring.c index 05efb10..2c9869d 100644 --- a/src/dstring.c +++ b/src/dstring.c @@ -2,7 +2,7 @@ // SPDX-License-Identifier: 0BSD #include "dstring.h" -#include +#include "diag.h" #include #include #include @@ -184,7 +184,7 @@ int dstrvcatf(char **str, const char *format, va_list args) { tail = *str + len; ret = vsnprintf(tail, tail_len + 1, format, copy); if (ret < 0 || (size_t)ret != tail_len) { - assert(!"Length of formatted string changed"); + bfs_bug("Length of formatted string changed"); goto fail; } } diff --git a/src/eval.c b/src/eval.c index 7444ec9..6cad3a9 100644 --- a/src/eval.c +++ b/src/eval.c @@ -142,7 +142,7 @@ bool bfs_expr_cmp(const struct bfs_expr *expr, long long n) { return n > expr->num; } - assert(!"Invalid comparison mode"); + bfs_bug("Invalid comparison mode"); return false; } @@ -476,7 +476,7 @@ bool eval_flags(const struct bfs_expr *expr, struct bfs_eval *state) { return (flags & set) || (flags & clear) != clear; } - assert(!"Invalid comparison mode"); + bfs_bug("Invalid comparison mode"); return false; } @@ -626,7 +626,7 @@ bool eval_perm(const struct bfs_expr *expr, struct bfs_eval *state) { return !(mode & target) == !target; } - assert(!"Invalid comparison mode"); + bfs_bug("Invalid comparison mode"); return false; } diff --git a/src/parse.c b/src/parse.c index 55f1e74..807892c 100644 --- a/src/parse.c +++ b/src/parse.c @@ -638,7 +638,7 @@ static const char *parse_int(const struct parser_state *state, char **arg, const break; default: - assert(!"Invalid int size"); + bfs_bug("Invalid int size"); goto bad; } @@ -3492,7 +3492,7 @@ static const char *bftw_strategy_name(enum bftw_strategy strategy) { return "eds"; } - assert(!"Invalid strategy"); + bfs_bug("Invalid strategy"); return "???"; } diff --git a/src/stat.c b/src/stat.c index 50ea345..590a1d6 100644 --- a/src/stat.c +++ b/src/stat.c @@ -4,7 +4,7 @@ #include "stat.h" #include "bfstd.h" #include "config.h" -#include +#include "diag.h" #include #include #include @@ -57,7 +57,7 @@ const char *bfs_stat_field_name(enum bfs_stat_field field) { return "modification time"; } - assert(!"Unrecognized stat field"); + bfs_bug("Unrecognized stat field"); return "???"; } @@ -340,7 +340,7 @@ const struct timespec *bfs_stat_time(const struct bfs_stat *buf, enum bfs_stat_f case BFS_STAT_MTIME: return &buf->mtime; default: - assert(!"Invalid stat field for time"); + bfs_bug("Invalid stat field for time"); errno = EINVAL; return NULL; } -- cgit v1.2.3 From 526133c11eb9a26a4cffb20bcd10bcbb36d940de Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 18 May 2023 16:44:30 -0400 Subject: Switch from assert() to bfs_assert()/bfs_verify() --- src/bfstd.c | 3 +- src/bftw.c | 28 ++++++++-------- src/color.c | 5 ++- src/diag.c | 3 +- src/dir.c | 4 +-- src/eval.c | 11 +++---- src/exec.c | 7 ++-- src/opt.c | 13 ++++---- src/parse.c | 7 ++-- src/printf.c | 5 ++- src/trie.c | 33 ++++++++++--------- src/xregex.c | 4 +-- tests/bfstd.c | 13 ++++---- tests/bit.c | 100 +++++++++++++++++++++++++++++----------------------------- tests/trie.c | 56 ++++++++++++++++---------------- 15 files changed, 140 insertions(+), 152 deletions(-) (limited to 'src/color.c') diff --git a/src/bfstd.c b/src/bfstd.c index 91383a2..37f5276 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -5,7 +5,6 @@ #include "config.h" #include "diag.h" #include "xregex.h" -#include #include #include #include @@ -393,7 +392,7 @@ void close_quietly(int fd) { int xclose(int fd) { int ret = close(fd); if (ret != 0) { - assert(errno != EBADF); + bfs_verify(errno != EBADF); } return ret; } diff --git a/src/bftw.c b/src/bftw.c index 14805de..6ec5cfa 100644 --- a/src/bftw.c +++ b/src/bftw.c @@ -19,13 +19,13 @@ #include "bftw.h" #include "bfstd.h" #include "config.h" +#include "diag.h" #include "dir.h" #include "dstring.h" #include "list.h" #include "mtab.h" #include "stat.h" #include "trie.h" -#include #include #include #include @@ -114,7 +114,7 @@ static void bftw_cache_remove(struct bftw_cache *cache, struct bftw_file *file) /** Close a bftw_file. */ static void bftw_file_close(struct bftw_cache *cache, struct bftw_file *file) { - assert(file->fd >= 0); + bfs_assert(file->fd >= 0); if (LIST_ATTACHED(cache, file, lru)) { bftw_cache_remove(cache, file); @@ -137,7 +137,7 @@ static int bftw_cache_pop(struct bftw_cache *cache) { /** Add a bftw_file to the cache. */ static int bftw_cache_add(struct bftw_cache *cache, struct bftw_file *file) { - assert(file->fd >= 0); + bfs_assert(file->fd >= 0); if (cache->capacity == 0 && bftw_cache_pop(cache) != 0) { bftw_file_close(cache, file); @@ -145,7 +145,7 @@ static int bftw_cache_add(struct bftw_cache *cache, struct bftw_file *file) { return -1; } - assert(cache->capacity > 0); + bfs_assert(cache->capacity > 0); --cache->capacity; LIST_INSERT(cache, cache->target, file, lru); @@ -169,9 +169,9 @@ static size_t bftw_child_nameoff(const struct bftw_file *parent) { /** Destroy a cache. */ static void bftw_cache_destroy(struct bftw_cache *cache) { - assert(!cache->head); - assert(!cache->tail); - assert(!cache->target); + bfs_assert(!cache->head); + bfs_assert(!cache->tail); + bfs_assert(!cache->target); } /** Create a new bftw_file. */ @@ -230,7 +230,7 @@ static struct bftw_file *bftw_file_new(struct bftw_file *parent, const char *nam * The opened file descriptor, or negative on error. */ static int bftw_file_openat(struct bftw_cache *cache, struct bftw_file *file, struct bftw_file *base, const char *at_path) { - assert(file->fd < 0); + bfs_assert(file->fd < 0); int at_fd = AT_FDCWD; if (base) { @@ -332,7 +332,7 @@ static struct bfs_dir *bftw_file_opendir(struct bftw_cache *cache, struct bftw_f /** Free a bftw_file. */ static void bftw_file_free(struct bftw_cache *cache, struct bftw_file *file) { - assert(file->refcount == 0); + bfs_assert(file->refcount == 0); if (file->fd >= 0) { bftw_file_close(cache, file); @@ -770,7 +770,7 @@ static enum bftw_action bftw_call_back(struct bftw_state *state, const char *nam /** Pop a directory to read from the queue. */ static bool bftw_pop_dir(struct bftw_state *state) { - assert(!state->file); + bfs_assert(!state->file); if (!state->dirs.head) { return false; @@ -787,7 +787,7 @@ static bool bftw_pop_dir(struct bftw_state *state) { /** Pop a file to visit from the queue. */ static bool bftw_pop_file(struct bftw_state *state) { - assert(!state->file); + bfs_assert(!state->file); state->file = state->files.head; if (state->file) { @@ -802,8 +802,8 @@ static bool bftw_pop_file(struct bftw_state *state) { * Open the current directory. */ static int bftw_opendir(struct bftw_state *state) { - assert(!state->dir); - assert(!state->de); + bfs_assert(!state->dir); + bfs_assert(!state->de); state->direrror = 0; @@ -863,7 +863,7 @@ static int bftw_gc(struct bftw_state *state, enum bftw_gc_flags flags) { if (state->dir) { struct bftw_file *file = state->file; - assert(file && file->fd >= 0); + bfs_assert(file && file->fd >= 0); if (file->refcount > 1) { // Keep the fd around if any subdirectories exist diff --git a/src/color.c b/src/color.c index 43ea9a4..a723084 100644 --- a/src/color.c +++ b/src/color.c @@ -12,7 +12,6 @@ #include "fsade.h" #include "stat.h" #include "trie.h" -#include #include #include #include @@ -699,7 +698,7 @@ static int print_colored(CFILE *cfile, const char *esc, const char *str, size_t /** Find the offset of the first broken path component. */ static ssize_t first_broken_offset(const char *path, const struct BFTW *ftwbuf, enum bfs_stat_flags flags, size_t max) { ssize_t ret = max; - assert(ret >= 0); + bfs_assert(ret >= 0); if (bftw_type(ftwbuf, flags) != BFS_ERROR) { goto out; @@ -1100,7 +1099,7 @@ static int cbuff(CFILE *cfile, const char *format, ...) { } int cvfprintf(CFILE *cfile, const char *format, va_list args) { - assert(dstrlen(cfile->buffer) == 0); + bfs_assert(dstrlen(cfile->buffer) == 0); int ret = -1; if (cvbuff(cfile, format, args) == 0) { diff --git a/src/diag.c b/src/diag.c index d7ffaa6..04e3678 100644 --- a/src/diag.c +++ b/src/diag.c @@ -6,7 +6,6 @@ #include "ctx.h" #include "color.h" #include "expr.h" -#include #include #include #include @@ -117,7 +116,7 @@ static bool highlight_expr_recursive(const struct bfs_ctx *ctx, const struct bfs for (size_t i = 0; i < ctx->argc; ++i) { if (&ctx->argv[i] == expr->argv) { for (size_t j = 0; j < expr->argc; ++j) { - assert(i + j < ctx->argc); + bfs_assert(i + j < ctx->argc); args[i + j] = true; ret = true; } diff --git a/src/dir.c b/src/dir.c index 6739f10..d9ee63b 100644 --- a/src/dir.c +++ b/src/dir.c @@ -4,7 +4,7 @@ #include "dir.h" #include "bfstd.h" #include "config.h" -#include +#include "diag.h" #include #include #include @@ -249,7 +249,7 @@ int bfs_closedir(struct bfs_dir *dir) { int ret = xclose(dir->fd); #else int ret = closedir(dir->dir); - assert(ret == 0 || errno != EBADF); + bfs_verify(ret == 0 || errno != EBADF); #endif free(dir); return ret; diff --git a/src/eval.c b/src/eval.c index 6cad3a9..342debd 100644 --- a/src/eval.c +++ b/src/eval.c @@ -26,7 +26,6 @@ #include "trie.h" #include "xregex.h" #include "xtime.h" -#include #include #include #include @@ -990,7 +989,7 @@ static bool eval_expr(struct bfs_expr *expr, struct bfs_eval *state) { } } - assert(!state->quit); + bfs_assert(!state->quit); bool ret = expr->eval_fn(expr, state); @@ -1006,10 +1005,10 @@ static bool eval_expr(struct bfs_expr *expr, struct bfs_eval *state) { } if (bfs_expr_never_returns(expr)) { - assert(state->quit); + bfs_assert(state->quit); } else if (!state->quit) { - assert(!expr->always_true || ret); - assert(!expr->always_false || !ret); + bfs_assert(!expr->always_true || ret); + bfs_assert(!expr->always_false || !ret); } return ret; @@ -1511,7 +1510,7 @@ static void dump_bftw_flags(enum bftw_flags flags) { DEBUG_FLAG(flags, BFTW_SORT); DEBUG_FLAG(flags, BFTW_BUFFER); - assert(!flags); + bfs_assert(flags == 0, "Missing bftw flag 0x%X", flags); } /** diff --git a/src/exec.c b/src/exec.c index 7f22d36..5912ad6 100644 --- a/src/exec.c +++ b/src/exec.c @@ -10,7 +10,6 @@ #include "diag.h" #include "dstring.h" #include "xspawn.h" -#include #include #include #include @@ -276,12 +275,12 @@ static void bfs_exec_free_arg(char *arg, const char *tmpl) { /** Open a file to use as the working directory. */ static int bfs_exec_openwd(struct bfs_exec *execbuf, const struct BFTW *ftwbuf) { - assert(execbuf->wd_fd < 0); - assert(!execbuf->wd_path); + bfs_assert(execbuf->wd_fd < 0); + bfs_assert(!execbuf->wd_path); if (ftwbuf->at_fd != AT_FDCWD) { // Rely on at_fd being the immediate parent - assert(xbaseoff(ftwbuf->at_path) == 0); + bfs_assert(xbaseoff(ftwbuf->at_path) == 0); execbuf->wd_fd = ftwbuf->at_fd; if (!(execbuf->flags & BFS_EXEC_MULTI)) { diff --git a/src/opt.c b/src/opt.c index 4ce9425..4699af4 100644 --- a/src/opt.c +++ b/src/opt.c @@ -35,7 +35,6 @@ #include "exec.h" #include "expr.h" #include "pwcache.h" -#include #include #include #include @@ -308,7 +307,7 @@ struct opt_state { /** Log an optimization. */ BFS_FORMATTER(3, 4) static bool opt_debug(const struct opt_state *state, int level, const char *format, ...) { - assert(state->ctx->optlevel >= level); + bfs_assert(state->ctx->optlevel >= level); if (bfs_debug(state->ctx, DEBUG_OPT, "${cyn}-O%d${rs}: ", level)) { va_list args; @@ -387,7 +386,7 @@ static struct bfs_expr *de_morgan(const struct opt_state *state, struct bfs_expr has_parent = false; } - assert(expr->eval_fn == eval_and || expr->eval_fn == eval_or); + bfs_assert(expr->eval_fn == eval_and || expr->eval_fn == eval_or); if (expr->eval_fn == eval_and) { expr->eval_fn = eval_or; expr->argv = &fake_or_arg; @@ -446,7 +445,7 @@ static struct bfs_expr *optimize_expr_recursive(struct opt_state *state, struct * Optimize a negation. */ static struct bfs_expr *optimize_not_expr(const struct opt_state *state, struct bfs_expr *expr) { - assert(expr->eval_fn == eval_not); + bfs_assert(expr->eval_fn == eval_not); struct bfs_expr *rhs = expr->rhs; @@ -498,7 +497,7 @@ fail: /** Optimize a conjunction. */ static struct bfs_expr *optimize_and_expr(const struct opt_state *state, struct bfs_expr *expr) { - assert(expr->eval_fn == eval_and); + bfs_assert(expr->eval_fn == eval_and); struct bfs_expr *lhs = expr->lhs; struct bfs_expr *rhs = expr->rhs; @@ -569,7 +568,7 @@ fail: /** Optimize a disjunction. */ static struct bfs_expr *optimize_or_expr(const struct opt_state *state, struct bfs_expr *expr) { - assert(expr->eval_fn == eval_or); + bfs_assert(expr->eval_fn == eval_or); struct bfs_expr *lhs = expr->lhs; struct bfs_expr *rhs = expr->rhs; @@ -673,7 +672,7 @@ static struct bfs_expr *ignore_result(const struct opt_state *state, struct bfs_ /** Optimize a comma expression. */ static struct bfs_expr *optimize_comma_expr(const struct opt_state *state, struct bfs_expr *expr) { - assert(expr->eval_fn == eval_comma); + bfs_assert(expr->eval_fn == eval_comma); struct bfs_expr *lhs = expr->lhs; struct bfs_expr *rhs = expr->rhs; diff --git a/src/parse.c b/src/parse.c index 807892c..1a04e68 100644 --- a/src/parse.c +++ b/src/parse.c @@ -29,7 +29,6 @@ #include "xregex.h" #include "xspawn.h" #include "xtime.h" -#include #include #include #include @@ -134,7 +133,7 @@ static struct bfs_expr *new_unary_expr(bfs_eval_fn *eval_fn, struct bfs_expr *rh expr->lhs = NULL; expr->rhs = rhs; - assert(bfs_expr_is_parent(expr)); + bfs_assert(bfs_expr_is_parent(expr)); expr->persistent_fds = rhs->persistent_fds; expr->ephemeral_fds = rhs->ephemeral_fds; @@ -154,7 +153,7 @@ static struct bfs_expr *new_binary_expr(bfs_eval_fn *eval_fn, struct bfs_expr *l expr->lhs = lhs; expr->rhs = rhs; - assert(bfs_expr_is_parent(expr)); + bfs_assert(bfs_expr_is_parent(expr)); expr->persistent_fds = lhs->persistent_fds + rhs->persistent_fds; if (lhs->ephemeral_fds > rhs->ephemeral_fds) { @@ -263,7 +262,7 @@ static void init_highlight(const struct bfs_ctx *ctx, bool *args) { static void highlight_args(const struct bfs_ctx *ctx, char **argv, size_t argc, bool *args) { size_t i = argv - ctx->argv; for (size_t j = 0; j < argc; ++j) { - assert(i + j < ctx->argc); + bfs_assert(i + j < ctx->argc); args[i + j] = true; } } diff --git a/src/printf.c b/src/printf.c index 9ccc216..6520d2d 100644 --- a/src/printf.c +++ b/src/printf.c @@ -16,7 +16,6 @@ #include "pwcache.h" #include "stat.h" #include "xtime.h" -#include #include #include #include @@ -74,7 +73,7 @@ static bool should_color(CFILE *cfile, const struct bfs_printf *directive) { #define BFS_PRINTF_BUF(buf, format, ...) \ char buf[256]; \ int ret = snprintf(buf, sizeof(buf), format, __VA_ARGS__); \ - assert(ret >= 0 && (size_t)ret < sizeof(buf)); \ + bfs_assert(ret >= 0 && (size_t)ret < sizeof(buf)); \ (void)ret /** @@ -190,7 +189,7 @@ static int bfs_printf_strftime(CFILE *cfile, const struct bfs_printf *directive, break; } - assert(ret >= 0 && (size_t)ret < sizeof(buf)); + bfs_assert(ret >= 0 && (size_t)ret < sizeof(buf)); (void)ret; return dyn_fprintf(cfile->file, directive, buf); diff --git a/src/trie.c b/src/trie.c index a2921de..8543eb1 100644 --- a/src/trie.c +++ b/src/trie.c @@ -86,7 +86,6 @@ #include "config.h" #include "diag.h" #include "list.h" -#include #include #include #include @@ -139,27 +138,27 @@ static bool trie_is_leaf(uintptr_t ptr) { /** Decode a pointer to a leaf. */ static struct trie_leaf *trie_decode_leaf(uintptr_t ptr) { - assert(trie_is_leaf(ptr)); + bfs_assert(trie_is_leaf(ptr)); return (struct trie_leaf *)(ptr ^ 1); } /** Encode a pointer to a leaf. */ static uintptr_t trie_encode_leaf(const struct trie_leaf *leaf) { uintptr_t ptr = (uintptr_t)leaf ^ 1; - assert(trie_is_leaf(ptr)); + bfs_assert(trie_is_leaf(ptr)); return ptr; } /** Decode a pointer to an internal node. */ static struct trie_node *trie_decode_node(uintptr_t ptr) { - assert(!trie_is_leaf(ptr)); + bfs_assert(!trie_is_leaf(ptr)); return (struct trie_node *)ptr; } /** Encode a pointer to an internal node. */ static uintptr_t trie_encode_node(const struct trie_node *node) { uintptr_t ptr = (uintptr_t)node; - assert(!trie_is_leaf(ptr)); + bfs_assert(!trie_is_leaf(ptr)); return ptr; } @@ -341,9 +340,9 @@ static void trie_leaf_free(struct trie *trie, struct trie_leaf *leaf) { /** Compute the size of a trie node with a certain number of children. */ static size_t trie_node_size(unsigned int size) { // Empty nodes aren't supported - assert(size > 0); + bfs_assert(size > 0); // Node size must be a power of two - assert(has_single_bit(size)); + bfs_assert(has_single_bit(size)); return flex_sizeof(struct trie_node, children, size); } @@ -435,7 +434,7 @@ static struct trie_leaf *trie_node_insert(struct trie *trie, uintptr_t *ptr, str unsigned int bit = 1U << nibble; // The child must not already be present - assert(!(node->bitmap & bit)); + bfs_assert(!(node->bitmap & bit)); node->bitmap |= bit; unsigned int target = count_ones(node->bitmap & (bit - 1)); @@ -474,7 +473,7 @@ static struct trie_leaf *trie_node_insert(struct trie *trie, uintptr_t *ptr, str static uintptr_t *trie_jump(uintptr_t *ptr, const char *key, size_t *offset) { // We only ever need to jump to leaf nodes, since internal nodes are // guaranteed to be within OFFSET_MAX anyway - assert(trie_is_leaf(*ptr)); + bfs_assert(trie_is_leaf(*ptr)); struct trie_node *node = malloc(trie_node_size(1)); if (!node) { @@ -512,7 +511,7 @@ static uintptr_t *trie_jump(uintptr_t *ptr, const char *key, size_t *offset) { static struct trie_leaf *trie_split(struct trie *trie, uintptr_t *ptr, struct trie_leaf *leaf, struct trie_leaf *rep, size_t offset, size_t mismatch) { unsigned char key_nibble = trie_key_nibble(leaf->key, mismatch); unsigned char rep_nibble = trie_key_nibble(rep->key, mismatch); - assert(key_nibble != rep_nibble); + bfs_assert(key_nibble != rep_nibble); struct trie_node *node = malloc(trie_node_size(2)); if (!node) { @@ -570,11 +569,11 @@ static struct trie_leaf *trie_insert_mem_impl(struct trie *trie, const void *key unsigned char nibble = trie_key_nibble(key, offset); unsigned int bit = 1U << nibble; if (node->bitmap & bit) { - assert(offset < mismatch); + bfs_assert(offset < mismatch); unsigned int index = count_ones(node->bitmap & (bit - 1)); ptr = &node->children[index]; } else { - assert(offset == mismatch); + bfs_assert(offset == mismatch); return trie_node_insert(trie, ptr, leaf, nibble); } } @@ -600,7 +599,7 @@ static void trie_free_singletons(struct trie *trie, uintptr_t ptr) { struct trie_node *node = trie_decode_node(ptr); // Make sure the bitmap is a power of two, i.e. it has just one child - assert(has_single_bit(node->bitmap)); + bfs_assert(has_single_bit(node->bitmap)); ptr = node->children[0]; free(node); @@ -651,12 +650,12 @@ static void trie_remove_impl(struct trie *trie, struct trie_leaf *leaf) { while (!trie_is_leaf(*child)) { struct trie_node *node = trie_decode_node(*child); offset += node->offset; - assert((offset >> 1) < leaf->length); + bfs_assert((offset >> 1) < leaf->length); unsigned char nibble = trie_key_nibble(leaf->key, offset); unsigned int bit = 1U << nibble; unsigned int bitmap = node->bitmap; - assert(bitmap & bit); + bfs_assert(bitmap & bit); unsigned int index = count_ones(bitmap & (bit - 1)); // Advance the parent pointer, unless this node had only one child @@ -669,7 +668,7 @@ static void trie_remove_impl(struct trie *trie, struct trie_leaf *leaf) { child = &node->children[index]; } - assert(trie_decode_leaf(*child) == leaf); + bfs_assert(trie_decode_leaf(*child) == leaf); if (!parent) { trie_free_singletons(trie, trie->root); @@ -683,7 +682,7 @@ static void trie_remove_impl(struct trie *trie, struct trie_leaf *leaf) { node->bitmap ^= child_bit; unsigned int parent_size = count_ones(node->bitmap); - assert(parent_size > 0); + bfs_assert(parent_size > 0); if (parent_size == 1 && trie_collapse_node(parent, node, child_index) == 0) { return; } diff --git a/src/xregex.c b/src/xregex.c index a7153b7..1143f23 100644 --- a/src/xregex.c +++ b/src/xregex.c @@ -3,7 +3,7 @@ #include "xregex.h" #include "config.h" -#include +#include "diag.h" #include #include #include @@ -140,7 +140,7 @@ int bfs_regcomp(struct bfs_regex **preg, const char *pattern, enum bfs_regex_typ syntax = ONIG_SYNTAX_GREP; break; } - assert(syntax); + bfs_assert(syntax); OnigOptionType options = syntax->options; if (flags & BFS_REGEX_ICASE) { diff --git a/tests/bfstd.c b/tests/bfstd.c index a986a23..1812a00 100644 --- a/tests/bfstd.c +++ b/tests/bfstd.c @@ -1,10 +1,9 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD -#undef NDEBUG #include "../src/bfstd.h" #include "../src/config.h" -#include +#include "../src/diag.h" #include #include #include @@ -39,11 +38,11 @@ int main(void) { alignas(64) int foo; int bar[]; }; - assert(flex_sizeof(struct flexible, bar, 0) >= sizeof(struct flexible)); - assert(flex_sizeof(struct flexible, bar, 16) % alignof(struct flexible) == 0); - assert(flex_sizeof(struct flexible, bar, SIZE_MAX / sizeof(int) + 1) - == align_floor(alignof(struct flexible), SIZE_MAX)); - assert(flex_sizeof_impl(8, 16, 4, 4, 1) == 16); + bfs_verify(flex_sizeof(struct flexible, bar, 0) >= sizeof(struct flexible)); + bfs_verify(flex_sizeof(struct flexible, bar, 16) % alignof(struct flexible) == 0); + bfs_verify(flex_sizeof(struct flexible, bar, SIZE_MAX / sizeof(int) + 1) + == align_floor(alignof(struct flexible), SIZE_MAX)); + bfs_verify(flex_sizeof_impl(8, 16, 4, 4, 1) == 16); // From man 3p basename check_base_dir("usr", ".", "usr"); diff --git a/tests/bit.c b/tests/bit.c index 7a7b0f3..cb339f4 100644 --- a/tests/bit.c +++ b/tests/bit.c @@ -1,11 +1,8 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD -#undef NDEBUG - #include "../src/bit.h" #include "../src/diag.h" -#include #include #include #include @@ -54,68 +51,71 @@ bfs_static_assert(UINTMAX_MAX == UWIDTH_MAX(UINTMAX_WIDTH)); bfs_static_assert(INTMAX_MIN == IWIDTH_MIN(INTMAX_WIDTH)); bfs_static_assert(INTMAX_MAX == IWIDTH_MAX(INTMAX_WIDTH)); +#define verify_eq(a, b) \ + bfs_verify((a) == (b), "(0x%jX) %s != %s (0x%jX)", (uintmax_t)(a), #a, #b, (uintmax_t)(b)) + int main(void) { - assert(bswap((uint8_t)0x12) == 0x12); - assert(bswap((uint16_t)0x1234) == 0x3412); - assert(bswap((uint32_t)0x12345678) == 0x78563412); - assert(bswap((uint64_t)0x1234567812345678) == 0x7856341278563412); - - assert(count_ones(0x0) == 0); - assert(count_ones(0x1) == 1); - assert(count_ones(0x2) == 1); - assert(count_ones(0x3) == 2); - assert(count_ones(0x137F) == 10); - - assert(count_zeros(0) == INT_WIDTH); - assert(count_zeros(0L) == LONG_WIDTH); - assert(count_zeros(0LL) == LLONG_WIDTH); - assert(count_zeros((uint8_t)0) == 8); - assert(count_zeros((uint16_t)0) == 16); - assert(count_zeros((uint32_t)0) == 32); - assert(count_zeros((uint64_t)0) == 64); - - assert(rotate_left((uint8_t)0xA1, 4) == 0x1A); - assert(rotate_left((uint16_t)0x1234, 12) == 0x4123); - assert(rotate_left((uint32_t)0x12345678, 20) == 0x67812345); - assert(rotate_left((uint32_t)0x12345678, 0) == 0x12345678); - - assert(rotate_right((uint8_t)0xA1, 4) == 0x1A); - assert(rotate_right((uint16_t)0x1234, 12) == 0x2341); - assert(rotate_right((uint32_t)0x12345678, 20) == 0x45678123); - assert(rotate_right((uint32_t)0x12345678, 0) == 0x12345678); + verify_eq(bswap((uint8_t)0x12), 0x12); + verify_eq(bswap((uint16_t)0x1234), 0x3412); + verify_eq(bswap((uint32_t)0x12345678), 0x78563412); + verify_eq(bswap((uint64_t)0x1234567812345678), 0x7856341278563412); + + verify_eq(count_ones(0x0), 0); + verify_eq(count_ones(0x1), 1); + verify_eq(count_ones(0x2), 1); + verify_eq(count_ones(0x3), 2); + verify_eq(count_ones(0x137F), 10); + + verify_eq(count_zeros(0), INT_WIDTH); + verify_eq(count_zeros(0L), LONG_WIDTH); + verify_eq(count_zeros(0LL), LLONG_WIDTH); + verify_eq(count_zeros((uint8_t)0), 8); + verify_eq(count_zeros((uint16_t)0), 16); + verify_eq(count_zeros((uint32_t)0), 32); + verify_eq(count_zeros((uint64_t)0), 64); + + verify_eq(rotate_left((uint8_t)0xA1, 4), 0x1A); + verify_eq(rotate_left((uint16_t)0x1234, 12), 0x4123); + verify_eq(rotate_left((uint32_t)0x12345678, 20), 0x67812345); + verify_eq(rotate_left((uint32_t)0x12345678, 0), 0x12345678); + + verify_eq(rotate_right((uint8_t)0xA1, 4), 0x1A); + verify_eq(rotate_right((uint16_t)0x1234, 12), 0x2341); + verify_eq(rotate_right((uint32_t)0x12345678, 20), 0x45678123); + verify_eq(rotate_right((uint32_t)0x12345678, 0), 0x12345678); for (int i = 0; i < 16; ++i) { uint16_t n = (uint16_t)1 << i; for (int j = i; j < 16; ++j) { uint16_t m = (uint16_t)1 << j; uint16_t nm = n | m; - assert(count_ones(nm) == 1 + (n != m)); - assert(count_zeros(nm) == 15 - (n != m)); - assert(leading_zeros(nm) == 15 - j); - assert(trailing_zeros(nm) == i); - assert(first_leading_one(nm) == j + 1); - assert(first_trailing_one(nm) == i + 1); - assert(bit_width(nm) == j + 1); - assert(bit_floor(nm) == m); + verify_eq(count_ones(nm), 1 + (n != m)); + verify_eq(count_zeros(nm), 15 - (n != m)); + verify_eq(leading_zeros(nm), 15 - j); + verify_eq(trailing_zeros(nm), i); + verify_eq(first_leading_one(nm), j + 1); + verify_eq(first_trailing_one(nm), i + 1); + verify_eq(bit_width(nm), j + 1); + verify_eq(bit_floor(nm), m); if (n == m) { - assert(bit_ceil(nm) == m); - assert(has_single_bit(nm)); + verify_eq(bit_ceil(nm), m); + bfs_verify(has_single_bit(nm)); } else { if (j < 15) { - assert(bit_ceil(nm) == (m << 1)); + verify_eq(bit_ceil(nm), (m << 1)); } - assert(!has_single_bit(nm)); + bfs_verify(!has_single_bit(nm)); } } } - assert(leading_zeros((uint16_t)0) == 16); - assert(trailing_zeros((uint16_t)0) == 16); - assert(first_leading_one(0) == 0); - assert(first_trailing_one(0) == 0); - assert(bit_width(0) == 0); - assert(bit_floor(0) == 0); - assert(bit_ceil(0) == 1); + verify_eq(leading_zeros((uint16_t)0), 16); + verify_eq(trailing_zeros((uint16_t)0), 16); + verify_eq(first_leading_one(0), 0); + verify_eq(first_trailing_one(0), 0); + verify_eq(bit_width(0), 0); + verify_eq(bit_floor(0), 0); + verify_eq(bit_ceil(0), 1); return EXIT_SUCCESS; } diff --git a/tests/trie.c b/tests/trie.c index ced14d4..e687f96 100644 --- a/tests/trie.c +++ b/tests/trie.c @@ -1,11 +1,9 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD -#undef NDEBUG - #include "../src/trie.h" #include "../src/config.h" -#include +#include "../src/diag.h" #include #include @@ -45,7 +43,7 @@ int main(void) { trie_init(&trie); for (size_t i = 0; i < nkeys; ++i) { - assert(!trie_find_str(&trie, keys[i])); + bfs_verify(!trie_find_str(&trie, keys[i])); const char *prefix = NULL; for (size_t j = 0; j < i; ++j) { @@ -58,38 +56,38 @@ int main(void) { struct trie_leaf *leaf = trie_find_prefix(&trie, keys[i]); if (prefix) { - assert(leaf); - assert(strcmp(prefix, leaf->key) == 0); + bfs_verify(leaf); + bfs_verify(strcmp(prefix, leaf->key) == 0); } else { - assert(!leaf); + bfs_verify(!leaf); } leaf = trie_insert_str(&trie, keys[i]); - assert(leaf); - assert(strcmp(keys[i], leaf->key) == 0); - assert(leaf->length == strlen(keys[i]) + 1); + bfs_verify(leaf); + bfs_verify(strcmp(keys[i], leaf->key) == 0); + bfs_verify(leaf->length == strlen(keys[i]) + 1); } { size_t i = 0; TRIE_FOR_EACH(&trie, leaf) { - assert(leaf == trie_find_str(&trie, keys[i])); - assert(!leaf->prev || leaf->prev->next == leaf); - assert(!leaf->next || leaf->next->prev == leaf); + bfs_verify(leaf == trie_find_str(&trie, keys[i])); + bfs_verify(!leaf->prev || leaf->prev->next == leaf); + bfs_verify(!leaf->next || leaf->next->prev == leaf); ++i; } - assert(i == nkeys); + bfs_verify(i == nkeys); } for (size_t i = 0; i < nkeys; ++i) { struct trie_leaf *leaf = trie_find_str(&trie, keys[i]); - assert(leaf); - assert(strcmp(keys[i], leaf->key) == 0); - assert(leaf->length == strlen(keys[i]) + 1); + bfs_verify(leaf); + bfs_verify(strcmp(keys[i], leaf->key) == 0); + bfs_verify(leaf->length == strlen(keys[i]) + 1); trie_remove(&trie, leaf); leaf = trie_find_str(&trie, keys[i]); - assert(!leaf); + bfs_verify(!leaf); const char *postfix = NULL; for (size_t j = i + 1; j < nkeys; ++j) { @@ -102,33 +100,33 @@ int main(void) { leaf = trie_find_postfix(&trie, keys[i]); if (postfix) { - assert(leaf); - assert(strcmp(postfix, leaf->key) == 0); + bfs_verify(leaf); + bfs_verify(strcmp(postfix, leaf->key) == 0); } else { - assert(!leaf); + bfs_verify(!leaf); } } TRIE_FOR_EACH(&trie, leaf) { - assert(false); + bfs_verify(false); } // This tests the "jump" node handling on 32-bit platforms size_t longsize = 1 << 20; char *longstr = malloc(longsize); - assert(longstr); + bfs_verify(longstr); memset(longstr, 0xAC, longsize); - assert(!trie_find_mem(&trie, longstr, longsize)); - assert(trie_insert_mem(&trie, longstr, longsize)); + bfs_verify(!trie_find_mem(&trie, longstr, longsize)); + bfs_verify(trie_insert_mem(&trie, longstr, longsize)); memset(longstr + longsize/2, 0xAB, longsize/2); - assert(!trie_find_mem(&trie, longstr, longsize)); - assert(trie_insert_mem(&trie, longstr, longsize)); + bfs_verify(!trie_find_mem(&trie, longstr, longsize)); + bfs_verify(trie_insert_mem(&trie, longstr, longsize)); memset(longstr, 0xAA, longsize/2); - assert(!trie_find_mem(&trie, longstr, longsize)); - assert(trie_insert_mem(&trie, longstr, longsize)); + bfs_verify(!trie_find_mem(&trie, longstr, longsize)); + bfs_verify(trie_insert_mem(&trie, longstr, longsize)); free(longstr); trie_destroy(&trie); -- cgit v1.2.3 From 1d1443193878ae72e54560bb21de79668cd954b9 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 8 Jun 2023 13:19:57 -0400 Subject: color: `fi=0` should not fall back to `no` --- src/color.c | 8 ++++---- tests/bfs/color_cd0_no.out | 20 ++++++++++++++++++++ tests/bfs/color_cd0_no.sh | 1 + tests/bfs/color_fi0_no.out | 20 ++++++++++++++++++++ tests/bfs/color_fi0_no.sh | 1 + tests/bfs/color_fi_no.out | 20 ++++++++++++++++++++ tests/bfs/color_fi_no.sh | 1 + tests/bfs/color_no.out | 20 ++++++++++++++++++++ tests/bfs/color_no.sh | 1 + 9 files changed, 88 insertions(+), 4 deletions(-) create mode 100644 tests/bfs/color_cd0_no.out create mode 100644 tests/bfs/color_cd0_no.sh create mode 100644 tests/bfs/color_fi0_no.out create mode 100644 tests/bfs/color_fi0_no.sh create mode 100644 tests/bfs/color_fi_no.out create mode 100644 tests/bfs/color_fi_no.sh create mode 100644 tests/bfs/color_no.out create mode 100644 tests/bfs/color_no.sh (limited to 'src/color.c') diff --git a/src/color.c b/src/color.c index a723084..87575c9 100644 --- a/src/color.c +++ b/src/color.c @@ -436,10 +436,11 @@ struct colors *parse_colors(void) { ret |= init_color(colors, "err", "01;31", &colors->error); // Defaults from man dir_colors + // "" means fall back to ->normal ret |= init_color(colors, "no", NULL, &colors->normal); - ret |= init_color(colors, "fi", NULL, &colors->file); + ret |= init_color(colors, "fi", "", &colors->file); ret |= init_color(colors, "mh", NULL, &colors->multi_hard); ret |= init_color(colors, "ex", "01;32", &colors->executable); ret |= init_color(colors, "ca", NULL, &colors->capable); @@ -472,8 +473,7 @@ struct colors *parse_colors(void) { if (colors->link && strcmp(colors->link, "target") == 0) { colors->link_as_target = true; - dstrfree(colors->link); - colors->link = NULL; + dstresize(&colors->link, 0); } return colors; @@ -634,7 +634,7 @@ static const char *file_color(const struct colors *colors, const char *filename, break; } - if (!color) { + if (color && !color[0]) { color = colors->normal; } diff --git a/tests/bfs/color_cd0_no.out b/tests/bfs/color_cd0_no.out new file mode 100644 index 0000000..d5c98a9 --- /dev/null +++ b/tests/bfs/color_cd0_no.out @@ -0,0 +1,20 @@ +rainbow +rainbow/exec.sh +rainbow/socket +rainbow/broken +rainbow/file.dat +rainbow/file.txt +rainbow/link.txt +rainbow/mh1 +rainbow/mh2 +rainbow/star.gz +rainbow/star.tar +rainbow/star.tar.gz +rainbow/sticky_ow +rainbow/sgid +rainbow/pipe +rainbow/ow +rainbow/sugid +rainbow/suid +rainbow/sticky +rainbow/chardev_link diff --git a/tests/bfs/color_cd0_no.sh b/tests/bfs/color_cd0_no.sh new file mode 100644 index 0000000..325a782 --- /dev/null +++ b/tests/bfs/color_cd0_no.sh @@ -0,0 +1 @@ +LS_COLORS="ln=target:cd=0:no=01;92:" bfs_diff rainbow -color diff --git a/tests/bfs/color_fi0_no.out b/tests/bfs/color_fi0_no.out new file mode 100644 index 0000000..77fc8a8 --- /dev/null +++ b/tests/bfs/color_fi0_no.out @@ -0,0 +1,20 @@ +rainbow +rainbow/exec.sh +rainbow/socket +rainbow/broken +rainbow/chardev_link +rainbow/link.txt +rainbow/sticky_ow +rainbow/sgid +rainbow/pipe +rainbow/ow +rainbow/sugid +rainbow/suid +rainbow/sticky +rainbow/file.dat +rainbow/file.txt +rainbow/mh1 +rainbow/mh2 +rainbow/star.gz +rainbow/star.tar +rainbow/star.tar.gz diff --git a/tests/bfs/color_fi0_no.sh b/tests/bfs/color_fi0_no.sh new file mode 100644 index 0000000..f947d64 --- /dev/null +++ b/tests/bfs/color_fi0_no.sh @@ -0,0 +1 @@ +LS_COLORS="fi=0:no=01;92:" bfs_diff rainbow -color diff --git a/tests/bfs/color_fi_no.out b/tests/bfs/color_fi_no.out new file mode 100644 index 0000000..7162ded --- /dev/null +++ b/tests/bfs/color_fi_no.out @@ -0,0 +1,20 @@ +rainbow +rainbow/exec.sh +rainbow/socket +rainbow/broken +rainbow/chardev_link +rainbow/link.txt +rainbow/file.dat +rainbow/file.txt +rainbow/mh1 +rainbow/mh2 +rainbow/star.gz +rainbow/star.tar +rainbow/star.tar.gz +rainbow/sticky_ow +rainbow/sgid +rainbow/pipe +rainbow/ow +rainbow/sugid +rainbow/suid +rainbow/sticky diff --git a/tests/bfs/color_fi_no.sh b/tests/bfs/color_fi_no.sh new file mode 100644 index 0000000..c2b4ec7 --- /dev/null +++ b/tests/bfs/color_fi_no.sh @@ -0,0 +1 @@ +LS_COLORS="fi=01;91:no=01;92:" bfs_diff rainbow -color diff --git a/tests/bfs/color_no.out b/tests/bfs/color_no.out new file mode 100644 index 0000000..9f0dd66 --- /dev/null +++ b/tests/bfs/color_no.out @@ -0,0 +1,20 @@ +rainbow +rainbow/exec.sh +rainbow/socket +rainbow/broken +rainbow/chardev_link +rainbow/link.txt +rainbow/file.dat +rainbow/file.txt +rainbow/mh1 +rainbow/mh2 +rainbow/star.gz +rainbow/star.tar +rainbow/star.tar.gz +rainbow/sticky_ow +rainbow/sgid +rainbow/pipe +rainbow/ow +rainbow/sugid +rainbow/suid +rainbow/sticky diff --git a/tests/bfs/color_no.sh b/tests/bfs/color_no.sh new file mode 100644 index 0000000..b7527cb --- /dev/null +++ b/tests/bfs/color_no.sh @@ -0,0 +1 @@ +LS_COLORS="no=01;92:" bfs_diff rainbow -color -- cgit v1.2.3 From 2eeee3e0d0d3aeca5e6487cc2431c1f65e35a6d8 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Fri, 16 Jun 2023 13:44:21 -0400 Subject: color: New %pq formatter for shell-escaped strings --- src/color.c | 18 ++++++++++++++++++ src/color.h | 1 + 2 files changed, 19 insertions(+) (limited to 'src/color.c') diff --git a/src/color.c b/src/color.c index 87575c9..1edd8b5 100644 --- a/src/color.c +++ b/src/color.c @@ -858,6 +858,18 @@ static int print_link_target(CFILE *cfile, const struct BFTW *ftwbuf) { return ret; } +/** Print an shell-escaped string. */ +static int print_wordesc(CFILE *cfile, const char *str) { + char *esc = wordesc(str); + if (!esc) { + return -1; + } + + int ret = dstrcat(&cfile->buffer, esc); + free(esc); + return ret; +} + /** Format some colored output to the buffer. */ BFS_FORMATTER(2, 3) static int cbuff(CFILE *cfile, const char *format, ...); @@ -994,6 +1006,12 @@ static int cvbuff(CFILE *cfile, const char *format, va_list args) { case 'p': switch (*++i) { + case 'q': + if (print_wordesc(cfile, va_arg(args, const char *)) != 0) { + return -1; + } + break; + case 'F': if (print_name(cfile, va_arg(args, const struct BFTW *)) != 0) { return -1; diff --git a/src/color.h b/src/color.h index 3db2b07..aca6a34 100644 --- a/src/color.h +++ b/src/color.h @@ -84,6 +84,7 @@ int cfclose(CFILE *cfile); * %s: A string * %zu: A size_t * %m: strerror(errno) + * %pq: A shell-escaped string, like bash's printf %q * %pF: A colored file name, from a const struct BFTW * argument * %pP: A colored file path, from a const struct BFTW * argument * %pL: A colored link target, from a const struct BFTW * argument -- cgit v1.2.3 From 90ded13e589b0089167ef25ca3d26be599dfec9b Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Mon, 19 Jun 2023 12:11:36 -0400 Subject: alloc: New header for memory allocation utilities --- Makefile | 3 +- src/alloc.c | 50 ++++++++++++++++++++ src/alloc.h | 149 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/bfstd.c | 13 ----- src/bfstd.h | 12 ----- src/bftw.c | 5 +- src/color.c | 5 +- src/config.h | 50 -------------------- src/ctx.c | 31 ++---------- src/dstring.c | 3 +- src/exec.c | 26 ++++------ src/ioq.c | 26 ++++------ src/ioq.h | 4 +- src/main.c | 1 + src/mtab.c | 5 +- src/parse.c | 28 ++--------- src/pwcache.c | 5 +- src/trie.c | 7 ++- src/xregex.c | 3 +- src/xspawn.c | 3 +- tests/alloc.c | 24 ++++++++++ tests/bfstd.c | 13 +---- 22 files changed, 271 insertions(+), 195 deletions(-) create mode 100644 src/alloc.c create mode 100644 src/alloc.h create mode 100644 tests/alloc.c (limited to 'src/color.c') diff --git a/Makefile b/Makefile index fb28e29..d38f581 100644 --- a/Makefile +++ b/Makefile @@ -217,6 +217,7 @@ $(OBJ)/FLAGS: $(OBJ)/FLAGS.new # All object files except the entry point LIBBFS := \ + $(OBJ)/src/alloc.o \ $(OBJ)/src/bar.o \ $(OBJ)/src/bfstd.o \ $(OBJ)/src/bftw.o \ @@ -246,7 +247,7 @@ LIBBFS := \ $(BIN)/bfs: $(OBJ)/src/main.o $(LIBBFS) # Standalone unit tests -UNITS := bfstd bit trie xtimegm +UNITS := alloc bfstd bit trie xtimegm UNIT_TESTS := $(UNITS:%=$(BIN)/tests/%) UNIT_CHECKS := $(UNITS:%=check-%) diff --git a/src/alloc.c b/src/alloc.c new file mode 100644 index 0000000..0003108 --- /dev/null +++ b/src/alloc.c @@ -0,0 +1,50 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include "alloc.h" +#include "bit.h" +#include "diag.h" +#include +#include +#include + +/** Portable aligned_alloc()/posix_memalign(). */ +static void *xmemalign(size_t align, size_t size) { + bfs_assert(has_single_bit(align)); + bfs_assert(align >= sizeof(void *)); + bfs_assert((size & (align - 1)) == 0); + +#if __APPLE__ + void *ptr = NULL; + errno = posix_memalign(&ptr, align, size); + return ptr; +#else + return aligned_alloc(align, size); +#endif +} + +void *alloc(size_t align, size_t size) { + bfs_assert(has_single_bit(align)); + bfs_assert((size & (align - 1)) == 0); + + if (align <= alignof(max_align_t)) { + return malloc(size); + } else { + return xmemalign(align, size); + } +} + +void *zalloc(size_t align, size_t size) { + bfs_assert(has_single_bit(align)); + bfs_assert((size & (align - 1)) == 0); + + if (align <= alignof(max_align_t)) { + return calloc(1, size); + } + + void *ret = xmemalign(align, size); + if (ret) { + memset(ret, 0, size); + } + return ret; +} diff --git a/src/alloc.h b/src/alloc.h new file mode 100644 index 0000000..899a4ec --- /dev/null +++ b/src/alloc.h @@ -0,0 +1,149 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +/** + * Memory allocation. + */ + +#ifndef BFS_ALLOC_H +#define BFS_ALLOC_H + +#include "config.h" +#include + +/** Round down to a multiple of an alignment. */ +static inline size_t align_floor(size_t align, size_t size) { + return size & ~(align - 1); +} + +/** Round up to a multiple of an alignment. */ +static inline size_t align_ceil(size_t align, size_t size) { + return align_floor(align, size + align - 1); +} + +/** + * Saturating array size. + * + * @param align + * Array element alignment. + * @param size + * Array element size. + * @param count + * Array element count. + * @return + * size * count, saturating to the maximum aligned value on overflow. + */ +static inline size_t array_size(size_t align, size_t size, size_t count) { + size_t ret = size * count; + return ret / size == count ? ret : ~(align - 1); +} + +/** Saturating array sizeof. */ +#define sizeof_array(type, count) \ + array_size(alignof(type), sizeof(type), count) + +/** Size of a struct/union field. */ +#define sizeof_member(type, member) \ + sizeof(((type *)NULL)->member) + +/** + * Saturating flexible struct size. + * + * @param align + * Struct alignment. + * @param min + * Minimum struct size. + * @param offset + * Flexible array member offset. + * @param size + * Flexible array element size. + * @param count + * Flexible array element count. + * @return + * The size of the struct with count flexible array elements. Saturates + * to the maximum aligned value on overflow. + */ +static inline size_t flex_size(size_t align, size_t min, size_t offset, size_t size, size_t count) { + size_t ret = size * count; + size_t overflow = ret / size != count; + + size_t extra = offset + align - 1; + ret += extra; + overflow |= ret < extra; + ret |= -overflow; + ret = align_floor(align, ret); + + // Make sure flex_sizeof(type, member, 0) >= sizeof(type), even if the + // type has more padding than necessary for alignment + if (min > align_ceil(align, offset)) { + ret = ret < min ? min : ret; + } + + return ret; +} + +/** + * Computes the size of a flexible struct. + * + * @param type + * The type of the struct containing the flexible array. + * @param member + * The name of the flexible array member. + * @param count + * The length of the flexible array. + * @return + * The size of the struct with count flexible array elements. Saturates + * to the maximum aligned value on overflow. + */ +#define sizeof_flex(type, member, count) \ + flex_size(alignof(type), sizeof(type), offsetof(type, member), sizeof_member(type, member[0]), count) + +/** + * General memory allocator. + * + * @param align + * The required alignment. + * @param size + * The size of the allocation. + * @return + * The allocated memory, or NULL on failure. + */ +void *alloc(size_t align, size_t size); + +/** + * Zero-initialized memory allocator. + * + * @param align + * The required alignment. + * @param size + * The size of the allocation. + * @return + * The allocated memory, or NULL on failure. + */ +void *zalloc(size_t align, size_t size); + +/** Allocate memory for the given type. */ +#define ALLOC(type) \ + (type *)alloc(alignof(type), sizeof(type)) + +/** Allocate zeroed memory for the given type. */ +#define ZALLOC(type) \ + (type *)zalloc(alignof(type), sizeof(type)) + +/** Allocate memory for an array. */ +#define ALLOC_ARRAY(type, count) \ + (type *)alloc(alignof(type), sizeof_array(type, count)); + +/** Allocate zeroed memory for an array. */ +#define ZALLOC_ARRAY(type, count) \ + (type *)zalloc(alignof(type), sizeof_array(type, count)); + +/** Allocate memory for a flexible struct. */ +#define ALLOC_FLEX(type, member, count) \ + (type *)alloc(alignof(type), sizeof_flex(type, member, count)) + +/** Allocate zeroed memory for a flexible struct. */ +#define ZALLOC_FLEX(type, member, count) \ + (type *)zalloc(alignof(type), sizeof_flex(type, member, count)) + +#endif // BFS_ALLOC_H diff --git a/src/bfstd.c b/src/bfstd.c index 856c76c..0e8ba5f 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -143,19 +143,6 @@ char *xgetdelim(FILE *file, char delim) { } } -void *xmemalign(size_t align, size_t size) { - bfs_assert(has_single_bit(align)); - bfs_assert((size & (align - 1)) == 0); - -#if __APPLE__ - void *ptr = NULL; - errno = posix_memalign(&ptr, align, size); - return ptr; -#else - return aligned_alloc(align, size); -#endif -} - /** Compile and execute a regular expression for xrpmatch(). */ static int xrpregex(nl_item item, const char *response) { const char *pattern = nl_langinfo(item); diff --git a/src/bfstd.h b/src/bfstd.h index 6f2e21e..cafe28f 100644 --- a/src/bfstd.h +++ b/src/bfstd.h @@ -105,18 +105,6 @@ char *xgetdelim(FILE *file, char delim); // #include -/** - * Portable version of aligned_alloc()/posix_memalign(). - * - * @param align - * The allocation's alignment. - * @param size - * The allocation's size. - * @return - * The allocation, or NULL on failure. - */ -void *xmemalign(size_t align, size_t size); - /** * Process a yes/no prompt. * diff --git a/src/bftw.c b/src/bftw.c index e711963..7ab14c7 100644 --- a/src/bftw.c +++ b/src/bftw.c @@ -17,6 +17,7 @@ */ #include "bftw.h" +#include "alloc.h" #include "bfstd.h" #include "config.h" #include "diag.h" @@ -241,9 +242,7 @@ static void bftw_cache_destroy(struct bftw_cache *cache) { /** Create a new bftw_file. */ static struct bftw_file *bftw_file_new(struct bftw_file *parent, const char *name) { size_t namelen = strlen(name); - size_t size = flex_sizeof(struct bftw_file, name, namelen + 1); - - struct bftw_file *file = malloc(size); + struct bftw_file *file = ALLOC_FLEX(struct bftw_file, name, namelen + 1); if (!file) { return NULL; } diff --git a/src/color.c b/src/color.c index 1edd8b5..b54ad53 100644 --- a/src/color.c +++ b/src/color.c @@ -2,6 +2,7 @@ // SPDX-License-Identifier: 0BSD #include "color.h" +#include "alloc.h" #include "bfstd.h" #include "bftw.h" #include "config.h" @@ -404,7 +405,7 @@ static void parse_gnu_ls_colors(struct colors *colors, const char *ls_colors) { } struct colors *parse_colors(void) { - struct colors *colors = malloc(sizeof(struct colors)); + struct colors *colors = ALLOC(struct colors); if (!colors) { return NULL; } @@ -497,7 +498,7 @@ void free_colors(struct colors *colors) { } CFILE *cfwrap(FILE *file, const struct colors *colors, bool close) { - CFILE *cfile = malloc(sizeof(*cfile)); + CFILE *cfile = ALLOC(CFILE); if (!cfile) { return NULL; } diff --git a/src/config.h b/src/config.h index 73348ac..1671a0d 100644 --- a/src/config.h +++ b/src/config.h @@ -141,56 +141,6 @@ */ #define countof(array) (sizeof(array) / sizeof(0[array])) -/** - * Round down to a multiple of an alignment. - */ -static inline size_t align_floor(size_t align, size_t size) { - return size & ~(align - 1); -} - -/** - * Round up to a multiple of an alignment. - */ -static inline size_t align_ceil(size_t align, size_t size) { - return align_floor(align, size + align - 1); -} - -/** - * Computes the size of a struct containing a flexible array member of the given - * length. - * - * @param type - * The type of the struct containing the flexible array. - * @param member - * The name of the flexible array member. - * @param count - * The length of the flexible array. - */ -#define flex_sizeof(type, member, count) \ - flex_sizeof_impl(alignof(type), sizeof(type), offsetof(type, member), sizeof(((type *)NULL)->member[0]), count) - -static inline size_t flex_sizeof_impl(size_t align, size_t min, size_t offset, size_t size, size_t count) { - size_t ret = size * count; - size_t overflow = ret / size != count; - - ret += offset; - overflow |= ret < offset; - - size_t mask = align - 1; - ret += mask; - overflow |= ret < mask; - ret |= -overflow; - ret &= ~mask; - - // Make sure flex_sizeof(type, member, 0) >= sizeof(type), even if the - // type has more padding than necessary for alignment - if (min > align_ceil(align, offset) && ret < min) { - ret = min; - } - - return ret; -} - /** * False sharing/destructive interference/largest cache line size. */ diff --git a/src/ctx.c b/src/ctx.c index e8ce0e8..a940bed 100644 --- a/src/ctx.c +++ b/src/ctx.c @@ -2,6 +2,7 @@ // SPDX-License-Identifier: 0BSD #include "ctx.h" +#include "alloc.h" #include "color.h" #include "darray.h" #include "diag.h" @@ -42,43 +43,17 @@ const char *debug_flag_name(enum debug_flags flag) { } struct bfs_ctx *bfs_ctx_new(void) { - struct bfs_ctx *ctx = malloc(sizeof(*ctx)); + struct bfs_ctx *ctx = ZALLOC(struct bfs_ctx); if (!ctx) { return NULL; } - ctx->argv = NULL; - ctx->paths = NULL; - ctx->expr = NULL; - ctx->exclude = NULL; - - ctx->mindepth = 0; ctx->maxdepth = INT_MAX; ctx->flags = BFTW_RECOVER; ctx->strategy = BFTW_BFS; - ctx->threads = 0; ctx->optlevel = 3; - ctx->debug = 0; - ctx->ignore_races = false; - ctx->posixly_correct = false; - ctx->status = false; - ctx->unique = false; - ctx->warn = false; - ctx->xargs_safe = false; - - ctx->colors = NULL; - ctx->colors_error = 0; - ctx->cout = NULL; - ctx->cerr = NULL; - - ctx->users = NULL; - ctx->groups = NULL; - - ctx->mtab = NULL; - ctx->mtab_error = 0; trie_init(&ctx->files); - ctx->nfiles = 0; struct rlimit rl; if (getrlimit(RLIMIT_NOFILE, &rl) != 0) { @@ -155,7 +130,7 @@ CFILE *bfs_ctx_dedup(struct bfs_ctx *ctx, CFILE *cfile, const char *path) { return ctx_file->cfile; } - leaf->value = ctx_file = malloc(sizeof(*ctx_file)); + leaf->value = ctx_file = ALLOC(struct bfs_ctx_file); if (!ctx_file) { trie_remove(&ctx->files, leaf); return NULL; diff --git a/src/dstring.c b/src/dstring.c index 2c9869d..7ca74d0 100644 --- a/src/dstring.c +++ b/src/dstring.c @@ -2,6 +2,7 @@ // SPDX-License-Identifier: 0BSD #include "dstring.h" +#include "alloc.h" #include "diag.h" #include #include @@ -24,7 +25,7 @@ static struct dstring *dstrheader(const char *dstr) { /** Get the correct size for a dstring with the given capacity. */ static size_t dstrsize(size_t capacity) { - return flex_sizeof(struct dstring, data, capacity + 1); + return sizeof_flex(struct dstring, data, capacity + 1); } /** Allocate a dstring with the given contents. */ diff --git a/src/exec.c b/src/exec.c index 5912ad6..ea7f897 100644 --- a/src/exec.c +++ b/src/exec.c @@ -2,6 +2,7 @@ // SPDX-License-Identifier: 0BSD #include "exec.h" +#include "alloc.h" #include "bfstd.h" #include "bftw.h" #include "ctx.h" @@ -124,26 +125,16 @@ static void bfs_exec_parse_error(const struct bfs_ctx *ctx, const struct bfs_exe } struct bfs_exec *bfs_exec_parse(const struct bfs_ctx *ctx, char **argv, enum bfs_exec_flags flags) { - struct bfs_exec *execbuf = malloc(sizeof(*execbuf)); + struct bfs_exec *execbuf = ZALLOC(struct bfs_exec); if (!execbuf) { - bfs_perror(ctx, "malloc()"); + bfs_perror(ctx, "zalloc()"); goto fail; } execbuf->flags = flags; execbuf->ctx = ctx; execbuf->tmpl_argv = argv + 1; - execbuf->tmpl_argc = 0; - execbuf->argv = NULL; - execbuf->argc = 0; - execbuf->argv_cap = 0; - execbuf->arg_size = 0; - execbuf->arg_max = 0; - execbuf->arg_min = 0; execbuf->wd_fd = -1; - execbuf->wd_path = NULL; - execbuf->wd_len = 0; - execbuf->ret = 0; while (true) { const char *arg = execbuf->tmpl_argv[execbuf->tmpl_argc]; @@ -176,9 +167,9 @@ struct bfs_exec *bfs_exec_parse(const struct bfs_ctx *ctx, char **argv, enum bfs } execbuf->argv_cap = execbuf->tmpl_argc + 1; - execbuf->argv = malloc(execbuf->argv_cap*sizeof(*execbuf->argv)); + execbuf->argv = ALLOC_ARRAY(char *, execbuf->argv_cap); if (!execbuf->argv) { - bfs_perror(ctx, "malloc()"); + bfs_perror(ctx, "alloc()"); goto fail; } @@ -224,9 +215,8 @@ static char *bfs_exec_format_path(const struct bfs_exec *execbuf, const struct B return NULL; } - strcpy(path, "./"); - strcpy(path + 2, name); - + char *cur = stpcpy(path, "./"); + cur = stpcpy(cur, name); return path; } @@ -612,7 +602,7 @@ static int bfs_exec_push(struct bfs_exec *execbuf, char *arg) { if (execbuf->argc + 1 >= execbuf->argv_cap) { size_t cap = 2*execbuf->argv_cap; - char **argv = realloc(execbuf->argv, cap*sizeof(*argv)); + char **argv = realloc(execbuf->argv, sizeof_array(char *, cap)); if (!argv) { return -1; } diff --git a/src/ioq.c b/src/ioq.c index 5550c91..3e304ce 100644 --- a/src/ioq.c +++ b/src/ioq.c @@ -2,6 +2,7 @@ // SPDX-License-Identifier: 0BSD #include "ioq.h" +#include "alloc.h" #include "atomic.h" #include "bfstd.h" #include "bit.h" @@ -114,7 +115,7 @@ static struct ioqq *ioqq_create(size_t size) { // Circular buffer size must be a power of two size = bit_ceil(size); - struct ioqq *ioqq = xmemalign(alignof(struct ioqq), flex_sizeof(struct ioqq, slots, size)); + struct ioqq *ioqq = ALLOC_FLEX(struct ioqq, slots, size); if (!ioqq) { return NULL; } @@ -124,7 +125,7 @@ static struct ioqq *ioqq_create(size_t size) { // Use a pool of monitors size_t nmonitors = size < 64 ? size : 64; - ioqq->monitors = xmemalign(alignof(struct ioq_monitor), nmonitors * sizeof(struct ioq_monitor)); + ioqq->monitors = ALLOC_ARRAY(struct ioq_monitor, nmonitors); if (!ioqq->monitors) { ioqq_destroy(ioqq); return NULL; @@ -273,7 +274,7 @@ struct ioq { /** The number of background threads. */ size_t nthreads; /** The background threads themselves. */ - pthread_t *threads; + pthread_t threads[]; }; /** Background thread entry point. */ @@ -303,18 +304,13 @@ static void *ioq_work(void *ptr) { return NULL; } -struct ioq *ioq_create(size_t depth, size_t threads) { - struct ioq *ioq = malloc(sizeof(*ioq)); +struct ioq *ioq_create(size_t depth, size_t nthreads) { + struct ioq *ioq = ZALLOC_FLEX(struct ioq, threads, nthreads); if (!ioq) { goto fail; } ioq->depth = depth; - ioq->size = 0; - - ioq->pending = NULL; - ioq->ready = NULL; - ioq->nthreads = 0; ioq->pending = ioqq_create(depth); if (!ioq->pending) { @@ -326,12 +322,7 @@ struct ioq *ioq_create(size_t depth, size_t threads) { goto fail; } - ioq->threads = malloc(threads * sizeof(ioq->threads[0])); - if (!ioq->threads) { - goto fail; - } - - for (size_t i = 0; i < threads; ++i) { + for (size_t i = 0; i < nthreads; ++i) { errno = pthread_create(&ioq->threads[i], NULL, ioq_work, ioq); if (errno != 0) { goto fail; @@ -354,7 +345,7 @@ int ioq_opendir(struct ioq *ioq, int dfd, const char *path, void *ptr) { return -1; } - union ioq_cmd *cmd = malloc(sizeof(*cmd)); + union ioq_cmd *cmd = ALLOC(union ioq_cmd); if (!cmd) { return -1; } @@ -412,7 +403,6 @@ void ioq_destroy(struct ioq *ioq) { abort(); } } - free(ioq->threads); ioqq_destroy(ioq->ready); ioqq_destroy(ioq->pending); diff --git a/src/ioq.h b/src/ioq.h index 9492034..0af5779 100644 --- a/src/ioq.h +++ b/src/ioq.h @@ -33,12 +33,12 @@ struct ioq_res { * * @param depth * The maximum depth of the queue. - * @param threads + * @param nthreads * The maximum number of background threads. * @return * The new I/O queue, or NULL on failure. */ -struct ioq *ioq_create(size_t depth, size_t threads); +struct ioq *ioq_create(size_t depth, size_t nthreads); /** * Asynchronous bfs_opendir(). diff --git a/src/main.c b/src/main.c index 76dde86..b7a08c1 100644 --- a/src/main.c +++ b/src/main.c @@ -20,6 +20,7 @@ * - bftw.[ch] (an extended version of nftw(3)) * * - Utilities: + * - alloc.[ch] (memory allocation) * - atomic.h (atomic operations) * - bar.[ch] (a terminal status bar) * - bit.h (bit manipulation) diff --git a/src/mtab.c b/src/mtab.c index 1d1ad94..e5c25ba 100644 --- a/src/mtab.c +++ b/src/mtab.c @@ -2,6 +2,7 @@ // SPDX-License-Identifier: 0BSD #include "mtab.h" +#include "alloc.h" #include "bfstd.h" #include "config.h" #include "darray.h" @@ -87,15 +88,13 @@ fail: } struct bfs_mtab *bfs_mtab_parse(void) { - struct bfs_mtab *mtab = malloc(sizeof(*mtab)); + struct bfs_mtab *mtab = ZALLOC(struct bfs_mtab); if (!mtab) { return NULL; } - mtab->entries = NULL; trie_init(&mtab->names); trie_init(&mtab->types); - mtab->types_filled = false; int error = 0; diff --git a/src/parse.c b/src/parse.c index 64e08cd..cf4f696 100644 --- a/src/parse.c +++ b/src/parse.c @@ -9,6 +9,7 @@ */ #include "parse.h" +#include "alloc.h" #include "bfstd.h" #include "bftw.h" #include "color.h" @@ -55,39 +56,16 @@ static char *fake_print_arg = "-print"; static char *fake_true_arg = "-true"; struct bfs_expr *bfs_expr_new(bfs_eval_fn *eval_fn, size_t argc, char **argv) { - struct bfs_expr *expr = malloc(sizeof(*expr)); + struct bfs_expr *expr = ZALLOC(struct bfs_expr); if (!expr) { - perror("malloc()"); + perror("zalloc()"); return NULL; } expr->eval_fn = eval_fn; expr->argc = argc; expr->argv = argv; - expr->persistent_fds = 0; - expr->ephemeral_fds = 0; - expr->pure = false; - expr->always_true = false; - expr->always_false = false; - expr->cost = 0.0; expr->probability = 0.5; - expr->evaluations = 0; - expr->successes = 0; - expr->elapsed.tv_sec = 0; - expr->elapsed.tv_nsec = 0; - - // Prevent bfs_expr_free() from freeing uninitialized pointers on error paths - if (bfs_expr_is_parent(expr)) { - expr->lhs = NULL; - expr->rhs = NULL; - } else if (eval_fn == eval_exec) { - expr->exec = NULL; - } else if (eval_fn == eval_fprintf) { - expr->printf = NULL; - } else if (eval_fn == eval_regex) { - expr->regex = NULL; - } - return expr; } diff --git a/src/pwcache.c b/src/pwcache.c index f52e4e1..9f32eb0 100644 --- a/src/pwcache.c +++ b/src/pwcache.c @@ -2,6 +2,7 @@ // SPDX-License-Identifier: 0BSD #include "pwcache.h" +#include "alloc.h" #include "config.h" #include "darray.h" #include "trie.h" @@ -71,7 +72,7 @@ struct bfs_users { }; struct bfs_users *bfs_users_new(void) { - struct bfs_users *users = malloc(sizeof(*users)); + struct bfs_users *users = ALLOC(struct bfs_users); if (!users) { return NULL; } @@ -144,7 +145,7 @@ struct bfs_groups { }; struct bfs_groups *bfs_groups_new(void) { - struct bfs_groups *groups = malloc(sizeof(*groups)); + struct bfs_groups *groups = ALLOC(struct bfs_groups); if (!groups) { return NULL; } diff --git a/src/trie.c b/src/trie.c index 8543eb1..19423cf 100644 --- a/src/trie.c +++ b/src/trie.c @@ -82,6 +82,7 @@ */ #include "trie.h" +#include "alloc.h" #include "bit.h" #include "config.h" #include "diag.h" @@ -317,7 +318,7 @@ struct trie_leaf *trie_find_prefix(const struct trie *trie, const char *key) { /** Create a new leaf, holding a copy of the given key. */ static struct trie_leaf *trie_leaf_alloc(struct trie *trie, const void *key, size_t length) { - struct trie_leaf *leaf = malloc(flex_sizeof(struct trie_leaf, key, length)); + struct trie_leaf *leaf = ALLOC_FLEX(struct trie_leaf, key, length); if (!leaf) { return NULL; } @@ -339,12 +340,10 @@ static void trie_leaf_free(struct trie *trie, struct trie_leaf *leaf) { /** Compute the size of a trie node with a certain number of children. */ static size_t trie_node_size(unsigned int size) { - // Empty nodes aren't supported - bfs_assert(size > 0); // Node size must be a power of two bfs_assert(has_single_bit(size)); - return flex_sizeof(struct trie_node, children, size); + return sizeof_flex(struct trie_node, children, size); } #if ENDIAN_NATIVE == ENDIAN_LITTLE diff --git a/src/xregex.c b/src/xregex.c index 89c2e90..ab5f793 100644 --- a/src/xregex.c +++ b/src/xregex.c @@ -2,6 +2,7 @@ // SPDX-License-Identifier: 0BSD #include "xregex.h" +#include "alloc.h" #include "config.h" #include "diag.h" #include "sanity.h" @@ -115,7 +116,7 @@ static int bfs_onig_initialize(OnigEncoding *enc) { #endif int bfs_regcomp(struct bfs_regex **preg, const char *pattern, enum bfs_regex_type type, enum bfs_regcomp_flags flags) { - struct bfs_regex *regex = *preg = malloc(sizeof(*regex)); + struct bfs_regex *regex = *preg = ALLOC(struct bfs_regex); if (!regex) { return -1; } diff --git a/src/xspawn.c b/src/xspawn.c index 740e38e..2cabdcc 100644 --- a/src/xspawn.c +++ b/src/xspawn.c @@ -2,6 +2,7 @@ // SPDX-License-Identifier: 0BSD #include "xspawn.h" +#include "alloc.h" #include "bfstd.h" #include "config.h" #include "list.h" @@ -62,7 +63,7 @@ int bfs_spawn_setflags(struct bfs_spawn *ctx, enum bfs_spawn_flags flags) { /** Add a spawn action to the chain. */ static struct bfs_spawn_action *bfs_spawn_add(struct bfs_spawn *ctx, enum bfs_spawn_op op) { - struct bfs_spawn_action *action = malloc(sizeof(*action)); + struct bfs_spawn_action *action = ALLOC(struct bfs_spawn_action); if (!action) { return NULL; } diff --git a/tests/alloc.c b/tests/alloc.c new file mode 100644 index 0000000..91b1b43 --- /dev/null +++ b/tests/alloc.c @@ -0,0 +1,24 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include "../src/alloc.h" +#include "../src/diag.h" +#include + +int main(void) { + // Check sizeof_flex() + struct flexible { + alignas(64) int foo; + int bar[]; + }; + bfs_verify(sizeof_flex(struct flexible, bar, 0) >= sizeof(struct flexible)); + bfs_verify(sizeof_flex(struct flexible, bar, 16) % alignof(struct flexible) == 0); + bfs_verify(sizeof_flex(struct flexible, bar, SIZE_MAX / sizeof(int) + 1) + == align_floor(alignof(struct flexible), SIZE_MAX)); + + // Corner case: sizeof(type) > align_ceil(alignof(type), offsetof(type, member)) + // Doesn't happen in typical ABIs + bfs_verify(flex_size(8, 16, 4, 4, 1) == 16); + + return EXIT_SUCCESS; +} diff --git a/tests/bfstd.c b/tests/bfstd.c index 7fea9b5..fa854a8 100644 --- a/tests/bfstd.c +++ b/tests/bfstd.c @@ -24,17 +24,6 @@ static void check_base_dir(const char *path, const char *dir, const char *base) } int main(void) { - // Check flex_sizeof() - struct flexible { - alignas(64) int foo; - int bar[]; - }; - bfs_verify(flex_sizeof(struct flexible, bar, 0) >= sizeof(struct flexible)); - bfs_verify(flex_sizeof(struct flexible, bar, 16) % alignof(struct flexible) == 0); - bfs_verify(flex_sizeof(struct flexible, bar, SIZE_MAX / sizeof(int) + 1) - == align_floor(alignof(struct flexible), SIZE_MAX)); - bfs_verify(flex_sizeof_impl(8, 16, 4, 4, 1) == 16); - // From man 3p basename check_base_dir("usr", ".", "usr"); check_base_dir("usr/", ".", "usr"); @@ -46,4 +35,6 @@ int main(void) { check_base_dir("/usr/lib", "/usr", "lib"); check_base_dir("//usr//lib//", "//usr", "lib"); check_base_dir("/home//dwc//test", "/home//dwc", "test"); + + return EXIT_SUCCESS; } -- cgit v1.2.3 From 27dc7a126d6c00b7a41e0559254928555200ee42 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 29 Jun 2023 15:17:27 -0400 Subject: color: Implement smart casing Since coreutils 9.2, ls does case-sensitive extension matching if the same extension is capitalized differently in $LS_COLORS. Implement the same logic. Link: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=33123 Link: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=9086 --- src/color.c | 591 +++++++++++++++++++++++++++---------------- tests/bfs/color_ext_case.out | 25 ++ tests/bfs/color_ext_case.sh | 1 + tests/bfs/color_nul.out | Bin 20 -> 908 bytes tests/bfs/color_nul.sh | 3 +- tests/bfs/color_star.out | 25 -- tests/bfs/color_star.sh | 2 +- 7 files changed, 401 insertions(+), 246 deletions(-) create mode 100644 tests/bfs/color_ext_case.out create mode 100644 tests/bfs/color_ext_case.sh delete mode 100644 tests/bfs/color_star.out (limited to 'src/color.c') diff --git a/src/color.c b/src/color.c index b54ad53..82ff763 100644 --- a/src/color.c +++ b/src/color.c @@ -22,69 +22,122 @@ #include #include +/** + * An escape sequence, which may contain embedded NUL bytes. + */ +struct esc_seq { + /** The length of the escape sequence. */ + size_t len; + /** The escape sequence iteself, without a terminating NUL. */ + char seq[]; +}; + +/** + * A colored file extension, like `*.tar=01;31`. + */ +struct ext_color { + /** Priority, to disambiguate case-sensitive and insensitive matches. */ + size_t priority; + /** The escape sequence associated with this extension. */ + struct esc_seq *esc; + /** The length of the extension to match. */ + size_t len; + /** Whether the comparison should be case-insensitive. */ + bool icase; + /** The extension to match (NUL-terminated). */ + char ext[]; +}; + struct colors { - char *reset; - char *leftcode; - char *rightcode; - char *endcode; - char *clear_to_eol; - - char *bold; - char *gray; - char *red; - char *green; - char *yellow; - char *blue; - char *magenta; - char *cyan; - char *white; - - char *warning; - char *error; - - char *normal; - - char *file; - char *multi_hard; - char *executable; - char *capable; - char *setgid; - char *setuid; - - char *directory; - char *sticky; - char *other_writable; - char *sticky_other_writable; - - char *link; - char *orphan; - char *missing; + /** esc_seq allocator. */ + struct varena esc_arena; + /** ext_color allocator. */ + struct varena ext_arena; + + // Known dircolors keys + + struct esc_seq *reset; + struct esc_seq *leftcode; + struct esc_seq *rightcode; + struct esc_seq *endcode; + struct esc_seq *clear_to_eol; + + struct esc_seq *bold; + struct esc_seq *gray; + struct esc_seq *red; + struct esc_seq *green; + struct esc_seq *yellow; + struct esc_seq *blue; + struct esc_seq *magenta; + struct esc_seq *cyan; + struct esc_seq *white; + + struct esc_seq *warning; + struct esc_seq *error; + + struct esc_seq *normal; + + struct esc_seq *file; + struct esc_seq *multi_hard; + struct esc_seq *executable; + struct esc_seq *capable; + struct esc_seq *setgid; + struct esc_seq *setuid; + + struct esc_seq *directory; + struct esc_seq *sticky; + struct esc_seq *other_writable; + struct esc_seq *sticky_other_writable; + + struct esc_seq *link; + struct esc_seq *orphan; + struct esc_seq *missing; bool link_as_target; - char *blockdev; - char *chardev; - char *door; - char *pipe; - char *socket; + struct esc_seq *blockdev; + struct esc_seq *chardev; + struct esc_seq *door; + struct esc_seq *pipe; + struct esc_seq *socket; /** A mapping from color names (fi, di, ln, etc.) to struct fields. */ struct trie names; - /** A mapping from file extensions to colors. */ - struct trie ext_colors; + /** Number of extensions. */ + size_t ext_count; + /** Case-sensitive extension trie. */ + struct trie ext_trie; + /** Case-insensitive extension trie. */ + struct trie iext_trie; }; +/** Allocate an escape sequence. */ +static struct esc_seq *new_esc(struct colors *colors, const char *seq, size_t len) { + struct esc_seq *esc = varena_alloc(&colors->esc_arena, len); + if (esc) { + esc->len = len; + memcpy(esc->seq, seq, len); + } + return esc; +} + +/** Free an escape sequence. */ +static void free_esc(struct colors *colors, struct esc_seq *seq) { + varena_free(&colors->esc_arena, seq, seq->len); +} + /** Initialize a color in the table. */ -static int init_color(struct colors *colors, const char *name, const char *value, char **field) { +static int init_esc(struct colors *colors, const char *name, const char *value, struct esc_seq **field) { + struct esc_seq *esc = NULL; if (value) { - *field = dstrdup(value); - if (!*field) { + esc = new_esc(colors, value, strlen(value)); + if (!esc) { return -1; } - } else { - *field = NULL; } + *field = esc; + struct trie_leaf *leaf = trie_insert_str(&colors->names, name); if (leaf) { leaf->value = field; @@ -94,100 +147,182 @@ static int init_color(struct colors *colors, const char *name, const char *value } } -/** Get a color from the table. */ -static char **get_color(const struct colors *colors, const char *name) { +/** Get an escape sequence from the table. */ +static struct esc_seq **get_esc(const struct colors *colors, const char *name) { const struct trie_leaf *leaf = trie_find_str(&colors->names, name); - if (leaf) { - return (char **)leaf->value; - } else { - return NULL; - } + return leaf ? leaf->value : NULL; } -/** Set the value of a color. */ -static int set_color(struct colors *colors, const char *name, char *value) { - char **color = get_color(colors, name); - if (color) { - dstrfree(*color); - *color = value; +/** Set a named escape sequence. */ +static int set_esc(struct colors *colors, const char *name, char *value) { + struct esc_seq **field = get_esc(colors, name); + if (!field) { return 0; - } else { - return -1; } + + if (*field) { + free_esc(colors, *field); + *field = NULL; + } + + if (value) { + *field = new_esc(colors, value, dstrlen(value)); + if (!*field) { + return -1; + } + } + + return 0; } -/** - * Transform a file extension for fast lookups, by reversing and lowercasing it. - */ -static void extxfrm(char *ext, size_t len) { - for (size_t i = 0; i < len - i; ++i) { - char a = ext[i]; - char b = ext[len - i - 1]; +/** Reverse a string, to turn suffix matches into prefix matches. */ +static void ext_reverse(char *ext, size_t len) { + for (size_t i = 0, j = len - 1; len && i < j; ++i, --j) { + char c = ext[i]; + ext[i] = ext[j]; + ext[j] = c; + } +} + +/** Convert a string to lowercase for case-insensitive matching. */ +static void ext_tolower(char *ext, size_t len) { + for (size_t i = 0; i < len; ++i) { + char c = ext[i]; // What's internationalization? Doesn't matter, this is what // GNU ls does. Luckily, since there's no standard C way to // casefold. Not using tolower() here since it respects the // current locale, which GNU ls doesn't do. - if (a >= 'A' && a <= 'Z') { - a += 'a' - 'A'; - } - if (b >= 'A' && b <= 'Z') { - b += 'a' - 'A'; + if (c >= 'A' && c <= 'Z') { + c += 'a' - 'A'; } - ext[i] = b; - ext[len - i - 1] = a; + ext[i] = c; } } /** Maximum supported extension length. */ #define EXT_MAX 255 -/** - * Set the color for an extension. - */ -static int set_ext_color(struct colors *colors, char *key, char *value) { +/** Set the color for an extension. */ +static int set_ext(struct colors *colors, char *key, char *value) { size_t len = dstrlen(key); - if (len > EXT_MAX) { + struct ext_color *ext = varena_alloc(&colors->ext_arena, len + 1); + if (!ext) { return -1; } - extxfrm(key, len); + ext->priority = colors->ext_count++; + ext->len = len; + ext->icase = true; + ext->esc = new_esc(colors, value, dstrlen(value)); + if (!ext->esc) { + goto fail; + } + + key = memcpy(ext->ext, key, len + 1); + + // Reverse the extension (`*.y.x` -> `x.y.*`) so we can use trie_find_prefix() + ext_reverse(key, len); + + // Find any pre-existing exact match + struct ext_color *prev = NULL; + struct trie_leaf *leaf = trie_find_str(&colors->ext_trie, key); + if (leaf) { + prev = leaf->value; + trie_remove(&colors->ext_trie, leaf); + } // A later *.x should override any earlier *.x, *.y.x, etc. - struct trie_leaf *match; - while ((match = trie_find_postfix(&colors->ext_colors, key))) { - dstrfree(match->value); - trie_remove(&colors->ext_colors, match); + while ((leaf = trie_find_postfix(&colors->ext_trie, key))) { + trie_remove(&colors->ext_trie, leaf); } - struct trie_leaf *leaf = trie_insert_str(&colors->ext_colors, key); - if (leaf) { - leaf->value = value; - return 0; - } else { - return -1; + // Insert the extension into the case-sensitive trie + leaf = trie_insert_str(&colors->ext_trie, key); + if (!leaf) { + goto fail; } + leaf->value = ext; + + // "Smart case": if the same extension is given with two different + // capitalizations (e.g. `*.y.x=31:*.Y.Z=32:`), make it case-sensitive + ext_tolower(key, len); + leaf = trie_insert_str(&colors->iext_trie, key); + if (!leaf) { + goto fail; + } + + // If a match for the lowercased extension exists and is different from + // the exact match, or is already case-sensitive, mark this one too + struct ext_color *iprev = leaf->value; + if (iprev && (iprev != prev || !iprev->icase)) { + iprev->icase = false; + ext->icase = false; + } + leaf->value = ext; + + return 0; + +fail: + if (ext->esc) { + free_esc(colors, ext->esc); + } + varena_free(&colors->ext_arena, ext, len + 1); + return -1; +} + +/** Rebuild the case-insensitive trie after all extensions have been parsed. */ +static int build_iext_trie(struct colors *colors) { + trie_destroy(&colors->iext_trie); + trie_init(&colors->iext_trie); + + TRIE_FOR_EACH(&colors->ext_trie, leaf) { + struct ext_color *ext = leaf->value; + if (!ext->icase) { + continue; + } + + // set_ext() already reversed and lowercased the extension + struct trie_leaf *ileaf; + while ((ileaf = trie_find_postfix(&colors->iext_trie, ext->ext))) { + trie_remove(&colors->ext_trie, ileaf); + } + + ileaf = trie_insert_str(&colors->iext_trie, ext->ext); + if (!ileaf) { + return -1; + } + ileaf->value = ext; + } + + return 0; } /** * Find a color by an extension. */ -static const char *get_ext_color(const struct colors *colors, const char *filename) { +static const struct esc_seq *get_ext(const struct colors *colors, const char *filename) { size_t name_len = strlen(filename); size_t ext_len = name_len < EXT_MAX ? name_len : EXT_MAX; - const char *ext = filename + name_len - ext_len; + const char *suffix = filename + name_len - ext_len; char xfrm[ext_len + 1]; - memcpy(xfrm, ext, sizeof(xfrm)); - extxfrm(xfrm, ext_len); + memcpy(xfrm, suffix, sizeof(xfrm)); - const struct trie_leaf *leaf = trie_find_prefix(&colors->ext_colors, xfrm); - if (leaf) { - return leaf->value; - } else { - return NULL; + ext_reverse(xfrm, ext_len); + const struct trie_leaf *leaf = trie_find_prefix(&colors->ext_trie, xfrm); + const struct ext_color *ext = leaf ? leaf->value : NULL; + + ext_tolower(xfrm, ext_len); + const struct trie_leaf *ileaf = trie_find_prefix(&colors->iext_trie, xfrm); + const struct ext_color *iext = ileaf ? ileaf->value : NULL; + + if (iext && (!ext || ext->priority < iext->priority)) { + ext = iext; } + + return ext ? ext->esc : NULL; } /** @@ -211,6 +346,8 @@ static const char *get_ext_color(const struct colors *colors, const char *filena * * See man dir_colors. * + * @param str + * A dstring to fill with the unescaped chunk. * @param value * The value to parse. * @param end @@ -218,16 +355,18 @@ static const char *get_ext_color(const struct colors *colors, const char *filena * @param[out] next * Will be set to the next chunk. * @return - * The parsed chunk as a dstring. + * 0 on success, -1 on failure. */ -static char *unescape(const char *value, char end, const char **next) { +static int unescape(char **str, const char *value, char end, const char **next) { + *next = NULL; + if (!value) { - goto fail; + errno = EINVAL; + return -1; } - char *str = dstralloc(0); - if (!str) { - goto fail_str; + if (dstresize(str, 0) != 0) { + return -1; } const char *i; @@ -304,7 +443,8 @@ static char *unescape(const char *value, char end, const char **next) { break; case '\0': - goto fail_str; + errno = EINVAL; + return -1; default: c = *i; @@ -318,7 +458,8 @@ static char *unescape(const char *value, char end, const char **next) { c = '\177'; break; case '\0': - goto fail_str; + errno = EINVAL; + return -1; default: // CTRL masks bits 6 and 7 c = *i & 0x1F; @@ -331,77 +472,70 @@ static char *unescape(const char *value, char end, const char **next) { break; } - if (dstrapp(&str, c) != 0) { - goto fail_str; + if (dstrapp(str, c) != 0) { + return -1; } } if (*i) { *next = i + 1; - } else { - *next = NULL; } - return str; - -fail_str: - dstrfree(str); -fail: - *next = NULL; - return NULL; + return 0; } /** Parse the GNU $LS_COLORS format. */ -static void parse_gnu_ls_colors(struct colors *colors, const char *ls_colors) { +static int parse_gnu_ls_colors(struct colors *colors, const char *ls_colors) { + int ret = -1; + char *key = NULL; + char *value = NULL; + for (const char *chunk = ls_colors, *next; chunk; chunk = next) { if (chunk[0] == '*') { - char *key = unescape(chunk + 1, '=', &next); - if (!key) { - continue; + if (unescape(&key, chunk + 1, '=', &next) != 0) { + goto fail; } - - char *value = unescape(next, ':', &next); - if (value) { - if (set_ext_color(colors, key, value) != 0) { - dstrfree(value); - } + if (unescape(&value, next, ':', &next) != 0) { + goto fail; + } + if (set_ext(colors, key, value) != 0) { + goto fail; } - - dstrfree(key); } else { const char *equals = strchr(chunk, '='); if (!equals) { break; } - char *value = unescape(equals + 1, ':', &next); - if (!value) { - continue; + if (dstrncpy(&key, chunk, equals - chunk) != 0) { + goto fail; } - - char *key = strndup(chunk, equals - chunk); - if (!key) { - dstrfree(value); - continue; + if (unescape(&value, equals + 1, ':', &next) != 0) { + goto fail; } // All-zero values should be treated like NULL, to fall // back on any other relevant coloring for that file + char *esc = value; if (strspn(value, "0") == strlen(value) && strcmp(key, "rs") != 0 && strcmp(key, "lc") != 0 && strcmp(key, "rc") != 0 && strcmp(key, "ec") != 0) { - dstrfree(value); - value = NULL; + esc = NULL; } - if (set_color(colors, key, value) != 0) { - dstrfree(value); + if (set_esc(colors, key, esc) != 0) { + goto fail; } - free(key); } } + + ret = 0; +fail: + dstrfree(value); + dstrfree(key); + return ret; } struct colors *parse_colors(void) { @@ -410,91 +544,105 @@ struct colors *parse_colors(void) { return NULL; } + VARENA_INIT(&colors->esc_arena, struct esc_seq, seq); + VARENA_INIT(&colors->ext_arena, struct ext_color, ext); trie_init(&colors->names); - trie_init(&colors->ext_colors); + colors->ext_count = 0; + trie_init(&colors->ext_trie); + trie_init(&colors->iext_trie); int ret = 0; // From man console_codes - ret |= init_color(colors, "rs", "0", &colors->reset); - ret |= init_color(colors, "lc", "\033[", &colors->leftcode); - ret |= init_color(colors, "rc", "m", &colors->rightcode); - ret |= init_color(colors, "ec", NULL, &colors->endcode); - ret |= init_color(colors, "cl", "\033[K", &colors->clear_to_eol); - - ret |= init_color(colors, "bld", "01;39", &colors->bold); - ret |= init_color(colors, "gry", "01;30", &colors->gray); - ret |= init_color(colors, "red", "01;31", &colors->red); - ret |= init_color(colors, "grn", "01;32", &colors->green); - ret |= init_color(colors, "ylw", "01;33", &colors->yellow); - ret |= init_color(colors, "blu", "01;34", &colors->blue); - ret |= init_color(colors, "mag", "01;35", &colors->magenta); - ret |= init_color(colors, "cyn", "01;36", &colors->cyan); - ret |= init_color(colors, "wht", "01;37", &colors->white); - - ret |= init_color(colors, "wrn", "01;33", &colors->warning); - ret |= init_color(colors, "err", "01;31", &colors->error); + ret |= init_esc(colors, "rs", "0", &colors->reset); + ret |= init_esc(colors, "lc", "\033[", &colors->leftcode); + ret |= init_esc(colors, "rc", "m", &colors->rightcode); + ret |= init_esc(colors, "ec", NULL, &colors->endcode); + ret |= init_esc(colors, "cl", "\033[K", &colors->clear_to_eol); + + ret |= init_esc(colors, "bld", "01;39", &colors->bold); + ret |= init_esc(colors, "gry", "01;30", &colors->gray); + ret |= init_esc(colors, "red", "01;31", &colors->red); + ret |= init_esc(colors, "grn", "01;32", &colors->green); + ret |= init_esc(colors, "ylw", "01;33", &colors->yellow); + ret |= init_esc(colors, "blu", "01;34", &colors->blue); + ret |= init_esc(colors, "mag", "01;35", &colors->magenta); + ret |= init_esc(colors, "cyn", "01;36", &colors->cyan); + ret |= init_esc(colors, "wht", "01;37", &colors->white); + + ret |= init_esc(colors, "wrn", "01;33", &colors->warning); + ret |= init_esc(colors, "err", "01;31", &colors->error); // Defaults from man dir_colors // "" means fall back to ->normal - ret |= init_color(colors, "no", NULL, &colors->normal); + ret |= init_esc(colors, "no", NULL, &colors->normal); - ret |= init_color(colors, "fi", "", &colors->file); - ret |= init_color(colors, "mh", NULL, &colors->multi_hard); - ret |= init_color(colors, "ex", "01;32", &colors->executable); - ret |= init_color(colors, "ca", NULL, &colors->capable); - ret |= init_color(colors, "sg", "30;43", &colors->setgid); - ret |= init_color(colors, "su", "37;41", &colors->setuid); + ret |= init_esc(colors, "fi", "", &colors->file); + ret |= init_esc(colors, "mh", NULL, &colors->multi_hard); + ret |= init_esc(colors, "ex", "01;32", &colors->executable); + ret |= init_esc(colors, "ca", NULL, &colors->capable); + ret |= init_esc(colors, "sg", "30;43", &colors->setgid); + ret |= init_esc(colors, "su", "37;41", &colors->setuid); - ret |= init_color(colors, "di", "01;34", &colors->directory); - ret |= init_color(colors, "st", "37;44", &colors->sticky); - ret |= init_color(colors, "ow", "34;42", &colors->other_writable); - ret |= init_color(colors, "tw", "30;42", &colors->sticky_other_writable); + ret |= init_esc(colors, "di", "01;34", &colors->directory); + ret |= init_esc(colors, "st", "37;44", &colors->sticky); + ret |= init_esc(colors, "ow", "34;42", &colors->other_writable); + ret |= init_esc(colors, "tw", "30;42", &colors->sticky_other_writable); - ret |= init_color(colors, "ln", "01;36", &colors->link); - ret |= init_color(colors, "or", NULL, &colors->orphan); - ret |= init_color(colors, "mi", NULL, &colors->missing); + ret |= init_esc(colors, "ln", "01;36", &colors->link); + ret |= init_esc(colors, "or", NULL, &colors->orphan); + ret |= init_esc(colors, "mi", NULL, &colors->missing); colors->link_as_target = false; - ret |= init_color(colors, "bd", "01;33", &colors->blockdev); - ret |= init_color(colors, "cd", "01;33", &colors->chardev); - ret |= init_color(colors, "do", "01;35", &colors->door); - ret |= init_color(colors, "pi", "33", &colors->pipe); - ret |= init_color(colors, "so", "01;35", &colors->socket); + ret |= init_esc(colors, "bd", "01;33", &colors->blockdev); + ret |= init_esc(colors, "cd", "01;33", &colors->chardev); + ret |= init_esc(colors, "do", "01;35", &colors->door); + ret |= init_esc(colors, "pi", "33", &colors->pipe); + ret |= init_esc(colors, "so", "01;35", &colors->socket); - if (ret) { - free_colors(colors); - return NULL; + if (ret != 0) { + goto fail; } - parse_gnu_ls_colors(colors, getenv("LS_COLORS")); - parse_gnu_ls_colors(colors, getenv("BFS_COLORS")); + if (parse_gnu_ls_colors(colors, getenv("LS_COLORS")) != 0) { + goto fail; + } + if (parse_gnu_ls_colors(colors, getenv("BFS_COLORS")) != 0) { + goto fail; + } + if (build_iext_trie(colors) != 0) { + goto fail; + } - if (colors->link && strcmp(colors->link, "target") == 0) { - colors->link_as_target = true; - dstresize(&colors->link, 0); + if (colors->link) { + size_t len = strlen("target"); + if (colors->link->len == len && memcmp(colors->link->seq, "target", len) == 0) { + colors->link_as_target = true; + colors->link->len = 0; + } } return colors; + +fail: + free_colors(colors); + return NULL; } void free_colors(struct colors *colors) { - if (colors) { - TRIE_FOR_EACH(&colors->ext_colors, leaf) { - dstrfree(leaf->value); - } - trie_destroy(&colors->ext_colors); + if (!colors) { + return; + } - TRIE_FOR_EACH(&colors->names, leaf) { - char **field = leaf->value; - dstrfree(*field); - } - trie_destroy(&colors->names); + trie_destroy(&colors->iext_trie); + trie_destroy(&colors->ext_trie); + trie_destroy(&colors->names); + varena_destroy(&colors->ext_arena); + varena_destroy(&colors->esc_arena); - free(colors); - } + free(colors); } CFILE *cfwrap(FILE *file, const struct colors *colors, bool close) { @@ -547,14 +695,14 @@ static bool is_link_broken(const struct BFTW *ftwbuf) { } /** Get the color for a file. */ -static const char *file_color(const struct colors *colors, const char *filename, const struct BFTW *ftwbuf, enum bfs_stat_flags flags) { +static const struct esc_seq *file_color(const struct colors *colors, const char *filename, const struct BFTW *ftwbuf, enum bfs_stat_flags flags) { enum bfs_type type = bftw_type(ftwbuf, flags); if (type == BFS_ERROR) { goto error; } const struct bfs_stat *statbuf = NULL; - const char *color = NULL; + const struct esc_seq *color = NULL; switch (type) { case BFS_REG: @@ -578,7 +726,7 @@ static const char *file_color(const struct colors *colors, const char *filename, } if (!color) { - color = get_ext_color(colors, filename); + color = get_ext(colors, filename); } if (!color) { @@ -635,7 +783,7 @@ static const char *file_color(const struct colors *colors, const char *filename, break; } - if (color && !color[0]) { + if (color && color->len == 0) { color = colors->normal; } @@ -649,17 +797,22 @@ error: } } +/** Print an escape sequence chunk. */ +static int print_esc_chunk(CFILE *cfile, const struct esc_seq *esc) { + return dstrxcat(&cfile->buffer, esc->seq, esc->len); +} + /** Print an ANSI escape sequence. */ -static int print_esc(CFILE *cfile, const char *esc) { +static int print_esc(CFILE *cfile, const struct esc_seq *esc) { const struct colors *colors = cfile->colors; - if (dstrdcat(&cfile->buffer, colors->leftcode) != 0) { + if (print_esc_chunk(cfile, colors->leftcode) != 0) { return -1; } - if (dstrdcat(&cfile->buffer, esc) != 0) { + if (print_esc_chunk(cfile, esc) != 0) { return -1; } - if (dstrdcat(&cfile->buffer, colors->rightcode) != 0) { + if (print_esc_chunk(cfile, colors->rightcode) != 0) { return -1; } @@ -671,20 +824,20 @@ static int print_reset(CFILE *cfile) { const struct colors *colors = cfile->colors; if (colors->endcode) { - return dstrdcat(&cfile->buffer, colors->endcode); + return dstrxcat(&cfile->buffer, colors->endcode->seq, colors->endcode->len); } else { return print_esc(cfile, colors->reset); } } /** Print a string with an optional color. */ -static int print_colored(CFILE *cfile, const char *esc, const char *str, size_t len) { +static int print_colored(CFILE *cfile, const struct esc_seq *esc, const char *str, size_t len) { if (esc) { if (print_esc(cfile, esc) != 0) { return -1; } } - if (dstrncat(&cfile->buffer, str, len) != 0) { + if (dstrxcat(&cfile->buffer, str, len) != 0) { return -1; } if (esc) { @@ -772,7 +925,7 @@ static int print_dirs_colored(CFILE *cfile, const char *path, const struct BFTW } if ((size_t)broken < nameoff) { - const char *color = colors->missing; + const struct esc_seq *color = colors->missing; if (!color) { color = colors->orphan; } @@ -786,8 +939,8 @@ static int print_dirs_colored(CFILE *cfile, const char *path, const struct BFTW /** Print a file name with colors. */ static int print_name_colored(CFILE *cfile, const char *name, const struct BFTW *ftwbuf, enum bfs_stat_flags flags) { - const char *color = file_color(cfile->colors, name, ftwbuf, flags); - return print_colored(cfile, color, name, strlen(name)); + const struct esc_seq *esc = file_color(cfile->colors, name, ftwbuf, flags); + return print_colored(cfile, esc, name, strlen(name)); } /** Print a path with colors. */ @@ -1077,7 +1230,7 @@ static int cvbuff(CFILE *cfile, const char *format, va_list args) { memcpy(name, i, len); name[len] = '\0'; - char **esc = get_color(colors, name); + struct esc_seq **esc = get_esc(colors, name); if (!esc) { goto invalid; } diff --git a/tests/bfs/color_ext_case.out b/tests/bfs/color_ext_case.out new file mode 100644 index 0000000..c3ded3a --- /dev/null +++ b/tests/bfs/color_ext_case.out @@ -0,0 +1,25 @@ +rainbow +rainbow/lower.gz +rainbow/lower.tar.gz +rainbow/exec.sh +rainbow/upper.GZ +rainbow/upper.TAR.GZ +rainbow/lower.tar +rainbow/upper.TAR +rainbow/ul.TAR.gz +rainbow/lu.tar.GZ +rainbow/socket +rainbow/broken +rainbow/chardev_link +rainbow/link.txt +rainbow/sticky_ow +rainbow/sgid +rainbow/pipe +rainbow/ow +rainbow/sugid +rainbow/suid +rainbow/sticky +rainbow/file.dat +rainbow/file.txt +rainbow/mh1 +rainbow/mh2 diff --git a/tests/bfs/color_ext_case.sh b/tests/bfs/color_ext_case.sh new file mode 100644 index 0000000..91f1f59 --- /dev/null +++ b/tests/bfs/color_ext_case.sh @@ -0,0 +1 @@ +LS_COLORS="*.gz=01;31:*.GZ=01;32:*.tAr=01;33:*.TAR.gz=01;34:*.tar.GZ=01;35:" bfs_diff rainbow -color diff --git a/tests/bfs/color_nul.out b/tests/bfs/color_nul.out index c328f82..4ea4d85 100644 Binary files a/tests/bfs/color_nul.out and b/tests/bfs/color_nul.out differ diff --git a/tests/bfs/color_nul.sh b/tests/bfs/color_nul.sh index 4979569..cb662d6 100644 --- a/tests/bfs/color_nul.sh +++ b/tests/bfs/color_nul.sh @@ -1,2 +1,3 @@ -LS_COLORS="ec=\33[m\0:" invoke_bfs rainbow -color -maxdepth 0 >"$OUT" +LS_COLORS="ec=\33[\0m:*.gz=\0\61;31:" invoke_bfs rainbow -color | tr '\0' '0' >"$OUT" +sort_output diff_output diff --git a/tests/bfs/color_star.out b/tests/bfs/color_star.out deleted file mode 100644 index 34c7153..0000000 --- a/tests/bfs/color_star.out +++ /dev/null @@ -1,25 +0,0 @@ -rainbow -rainbow/exec.sh -rainbow/socket -rainbow/broken -rainbow/chardev_link -rainbow/link.txt -rainbow/sticky_ow -rainbow/sgid -rainbow/pipe -rainbow/ow -rainbow/sugid -rainbow/suid -rainbow/sticky -rainbow/file.dat -rainbow/file.txt -rainbow/lower.gz -rainbow/lower.tar -rainbow/lower.tar.gz -rainbow/lu.tar.GZ -rainbow/mh1 -rainbow/mh2 -rainbow/ul.TAR.gz -rainbow/upper.GZ -rainbow/upper.TAR -rainbow/upper.TAR.GZ diff --git a/tests/bfs/color_star.sh b/tests/bfs/color_star.sh index 3ada4fd..6d5312e 100644 --- a/tests/bfs/color_star.sh +++ b/tests/bfs/color_star.sh @@ -1,2 +1,2 @@ # Regression test: don't segfault on LS_COLORS="*" -LS_COLORS="*" bfs_diff rainbow -color +! LS_COLORS="*" invoke_bfs rainbow -color -- cgit v1.2.3 From 2ea6a1d7b99dbb389ec81054d136e5030717d52a Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Fri, 30 Jun 2023 10:25:42 -0400 Subject: color: Compare values too when deciding to smart-case --- src/color.c | 81 +++++++++++++++++++++++++++++++++++--------- tests/bfs/color_ext_case.out | 2 +- tests/bfs/color_ext_case.sh | 7 +++- 3 files changed, 72 insertions(+), 18 deletions(-) (limited to 'src/color.c') diff --git a/src/color.c b/src/color.c index 82ff763..ec24d98 100644 --- a/src/color.c +++ b/src/color.c @@ -42,8 +42,8 @@ struct ext_color { struct esc_seq *esc; /** The length of the extension to match. */ size_t len; - /** Whether the comparison should be case-insensitive. */ - bool icase; + /** Whether the comparison should be case-sensitive. */ + bool case_sensitive; /** The extension to match (NUL-terminated). */ char ext[]; }; @@ -147,6 +147,11 @@ static int init_esc(struct colors *colors, const char *name, const char *value, } } +/** Check if an escape sequence is equal to a string. */ +static bool esc_eq(const struct esc_seq *esc, const char *str, size_t len) { + return esc->len == len && memcmp(esc->seq, str, len) == 0; +} + /** Get an escape sequence from the table. */ static struct esc_seq **get_esc(const struct colors *colors, const char *name) { const struct trie_leaf *leaf = trie_find_str(&colors->names, name); @@ -204,6 +209,55 @@ static void ext_tolower(char *ext, size_t len) { /** Maximum supported extension length. */ #define EXT_MAX 255 +/** + * The "smart case" algorithm. + * + * @param ext + * The current extension being added. + * @param prev + * The previous case-sensitive match, if any, for the same extension. + * @param iprev + * The previous case-insensitive match, if any, for the same extension. + * @return + * Whether this extension should become case-sensitive. + */ +static bool ext_case_sensitive(struct ext_color *ext, struct ext_color *prev, struct ext_color *iprev) { + // This is the first case-insensitive occurrence of this extension, e.g. + // + // *.gz=01;31:*.tar.gz=01;33 + if (!iprev) { + bfs_assert(!prev); + return false; + } + + // If the last version of this extension is already case-sensitive, + // this one should be too, e.g. + // + // *.tar.gz=01;31:*.TAR.GZ=01;32:*.TAR.GZ=01;33 + if (iprev->case_sensitive) { + return true; + } + + // The case matches the last occurrence exactly, e.g. + // + // *.tar.gz=01;31:*.tar.gz=01;33 + if (iprev == prev) { + return false; + } + + // Different case, but same value, e.g. + // + // *.tar.gz=01;31:*.TAR.GZ=01;31 + if (esc_eq(iprev->esc, ext->esc->seq, ext->esc->len)) { + return false; + } + + // Different case, different value, e.g. + // + // *.tar.gz=01;31:*.TAR.GZ=01;33 + return true; +} + /** Set the color for an extension. */ static int set_ext(struct colors *colors, char *key, char *value) { size_t len = dstrlen(key); @@ -214,7 +268,7 @@ static int set_ext(struct colors *colors, char *key, char *value) { ext->priority = colors->ext_count++; ext->len = len; - ext->icase = true; + ext->case_sensitive = false; ext->esc = new_esc(colors, value, dstrlen(value)); if (!ext->esc) { goto fail; @@ -253,12 +307,10 @@ static int set_ext(struct colors *colors, char *key, char *value) { goto fail; } - // If a match for the lowercased extension exists and is different from - // the exact match, or is already case-sensitive, mark this one too struct ext_color *iprev = leaf->value; - if (iprev && (iprev != prev || !iprev->icase)) { - iprev->icase = false; - ext->icase = false; + if (ext_case_sensitive(ext, prev, iprev)) { + iprev->case_sensitive = true; + ext->case_sensitive = true; } leaf->value = ext; @@ -279,14 +331,14 @@ static int build_iext_trie(struct colors *colors) { TRIE_FOR_EACH(&colors->ext_trie, leaf) { struct ext_color *ext = leaf->value; - if (!ext->icase) { + if (ext->case_sensitive) { continue; } // set_ext() already reversed and lowercased the extension struct trie_leaf *ileaf; while ((ileaf = trie_find_postfix(&colors->iext_trie, ext->ext))) { - trie_remove(&colors->ext_trie, ileaf); + trie_remove(&colors->iext_trie, ileaf); } ileaf = trie_insert_str(&colors->iext_trie, ext->ext); @@ -616,12 +668,9 @@ struct colors *parse_colors(void) { goto fail; } - if (colors->link) { - size_t len = strlen("target"); - if (colors->link->len == len && memcmp(colors->link->seq, "target", len) == 0) { - colors->link_as_target = true; - colors->link->len = 0; - } + if (colors->link && esc_eq(colors->link, "target", strlen("target"))) { + colors->link_as_target = true; + colors->link->len = 0; } return colors; diff --git a/tests/bfs/color_ext_case.out b/tests/bfs/color_ext_case.out index c3ded3a..4e7258d 100644 --- a/tests/bfs/color_ext_case.out +++ b/tests/bfs/color_ext_case.out @@ -16,10 +16,10 @@ rainbow/sgid rainbow/pipe rainbow/ow +rainbow/file.txt rainbow/sugid rainbow/suid rainbow/sticky rainbow/file.dat -rainbow/file.txt rainbow/mh1 rainbow/mh2 diff --git a/tests/bfs/color_ext_case.sh b/tests/bfs/color_ext_case.sh index 91f1f59..4adba69 100644 --- a/tests/bfs/color_ext_case.sh +++ b/tests/bfs/color_ext_case.sh @@ -1 +1,6 @@ -LS_COLORS="*.gz=01;31:*.GZ=01;32:*.tAr=01;33:*.TAR.gz=01;34:*.tar.GZ=01;35:" bfs_diff rainbow -color +# *.gz=01;31:*.GZ=01;32 -- case sensitive +# *.tAr=01;33:*.TaR=01;33 -- case-insensitive +# *.TAR.gz=01;34:*.tar.GZ=01;35 -- case-sensitive +# *.txt=35:*TXT=36 -- case-insensitive +export LS_COLORS="*.gz=01;31:*.GZ=01;32:*.tAr=01;33:*.TaR=01;33:*.TAR.gz=01;34:*.tar.GZ=01;35:*.txt=35:*TXT=36" +bfs_diff rainbow -color -- cgit v1.2.3 From 1864ca8d8e9e93beb3593b316e447c6d817ddfd9 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Fri, 30 Jun 2023 11:46:22 -0400 Subject: color: Don't print unnecessary reset sequences --- src/color.c | 67 +++++++++++++++++++++++++++++++++++++++---------------------- src/color.h | 2 ++ 2 files changed, 45 insertions(+), 24 deletions(-) (limited to 'src/color.c') diff --git a/src/color.c b/src/color.c index ec24d98..ec14303 100644 --- a/src/color.c +++ b/src/color.c @@ -707,6 +707,7 @@ CFILE *cfwrap(FILE *file, const struct colors *colors, bool close) { } cfile->file = file; + cfile->need_reset = false; cfile->close = close; if (isatty(fileno(file))) { @@ -853,15 +854,22 @@ static int print_esc_chunk(CFILE *cfile, const struct esc_seq *esc) { /** Print an ANSI escape sequence. */ static int print_esc(CFILE *cfile, const struct esc_seq *esc) { + if (!esc) { + return 0; + } + const struct colors *colors = cfile->colors; + if (esc != colors->reset) { + cfile->need_reset = true; + } - if (print_esc_chunk(cfile, colors->leftcode) != 0) { + if (print_esc_chunk(cfile, cfile->colors->leftcode) != 0) { return -1; } if (print_esc_chunk(cfile, esc) != 0) { return -1; } - if (print_esc_chunk(cfile, colors->rightcode) != 0) { + if (print_esc_chunk(cfile, cfile->colors->rightcode) != 0) { return -1; } @@ -870,10 +878,14 @@ static int print_esc(CFILE *cfile, const struct esc_seq *esc) { /** Reset after an ANSI escape sequence. */ static int print_reset(CFILE *cfile) { - const struct colors *colors = cfile->colors; + if (!cfile->need_reset) { + return 0; + } + cfile->need_reset = false; + const struct colors *colors = cfile->colors; if (colors->endcode) { - return dstrxcat(&cfile->buffer, colors->endcode->seq, colors->endcode->len); + return print_esc_chunk(cfile, colors->endcode); } else { return print_esc(cfile, colors->reset); } @@ -881,18 +893,14 @@ static int print_reset(CFILE *cfile) { /** Print a string with an optional color. */ static int print_colored(CFILE *cfile, const struct esc_seq *esc, const char *str, size_t len) { - if (esc) { - if (print_esc(cfile, esc) != 0) { - return -1; - } + if (print_esc(cfile, esc) != 0) { + return -1; } if (dstrxcat(&cfile->buffer, str, len) != 0) { return -1; } - if (esc) { - if (print_reset(cfile) != 0) { - return -1; - } + if (print_reset(cfile) != 0) { + return -1; } return 0; @@ -1151,13 +1159,19 @@ static int cvbuff(CFILE *cfile, const char *format, va_list args) { const struct colors *colors = cfile->colors; int error = errno; + // Color specifier (e.g. ${blu}) state + struct esc_seq **esc; + const char *end; + size_t len; + char name[4]; + for (const char *i = format; *i; ++i) { size_t verbatim = strcspn(i, "%$"); if (dstrncat(&cfile->buffer, i, verbatim) != 0) { return -1; } - i += verbatim; + switch (*i) { case '%': switch (*++i) { @@ -1263,9 +1277,9 @@ static int cvbuff(CFILE *cfile, const char *format, va_list args) { } break; - case '{': { + case '{': ++i; - const char *end = strchr(i, '}'); + end = strchr(i, '}'); if (!end) { goto invalid; } @@ -1274,16 +1288,22 @@ static int cvbuff(CFILE *cfile, const char *format, va_list args) { break; } - size_t len = end - i; - char name[len + 1]; + len = end - i; + if (len >= sizeof(name)) { + goto invalid; + } memcpy(name, i, len); name[len] = '\0'; - struct esc_seq **esc = get_esc(colors, name); - if (!esc) { - goto invalid; - } - if (*esc) { + if (strcmp(name, "rs") == 0) { + if (print_reset(cfile) != 0) { + return -1; + } + } else { + esc = get_esc(colors, name); + if (!esc) { + goto invalid; + } if (print_esc(cfile, *esc) != 0) { return -1; } @@ -1291,7 +1311,6 @@ static int cvbuff(CFILE *cfile, const char *format, va_list args) { i = end; break; - } default: goto invalid; @@ -1306,7 +1325,7 @@ static int cvbuff(CFILE *cfile, const char *format, va_list args) { return 0; invalid: - bfs_bug("Invalid format string"); + bfs_bug("Invalid format string '%s'", format); errno = EINVAL; return -1; } diff --git a/src/color.h b/src/color.h index aca6a34..932d551 100644 --- a/src/color.h +++ b/src/color.h @@ -42,6 +42,8 @@ typedef struct CFILE { const struct colors *colors; /** A buffer for colored formatting. */ char *buffer; + /** Whether the next ${rs} is actually necessary. */ + bool need_reset; /** Whether to close the underlying stream. */ bool close; } CFILE; -- cgit v1.2.3 From 66264f1518d1e19123cca23ec92eace4c7982731 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 6 Jul 2023 08:59:37 -0400 Subject: diag: Shell-escape expression arguments --- src/color.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/color.c') diff --git a/src/color.c b/src/color.c index ec14303..2e039f4 100644 --- a/src/color.c +++ b/src/color.c @@ -1102,17 +1102,17 @@ static int print_expr(CFILE *cfile, const struct bfs_expr *expr, bool verbose) { lhs = expr->lhs; rhs = expr->rhs; - if (cbuff(cfile, "${red}%s${rs}", expr->argv[0]) < 0) { + if (cbuff(cfile, "${red}%pq${rs}", expr->argv[0]) < 0) { return -1; } } else { - if (cbuff(cfile, "${blu}%s${rs}", expr->argv[0]) < 0) { + if (cbuff(cfile, "${blu}%pq${rs}", expr->argv[0]) < 0) { return -1; } } for (size_t i = 1; i < expr->argc; ++i) { - if (cbuff(cfile, " ${bld}%s${rs}", expr->argv[i]) < 0) { + if (cbuff(cfile, " ${bld}%pq${rs}", expr->argv[i]) < 0) { return -1; } } -- cgit v1.2.3 From 2c396fce53100cad4e472f29851f07030a80ee50 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 13 Jul 2023 13:30:16 -0400 Subject: bfstd: Support wordesc() without allocating --- src/bfstd.c | 92 +++++++++++++++++++++++++++++++++++------------------------ src/bfstd.h | 47 +++++++++++++++++++++++++++--- src/color.c | 20 +++++-------- src/diag.c | 29 ++++++++++--------- src/diag.h | 4 +-- src/dstring.c | 22 ++++++++++++++ src/dstring.h | 31 ++++++++++++++++++++ 7 files changed, 175 insertions(+), 70 deletions(-) (limited to 'src/color.c') diff --git a/src/bfstd.c b/src/bfstd.c index 6f39f54..97fa3b3 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -575,7 +576,7 @@ size_t xstrwidth(const char *str) { } /** Get the length of the longest printable prefix of a string. */ -static size_t printable_len(const char *str, size_t len) { +static size_t printable_len(const char *str, size_t len, enum wesc_flags flags) { mbstate_t mb; memset(&mb, 0, sizeof(mb)); @@ -583,9 +584,23 @@ static size_t printable_len(const char *str, size_t len) { while (len > 0) { wchar_t wc; size_t mblen = mbrtowc(&wc, cur, len, &mb); - if (mblen == (size_t)-1 || mblen == (size_t)-2 || !iswprint(wc)) { + if (mblen == (size_t)-1 || mblen == (size_t)-2) { break; } + + bool safe = iswprint(wc); + + // Technically a literal newline is safe inside single quotes, + // but $'\n' is much nicer than ' + // ' + if (!(flags & WESC_SHELL) && iswspace(wc)) { + safe = true; + } + + if (!safe) { + break; + } + cur += mblen; len -= mblen; } @@ -623,13 +638,13 @@ static const char *dollar_esc(char c) { } /** $'Quote' a string for the shell. */ -static char *dollar_quote(char *dest, char *end, const char *str, size_t len) { +static char *dollar_quote(char *dest, char *end, const char *str, size_t len, enum wesc_flags flags) { static const char *hex[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"}; dest = xstpecpy(dest, end, "$'"); while (len > 0) { - size_t plen = printable_len(str, len); + size_t plen = printable_len(str, len, flags); size_t elen = strcspn(str, "'\\"); size_t min = plen < elen ? plen : elen; dest = xstpencpy(dest, end, str, min); @@ -657,85 +672,86 @@ static char *dollar_quote(char *dest, char *end, const char *str, size_t len) { } /** How much of this string is safe as a bare word? */ -static size_t bare_len(const char *str) { +static size_t bare_len(const char *str, size_t len) { // https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_02 - return strcspn(str, "|&;<>()$`\\\"' *?[#˜=%!"); + size_t ret = strcspn(str, "|&;<>()$`\\\"' *?[#˜=%!"); + return ret < len ? ret : len; } /** How much of this string is safe to double-quote? */ -static size_t quotable_len(const char *str) { +static size_t quotable_len(const char *str, size_t len) { // https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_02_03 - return strcspn(str, "`$\\\"!"); + size_t ret = strcspn(str, "`$\\\"!"); + return ret < len ? ret : len; } /** "Quote" a string for the shell. */ -static char *double_quote(char *dest, char *end, const char *str) { +static char *double_quote(char *dest, char *end, const char *str, size_t len) { dest = xstpecpy(dest, end, "\""); - dest = xstpecpy(dest, end, str); + dest = xstpencpy(dest, end, str, len); return xstpecpy(dest, end, "\""); } /** 'Quote' a string for the shell. */ -static char *single_quote(char *dest, char *end, const char *str) { +static char *single_quote(char *dest, char *end, const char *str, size_t len) { bool open = false; - while (*str) { - size_t len = strcspn(str, "'"); - if (len > 0) { + while (len > 0) { + size_t chunk = strcspn(str, "'"); + chunk = chunk < len ? chunk : len; + if (chunk > 0) { if (!open) { dest = xstpecpy(dest, end, "'"); open = true; } - dest = xstpencpy(dest, end, str, len); - str += len; + dest = xstpencpy(dest, end, str, chunk); + str += chunk; + len -= chunk; } - while (*str == '\'') { + while (len > 0 && *str == '\'') { if (open) { dest = xstpecpy(dest, end, "'"); open = false; } dest = xstpecpy(dest, end, "\\'"); ++str; + --len; } } if (open) { dest = xstpecpy(dest, end, "'"); } + return dest; } -char *wordesc(const char *str) { - size_t len = strlen(str); +char *wordesc(char *dest, char *end, const char *str, enum wesc_flags flags) { + return wordnesc(dest, end, str, SIZE_MAX, flags); +} - // Worst case: every char is replaced with $'\xXX', so at most a 7x growth - size_t max_size = 7 * len + 3; - char *ret = malloc(max_size); - if (!ret) { - return NULL; - } - char *cur = ret; - char *end = ret + max_size; +char *wordnesc(char *dest, char *end, const char *str, size_t n, enum wesc_flags flags) { + size_t len = strnlen(str, n); + char *start = dest; - if (printable_len(str, len) < len) { + if (printable_len(str, len, flags) < len) { // String contains unprintable chars, use $'this\x7Fsyntax' - cur = dollar_quote(cur, end, str, len); - } else if (bare_len(str) == len) { + dest = dollar_quote(dest, end, str, len, flags); + } else if (!(flags & WESC_SHELL) || bare_len(str, len) == len) { // Whole string is safe as a bare word - cur = xstpecpy(cur, end, str); - } else if (quotable_len(str) == len) { + dest = xstpencpy(dest, end, str, len); + } else if (quotable_len(str, len) == len) { // Whole string is safe to double-quote - cur = double_quote(cur, end, str); + dest = double_quote(dest, end, str, len); } else { // Single-quote the whole string - cur = single_quote(cur, end, str); + dest = single_quote(dest, end, str, len); } - if (cur == ret) { - cur = xstpecpy(cur, end, "\"\""); + if (dest == start) { + dest = xstpecpy(dest, end, "\"\""); } - bfs_assert(cur != end, "Result truncated!"); - return ret; + return dest; } diff --git a/src/bfstd.h b/src/bfstd.h index 832db66..fb77399 100644 --- a/src/bfstd.h +++ b/src/bfstd.h @@ -319,15 +319,54 @@ size_t xstrwidth(const char *str); // #include +/** + * Flags for wordesc(). + */ +enum wesc_flags { + /** + * Escape special characters so that the shell will treat the escaped + * string as a single word. + */ + WESC_SHELL = 1 << 0, + /** + * Escape special characters so that the escaped string is safe to print + * to a TTY. + */ + WESC_TTY = 1 << 1, +}; + /** * Escape a string as a single shell word. * - * @param str + * @param dest + * The destination string to fill. + * @param end + * The end of the destination buffer. + * @param src + * The string to escape. + * @param flags + * Controls which characters to escape. + * @return + * The new NUL terminator of the destination, or `end` on truncation. + */ +char *wordesc(char *dest, char *end, const char *str, enum wesc_flags flags); + +/** + * Escape a string as a single shell word. + * + * @param dest + * The destination string to fill. + * @param end + * The end of the destination buffer. + * @param src * The string to escape. + * @param n + * The maximum length of the string. + * @param flags + * Controls which characters to escape. * @return - * A string that a shell would evaluate to str, dynamically allocated, - * or NULL on failure. + * The new NUL terminator of the destination, or `end` on truncation. */ -char *wordesc(const char *str); +char *wordnesc(char *dest, char *end, const char *str, size_t n, enum wesc_flags flags); #endif // BFS_BFSTD_H diff --git a/src/color.c b/src/color.c index 2e039f4..0f5829f 100644 --- a/src/color.c +++ b/src/color.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -891,6 +892,11 @@ static int print_reset(CFILE *cfile) { } } +/** Print a shell-escaped string. */ +static int print_wordesc(CFILE *cfile, const char *str, size_t n, enum wesc_flags flags) { + return dstrnescat(&cfile->buffer, str, n, flags); +} + /** Print a string with an optional color. */ static int print_colored(CFILE *cfile, const struct esc_seq *esc, const char *str, size_t len) { if (print_esc(cfile, esc) != 0) { @@ -1069,18 +1075,6 @@ static int print_link_target(CFILE *cfile, const struct BFTW *ftwbuf) { return ret; } -/** Print an shell-escaped string. */ -static int print_wordesc(CFILE *cfile, const char *str) { - char *esc = wordesc(str); - if (!esc) { - return -1; - } - - int ret = dstrcat(&cfile->buffer, esc); - free(esc); - return ret; -} - /** Format some colored output to the buffer. */ BFS_FORMATTER(2, 3) static int cbuff(CFILE *cfile, const char *format, ...); @@ -1224,7 +1218,7 @@ static int cvbuff(CFILE *cfile, const char *format, va_list args) { case 'p': switch (*++i) { case 'q': - if (print_wordesc(cfile, va_arg(args, const char *)) != 0) { + if (print_wordesc(cfile, va_arg(args, const char *), SIZE_MAX, WESC_SHELL | WESC_TTY) != 0) { return -1; } break; diff --git a/src/diag.c b/src/diag.c index acea9ad..0590847 100644 --- a/src/diag.c +++ b/src/diag.c @@ -2,6 +2,7 @@ // SPDX-License-Identifier: 0BSD #include "diag.h" +#include "alloc.h" #include "bfstd.h" #include "ctx.h" #include "color.h" @@ -114,7 +115,7 @@ bool bfs_debug_prefix(const struct bfs_ctx *ctx, enum debug_flags flag) { } /** Recursive part of highlight_expr(). */ -static bool highlight_expr_recursive(const struct bfs_ctx *ctx, const struct bfs_expr *expr, bool *args) { +static bool highlight_expr_recursive(const struct bfs_ctx *ctx, const struct bfs_expr *expr, bool args[]) { if (!expr) { return false; } @@ -141,7 +142,7 @@ static bool highlight_expr_recursive(const struct bfs_ctx *ctx, const struct bfs } /** Highlight an expression in the command line. */ -static bool highlight_expr(const struct bfs_ctx *ctx, const struct bfs_expr *expr, bool *args) { +static bool highlight_expr(const struct bfs_ctx *ctx, const struct bfs_expr *expr, bool args[]) { for (size_t i = 0; i < ctx->argc; ++i) { args[i] = false; } @@ -150,21 +151,21 @@ static bool highlight_expr(const struct bfs_ctx *ctx, const struct bfs_expr *exp } /** Print a highlighted portion of the command line. */ -static void bfs_argv_diag(const struct bfs_ctx *ctx, const bool *args, bool warning) { +static void bfs_argv_diag(const struct bfs_ctx *ctx, const bool args[], bool warning) { if (warning) { bfs_warning_prefix(ctx); } else { bfs_error_prefix(ctx); } - char *argv[ctx->argc]; + char **argv = ZALLOC_ARRAY(char *, ctx->argc); + if (!argv) { + return; + } + for (size_t i = 0; i < ctx->argc; ++i) { - argv[i] = wordesc(ctx->argv[i]); - if (!argv[i]) { - for (size_t j = 0; j < i; ++j) { - free(argv[j]); - } - return; + if (dstrescat(&argv[i], ctx->argv[i], WESC_SHELL | WESC_TTY) != 0) { + goto done; } } @@ -223,12 +224,14 @@ static void bfs_argv_diag(const struct bfs_ctx *ctx, const bool *args, bool warn cfprintf(ctx->cerr, "\n"); +done: for (size_t i = 0; i < ctx->argc; ++i) { - free(argv[i]); + dstrfree(argv[i]); } + free(argv); } -void bfs_argv_error(const struct bfs_ctx *ctx, const bool *args) { +void bfs_argv_error(const struct bfs_ctx *ctx, const bool args[]) { bfs_argv_diag(ctx, args, false); } @@ -239,7 +242,7 @@ void bfs_expr_error(const struct bfs_ctx *ctx, const struct bfs_expr *expr) { } } -bool bfs_argv_warning(const struct bfs_ctx *ctx, const bool *args) { +bool bfs_argv_warning(const struct bfs_ctx *ctx, const bool args[]) { if (!ctx->warn) { return false; } diff --git a/src/diag.h b/src/diag.h index c909da5..e019db0 100644 --- a/src/diag.h +++ b/src/diag.h @@ -149,7 +149,7 @@ bool bfs_debug_prefix(const struct bfs_ctx *ctx, enum debug_flags flag); /** * Highlight parts of the command line in an error message. */ -void bfs_argv_error(const struct bfs_ctx *ctx, const bool *args); +void bfs_argv_error(const struct bfs_ctx *ctx, const bool args[]); /** * Highlight parts of an expression in an error message. @@ -159,7 +159,7 @@ void bfs_expr_error(const struct bfs_ctx *ctx, const struct bfs_expr *expr); /** * Highlight parts of the command line in a warning message. */ -bool bfs_argv_warning(const struct bfs_ctx *ctx, const bool *args); +bool bfs_argv_warning(const struct bfs_ctx *ctx, const bool args[]); /** * Highlight parts of an expression in a warning message. diff --git a/src/dstring.c b/src/dstring.c index dada70b..60a7df9 100644 --- a/src/dstring.c +++ b/src/dstring.c @@ -232,6 +232,28 @@ fail: return -1; } +int dstrescat(char **dest, const char *str, enum wesc_flags flags) { + return dstrnescat(dest, str, SIZE_MAX, flags); +} + +int dstrnescat(char **dest, const char *str, size_t n, enum wesc_flags flags) { + size_t len = *dest ? dstrlen(*dest) : 0; + + // Worst case growth is `ccc...` => $'\xCC\xCC\xCC...' + n = strnlen(str, n); + size_t cap = len + 4 * n + 3; + if (dstreserve(dest, cap) != 0) { + return -1; + } + + char *cur = *dest + len; + char *end = *dest + cap + 1; + cur = wordnesc(cur, end, str, n, flags); + bfs_assert(cur != end, "wordesc() result truncated"); + + return dstresize(dest, cur - *dest); +} + void dstrfree(char *dstr) { if (dstr) { free(dstrheader(dstr)); diff --git a/src/dstring.h b/src/dstring.h index 2673f1b..88ca79f 100644 --- a/src/dstring.h +++ b/src/dstring.h @@ -8,6 +8,7 @@ #ifndef BFS_DSTRING_H #define BFS_DSTRING_H +#include "bfstd.h" #include "config.h" #include #include @@ -261,6 +262,36 @@ int dstrcatf(char **str, const char *format, ...); BFS_FORMATTER(2, 0) int dstrvcatf(char **str, const char *format, va_list args); +/** + * Concatenate while shell-escaping. + * + * @param dest + * The destination dynamic string. + * @param str + * The string to escape. + * @param flags + * Flags for wordesc(). + * @return + * 0 on success, -1 on failure. + */ +int dstrescat(char **dest, const char *str, enum wesc_flags flags); + +/** + * Concatenate while shell-escaping. + * + * @param dest + * The destination dynamic string. + * @param str + * The string to escape. + * @param n + * The maximum length of the string. + * @param flags + * Flags for wordesc(). + * @return + * 0 on success, -1 on failure. + */ +int dstrnescat(char **dest, const char *str, size_t n, enum wesc_flags flags); + /** * Free a dynamic string. * -- cgit v1.2.3 From b577bedfd37d93cb802c36beb93cf6581af51930 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 13 Jul 2023 13:40:46 -0400 Subject: color: Get rid of EXT_MAX --- src/color.c | 40 ++++++++++++++++++++++++++++++---------- tests/bfs/color_deep.out | 16 ++++++++++++++++ tests/bfs/color_deep.sh | 7 +++++++ 3 files changed, 53 insertions(+), 10 deletions(-) create mode 100644 tests/bfs/color_deep.out create mode 100644 tests/bfs/color_deep.sh (limited to 'src/color.c') diff --git a/src/color.c b/src/color.c index 0f5829f..00d7920 100644 --- a/src/color.c +++ b/src/color.c @@ -106,6 +106,8 @@ struct colors { /** Number of extensions. */ size_t ext_count; + /** Longest extension. */ + size_t ext_len; /** Case-sensitive extension trie. */ struct trie ext_trie; /** Case-insensitive extension trie. */ @@ -207,9 +209,6 @@ static void ext_tolower(char *ext, size_t len) { } } -/** Maximum supported extension length. */ -#define EXT_MAX 255 - /** * The "smart case" algorithm. * @@ -331,6 +330,11 @@ static int build_iext_trie(struct colors *colors) { trie_init(&colors->iext_trie); TRIE_FOR_EACH(&colors->ext_trie, leaf) { + size_t len = leaf->length - 1; + if (colors->ext_len < len) { + colors->ext_len = len; + } + struct ext_color *ext = leaf->value; if (ext->case_sensitive) { continue; @@ -356,25 +360,40 @@ static int build_iext_trie(struct colors *colors) { * Find a color by an extension. */ static const struct esc_seq *get_ext(const struct colors *colors, const char *filename) { + size_t ext_len = colors->ext_len; size_t name_len = strlen(filename); - size_t ext_len = name_len < EXT_MAX ? name_len : EXT_MAX; + if (name_len < ext_len) { + ext_len = name_len; + } const char *suffix = filename + name_len - ext_len; - char xfrm[ext_len + 1]; - memcpy(xfrm, suffix, sizeof(xfrm)); + char buf[256]; + char *copy; + if (ext_len < sizeof(buf)) { + copy = memcpy(buf, suffix, ext_len + 1); + } else { + copy = strndup(suffix, ext_len); + if (!copy) { + return NULL; + } + } - ext_reverse(xfrm, ext_len); - const struct trie_leaf *leaf = trie_find_prefix(&colors->ext_trie, xfrm); + ext_reverse(copy, ext_len); + const struct trie_leaf *leaf = trie_find_prefix(&colors->ext_trie, copy); const struct ext_color *ext = leaf ? leaf->value : NULL; - ext_tolower(xfrm, ext_len); - const struct trie_leaf *ileaf = trie_find_prefix(&colors->iext_trie, xfrm); + ext_tolower(copy, ext_len); + const struct trie_leaf *ileaf = trie_find_prefix(&colors->iext_trie, copy); const struct ext_color *iext = ileaf ? ileaf->value : NULL; if (iext && (!ext || ext->priority < iext->priority)) { ext = iext; } + if (copy != buf) { + free(copy); + } + return ext ? ext->esc : NULL; } @@ -601,6 +620,7 @@ struct colors *parse_colors(void) { VARENA_INIT(&colors->ext_arena, struct ext_color, ext); trie_init(&colors->names); colors->ext_count = 0; + colors->ext_len = 0; trie_init(&colors->ext_trie); trie_init(&colors->iext_trie); diff --git a/tests/bfs/color_deep.out b/tests/bfs/color_deep.out new file mode 100644 index 0000000..fb990d5 --- /dev/null +++ b/tests/bfs/color_deep.out @@ -0,0 +1,16 @@ +0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE +0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE +0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE +0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE +0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE +0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE +0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE +0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE +0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE +0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE +0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE +0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE +0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE +0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE +0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE +0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDE diff --git a/tests/bfs/color_deep.sh b/tests/bfs/color_deep.sh new file mode 100644 index 0000000..a83ee0e --- /dev/null +++ b/tests/bfs/color_deep.sh @@ -0,0 +1,7 @@ +name="0123456789ABCDEF" +name="${name}${name}${name}${name}" +name="${name}${name}${name}${name}" +name="${name:0:255}" +export LS_COLORS="*${name}=01:" + +bfs_diff deep -color -type f -printf '%f\n' -- cgit v1.2.3 From c5a2bfd924445dfccd943ea34374a5d1266f5cb9 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 13 Jul 2023 15:22:42 -0400 Subject: color: TTY-escape filenames --- src/color.c | 10 +++++++++- src/color.h | 1 + src/printf.c | 4 ++-- tests/bfs/color.out | 2 ++ tests/bfs/color_L.out | 2 ++ tests/bfs/color_L_ln_target.out | 2 ++ tests/bfs/color_L_no_stat.out | 2 ++ tests/bfs/color_cd0_no.out | 2 ++ tests/bfs/color_escapes.out | 2 ++ tests/bfs/color_ext.out | 2 ++ tests/bfs/color_ext0.out | 2 ++ tests/bfs/color_ext_case.out | 2 ++ tests/bfs/color_ext_override.out | 2 ++ tests/bfs/color_ext_underride.out | 2 ++ tests/bfs/color_fi0_no.out | 2 ++ tests/bfs/color_fi_no.out | 2 ++ tests/bfs/color_ln_target.out | 2 ++ tests/bfs/color_mh.out | 2 ++ tests/bfs/color_mh0.out | 2 ++ tests/bfs/color_mi.out | 2 ++ tests/bfs/color_missing_colon.out | 2 ++ tests/bfs/color_no.out | 2 ++ tests/bfs/color_no_stat.out | 2 ++ tests/bfs/color_nul.out | 2 ++ tests/bfs/color_or.out | 2 ++ tests/bfs/color_or0_mi.out | 2 ++ tests/bfs/color_or0_mi0.out | 2 ++ tests/bfs/color_or_mi.out | 2 ++ tests/bfs/color_or_mi0.out | 2 ++ tests/bfs/color_rs_lc_rc_ec.out | 2 ++ tests/bfs/color_st0_tw0_ow.out | 2 ++ tests/bfs/color_st0_tw0_ow0.out | 2 ++ tests/bfs/color_st0_tw_ow.out | 2 ++ tests/bfs/color_st0_tw_ow0.out | 2 ++ tests/bfs/color_st_tw0_ow.out | 2 ++ tests/bfs/color_st_tw0_ow0.out | 2 ++ tests/bfs/color_st_tw_ow0.out | 2 ++ tests/bfs/color_su0_sg.out | 2 ++ tests/bfs/color_su0_sg0.out | 2 ++ tests/bfs/color_su_sg0.out | 2 ++ tests/bfs/nocolor.out | 2 ++ tests/gnu/empty_special.out | 1 + tests/tests.sh | 1 + 43 files changed, 90 insertions(+), 3 deletions(-) (limited to 'src/color.c') diff --git a/src/color.c b/src/color.c index 00d7920..6593f5b 100644 --- a/src/color.c +++ b/src/color.c @@ -922,9 +922,12 @@ static int print_colored(CFILE *cfile, const struct esc_seq *esc, const char *st if (print_esc(cfile, esc) != 0) { return -1; } - if (dstrxcat(&cfile->buffer, str, len) != 0) { + + // Don't let the string itself interfere with the colors + if (print_wordesc(cfile, str, len, WESC_TTY) != 0) { return -1; } + if (print_reset(cfile) != 0) { return -1; } @@ -1242,6 +1245,11 @@ static int cvbuff(CFILE *cfile, const char *format, va_list args) { return -1; } break; + case 'Q': + if (print_wordesc(cfile, va_arg(args, const char *), SIZE_MAX, WESC_TTY) != 0) { + return -1; + } + break; case 'F': if (print_name(cfile, va_arg(args, const struct BFTW *)) != 0) { diff --git a/src/color.h b/src/color.h index 932d551..0d46c33 100644 --- a/src/color.h +++ b/src/color.h @@ -87,6 +87,7 @@ int cfclose(CFILE *cfile); * %zu: A size_t * %m: strerror(errno) * %pq: A shell-escaped string, like bash's printf %q + * %pQ: A TTY-escaped string. * %pF: A colored file name, from a const struct BFTW * argument * %pP: A colored file path, from a const struct BFTW * argument * %pL: A colored link target, from a const struct BFTW * argument diff --git a/src/printf.c b/src/printf.c index 6520d2d..f0910fa 100644 --- a/src/printf.c +++ b/src/printf.c @@ -298,7 +298,7 @@ static int bfs_printf_h(CFILE *cfile, const struct bfs_printf *directive, const int ret; if (should_color(cfile, directive)) { - ret = cfprintf(cfile, "${di}%s${rs}", buf); + ret = cfprintf(cfile, "${di}%pQ${rs}", buf); } else { ret = dyn_fprintf(cfile->file, directive, buf); } @@ -313,7 +313,7 @@ static int bfs_printf_H(CFILE *cfile, const struct bfs_printf *directive, const if (ftwbuf->depth == 0) { return cfprintf(cfile, "%pP", ftwbuf); } else { - return cfprintf(cfile, "${di}%s${rs}", ftwbuf->root); + return cfprintf(cfile, "${di}%pQ${rs}", ftwbuf->root); } } else { return dyn_fprintf(cfile->file, directive, ftwbuf->root); diff --git a/tests/bfs/color.out b/tests/bfs/color.out index 34c7153..5c6b43e 100644 --- a/tests/bfs/color.out +++ b/tests/bfs/color.out @@ -1,5 +1,7 @@ +$'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/exec.sh +rainbow/$'\e[1m' rainbow/socket rainbow/broken rainbow/chardev_link diff --git a/tests/bfs/color_L.out b/tests/bfs/color_L.out index 89f9410..6904e39 100644 --- a/tests/bfs/color_L.out +++ b/tests/bfs/color_L.out @@ -1,6 +1,8 @@ +$'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/exec.sh rainbow/chardev_link +rainbow/$'\e[1m' rainbow/socket rainbow/broken rainbow/sticky_ow diff --git a/tests/bfs/color_L_ln_target.out b/tests/bfs/color_L_ln_target.out index 2562c98..50105c3 100644 --- a/tests/bfs/color_L_ln_target.out +++ b/tests/bfs/color_L_ln_target.out @@ -1,7 +1,9 @@ +$'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/broken rainbow/exec.sh rainbow/chardev_link +rainbow/$'\e[1m' rainbow/socket rainbow/sticky_ow rainbow/sgid diff --git a/tests/bfs/color_L_no_stat.out b/tests/bfs/color_L_no_stat.out index 4fe99c0..beb538c 100644 --- a/tests/bfs/color_L_no_stat.out +++ b/tests/bfs/color_L_no_stat.out @@ -1,5 +1,7 @@ +$'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/chardev_link +rainbow/$'\e[1m' rainbow/ow rainbow/sticky rainbow/sticky_ow diff --git a/tests/bfs/color_cd0_no.out b/tests/bfs/color_cd0_no.out index 30ad97f..4d710fd 100644 --- a/tests/bfs/color_cd0_no.out +++ b/tests/bfs/color_cd0_no.out @@ -1,5 +1,7 @@ +$'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/exec.sh +rainbow/$'\e[1m' rainbow/socket rainbow/broken rainbow/file.dat diff --git a/tests/bfs/color_escapes.out b/tests/bfs/color_escapes.out index 808585e..746a9ea 100644 --- a/tests/bfs/color_escapes.out +++ b/tests/bfs/color_escapes.out @@ -1,5 +1,7 @@ +:$'rainbow/\e[1m/'$'\e[0m' :rainbow :rainbow/:exec.sh +:rainbow/:$'\e[1m' :rainbow/:socket :rainbow/:broken :rainbow/:chardev_link diff --git a/tests/bfs/color_ext.out b/tests/bfs/color_ext.out index be22b82..a35ca0b 100644 --- a/tests/bfs/color_ext.out +++ b/tests/bfs/color_ext.out @@ -1,5 +1,7 @@ +$'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/exec.sh +rainbow/$'\e[1m' rainbow/socket rainbow/broken rainbow/chardev_link diff --git a/tests/bfs/color_ext0.out b/tests/bfs/color_ext0.out index d151319..37301cc 100644 --- a/tests/bfs/color_ext0.out +++ b/tests/bfs/color_ext0.out @@ -1,6 +1,8 @@ +$'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/file.txt rainbow/exec.sh +rainbow/$'\e[1m' rainbow/socket rainbow/broken rainbow/chardev_link diff --git a/tests/bfs/color_ext_case.out b/tests/bfs/color_ext_case.out index 4e7258d..9388343 100644 --- a/tests/bfs/color_ext_case.out +++ b/tests/bfs/color_ext_case.out @@ -1,3 +1,4 @@ +$'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/lower.gz rainbow/lower.tar.gz @@ -6,6 +7,7 @@ rainbow/upper.TAR.GZ rainbow/lower.tar rainbow/upper.TAR +rainbow/$'\e[1m' rainbow/ul.TAR.gz rainbow/lu.tar.GZ rainbow/socket diff --git a/tests/bfs/color_ext_override.out b/tests/bfs/color_ext_override.out index 3a09cd2..1e0146c 100644 --- a/tests/bfs/color_ext_override.out +++ b/tests/bfs/color_ext_override.out @@ -1,3 +1,4 @@ +$'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/exec.sh rainbow/lower.tar @@ -8,6 +9,7 @@ rainbow/ul.TAR.gz rainbow/upper.GZ rainbow/upper.TAR.GZ +rainbow/$'\e[1m' rainbow/socket rainbow/broken rainbow/chardev_link diff --git a/tests/bfs/color_ext_underride.out b/tests/bfs/color_ext_underride.out index 073d176..1ed66da 100644 --- a/tests/bfs/color_ext_underride.out +++ b/tests/bfs/color_ext_underride.out @@ -1,3 +1,4 @@ +$'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/lower.tar.gz rainbow/lu.tar.GZ @@ -8,6 +9,7 @@ rainbow/upper.TAR rainbow/lower.gz rainbow/upper.GZ +rainbow/$'\e[1m' rainbow/socket rainbow/broken rainbow/chardev_link diff --git a/tests/bfs/color_fi0_no.out b/tests/bfs/color_fi0_no.out index 34c7153..5c6b43e 100644 --- a/tests/bfs/color_fi0_no.out +++ b/tests/bfs/color_fi0_no.out @@ -1,5 +1,7 @@ +$'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/exec.sh +rainbow/$'\e[1m' rainbow/socket rainbow/broken rainbow/chardev_link diff --git a/tests/bfs/color_fi_no.out b/tests/bfs/color_fi_no.out index 8df9355..e64684d 100644 --- a/tests/bfs/color_fi_no.out +++ b/tests/bfs/color_fi_no.out @@ -1,5 +1,7 @@ +$'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/exec.sh +rainbow/$'\e[1m' rainbow/socket rainbow/broken rainbow/chardev_link diff --git a/tests/bfs/color_ln_target.out b/tests/bfs/color_ln_target.out index 2562c98..50105c3 100644 --- a/tests/bfs/color_ln_target.out +++ b/tests/bfs/color_ln_target.out @@ -1,7 +1,9 @@ +$'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/broken rainbow/exec.sh rainbow/chardev_link +rainbow/$'\e[1m' rainbow/socket rainbow/sticky_ow rainbow/sgid diff --git a/tests/bfs/color_mh.out b/tests/bfs/color_mh.out index 7521b31..93bfde1 100644 --- a/tests/bfs/color_mh.out +++ b/tests/bfs/color_mh.out @@ -1,5 +1,7 @@ +$'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/exec.sh +rainbow/$'\e[1m' rainbow/socket rainbow/broken rainbow/chardev_link diff --git a/tests/bfs/color_mh0.out b/tests/bfs/color_mh0.out index 34c7153..5c6b43e 100644 --- a/tests/bfs/color_mh0.out +++ b/tests/bfs/color_mh0.out @@ -1,5 +1,7 @@ +$'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/exec.sh +rainbow/$'\e[1m' rainbow/socket rainbow/broken rainbow/chardev_link diff --git a/tests/bfs/color_mi.out b/tests/bfs/color_mi.out index 34c7153..5c6b43e 100644 --- a/tests/bfs/color_mi.out +++ b/tests/bfs/color_mi.out @@ -1,5 +1,7 @@ +$'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/exec.sh +rainbow/$'\e[1m' rainbow/socket rainbow/broken rainbow/chardev_link diff --git a/tests/bfs/color_missing_colon.out b/tests/bfs/color_missing_colon.out index be22b82..a35ca0b 100644 --- a/tests/bfs/color_missing_colon.out +++ b/tests/bfs/color_missing_colon.out @@ -1,5 +1,7 @@ +$'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/exec.sh +rainbow/$'\e[1m' rainbow/socket rainbow/broken rainbow/chardev_link diff --git a/tests/bfs/color_no.out b/tests/bfs/color_no.out index b70e47d..c61d246 100644 --- a/tests/bfs/color_no.out +++ b/tests/bfs/color_no.out @@ -1,5 +1,7 @@ +$'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/exec.sh +rainbow/$'\e[1m' rainbow/socket rainbow/broken rainbow/chardev_link diff --git a/tests/bfs/color_no_stat.out b/tests/bfs/color_no_stat.out index 7d7d767..e57e11a 100644 --- a/tests/bfs/color_no_stat.out +++ b/tests/bfs/color_no_stat.out @@ -1,4 +1,6 @@ +$'rainbow/\e[1m/'$'\e[0m' rainbow +rainbow/$'\e[1m' rainbow/ow rainbow/sticky rainbow/sticky_ow diff --git a/tests/bfs/color_nul.out b/tests/bfs/color_nul.out index 4ea4d85..7140e32 100644 --- a/tests/bfs/color_nul.out +++ b/tests/bfs/color_nul.out @@ -1,3 +1,4 @@ +$'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/lower.gz rainbow/lower.tar.gz @@ -6,6 +7,7 @@ rainbow/upper.GZ rainbow/upper.TAR.GZ rainbow/exec.sh +rainbow/$'\e[1m' rainbow/socket rainbow/broken rainbow/chardev_link diff --git a/tests/bfs/color_or.out b/tests/bfs/color_or.out index 98efb63..07916da 100644 --- a/tests/bfs/color_or.out +++ b/tests/bfs/color_or.out @@ -1,5 +1,7 @@ +$'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/exec.sh +rainbow/$'\e[1m' rainbow/socket rainbow/chardev_link rainbow/link.txt diff --git a/tests/bfs/color_or0_mi.out b/tests/bfs/color_or0_mi.out index 34c7153..5c6b43e 100644 --- a/tests/bfs/color_or0_mi.out +++ b/tests/bfs/color_or0_mi.out @@ -1,5 +1,7 @@ +$'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/exec.sh +rainbow/$'\e[1m' rainbow/socket rainbow/broken rainbow/chardev_link diff --git a/tests/bfs/color_or0_mi0.out b/tests/bfs/color_or0_mi0.out index 34c7153..5c6b43e 100644 --- a/tests/bfs/color_or0_mi0.out +++ b/tests/bfs/color_or0_mi0.out @@ -1,5 +1,7 @@ +$'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/exec.sh +rainbow/$'\e[1m' rainbow/socket rainbow/broken rainbow/chardev_link diff --git a/tests/bfs/color_or_mi.out b/tests/bfs/color_or_mi.out index a9dc229..20bc61d 100644 --- a/tests/bfs/color_or_mi.out +++ b/tests/bfs/color_or_mi.out @@ -1,6 +1,8 @@ +$'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/broken rainbow/exec.sh +rainbow/$'\e[1m' rainbow/socket rainbow/chardev_link rainbow/link.txt diff --git a/tests/bfs/color_or_mi0.out b/tests/bfs/color_or_mi0.out index a9dc229..20bc61d 100644 --- a/tests/bfs/color_or_mi0.out +++ b/tests/bfs/color_or_mi0.out @@ -1,6 +1,8 @@ +$'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/broken rainbow/exec.sh +rainbow/$'\e[1m' rainbow/socket rainbow/chardev_link rainbow/link.txt diff --git a/tests/bfs/color_rs_lc_rc_ec.out b/tests/bfs/color_rs_lc_rc_ec.out index 82d94ec..f78b41f 100644 --- a/tests/bfs/color_rs_lc_rc_ec.out +++ b/tests/bfs/color_rs_lc_rc_ec.out @@ -1,4 +1,6 @@ +LC01;34RC$'rainbow/\e[1m/'EC$'\e[0m' LC01;34RCrainbow/ECLC01;32RCexec.shEC +LC01;34RCrainbow/ECLC01;34RC$'\e[1m'EC LC01;34RCrainbow/ECLC01;35RCsocketEC LC01;34RCrainbow/ECLC01;36RCbrokenEC LC01;34RCrainbow/ECLC01;36RCchardev_linkEC diff --git a/tests/bfs/color_st0_tw0_ow.out b/tests/bfs/color_st0_tw0_ow.out index bdc5942..d1fec74 100644 --- a/tests/bfs/color_st0_tw0_ow.out +++ b/tests/bfs/color_st0_tw0_ow.out @@ -1,5 +1,7 @@ +$'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/exec.sh +rainbow/$'\e[1m' rainbow/sticky rainbow/socket rainbow/broken diff --git a/tests/bfs/color_st0_tw0_ow0.out b/tests/bfs/color_st0_tw0_ow0.out index f13b7f3..cb80cb8 100644 --- a/tests/bfs/color_st0_tw0_ow0.out +++ b/tests/bfs/color_st0_tw0_ow0.out @@ -1,5 +1,7 @@ +$'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/exec.sh +rainbow/$'\e[1m' rainbow/ow rainbow/sticky rainbow/sticky_ow diff --git a/tests/bfs/color_st0_tw_ow.out b/tests/bfs/color_st0_tw_ow.out index 2d7f682..a183932 100644 --- a/tests/bfs/color_st0_tw_ow.out +++ b/tests/bfs/color_st0_tw_ow.out @@ -1,5 +1,7 @@ +$'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/exec.sh +rainbow/$'\e[1m' rainbow/sticky rainbow/socket rainbow/broken diff --git a/tests/bfs/color_st0_tw_ow0.out b/tests/bfs/color_st0_tw_ow0.out index 7e343b8..cdc5cdd 100644 --- a/tests/bfs/color_st0_tw_ow0.out +++ b/tests/bfs/color_st0_tw_ow0.out @@ -1,5 +1,7 @@ +$'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/exec.sh +rainbow/$'\e[1m' rainbow/ow rainbow/sticky rainbow/socket diff --git a/tests/bfs/color_st_tw0_ow.out b/tests/bfs/color_st_tw0_ow.out index c61a327..f45c75c 100644 --- a/tests/bfs/color_st_tw0_ow.out +++ b/tests/bfs/color_st_tw0_ow.out @@ -1,5 +1,7 @@ +$'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/exec.sh +rainbow/$'\e[1m' rainbow/socket rainbow/broken rainbow/chardev_link diff --git a/tests/bfs/color_st_tw0_ow0.out b/tests/bfs/color_st_tw0_ow0.out index 929a993..d95d12a 100644 --- a/tests/bfs/color_st_tw0_ow0.out +++ b/tests/bfs/color_st_tw0_ow0.out @@ -1,5 +1,7 @@ +$'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/exec.sh +rainbow/$'\e[1m' rainbow/ow rainbow/socket rainbow/broken diff --git a/tests/bfs/color_st_tw_ow0.out b/tests/bfs/color_st_tw_ow0.out index 7092f5a..f1059dd 100644 --- a/tests/bfs/color_st_tw_ow0.out +++ b/tests/bfs/color_st_tw_ow0.out @@ -1,5 +1,7 @@ +$'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/exec.sh +rainbow/$'\e[1m' rainbow/ow rainbow/socket rainbow/broken diff --git a/tests/bfs/color_su0_sg.out b/tests/bfs/color_su0_sg.out index 2bce534..31d5108 100644 --- a/tests/bfs/color_su0_sg.out +++ b/tests/bfs/color_su0_sg.out @@ -1,5 +1,7 @@ +$'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/exec.sh +rainbow/$'\e[1m' rainbow/socket rainbow/broken rainbow/chardev_link diff --git a/tests/bfs/color_su0_sg0.out b/tests/bfs/color_su0_sg0.out index 0c3d757..4804030 100644 --- a/tests/bfs/color_su0_sg0.out +++ b/tests/bfs/color_su0_sg0.out @@ -1,5 +1,7 @@ +$'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/exec.sh +rainbow/$'\e[1m' rainbow/socket rainbow/broken rainbow/chardev_link diff --git a/tests/bfs/color_su_sg0.out b/tests/bfs/color_su_sg0.out index 7a70598..3dbc7fe 100644 --- a/tests/bfs/color_su_sg0.out +++ b/tests/bfs/color_su_sg0.out @@ -1,5 +1,7 @@ +$'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/exec.sh +rainbow/$'\e[1m' rainbow/socket rainbow/broken rainbow/chardev_link diff --git a/tests/bfs/nocolor.out b/tests/bfs/nocolor.out index 29e7de8..d51d24d 100644 --- a/tests/bfs/nocolor.out +++ b/tests/bfs/nocolor.out @@ -1,4 +1,6 @@ rainbow +rainbow/ +rainbow// rainbow/broken rainbow/chardev_link rainbow/exec.sh diff --git a/tests/gnu/empty_special.out b/tests/gnu/empty_special.out index 3aa57d2..fa35478 100644 --- a/tests/gnu/empty_special.out +++ b/tests/gnu/empty_special.out @@ -1,3 +1,4 @@ +rainbow// rainbow/exec.sh rainbow/file.dat rainbow/file.txt diff --git a/tests/tests.sh b/tests/tests.sh index 46e3e33..66a79a8 100755 --- a/tests/tests.sh +++ b/tests/tests.sh @@ -432,6 +432,7 @@ function make_rainbow() { chmod +t "$1"/sticky* "$XTOUCH" -p "$1"/exec.sh chmod +x "$1"/exec.sh + "$XTOUCH" -p "$1/"$'\e[1m/\e[0m' } make_rainbow "$TMP/rainbow" -- cgit v1.2.3 From 0e4dffeb46f3d8bfe30d60a0cfe1e1fa5a082b13 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 13 Jul 2023 15:45:08 -0400 Subject: color: Don't break up leading and trailing dirs --- src/color.c | 59 +++++++++++++++++++++------------------ tests/bfs/color.out | 2 +- tests/bfs/color_L.out | 2 +- tests/bfs/color_L_ln_target.out | 2 +- tests/bfs/color_L_no_stat.out | 8 +++--- tests/bfs/color_cd0_no.out | 2 +- tests/bfs/color_escapes.out | 2 +- tests/bfs/color_ext.out | 2 +- tests/bfs/color_ext0.out | 2 +- tests/bfs/color_ext_case.out | 2 +- tests/bfs/color_ext_override.out | 2 +- tests/bfs/color_ext_underride.out | 2 +- tests/bfs/color_fi0_no.out | 2 +- tests/bfs/color_fi_no.out | 2 +- tests/bfs/color_ln_target.out | 2 +- tests/bfs/color_ls.out | 16 +++++------ tests/bfs/color_mh.out | 2 +- tests/bfs/color_mh0.out | 2 +- tests/bfs/color_mi.out | 2 +- tests/bfs/color_missing_colon.out | 2 +- tests/bfs/color_no.out | 2 +- tests/bfs/color_no_stat.out | 8 +++--- tests/bfs/color_nul.out | 2 +- tests/bfs/color_or.out | 2 +- tests/bfs/color_or0_mi.out | 2 +- tests/bfs/color_or0_mi0.out | 2 +- tests/bfs/color_or_mi.out | 2 +- tests/bfs/color_or_mi0.out | 2 +- tests/bfs/color_rs_lc_rc_ec.out | 2 +- tests/bfs/color_st0_tw0_ow.out | 4 +-- tests/bfs/color_st0_tw0_ow0.out | 8 +++--- tests/bfs/color_st0_tw_ow.out | 4 +-- tests/bfs/color_st0_tw_ow0.out | 6 ++-- tests/bfs/color_st_tw0_ow.out | 2 +- tests/bfs/color_st_tw0_ow0.out | 4 +-- tests/bfs/color_st_tw_ow0.out | 4 +-- tests/bfs/color_su0_sg.out | 2 +- tests/bfs/color_su0_sg0.out | 2 +- tests/bfs/color_su_sg0.out | 2 +- tests/bfs/printf_color.out | 4 ++- 40 files changed, 95 insertions(+), 88 deletions(-) (limited to 'src/color.c') diff --git a/src/color.c b/src/color.c index 6593f5b..7d98978 100644 --- a/src/color.c +++ b/src/color.c @@ -995,27 +995,48 @@ out: return ret; } -/** Print the directories leading up to a file. */ -static int print_dirs_colored(CFILE *cfile, const char *path, const struct BFTW *ftwbuf, enum bfs_stat_flags flags, size_t nameoff) { - const struct colors *colors = cfile->colors; +/** Print a path with colors. */ +static int print_path_colored(CFILE *cfile, const char *path, const struct BFTW *ftwbuf, enum bfs_stat_flags flags) { + size_t nameoff; + if (path == ftwbuf->path) { + nameoff = ftwbuf->nameoff; + } else { + nameoff = xbaseoff(path); + } + + const char *name = path + nameoff; + size_t pathlen = nameoff + strlen(name); ssize_t broken = first_broken_offset(path, ftwbuf, flags, nameoff); if (broken < 0) { return -1; } + size_t split = broken; - if (broken > 0) { - if (print_colored(cfile, colors->directory, path, broken) != 0) { - return -1; + const struct colors *colors = cfile->colors; + const struct esc_seq *dirs_color = colors->directory; + const struct esc_seq *name_color; + + if (split < nameoff) { + name_color = colors->missing; + if (!name_color) { + name_color = colors->orphan; + } + } else { + name_color = file_color(cfile->colors, path + nameoff, ftwbuf, flags); + if (name_color == dirs_color) { + split = pathlen; } } - if ((size_t)broken < nameoff) { - const struct esc_seq *color = colors->missing; - if (!color) { - color = colors->orphan; + if (split > 0) { + if (print_colored(cfile, dirs_color, path, split) != 0) { + return -1; } - if (print_colored(cfile, color, path + broken, nameoff - broken) != 0) { + } + + if (split < pathlen) { + if (print_colored(cfile, name_color, path + split, pathlen - split) != 0) { return -1; } } @@ -1029,22 +1050,6 @@ static int print_name_colored(CFILE *cfile, const char *name, const struct BFTW return print_colored(cfile, esc, name, strlen(name)); } -/** Print a path with colors. */ -static int print_path_colored(CFILE *cfile, const char *path, const struct BFTW *ftwbuf, enum bfs_stat_flags flags) { - size_t nameoff; - if (path == ftwbuf->path) { - nameoff = ftwbuf->nameoff; - } else { - nameoff = xbaseoff(path); - } - - if (print_dirs_colored(cfile, path, ftwbuf, flags, nameoff) != 0) { - return -1; - } - - return print_name_colored(cfile, path + nameoff, ftwbuf, flags); -} - /** Print the name of a file with the appropriate colors. */ static int print_name(CFILE *cfile, const struct BFTW *ftwbuf) { const char *name = ftwbuf->path + ftwbuf->nameoff; diff --git a/tests/bfs/color.out b/tests/bfs/color.out index 5c6b43e..a439814 100644 --- a/tests/bfs/color.out +++ b/tests/bfs/color.out @@ -1,7 +1,7 @@ +$'rainbow/\e[1m' $'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/exec.sh -rainbow/$'\e[1m' rainbow/socket rainbow/broken rainbow/chardev_link diff --git a/tests/bfs/color_L.out b/tests/bfs/color_L.out index 6904e39..85923db 100644 --- a/tests/bfs/color_L.out +++ b/tests/bfs/color_L.out @@ -1,8 +1,8 @@ +$'rainbow/\e[1m' $'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/exec.sh rainbow/chardev_link -rainbow/$'\e[1m' rainbow/socket rainbow/broken rainbow/sticky_ow diff --git a/tests/bfs/color_L_ln_target.out b/tests/bfs/color_L_ln_target.out index 50105c3..23fe8d7 100644 --- a/tests/bfs/color_L_ln_target.out +++ b/tests/bfs/color_L_ln_target.out @@ -1,9 +1,9 @@ +$'rainbow/\e[1m' $'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/broken rainbow/exec.sh rainbow/chardev_link -rainbow/$'\e[1m' rainbow/socket rainbow/sticky_ow rainbow/sgid diff --git a/tests/bfs/color_L_no_stat.out b/tests/bfs/color_L_no_stat.out index beb538c..72e0319 100644 --- a/tests/bfs/color_L_no_stat.out +++ b/tests/bfs/color_L_no_stat.out @@ -1,10 +1,7 @@ +$'rainbow/\e[1m' $'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/chardev_link -rainbow/$'\e[1m' -rainbow/ow -rainbow/sticky -rainbow/sticky_ow rainbow/socket rainbow/broken rainbow/file.txt @@ -25,3 +22,6 @@ rainbow/upper.GZ rainbow/upper.TAR rainbow/upper.TAR.GZ +rainbow/ow +rainbow/sticky +rainbow/sticky_ow diff --git a/tests/bfs/color_cd0_no.out b/tests/bfs/color_cd0_no.out index 4d710fd..37b3fbc 100644 --- a/tests/bfs/color_cd0_no.out +++ b/tests/bfs/color_cd0_no.out @@ -1,7 +1,7 @@ +$'rainbow/\e[1m' $'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/exec.sh -rainbow/$'\e[1m' rainbow/socket rainbow/broken rainbow/file.dat diff --git a/tests/bfs/color_escapes.out b/tests/bfs/color_escapes.out index 746a9ea..0bf9fbb 100644 --- a/tests/bfs/color_escapes.out +++ b/tests/bfs/color_escapes.out @@ -1,7 +1,7 @@ +:$'rainbow/\e[1m' :$'rainbow/\e[1m/'$'\e[0m' :rainbow :rainbow/:exec.sh -:rainbow/:$'\e[1m' :rainbow/:socket :rainbow/:broken :rainbow/:chardev_link diff --git a/tests/bfs/color_ext.out b/tests/bfs/color_ext.out index a35ca0b..218100f 100644 --- a/tests/bfs/color_ext.out +++ b/tests/bfs/color_ext.out @@ -1,7 +1,7 @@ +$'rainbow/\e[1m' $'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/exec.sh -rainbow/$'\e[1m' rainbow/socket rainbow/broken rainbow/chardev_link diff --git a/tests/bfs/color_ext0.out b/tests/bfs/color_ext0.out index 37301cc..d2a7fd5 100644 --- a/tests/bfs/color_ext0.out +++ b/tests/bfs/color_ext0.out @@ -1,8 +1,8 @@ +$'rainbow/\e[1m' $'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/file.txt rainbow/exec.sh -rainbow/$'\e[1m' rainbow/socket rainbow/broken rainbow/chardev_link diff --git a/tests/bfs/color_ext_case.out b/tests/bfs/color_ext_case.out index 9388343..93dc8f6 100644 --- a/tests/bfs/color_ext_case.out +++ b/tests/bfs/color_ext_case.out @@ -1,3 +1,4 @@ +$'rainbow/\e[1m' $'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/lower.gz @@ -7,7 +8,6 @@ rainbow/upper.TAR.GZ rainbow/lower.tar rainbow/upper.TAR -rainbow/$'\e[1m' rainbow/ul.TAR.gz rainbow/lu.tar.GZ rainbow/socket diff --git a/tests/bfs/color_ext_override.out b/tests/bfs/color_ext_override.out index 1e0146c..0acfcbc 100644 --- a/tests/bfs/color_ext_override.out +++ b/tests/bfs/color_ext_override.out @@ -1,3 +1,4 @@ +$'rainbow/\e[1m' $'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/exec.sh @@ -9,7 +10,6 @@ rainbow/ul.TAR.gz rainbow/upper.GZ rainbow/upper.TAR.GZ -rainbow/$'\e[1m' rainbow/socket rainbow/broken rainbow/chardev_link diff --git a/tests/bfs/color_ext_underride.out b/tests/bfs/color_ext_underride.out index 1ed66da..5c98341 100644 --- a/tests/bfs/color_ext_underride.out +++ b/tests/bfs/color_ext_underride.out @@ -1,3 +1,4 @@ +$'rainbow/\e[1m' $'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/lower.tar.gz @@ -9,7 +10,6 @@ rainbow/upper.TAR rainbow/lower.gz rainbow/upper.GZ -rainbow/$'\e[1m' rainbow/socket rainbow/broken rainbow/chardev_link diff --git a/tests/bfs/color_fi0_no.out b/tests/bfs/color_fi0_no.out index 5c6b43e..a439814 100644 --- a/tests/bfs/color_fi0_no.out +++ b/tests/bfs/color_fi0_no.out @@ -1,7 +1,7 @@ +$'rainbow/\e[1m' $'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/exec.sh -rainbow/$'\e[1m' rainbow/socket rainbow/broken rainbow/chardev_link diff --git a/tests/bfs/color_fi_no.out b/tests/bfs/color_fi_no.out index e64684d..1c1ad8e 100644 --- a/tests/bfs/color_fi_no.out +++ b/tests/bfs/color_fi_no.out @@ -1,7 +1,7 @@ +$'rainbow/\e[1m' $'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/exec.sh -rainbow/$'\e[1m' rainbow/socket rainbow/broken rainbow/chardev_link diff --git a/tests/bfs/color_ln_target.out b/tests/bfs/color_ln_target.out index 50105c3..23fe8d7 100644 --- a/tests/bfs/color_ln_target.out +++ b/tests/bfs/color_ln_target.out @@ -1,9 +1,9 @@ +$'rainbow/\e[1m' $'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/broken rainbow/exec.sh rainbow/chardev_link -rainbow/$'\e[1m' rainbow/socket rainbow/sticky_ow rainbow/sgid diff --git a/tests/bfs/color_ls.out b/tests/bfs/color_ls.out index b08d894..b5216c4 100644 --- a/tests/bfs/color_ls.out +++ b/tests/bfs/color_ls.out @@ -1,12 +1,12 @@ -scratch/foo/bar -scratch/foo/bar -/__bfs__/nowhere -/__bfs__/nowhere -foo/bar/baz/qux -foo/bar/baz/qux +scratch/foo/bar +scratch/foo/bar +/__bfs__/nowhere +/__bfs__/nowhere +foo/bar/baz/qux +foo/bar/baz/qux foo/bar/nowhere foo/bar/nowhere -foo/bar/nowhere/nothing -foo/bar/nowhere/nothing +foo/bar/nowhere/nothing +foo/bar/nowhere/nothing foo/bar/baz foo/bar/baz diff --git a/tests/bfs/color_mh.out b/tests/bfs/color_mh.out index 93bfde1..c658082 100644 --- a/tests/bfs/color_mh.out +++ b/tests/bfs/color_mh.out @@ -1,7 +1,7 @@ +$'rainbow/\e[1m' $'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/exec.sh -rainbow/$'\e[1m' rainbow/socket rainbow/broken rainbow/chardev_link diff --git a/tests/bfs/color_mh0.out b/tests/bfs/color_mh0.out index 5c6b43e..a439814 100644 --- a/tests/bfs/color_mh0.out +++ b/tests/bfs/color_mh0.out @@ -1,7 +1,7 @@ +$'rainbow/\e[1m' $'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/exec.sh -rainbow/$'\e[1m' rainbow/socket rainbow/broken rainbow/chardev_link diff --git a/tests/bfs/color_mi.out b/tests/bfs/color_mi.out index 5c6b43e..a439814 100644 --- a/tests/bfs/color_mi.out +++ b/tests/bfs/color_mi.out @@ -1,7 +1,7 @@ +$'rainbow/\e[1m' $'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/exec.sh -rainbow/$'\e[1m' rainbow/socket rainbow/broken rainbow/chardev_link diff --git a/tests/bfs/color_missing_colon.out b/tests/bfs/color_missing_colon.out index a35ca0b..218100f 100644 --- a/tests/bfs/color_missing_colon.out +++ b/tests/bfs/color_missing_colon.out @@ -1,7 +1,7 @@ +$'rainbow/\e[1m' $'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/exec.sh -rainbow/$'\e[1m' rainbow/socket rainbow/broken rainbow/chardev_link diff --git a/tests/bfs/color_no.out b/tests/bfs/color_no.out index c61d246..67e1eee 100644 --- a/tests/bfs/color_no.out +++ b/tests/bfs/color_no.out @@ -1,7 +1,7 @@ +$'rainbow/\e[1m' $'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/exec.sh -rainbow/$'\e[1m' rainbow/socket rainbow/broken rainbow/chardev_link diff --git a/tests/bfs/color_no_stat.out b/tests/bfs/color_no_stat.out index e57e11a..e3031b2 100644 --- a/tests/bfs/color_no_stat.out +++ b/tests/bfs/color_no_stat.out @@ -1,9 +1,6 @@ +$'rainbow/\e[1m' $'rainbow/\e[1m/'$'\e[0m' rainbow -rainbow/$'\e[1m' -rainbow/ow -rainbow/sticky -rainbow/sticky_ow rainbow/socket rainbow/broken rainbow/chardev_link @@ -25,3 +22,6 @@ rainbow/upper.GZ rainbow/upper.TAR rainbow/upper.TAR.GZ +rainbow/ow +rainbow/sticky +rainbow/sticky_ow diff --git a/tests/bfs/color_nul.out b/tests/bfs/color_nul.out index 7140e32..8ccd9a7 100644 --- a/tests/bfs/color_nul.out +++ b/tests/bfs/color_nul.out @@ -1,3 +1,4 @@ +$'rainbow/\e[1m' $'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/lower.gz @@ -7,7 +8,6 @@ rainbow/upper.GZ rainbow/upper.TAR.GZ rainbow/exec.sh -rainbow/$'\e[1m' rainbow/socket rainbow/broken rainbow/chardev_link diff --git a/tests/bfs/color_or.out b/tests/bfs/color_or.out index 07916da..0bd2570 100644 --- a/tests/bfs/color_or.out +++ b/tests/bfs/color_or.out @@ -1,7 +1,7 @@ +$'rainbow/\e[1m' $'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/exec.sh -rainbow/$'\e[1m' rainbow/socket rainbow/chardev_link rainbow/link.txt diff --git a/tests/bfs/color_or0_mi.out b/tests/bfs/color_or0_mi.out index 5c6b43e..a439814 100644 --- a/tests/bfs/color_or0_mi.out +++ b/tests/bfs/color_or0_mi.out @@ -1,7 +1,7 @@ +$'rainbow/\e[1m' $'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/exec.sh -rainbow/$'\e[1m' rainbow/socket rainbow/broken rainbow/chardev_link diff --git a/tests/bfs/color_or0_mi0.out b/tests/bfs/color_or0_mi0.out index 5c6b43e..a439814 100644 --- a/tests/bfs/color_or0_mi0.out +++ b/tests/bfs/color_or0_mi0.out @@ -1,7 +1,7 @@ +$'rainbow/\e[1m' $'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/exec.sh -rainbow/$'\e[1m' rainbow/socket rainbow/broken rainbow/chardev_link diff --git a/tests/bfs/color_or_mi.out b/tests/bfs/color_or_mi.out index 20bc61d..fb67e58 100644 --- a/tests/bfs/color_or_mi.out +++ b/tests/bfs/color_or_mi.out @@ -1,8 +1,8 @@ +$'rainbow/\e[1m' $'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/broken rainbow/exec.sh -rainbow/$'\e[1m' rainbow/socket rainbow/chardev_link rainbow/link.txt diff --git a/tests/bfs/color_or_mi0.out b/tests/bfs/color_or_mi0.out index 20bc61d..fb67e58 100644 --- a/tests/bfs/color_or_mi0.out +++ b/tests/bfs/color_or_mi0.out @@ -1,8 +1,8 @@ +$'rainbow/\e[1m' $'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/broken rainbow/exec.sh -rainbow/$'\e[1m' rainbow/socket rainbow/chardev_link rainbow/link.txt diff --git a/tests/bfs/color_rs_lc_rc_ec.out b/tests/bfs/color_rs_lc_rc_ec.out index f78b41f..077ef8d 100644 --- a/tests/bfs/color_rs_lc_rc_ec.out +++ b/tests/bfs/color_rs_lc_rc_ec.out @@ -1,6 +1,6 @@ +LC01;34RC$'rainbow/\e[1m'EC LC01;34RC$'rainbow/\e[1m/'EC$'\e[0m' LC01;34RCrainbow/ECLC01;32RCexec.shEC -LC01;34RCrainbow/ECLC01;34RC$'\e[1m'EC LC01;34RCrainbow/ECLC01;35RCsocketEC LC01;34RCrainbow/ECLC01;36RCbrokenEC LC01;34RCrainbow/ECLC01;36RCchardev_linkEC diff --git a/tests/bfs/color_st0_tw0_ow.out b/tests/bfs/color_st0_tw0_ow.out index d1fec74..a82762b 100644 --- a/tests/bfs/color_st0_tw0_ow.out +++ b/tests/bfs/color_st0_tw0_ow.out @@ -1,8 +1,7 @@ +$'rainbow/\e[1m' $'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/exec.sh -rainbow/$'\e[1m' -rainbow/sticky rainbow/socket rainbow/broken rainbow/chardev_link @@ -25,3 +24,4 @@ rainbow/upper.GZ rainbow/upper.TAR rainbow/upper.TAR.GZ +rainbow/sticky diff --git a/tests/bfs/color_st0_tw0_ow0.out b/tests/bfs/color_st0_tw0_ow0.out index cb80cb8..041f1d4 100644 --- a/tests/bfs/color_st0_tw0_ow0.out +++ b/tests/bfs/color_st0_tw0_ow0.out @@ -1,10 +1,7 @@ +$'rainbow/\e[1m' $'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/exec.sh -rainbow/$'\e[1m' -rainbow/ow -rainbow/sticky -rainbow/sticky_ow rainbow/socket rainbow/broken rainbow/chardev_link @@ -25,3 +22,6 @@ rainbow/upper.GZ rainbow/upper.TAR rainbow/upper.TAR.GZ +rainbow/ow +rainbow/sticky +rainbow/sticky_ow diff --git a/tests/bfs/color_st0_tw_ow.out b/tests/bfs/color_st0_tw_ow.out index a183932..4dcb2f2 100644 --- a/tests/bfs/color_st0_tw_ow.out +++ b/tests/bfs/color_st0_tw_ow.out @@ -1,8 +1,7 @@ +$'rainbow/\e[1m' $'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/exec.sh -rainbow/$'\e[1m' -rainbow/sticky rainbow/socket rainbow/broken rainbow/chardev_link @@ -25,3 +24,4 @@ rainbow/upper.GZ rainbow/upper.TAR rainbow/upper.TAR.GZ +rainbow/sticky diff --git a/tests/bfs/color_st0_tw_ow0.out b/tests/bfs/color_st0_tw_ow0.out index cdc5cdd..954ce9c 100644 --- a/tests/bfs/color_st0_tw_ow0.out +++ b/tests/bfs/color_st0_tw_ow0.out @@ -1,9 +1,7 @@ +$'rainbow/\e[1m' $'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/exec.sh -rainbow/$'\e[1m' -rainbow/ow -rainbow/sticky rainbow/socket rainbow/broken rainbow/chardev_link @@ -25,3 +23,5 @@ rainbow/upper.GZ rainbow/upper.TAR rainbow/upper.TAR.GZ +rainbow/ow +rainbow/sticky diff --git a/tests/bfs/color_st_tw0_ow.out b/tests/bfs/color_st_tw0_ow.out index f45c75c..a6e9a16 100644 --- a/tests/bfs/color_st_tw0_ow.out +++ b/tests/bfs/color_st_tw0_ow.out @@ -1,7 +1,7 @@ +$'rainbow/\e[1m' $'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/exec.sh -rainbow/$'\e[1m' rainbow/socket rainbow/broken rainbow/chardev_link diff --git a/tests/bfs/color_st_tw0_ow0.out b/tests/bfs/color_st_tw0_ow0.out index d95d12a..756dafb 100644 --- a/tests/bfs/color_st_tw0_ow0.out +++ b/tests/bfs/color_st_tw0_ow0.out @@ -1,8 +1,7 @@ +$'rainbow/\e[1m' $'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/exec.sh -rainbow/$'\e[1m' -rainbow/ow rainbow/socket rainbow/broken rainbow/chardev_link @@ -25,3 +24,4 @@ rainbow/upper.GZ rainbow/upper.TAR rainbow/upper.TAR.GZ +rainbow/ow diff --git a/tests/bfs/color_st_tw_ow0.out b/tests/bfs/color_st_tw_ow0.out index f1059dd..6e4a260 100644 --- a/tests/bfs/color_st_tw_ow0.out +++ b/tests/bfs/color_st_tw_ow0.out @@ -1,8 +1,7 @@ +$'rainbow/\e[1m' $'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/exec.sh -rainbow/$'\e[1m' -rainbow/ow rainbow/socket rainbow/broken rainbow/chardev_link @@ -25,3 +24,4 @@ rainbow/upper.GZ rainbow/upper.TAR rainbow/upper.TAR.GZ +rainbow/ow diff --git a/tests/bfs/color_su0_sg.out b/tests/bfs/color_su0_sg.out index 31d5108..d13b6b6 100644 --- a/tests/bfs/color_su0_sg.out +++ b/tests/bfs/color_su0_sg.out @@ -1,7 +1,7 @@ +$'rainbow/\e[1m' $'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/exec.sh -rainbow/$'\e[1m' rainbow/socket rainbow/broken rainbow/chardev_link diff --git a/tests/bfs/color_su0_sg0.out b/tests/bfs/color_su0_sg0.out index 4804030..77fba58 100644 --- a/tests/bfs/color_su0_sg0.out +++ b/tests/bfs/color_su0_sg0.out @@ -1,7 +1,7 @@ +$'rainbow/\e[1m' $'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/exec.sh -rainbow/$'\e[1m' rainbow/socket rainbow/broken rainbow/chardev_link diff --git a/tests/bfs/color_su_sg0.out b/tests/bfs/color_su_sg0.out index 3dbc7fe..8fab046 100644 --- a/tests/bfs/color_su_sg0.out +++ b/tests/bfs/color_su_sg0.out @@ -1,7 +1,7 @@ +$'rainbow/\e[1m' $'rainbow/\e[1m/'$'\e[0m' rainbow rainbow/exec.sh -rainbow/$'\e[1m' rainbow/socket rainbow/broken rainbow/chardev_link diff --git a/tests/bfs/printf_color.out b/tests/bfs/printf_color.out index 0468f7d..6641e9a 100644 --- a/tests/bfs/printf_color.out +++ b/tests/bfs/printf_color.out @@ -1,5 +1,7 @@ -. . rainbow ./rainbow rainbow +. $'./rainbow/\e[1m' $'\e[0m' $'./rainbow/\e[1m/'$'\e[0m' $'rainbow/\e[1m/'$'\e[0m' +. . rainbow ./rainbow rainbow . ./rainbow exec.sh ./rainbow/exec.sh rainbow/exec.sh +. ./rainbow $'\e[1m' $'./rainbow/\e[1m' $'rainbow/\e[1m' . ./rainbow socket ./rainbow/socket rainbow/socket . ./rainbow broken ./rainbow/broken rainbow/broken nowhere . ./rainbow chardev_link ./rainbow/chardev_link rainbow/chardev_link /dev/null -- cgit v1.2.3 From b4c3201ccceb9c73dd7751d7f9937b4afe78966f Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 13 Jul 2023 16:00:02 -0400 Subject: color: Only highlight the trailing slash on ENOTDIR --- src/color.c | 6 ++++-- tests/bfs/color_ls.out | 4 ++-- tests/bfs/color_ls.sh | 6 +++--- 3 files changed, 9 insertions(+), 7 deletions(-) (limited to 'src/color.c') diff --git a/src/color.c b/src/color.c index 7d98978..f7a5d86 100644 --- a/src/color.c +++ b/src/color.c @@ -982,8 +982,10 @@ static ssize_t first_broken_offset(const char *path, const struct BFTW *ftwbuf, while (ret && at_path[len - 1] == '/') { --len, --ret; } - while (ret && at_path[len - 1] != '/') { - --len, --ret; + if (errno != ENOTDIR) { + while (ret && at_path[len - 1] != '/') { + --len, --ret; + } } dstresize(&at_path, len); diff --git a/tests/bfs/color_ls.out b/tests/bfs/color_ls.out index b5216c4..f69eb9c 100644 --- a/tests/bfs/color_ls.out +++ b/tests/bfs/color_ls.out @@ -2,11 +2,11 @@ scratch/foo/bar /__bfs__/nowhere /__bfs__/nowhere -foo/bar/baz/qux -foo/bar/baz/qux foo/bar/nowhere foo/bar/nowhere foo/bar/nowhere/nothing foo/bar/nowhere/nothing foo/bar/baz foo/bar/baz +foo/bar/baz//qux +foo/bar/baz//qux diff --git a/tests/bfs/color_ls.sh b/tests/bfs/color_ls.sh index 37d088f..f2d3c72 100644 --- a/tests/bfs/color_ls.sh +++ b/tests/bfs/color_ls.sh @@ -3,13 +3,13 @@ clean_scratch ln -s foo/bar/baz scratch/link ln -s foo/bar/nowhere scratch/broken ln -s foo/bar/nowhere/nothing scratch/nested -ln -s foo/bar/baz/qux scratch/notdir +ln -s foo/bar/baz//qux scratch/notdir ln -s scratch/foo/bar scratch/relative mkdir scratch/__bfs__ ln -s /__bfs__/nowhere scratch/absolute -LS_COLORS="or=01;31:" invoke_bfs scratch/{,link,broken,nested,notdir,relative,absolute} -color -type l -ls \ +export LS_COLORS="or=01;31:" +invoke_bfs scratch/{,link,broken,nested,notdir,relative,absolute} -color -type l -ls \ | sed 's/.* -> //' \ | sort >"$OUT" - diff_output -- cgit v1.2.3 From 345047be5b8766a9763d4a717ff034e4e4083ade Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 31 Aug 2023 10:16:35 -0400 Subject: trie: New trie_clear() function --- src/color.c | 3 +-- src/trie.c | 8 ++++++++ src/trie.h | 5 +++++ 3 files changed, 14 insertions(+), 2 deletions(-) (limited to 'src/color.c') diff --git a/src/color.c b/src/color.c index f7a5d86..b9a788b 100644 --- a/src/color.c +++ b/src/color.c @@ -326,8 +326,7 @@ fail: /** Rebuild the case-insensitive trie after all extensions have been parsed. */ static int build_iext_trie(struct colors *colors) { - trie_destroy(&colors->iext_trie); - trie_init(&colors->iext_trie); + trie_clear(&colors->iext_trie); TRIE_FOR_EACH(&colors->ext_trie, leaf) { size_t len = leaf->length - 1; diff --git a/src/trie.c b/src/trie.c index 0206509..77aa2d0 100644 --- a/src/trie.c +++ b/src/trie.c @@ -715,6 +715,14 @@ void trie_remove(struct trie *trie, struct trie_leaf *leaf) { trie_remove_impl(trie, leaf); } +void trie_clear(struct trie *trie) { + trie->root = 0; + LIST_INIT(trie); + + varena_clear(&trie->leaves); + varena_clear(&trie->nodes); +} + void trie_destroy(struct trie *trie) { varena_destroy(&trie->leaves); varena_destroy(&trie->nodes); diff --git a/src/trie.h b/src/trie.h index 6921f62..dfaae15 100644 --- a/src/trie.h +++ b/src/trie.h @@ -128,6 +128,11 @@ struct trie_leaf *trie_insert_mem(struct trie *trie, const void *key, size_t len */ void trie_remove(struct trie *trie, struct trie_leaf *leaf); +/** + * Remove all leaves from a trie. + */ +void trie_clear(struct trie *trie); + /** * Destroy a trie and its contents. */ -- cgit v1.2.3 From 76253d272c50ba08002a47395e47a4f9ce4fb53e Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Mon, 25 Sep 2023 13:58:19 -0400 Subject: Use the new list macros --- src/bftw.c | 24 +++++++++++------------- src/color.c | 2 +- src/ctx.c | 4 ++-- src/trie.h | 7 +++---- src/xspawn.c | 11 +++++------ tests/trie.c | 4 ++-- 6 files changed, 24 insertions(+), 28 deletions(-) (limited to 'src/color.c') diff --git a/src/bftw.c b/src/bftw.c index e6b8cd5..f3060ce 100644 --- a/src/bftw.c +++ b/src/bftw.c @@ -318,8 +318,7 @@ static size_t bftw_child_nameoff(const struct bftw_file *parent) { /** Destroy a cache. */ static void bftw_cache_destroy(struct bftw_cache *cache) { - bfs_assert(!cache->head); - bfs_assert(!cache->tail); + bfs_assert(LIST_EMPTY(cache)); bfs_assert(!cache->target); varena_destroy(&cache->files); @@ -347,9 +346,9 @@ static struct bftw_file *bftw_file_new(struct bftw_cache *cache, struct bftw_fil file->nameoff = 0; } - file->next = NULL; - file->to_read.next = NULL; - file->lru.prev = file->lru.next = NULL; + SLIST_ITEM_INIT(file); + SLIST_ITEM_INIT(file, to_read); + LIST_ITEM_INIT(file, lru); file->refcount = 1; file->pincount = 0; @@ -833,12 +832,11 @@ static void bftw_push_dir(struct bftw_state *state, struct bftw_file *file) { SLIST_APPEND(&state->to_read, file, to_read); } - while (state->to_open.head) { - if (bftw_ioq_opendir(state, state->to_open.head) == 0) { - SLIST_POP(&state->to_open); - } else { + for_slist (struct bftw_file, dir, &state->to_open) { + if (bftw_ioq_opendir(state, dir) != 0) { break; } + SLIST_POP(&state->to_open); } } @@ -847,7 +845,7 @@ static bool bftw_pop_dir(struct bftw_state *state) { bfs_assert(!state->file); struct bftw_cache *cache = &state->cache; - bool have_files = state->to_visit.head; + bool have_files = !SLIST_EMPTY(&state->to_visit); if (state->flags & BFTW_SORT) { // Keep strict breadth-first order when sorting @@ -855,9 +853,9 @@ static bool bftw_pop_dir(struct bftw_state *state) { return false; } } else { - while (!state->to_read.head) { + while (SLIST_EMPTY(&state->to_read)) { // Block if we have no other files/dirs to visit, or no room in the cache - bool have_dirs = state->to_open.head; + bool have_dirs = !SLIST_EMPTY(&state->to_open); bool have_room = cache->capacity > 0 && cache->dirlimit > 0; bool block = !(have_dirs || have_files) || !have_room; @@ -1303,7 +1301,7 @@ static void bftw_list_sort(struct bftw_list *list) { bftw_list_sort(&right); // Merge - while (left.head && right.head) { + while (!SLIST_EMPTY(&left) && !SLIST_EMPTY(&right)) { struct bftw_file *lf = left.head; struct bftw_file *rf = right.head; diff --git a/src/color.c b/src/color.c index b9a788b..5e78c6c 100644 --- a/src/color.c +++ b/src/color.c @@ -328,7 +328,7 @@ fail: static int build_iext_trie(struct colors *colors) { trie_clear(&colors->iext_trie); - TRIE_FOR_EACH(&colors->ext_trie, leaf) { + for_trie (leaf, &colors->ext_trie) { size_t len = leaf->length - 1; if (colors->ext_len < len) { colors->ext_len = len; diff --git a/src/ctx.c b/src/ctx.c index a940bed..3a44e68 100644 --- a/src/ctx.c +++ b/src/ctx.c @@ -152,7 +152,7 @@ void bfs_ctx_flush(const struct bfs_ctx *ctx) { // - the user sees everything relevant before an -ok[dir] prompt // - output from commands is interleaved consistently with bfs // - executed commands can rely on I/O from other bfs actions - TRIE_FOR_EACH(&ctx->files, leaf) { + for_trie (leaf, &ctx->files) { struct bfs_ctx_file *ctx_file = leaf->value; CFILE *cfile = ctx_file->cfile; if (fflush(cfile->file) == 0) { @@ -239,7 +239,7 @@ int bfs_ctx_free(struct bfs_ctx *ctx) { bfs_groups_free(ctx->groups); bfs_users_free(ctx->users); - TRIE_FOR_EACH(&ctx->files, leaf) { + for_trie (leaf, &ctx->files) { struct bfs_ctx_file *ctx_file = leaf->value; if (ctx_file->error) { diff --git a/src/trie.h b/src/trie.h index dfaae15..2f51db5 100644 --- a/src/trie.h +++ b/src/trie.h @@ -6,6 +6,7 @@ #include "config.h" #include "alloc.h" +#include "list.h" #include #include @@ -141,9 +142,7 @@ void trie_destroy(struct trie *trie); /** * Iterate over the leaves of a trie. */ -#define TRIE_FOR_EACH(trie, leaf) \ - for (struct trie_leaf *leaf = (trie)->head, *_next; \ - leaf && (_next = leaf->next, true); \ - leaf = _next) +#define for_trie(leaf, trie) \ + for_list(struct trie_leaf, leaf, trie) #endif // BFS_TRIE_H diff --git a/src/xspawn.c b/src/xspawn.c index 2cabdcc..80bafef 100644 --- a/src/xspawn.c +++ b/src/xspawn.c @@ -49,8 +49,8 @@ int bfs_spawn_init(struct bfs_spawn *ctx) { } int bfs_spawn_destroy(struct bfs_spawn *ctx) { - while (ctx->head) { - free(SLIST_POP(ctx)); + for_slist (struct bfs_spawn_action, action, ctx) { + free(action); } return 0; @@ -68,7 +68,7 @@ static struct bfs_spawn_action *bfs_spawn_add(struct bfs_spawn *ctx, enum bfs_sp return NULL; } - action->next = NULL; + SLIST_ITEM_INIT(action); action->op = op; action->in_fd = -1; action->out_fd = -1; @@ -138,7 +138,7 @@ int bfs_spawn_addsetrlimit(struct bfs_spawn *ctx, int resource, const struct rli static void bfs_spawn_exec(const char *exe, const struct bfs_spawn *ctx, char **argv, char **envp, int pipefd[2]) { xclose(pipefd[0]); - for (const struct bfs_spawn_action *action = ctx ? ctx->head : NULL; action; action = action->next) { + for_slist (const struct bfs_spawn_action, action, ctx) { // Move the error-reporting pipe out of the way if necessary... if (action->out_fd == pipefd[1]) { int fd = dup_cloexec(pipefd[1]); @@ -199,9 +199,8 @@ pid_t bfs_spawn(const char *exe, const struct bfs_spawn *ctx, char **argv, char envp = environ; } - enum bfs_spawn_flags flags = ctx ? ctx->flags : 0; char *resolved = NULL; - if (flags & BFS_SPAWN_USEPATH) { + if (ctx->flags & BFS_SPAWN_USEPATH) { exe = resolved = bfs_spawn_resolve(exe); if (!resolved) { return -1; diff --git a/tests/trie.c b/tests/trie.c index e687f96..6ea94a2 100644 --- a/tests/trie.c +++ b/tests/trie.c @@ -70,7 +70,7 @@ int main(void) { { size_t i = 0; - TRIE_FOR_EACH(&trie, leaf) { + for_trie (leaf, &trie) { bfs_verify(leaf == trie_find_str(&trie, keys[i])); bfs_verify(!leaf->prev || leaf->prev->next == leaf); bfs_verify(!leaf->next || leaf->next->prev == leaf); @@ -107,7 +107,7 @@ int main(void) { } } - TRIE_FOR_EACH(&trie, leaf) { + for_trie (leaf, &trie) { bfs_verify(false); } -- cgit v1.2.3 From dccb52556730ff060bcccbe764cef4b13b3d5712 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Tue, 26 Sep 2023 12:48:21 -0400 Subject: dstring: New dchar typedef for dynamic strings --- src/bar.c | 2 +- src/bftw.c | 2 +- src/color.c | 6 +++--- src/color.h | 3 ++- src/diag.c | 2 +- src/dstring.c | 55 ++++++++++++++++++++++++++------------------------- src/dstring.h | 63 ++++++++++++++++++++++++++++++++++++++--------------------- src/eval.c | 4 ++-- src/exec.c | 4 ++-- src/fsade.c | 4 ++-- src/printf.c | 4 ++-- 11 files changed, 85 insertions(+), 64 deletions(-) (limited to 'src/color.c') diff --git a/src/bar.c b/src/bar.c index d2c663c..e0b9393 100644 --- a/src/bar.c +++ b/src/bar.c @@ -129,7 +129,7 @@ BFS_FORMATTER(2, 3) static int bfs_bar_printf(struct bfs_bar *bar, const char *format, ...) { va_list args; va_start(args, format); - char *str = dstrvprintf(format, args); + dchar *str = dstrvprintf(format, args); va_end(args); if (!str) { diff --git a/src/bftw.c b/src/bftw.c index f3060ce..5e5f4a5 100644 --- a/src/bftw.c +++ b/src/bftw.c @@ -435,7 +435,7 @@ struct bftw_state { struct bftw_list batch; /** The current path. */ - char *path; + dchar *path; /** The current file. */ struct bftw_file *file; /** The previous file. */ diff --git a/src/color.c b/src/color.c index 5e78c6c..8d0b995 100644 --- a/src/color.c +++ b/src/color.c @@ -558,8 +558,8 @@ static int unescape(char **str, const char *value, char end, const char **next) /** Parse the GNU $LS_COLORS format. */ static int parse_gnu_ls_colors(struct colors *colors, const char *ls_colors) { int ret = -1; - char *key = NULL; - char *value = NULL; + dchar *key = NULL; + dchar *value = NULL; for (const char *chunk = ls_colors, *next; chunk; chunk = next) { if (chunk[0] == '*') { @@ -943,7 +943,7 @@ static ssize_t first_broken_offset(const char *path, const struct BFTW *ftwbuf, goto out; } - char *at_path; + dchar *at_path; int at_fd; if (path == ftwbuf->path) { if (ftwbuf->depth == 0) { diff --git a/src/color.h b/src/color.h index 0d46c33..b118f77 100644 --- a/src/color.h +++ b/src/color.h @@ -9,6 +9,7 @@ #define BFS_COLOR_H #include "config.h" +#include "dstring.h" #include #include @@ -41,7 +42,7 @@ typedef struct CFILE { /** The color table to use, if any. */ const struct colors *colors; /** A buffer for colored formatting. */ - char *buffer; + dchar *buffer; /** Whether the next ${rs} is actually necessary. */ bool need_reset; /** Whether to close the underlying stream. */ diff --git a/src/diag.c b/src/diag.c index 0590847..fa9db39 100644 --- a/src/diag.c +++ b/src/diag.c @@ -158,7 +158,7 @@ static void bfs_argv_diag(const struct bfs_ctx *ctx, const bool args[], bool war bfs_error_prefix(ctx); } - char **argv = ZALLOC_ARRAY(char *, ctx->argc); + dchar **argv = ZALLOC_ARRAY(dchar *, ctx->argc); if (!argv) { return; } diff --git a/src/dstring.c b/src/dstring.c index 60a7df9..ef4e733 100644 --- a/src/dstring.c +++ b/src/dstring.c @@ -4,6 +4,7 @@ #include "dstring.h" #include "alloc.h" #include "bit.h" +#include "config.h" #include "diag.h" #include #include @@ -16,11 +17,11 @@ struct dstring { size_t capacity; size_t length; - char data[]; + alignas(dchar) char data[]; }; /** Get the string header from the string data pointer. */ -static struct dstring *dstrheader(const char *dstr) { +static struct dstring *dstrheader(const dchar *dstr) { return (struct dstring *)(dstr - offsetof(struct dstring, data)); } @@ -30,7 +31,7 @@ static size_t dstrsize(size_t capacity) { } /** Allocate a dstring with the given contents. */ -static char *dstralloc_impl(size_t capacity, size_t length, const char *data) { +static dchar *dstralloc_impl(size_t capacity, size_t length, const char *data) { // Avoid reallocations for small strings if (capacity < 7) { capacity = 7; @@ -49,31 +50,31 @@ static char *dstralloc_impl(size_t capacity, size_t length, const char *data) { return header->data; } -char *dstralloc(size_t capacity) { +dchar *dstralloc(size_t capacity) { return dstralloc_impl(capacity, 0, ""); } -char *dstrdup(const char *str) { +dchar *dstrdup(const char *str) { return dstrxdup(str, strlen(str)); } -char *dstrndup(const char *str, size_t n) { +dchar *dstrndup(const char *str, size_t n) { return dstrxdup(str, strnlen(str, n)); } -char *dstrddup(const char *dstr) { +dchar *dstrddup(const dchar *dstr) { return dstrxdup(dstr, dstrlen(dstr)); } -char *dstrxdup(const char *str, size_t len) { +dchar *dstrxdup(const char *str, size_t len) { return dstralloc_impl(len, len, str); } -size_t dstrlen(const char *dstr) { +size_t dstrlen(const dchar *dstr) { return dstrheader(dstr)->length; } -int dstreserve(char **dstr, size_t capacity) { +int dstreserve(dchar **dstr, size_t capacity) { if (!*dstr) { *dstr = dstralloc(capacity); return *dstr ? 0 : -1; @@ -96,7 +97,7 @@ int dstreserve(char **dstr, size_t capacity) { return 0; } -int dstresize(char **dstr, size_t length) { +int dstresize(dchar **dstr, size_t length) { if (dstreserve(dstr, length) != 0) { return -1; } @@ -107,19 +108,19 @@ int dstresize(char **dstr, size_t length) { return 0; } -int dstrcat(char **dest, const char *src) { +int dstrcat(dchar **dest, const char *src) { return dstrxcat(dest, src, strlen(src)); } -int dstrncat(char **dest, const char *src, size_t n) { +int dstrncat(dchar **dest, const char *src, size_t n) { return dstrxcat(dest, src, strnlen(src, n)); } -int dstrdcat(char **dest, const char *src) { +int dstrdcat(dchar **dest, const dchar *src) { return dstrxcat(dest, src, dstrlen(src)); } -int dstrxcat(char **dest, const char *src, size_t len) { +int dstrxcat(dchar **dest, const char *src, size_t len) { size_t oldlen = dstrlen(*dest); size_t newlen = oldlen + len; @@ -131,23 +132,23 @@ int dstrxcat(char **dest, const char *src, size_t len) { return 0; } -int dstrapp(char **str, char c) { +int dstrapp(dchar **str, char c) { return dstrxcat(str, &c, 1); } -int dstrcpy(char **dest, const char *src) { +int dstrcpy(dchar **dest, const char *src) { return dstrxcpy(dest, src, strlen(src)); } -int dstrncpy(char **dest, const char *src, size_t n) { +int dstrncpy(dchar **dest, const char *src, size_t n) { return dstrxcpy(dest, src, strnlen(src, n)); } -int dstrdcpy(char **dest, const char *src) { +int dstrdcpy(dchar **dest, const dchar *src) { return dstrxcpy(dest, src, dstrlen(src)); } -int dstrxcpy(char **dest, const char *src, size_t len) { +int dstrxcpy(dchar **dest, const char *src, size_t len) { if (dstresize(dest, len) != 0) { return -1; } @@ -160,7 +161,7 @@ char *dstrprintf(const char *format, ...) { va_list args; va_start(args, format); - char *str = dstrvprintf(format, args); + dchar *str = dstrvprintf(format, args); va_end(args); return str; @@ -168,7 +169,7 @@ char *dstrprintf(const char *format, ...) { char *dstrvprintf(const char *format, va_list args) { // Guess a capacity to try to avoid reallocating - char *str = dstralloc(2*strlen(format)); + dchar *str = dstralloc(2*strlen(format)); if (!str) { return NULL; } @@ -181,7 +182,7 @@ char *dstrvprintf(const char *format, va_list args) { return str; } -int dstrcatf(char **str, const char *format, ...) { +int dstrcatf(dchar **str, const char *format, ...) { va_list args; va_start(args, format); @@ -191,7 +192,7 @@ int dstrcatf(char **str, const char *format, ...) { return ret; } -int dstrvcatf(char **str, const char *format, va_list args) { +int dstrvcatf(dchar **str, const char *format, va_list args) { // Guess a capacity to try to avoid calling vsnprintf() twice size_t len = dstrlen(*str); dstreserve(str, len + 2*strlen(format)); @@ -232,11 +233,11 @@ fail: return -1; } -int dstrescat(char **dest, const char *str, enum wesc_flags flags) { +int dstrescat(dchar **dest, const char *str, enum wesc_flags flags) { return dstrnescat(dest, str, SIZE_MAX, flags); } -int dstrnescat(char **dest, const char *str, size_t n, enum wesc_flags flags) { +int dstrnescat(dchar **dest, const char *str, size_t n, enum wesc_flags flags) { size_t len = *dest ? dstrlen(*dest) : 0; // Worst case growth is `ccc...` => $'\xCC\xCC\xCC...' @@ -254,7 +255,7 @@ int dstrnescat(char **dest, const char *str, size_t n, enum wesc_flags flags) { return dstresize(dest, cur - *dest); } -void dstrfree(char *dstr) { +void dstrfree(dchar *dstr) { if (dstr) { free(dstrheader(dstr)); } diff --git a/src/dstring.h b/src/dstring.h index 88ca79f..91a600c 100644 --- a/src/dstring.h +++ b/src/dstring.h @@ -13,13 +13,32 @@ #include #include +/** Marker type for dynamic strings. */ +#if __clang__ +// Abuse __attribute__(aligned) to make a type that allows +// +// dchar * -> char * +// +// conversions, but warns on +// +// char * -> dchar * +// +// (with Clang's -Walign-mismatch). The alignment is not a lie, due to the +// layout of struct dstring, but we only enable this on Clang because GCC +// tracks alignment through array accesses, reporting UBSan errors on (and +// maybe even miscompiling) dstr[1]. +typedef __attribute__((aligned(alignof(size_t)))) char dchar; +#else +typedef char dchar; +#endif + /** * Allocate a dynamic string. * * @param capacity * The initial capacity of the string. */ -char *dstralloc(size_t capacity); +dchar *dstralloc(size_t capacity); /** * Create a dynamic copy of a string. @@ -27,7 +46,7 @@ char *dstralloc(size_t capacity); * @param str * The NUL-terminated string to copy. */ -char *dstrdup(const char *str); +dchar *dstrdup(const char *str); /** * Create a length-limited dynamic copy of a string. @@ -37,7 +56,7 @@ char *dstrdup(const char *str); * @param n * The maximum number of characters to copy from str. */ -char *dstrndup(const char *str, size_t n); +dchar *dstrndup(const char *str, size_t n); /** * Create a dynamic copy of a dynamic string. @@ -45,7 +64,7 @@ char *dstrndup(const char *str, size_t n); * @param dstr * The dynamic string to copy. */ -char *dstrddup(const char *dstr); +dchar *dstrddup(const dchar *dstr); /** * Create an exact-sized dynamic copy of a string. @@ -55,7 +74,7 @@ char *dstrddup(const char *dstr); * @param len * The length of the string, which may include internal NUL bytes. */ -char *dstrxdup(const char *str, size_t len); +dchar *dstrxdup(const char *str, size_t len); /** * Get a dynamic string's length. @@ -65,7 +84,7 @@ char *dstrxdup(const char *str, size_t len); * @return * The length of dstr. */ -size_t dstrlen(const char *dstr); +size_t dstrlen(const dchar *dstr); /** * Reserve some capacity in a dynamic string. @@ -77,7 +96,7 @@ size_t dstrlen(const char *dstr); * @return * 0 on success, -1 on failure. */ -int dstreserve(char **dstr, size_t capacity); +int dstreserve(dchar **dstr, size_t capacity); /** * Resize a dynamic string. @@ -89,7 +108,7 @@ int dstreserve(char **dstr, size_t capacity); * @return * 0 on success, -1 on failure. */ -int dstresize(char **dstr, size_t length); +int dstresize(dchar **dstr, size_t length); /** * Append to a dynamic string. @@ -100,7 +119,7 @@ int dstresize(char **dstr, size_t length); * The string to append. * @return 0 on success, -1 on failure. */ -int dstrcat(char **dest, const char *src); +int dstrcat(dchar **dest, const char *src); /** * Append to a dynamic string. @@ -114,7 +133,7 @@ int dstrcat(char **dest, const char *src); * @return * 0 on success, -1 on failure. */ -int dstrncat(char **dest, const char *src, size_t n); +int dstrncat(dchar **dest, const char *src, size_t n); /** * Append a dynamic string to another dynamic string. @@ -126,7 +145,7 @@ int dstrncat(char **dest, const char *src, size_t n); * @return * 0 on success, -1 on failure. */ -int dstrdcat(char **dest, const char *src); +int dstrdcat(dchar **dest, const dchar *src); /** * Append to a dynamic string. @@ -140,7 +159,7 @@ int dstrdcat(char **dest, const char *src); * @return * 0 on success, -1 on failure. */ -int dstrxcat(char **dest, const char *src, size_t len); +int dstrxcat(dchar **dest, const char *src, size_t len); /** * Append a single character to a dynamic string. @@ -152,7 +171,7 @@ int dstrxcat(char **dest, const char *src, size_t len); * @return * 0 on success, -1 on failure. */ -int dstrapp(char **str, char c); +int dstrapp(dchar **str, char c); /** * Copy a string into a dynamic string. @@ -164,7 +183,7 @@ int dstrapp(char **str, char c); * @returns * 0 on success, -1 on failure. */ -int dstrcpy(char **dest, const char *str); +int dstrcpy(dchar **dest, const char *str); /** * Copy a dynamic string into another one. @@ -176,7 +195,7 @@ int dstrcpy(char **dest, const char *str); * @returns * 0 on success, -1 on failure. */ -int dstrdcpy(char **dest, const char *str); +int dstrdcpy(dchar **dest, const dchar *str); /** * Copy a string into a dynamic string. @@ -190,7 +209,7 @@ int dstrdcpy(char **dest, const char *str); * @returns * 0 on success, -1 on failure. */ -int dstrncpy(char **dest, const char *str, size_t n); +int dstrncpy(dchar **dest, const char *str, size_t n); /** * Copy a string into a dynamic string. @@ -204,7 +223,7 @@ int dstrncpy(char **dest, const char *str, size_t n); * @returns * 0 on success, -1 on failure. */ -int dstrxcpy(char **dest, const char *str, size_t len); +int dstrxcpy(dchar **dest, const char *str, size_t len); /** * Create a dynamic string from a format string. @@ -245,7 +264,7 @@ char *dstrvprintf(const char *format, va_list args); * 0 on success, -1 on failure. */ BFS_FORMATTER(2, 3) -int dstrcatf(char **str, const char *format, ...); +int dstrcatf(dchar **str, const char *format, ...); /** * Format some text from a va_list onto the end of a dynamic string. @@ -260,7 +279,7 @@ int dstrcatf(char **str, const char *format, ...); * 0 on success, -1 on failure. */ BFS_FORMATTER(2, 0) -int dstrvcatf(char **str, const char *format, va_list args); +int dstrvcatf(dchar **str, const char *format, va_list args); /** * Concatenate while shell-escaping. @@ -274,7 +293,7 @@ int dstrvcatf(char **str, const char *format, va_list args); * @return * 0 on success, -1 on failure. */ -int dstrescat(char **dest, const char *str, enum wesc_flags flags); +int dstrescat(dchar **dest, const char *str, enum wesc_flags flags); /** * Concatenate while shell-escaping. @@ -290,7 +309,7 @@ int dstrescat(char **dest, const char *str, enum wesc_flags flags); * @return * 0 on success, -1 on failure. */ -int dstrnescat(char **dest, const char *str, size_t n, enum wesc_flags flags); +int dstrnescat(dchar **dest, const char *str, size_t n, enum wesc_flags flags); /** * Free a dynamic string. @@ -298,6 +317,6 @@ int dstrnescat(char **dest, const char *str, size_t n, enum wesc_flags flags); * @param dstr * The string to free. */ -void dstrfree(char *dstr); +void dstrfree(dchar *dstr); #endif // BFS_DSTRING_H diff --git a/src/eval.c b/src/eval.c index 0faf533..3550751 100644 --- a/src/eval.c +++ b/src/eval.c @@ -1115,7 +1115,7 @@ static void eval_status(struct bfs_eval *state, struct bfs_bar *bar, struct time const struct BFTW *ftwbuf = state->ftwbuf; - char *rhs = dstrprintf(" (visited: %zu, depth: %2zu)", count, ftwbuf->depth); + dchar *rhs = dstrprintf(" (visited: %zu, depth: %2zu)", count, ftwbuf->depth); if (!rhs) { return; } @@ -1126,7 +1126,7 @@ static void eval_status(struct bfs_eval *state, struct bfs_bar *bar, struct time rhslen = 0; } - char *status = dstralloc(0); + dchar *status = dstralloc(0); if (!status) { goto out_rhs; } diff --git a/src/exec.c b/src/exec.c index ea7f897..7b55522 100644 --- a/src/exec.c +++ b/src/exec.c @@ -227,7 +227,7 @@ static char *bfs_exec_format_arg(char *arg, const char *path) { return arg; } - char *ret = dstralloc(0); + dchar *ret = dstralloc(0); if (!ret) { return NULL; } @@ -259,7 +259,7 @@ err: /** Free a formatted argument. */ static void bfs_exec_free_arg(char *arg, const char *tmpl) { if (arg != tmpl) { - dstrfree(arg); + dstrfree((dchar *)arg); } } diff --git a/src/fsade.c b/src/fsade.c index c401426..8dec5a8 100644 --- a/src/fsade.c +++ b/src/fsade.c @@ -37,7 +37,7 @@ static const char *fake_at(const struct BFTW *ftwbuf) { static atomic int proc_works = -1; - char *path = NULL; + dchar *path = NULL; if (ftwbuf->at_fd == AT_FDCWD || load(&proc_works, relaxed) == 0) { goto fail; } @@ -69,7 +69,7 @@ fail: static void free_fake_at(const struct BFTW *ftwbuf, const char *path) { if (path != ftwbuf->path) { - dstrfree((char *)path); + dstrfree((dchar *)path); } } diff --git a/src/printf.c b/src/printf.c index f0910fa..5de5a28 100644 --- a/src/printf.c +++ b/src/printf.c @@ -38,7 +38,7 @@ struct bfs_printf { /** The printing function to invoke. */ bfs_printf_fn *fn; /** String data associated with this directive. */ - char *str; + dchar *str; /** The stat field to print. */ enum bfs_stat_field stat_field; /** Character data associated with this directive. */ @@ -596,7 +596,7 @@ static int append_directive(const struct bfs_ctx *ctx, struct bfs_printf **forma int bfs_printf_parse(const struct bfs_ctx *ctx, struct bfs_expr *expr, const char *format) { expr->printf = NULL; - char *literal = dstralloc(0); + dchar *literal = dstralloc(0); if (!literal) { bfs_perror(ctx, "dstralloc()"); goto error; -- cgit v1.2.3 From 52de184ba28551734e1cb13233588504ab5f62ec Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Wed, 27 Sep 2023 12:11:15 -0400 Subject: Formatting fixes --- src/color.c | 6 +++--- src/ctx.c | 1 - src/darray.c | 4 ++-- src/diag.c | 8 ++++---- src/diag.h | 2 +- src/dstring.c | 4 ++-- src/eval.c | 15 +++++++-------- src/exec.c | 16 ++++++++-------- src/fsade.c | 6 +++--- src/ioq.c | 2 +- src/opt.c | 11 +++++------ src/opt.h | 1 - src/parse.c | 45 ++++++++++++++++++++++----------------------- src/printf.c | 46 +++++++++++++++++++++++----------------------- src/pwcache.c | 1 - src/stat.c | 2 +- src/trie.c | 2 +- src/trie.h | 4 ++-- src/xregex.c | 2 +- src/xspawn.c | 2 +- src/xtime.c | 12 ++++++------ tests/bfstd.c | 2 +- tests/mksock.c | 2 +- tests/trie.c | 4 ++-- tests/xtimegm.c | 6 +++--- 25 files changed, 100 insertions(+), 106 deletions(-) (limited to 'src/color.c') diff --git a/src/color.c b/src/color.c index 8d0b995..788d35d 100644 --- a/src/color.c +++ b/src/color.c @@ -1143,11 +1143,11 @@ static int print_expr(CFILE *cfile, const struct bfs_expr *expr, bool verbose) { if (verbose) { double rate = 0.0, time = 0.0; if (expr->evaluations) { - rate = 100.0*expr->successes/expr->evaluations; - time = (1.0e9*expr->elapsed.tv_sec + expr->elapsed.tv_nsec)/expr->evaluations; + rate = 100.0 * expr->successes / expr->evaluations; + time = (1.0e9 * expr->elapsed.tv_sec + expr->elapsed.tv_nsec) / expr->evaluations; } if (cbuff(cfile, " [${ylw}%zu${rs}/${ylw}%zu${rs}=${ylw}%g%%${rs}; ${ylw}%gns${rs}]", - expr->successes, expr->evaluations, rate, time)) { + expr->successes, expr->evaluations, rate, time)) { return -1; } } diff --git a/src/ctx.c b/src/ctx.c index 3a44e68..9a24a33 100644 --- a/src/ctx.c +++ b/src/ctx.c @@ -168,7 +168,6 @@ void bfs_ctx_flush(const struct bfs_ctx *ctx) { } else if (cfile == ctx->cout) { bfs_error(ctx, "(standard output): %m.\n"); } - } // Flush the user/group caches, in case the executed command edits the diff --git a/src/darray.c b/src/darray.c index 42b8397..3e66a55 100644 --- a/src/darray.c +++ b/src/darray.c @@ -55,7 +55,7 @@ void *darray_push(void *da, const void *item, size_t size) { size_t i = header->length++; if (i >= capacity) { capacity *= 2; - header = realloc(header, sizeof(*header) + capacity*size); + header = realloc(header, sizeof(*header) + capacity * size); if (!header) { // This failure will be detected by darray_check() return da; @@ -64,7 +64,7 @@ void *darray_push(void *da, const void *item, size_t size) { } char *data = darray_data(header); - memcpy(data + i*size, item, size); + memcpy(data + i * size, item, size); return data; } diff --git a/src/diag.c b/src/diag.c index fa9db39..fa66525 100644 --- a/src/diag.c +++ b/src/diag.c @@ -4,9 +4,9 @@ #include "diag.h" #include "alloc.h" #include "bfstd.h" -#include "ctx.h" #include "color.h" #include "config.h" +#include "ctx.h" #include "dstring.h" #include "expr.h" #include @@ -31,14 +31,14 @@ void bfs_perror(const struct bfs_ctx *ctx, const char *str) { bfs_error(ctx, "%s: %m.\n", str); } -void bfs_error(const struct bfs_ctx *ctx, const char *format, ...) { +void bfs_error(const struct bfs_ctx *ctx, const char *format, ...) { va_list args; va_start(args, format); bfs_verror(ctx, format, args); va_end(args); } -bool bfs_warning(const struct bfs_ctx *ctx, const char *format, ...) { +bool bfs_warning(const struct bfs_ctx *ctx, const char *format, ...) { va_list args; va_start(args, format); bool ret = bfs_vwarning(ctx, format, args); @@ -46,7 +46,7 @@ bool bfs_warning(const struct bfs_ctx *ctx, const char *format, ...) { return ret; } -bool bfs_debug(const struct bfs_ctx *ctx, enum debug_flags flag, const char *format, ...) { +bool bfs_debug(const struct bfs_ctx *ctx, enum debug_flags flag, const char *format, ...) { va_list args; va_start(args, format); bool ret = bfs_vdebug(ctx, flag, format, args); diff --git a/src/diag.h b/src/diag.h index e019db0..fea8847 100644 --- a/src/diag.h +++ b/src/diag.h @@ -8,8 +8,8 @@ #ifndef BFS_DIAG_H #define BFS_DIAG_H -#include "ctx.h" #include "config.h" +#include "ctx.h" #include /** diff --git a/src/dstring.c b/src/dstring.c index ef4e733..f947741 100644 --- a/src/dstring.c +++ b/src/dstring.c @@ -169,7 +169,7 @@ char *dstrprintf(const char *format, ...) { char *dstrvprintf(const char *format, va_list args) { // Guess a capacity to try to avoid reallocating - dchar *str = dstralloc(2*strlen(format)); + dchar *str = dstralloc(2 * strlen(format)); if (!str) { return NULL; } @@ -195,7 +195,7 @@ int dstrcatf(dchar **str, const char *format, ...) { int dstrvcatf(dchar **str, const char *format, va_list args) { // Guess a capacity to try to avoid calling vsnprintf() twice size_t len = dstrlen(*str); - dstreserve(str, len + 2*strlen(format)); + dstreserve(str, len + 2 * strlen(format)); size_t cap = dstrheader(*str)->capacity; va_list copy; diff --git a/src/eval.c b/src/eval.c index 3550751..9f4896a 100644 --- a/src/eval.c +++ b/src/eval.c @@ -239,7 +239,7 @@ bool eval_time(const struct bfs_expr *expr, struct bfs_eval *state) { time_t diff = timespec_diff(&expr->reftime, time); switch (expr->time_unit) { case BFS_DAYS: - diff /= 60*24; + diff /= 60 * 24; fallthru; case BFS_MINUTES: diff /= 60; @@ -271,7 +271,7 @@ bool eval_used(const struct bfs_expr *expr, struct bfs_eval *state) { return false; } - long long day_seconds = 60*60*24; + long long day_seconds = 60 * 60 * 24; diff = (diff + day_seconds - 1) / day_seconds; return bfs_expr_cmp(expr, diff); } @@ -685,7 +685,7 @@ bool eval_fls(const struct bfs_expr *expr, struct bfs_eval *state) { uintmax_t ino = statbuf->ino; uintmax_t block_size = ctx->posixly_correct ? 512 : 1024; - uintmax_t blocks = ((uintmax_t)statbuf->blocks*BFS_STAT_BLKSIZE + block_size - 1)/block_size; + uintmax_t blocks = ((uintmax_t)statbuf->blocks * BFS_STAT_BLKSIZE + block_size - 1) / block_size; char mode[11]; xstrmode(statbuf->mode, mode); char acl = bfs_check_acl(ftwbuf) > 0 ? '+' : ' '; @@ -721,8 +721,8 @@ bool eval_fls(const struct bfs_expr *expr, struct bfs_eval *state) { time_t time = statbuf->mtime.tv_sec; time_t now = ctx->now.tv_sec; - time_t six_months_ago = now - 6*30*24*60*60; - time_t tomorrow = now + 24*60*60; + time_t six_months_ago = now - 6 * 30 * 24 * 60 * 60; + time_t tomorrow = now + 24 * 60 * 60; struct tm tm; if (xlocaltime(&time, &tm) != 0) { goto error; @@ -823,7 +823,6 @@ bool eval_fprintx(const struct bfs_expr *expr, struct bfs_eval *state) { ++path; } - if (fputc('\n', file) == EOF) { goto error; } @@ -905,7 +904,7 @@ bool eval_size(const struct bfs_expr *expr, struct bfs_eval *state) { }; off_t scale = scales[expr->size_unit]; - off_t size = (statbuf->size + scale - 1)/scale; // Round up + off_t size = (statbuf->size + scale - 1) / scale; // Round up return bfs_expr_cmp(expr, size); } @@ -918,7 +917,7 @@ bool eval_sparse(const struct bfs_expr *expr, struct bfs_eval *state) { return false; } - blkcnt_t expected = (statbuf->size + BFS_STAT_BLKSIZE - 1)/BFS_STAT_BLKSIZE; + blkcnt_t expected = (statbuf->size + BFS_STAT_BLKSIZE - 1) / BFS_STAT_BLKSIZE; return statbuf->blocks < expected; } diff --git a/src/exec.c b/src/exec.c index 7b55522..0e0d585 100644 --- a/src/exec.c +++ b/src/exec.c @@ -5,9 +5,9 @@ #include "alloc.h" #include "bfstd.h" #include "bftw.h" -#include "ctx.h" #include "color.h" #include "config.h" +#include "ctx.h" #include "diag.h" #include "dstring.h" #include "xspawn.h" @@ -348,7 +348,7 @@ static int bfs_exec_spawn(const struct bfs_exec *execbuf) { if (execbuf->flags & BFS_EXEC_MULTI) { bfs_exec_debug(execbuf, "Executing '%s' ... [%zu arguments] (size %zu)\n", - execbuf->argv[0], execbuf->argc - 1, execbuf->arg_size); + execbuf->argv[0], execbuf->argc - 1, execbuf->arg_size); } else { bfs_exec_debug(execbuf, "Executing '%s' ... [%zu arguments]\n", execbuf->argv[0], execbuf->argc - 1); } @@ -471,7 +471,7 @@ static bool bfs_exec_args_remain(const struct bfs_exec *execbuf) { static size_t bfs_exec_estimate_max(const struct bfs_exec *execbuf) { size_t min = execbuf->arg_min; size_t max = execbuf->arg_max; - return min + (max - min)/2; + return min + (max - min) / 2; } /** Update the ARG_MAX lower bound from a successful execution. */ @@ -486,7 +486,7 @@ static void bfs_exec_update_min(struct bfs_exec *execbuf) { size_t estimate = bfs_exec_estimate_max(execbuf); bfs_exec_debug(execbuf, "ARG_MAX between [%zu, %zu], trying %zu\n", - execbuf->arg_min, execbuf->arg_max, estimate); + execbuf->arg_min, execbuf->arg_max, estimate); } } @@ -502,7 +502,7 @@ static size_t bfs_exec_update_max(struct bfs_exec *execbuf) { // Trim a fraction off the max size to avoid repeated failures near the // top end of the working range - size -= size/16; + size -= size / 16; if (size < execbuf->arg_max) { execbuf->arg_max = size; @@ -515,7 +515,7 @@ static size_t bfs_exec_update_max(struct bfs_exec *execbuf) { // Binary search for a more precise bound size_t estimate = bfs_exec_estimate_max(execbuf); bfs_exec_debug(execbuf, "ARG_MAX between [%zu, %zu], trying %zu\n", - execbuf->arg_min, execbuf->arg_max, estimate); + execbuf->arg_min, execbuf->arg_max, estimate); return estimate; } @@ -589,7 +589,7 @@ static bool bfs_exec_would_overflow(const struct bfs_exec *execbuf, const char * size_t next_size = execbuf->arg_size + bfs_exec_arg_size(arg); if (next_size > arg_max) { bfs_exec_debug(execbuf, "Command size (%zu) would exceed maximum (%zu), executing buffered command\n", - next_size, arg_max); + next_size, arg_max); return true; } @@ -601,7 +601,7 @@ static int bfs_exec_push(struct bfs_exec *execbuf, char *arg) { execbuf->argv[execbuf->argc] = arg; if (execbuf->argc + 1 >= execbuf->argv_cap) { - size_t cap = 2*execbuf->argv_cap; + size_t cap = 2 * execbuf->argv_cap; char **argv = realloc(execbuf->argv, sizeof_array(char *, cap)); if (!argv) { return -1; diff --git a/src/fsade.c b/src/fsade.c index 8dec5a8..cbff47b 100644 --- a/src/fsade.c +++ b/src/fsade.c @@ -3,9 +3,9 @@ #include "fsade.h" #include "atomic.h" -#include "config.h" #include "bfstd.h" #include "bftw.h" +#include "config.h" #include "dir.h" #include "dstring.h" #include "sanity.h" @@ -292,7 +292,7 @@ int bfs_check_xattrs(const struct BFTW *ftwbuf) { ssize_t len; #if BFS_USE_SYS_EXTATTR_H - ssize_t (*extattr_list)(const char *, int, void*, size_t) = + ssize_t (*extattr_list)(const char *, int, void *, size_t) = ftwbuf->type == BFS_LNK ? extattr_list_link : extattr_list_file; len = extattr_list(path, EXTATTR_NAMESPACE_SYSTEM, NULL, 0); @@ -331,7 +331,7 @@ int bfs_check_xattr_named(const struct BFTW *ftwbuf, const char *name) { ssize_t len; #if BFS_USE_SYS_EXTATTR_H - ssize_t (*extattr_get)(const char *, int, const char *, void*, size_t) = + ssize_t (*extattr_get)(const char *, int, const char *, void *, size_t) = ftwbuf->type == BFS_LNK ? extattr_get_link : extattr_get_file; len = extattr_get(path, EXTATTR_NAMESPACE_SYSTEM, name, NULL, 0); diff --git a/src/ioq.c b/src/ioq.c index f7ca8c6..d3ba2de 100644 --- a/src/ioq.c +++ b/src/ioq.c @@ -9,8 +9,8 @@ #include "config.h" #include "diag.h" #include "dir.h" -#include "thread.h" #include "sanity.h" +#include "thread.h" #include #include #include diff --git a/src/opt.c b/src/opt.c index 14de081..77c2798 100644 --- a/src/opt.c +++ b/src/opt.c @@ -535,8 +535,8 @@ static struct bfs_expr *optimize_and_expr(const struct opt_state *state, struct expr->pure = lhs->pure && rhs->pure; expr->always_true = lhs->always_true && rhs->always_true; expr->always_false = lhs->always_false || rhs->always_false; - expr->cost = lhs->cost + lhs->probability*rhs->cost; - expr->probability = lhs->probability*rhs->probability; + expr->cost = lhs->cost + lhs->probability * rhs->cost; + expr->probability = lhs->probability * rhs->probability; return expr; } @@ -606,8 +606,8 @@ static struct bfs_expr *optimize_or_expr(const struct opt_state *state, struct b expr->pure = lhs->pure && rhs->pure; expr->always_true = lhs->always_true || rhs->always_true; expr->always_false = lhs->always_false && rhs->always_false; - expr->cost = lhs->cost + (1 - lhs->probability)*rhs->cost; - expr->probability = lhs->probability + rhs->probability - lhs->probability*rhs->probability; + expr->cost = lhs->cost + (1 - lhs->probability) * rhs->cost; + expr->probability = lhs->probability + rhs->probability - lhs->probability * rhs->probability; return expr; } @@ -1078,7 +1078,6 @@ static const struct { {eval_xattrname, 0.01}, }; - /** * Table of simple predicates. */ @@ -1331,7 +1330,7 @@ static bool reorder_expr_recursive(const struct opt_state *state, struct bfs_exp if (expr->eval_fn == eval_and || expr->eval_fn == eval_or) { if (lhs->pure && rhs->pure) { float rhs_prob = expr->eval_fn == eval_and ? rhs->probability : 1.0 - rhs->probability; - float swapped_cost = rhs->cost + rhs_prob*lhs->cost; + float swapped_cost = rhs->cost + rhs_prob * lhs->cost; ret |= reorder_expr(state, expr, swapped_cost); } } diff --git a/src/opt.h b/src/opt.h index 28cadb9..4aac129 100644 --- a/src/opt.h +++ b/src/opt.h @@ -21,4 +21,3 @@ struct bfs_ctx; int bfs_optimize(struct bfs_ctx *ctx); #endif // BFS_OPT_H - diff --git a/src/parse.c b/src/parse.c index 3416d9e..7766a7b 100644 --- a/src/parse.c +++ b/src/parse.c @@ -41,8 +41,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -1797,10 +1797,10 @@ static int parse_reftime(const struct parser_state *state, struct bfs_expr *expr #else int gmtoff = -timezone; #endif - int tz_hour = gmtoff/3600; - int tz_min = (labs(gmtoff)/60)%60; + int tz_hour = gmtoff / 3600; + int tz_min = (labs(gmtoff) / 60) % 60; fprintf(stderr, " - %04d-%02d-%02dT%02d:%02d:%02d%+03d:%02d\n", - year, month, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, tz_hour, tz_min); + year, month, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, tz_hour, tz_min); if (xgmtime(&state->now.tv_sec, &tm) != 0) { parse_perror(state, "xgmtime()"); @@ -1832,8 +1832,8 @@ static struct bfs_expr *parse_newerxy(struct parser_state *state, int arg1, int expr->stat_field = parse_newerxy_field(arg[6]); if (!expr->stat_field) { parse_expr_error(state, expr, - "For ${blu}-newer${bld}XY${rs}, ${bld}X${rs} should be ${bld}a${rs}, ${bld}c${rs}, ${bld}m${rs}, or ${bld}B${rs}, not ${err}%c${rs}.\n", - arg[6]); + "For ${blu}-newer${bld}XY${rs}, ${bld}X${rs} should be ${bld}a${rs}, ${bld}c${rs}, ${bld}m${rs}, or ${bld}B${rs}, not ${err}%c${rs}.\n", + arg[6]); goto fail; } @@ -1845,8 +1845,8 @@ static struct bfs_expr *parse_newerxy(struct parser_state *state, int arg1, int enum bfs_stat_field field = parse_newerxy_field(arg[7]); if (!field) { parse_expr_error(state, expr, - "For ${blu}-newer${bld}XY${rs}, ${bld}Y${rs} should be ${bld}a${rs}, ${bld}c${rs}, ${bld}m${rs}, ${bld}B${rs}, or ${bld}t${rs}, not ${err}%c${rs}.\n", - arg[7]); + "For ${blu}-newer${bld}XY${rs}, ${bld}Y${rs} should be ${bld}a${rs}, ${bld}c${rs}, ${bld}m${rs}, ${bld}B${rs}, or ${bld}t${rs}, not ${err}%c${rs}.\n", + arg[7]); goto fail; } @@ -1855,7 +1855,6 @@ static struct bfs_expr *parse_newerxy(struct parser_state *state, int arg1, int goto fail; } - const struct timespec *reftime = bfs_stat_time(&sb, field); if (!reftime) { parse_expr_error(state, expr, "Couldn't get file %s.\n", bfs_stat_field_name(field)); @@ -1905,7 +1904,7 @@ static struct bfs_expr *parse_nohidden(struct parser_state *state, int arg1, int */ static struct bfs_expr *parse_noleaf(struct parser_state *state, int arg1, int arg2) { parse_warning(state, "${ex}%s${rs} does not apply the optimization that ${blu}%s${rs} inhibits.\n\n", - BFS_COMMAND, state->argv[0]); + BFS_COMMAND, state->argv[0]); return parse_nullary_option(state); } @@ -2730,12 +2729,12 @@ static struct bfs_expr *parse_help(struct parser_state *state, int arg1, int arg } cfprintf(cout, "Usage: ${ex}%s${rs} [${cyn}flags${rs}...] [${mag}paths${rs}...] [${blu}expression${rs}...]\n\n", - state->command); + state->command); cfprintf(cout, "${ex}%s${rs} is compatible with ${ex}find${rs}, with some extensions. " - "${cyn}Flags${rs} (${cyn}-H${rs}/${cyn}-L${rs}/${cyn}-P${rs} etc.), ${mag}paths${rs},\n" - "and ${blu}expressions${rs} may be freely mixed in any order.\n\n", - BFS_COMMAND); + "${cyn}Flags${rs} (${cyn}-H${rs}/${cyn}-L${rs}/${cyn}-P${rs} etc.), ${mag}paths${rs},\n" + "and ${blu}expressions${rs} may be freely mixed in any order.\n\n", + BFS_COMMAND); cfprintf(cout, "${bld}Flags:${rs}\n\n"); @@ -2807,7 +2806,7 @@ static struct bfs_expr *parse_help(struct parser_state *state, int arg1, int arg cfprintf(cout, " ${blu}-ignore_readdir_race${rs}\n"); cfprintf(cout, " ${blu}-noignore_readdir_race${rs}\n"); cfprintf(cout, " Whether to report an error if ${ex}%s${rs} detects that the file tree is modified\n", - BFS_COMMAND); + BFS_COMMAND); cfprintf(cout, " during the search (default: ${blu}-noignore_readdir_race${rs})\n"); cfprintf(cout, " ${blu}-maxdepth${rs} ${bld}N${rs}\n"); cfprintf(cout, " ${blu}-mindepth${rs} ${bld}N${rs}\n"); @@ -3462,14 +3461,14 @@ static struct bfs_expr *parse_whole_expr(struct parser_state *state) { if (state->mount_arg && state->xdev_arg) { parse_conflict_warning(state, state->mount_arg, 1, state->xdev_arg, 1, - "${blu}%s${rs} is redundant in the presence of ${blu}%s${rs}.\n\n", - state->xdev_arg[0], state->mount_arg[0]); + "${blu}%s${rs} is redundant in the presence of ${blu}%s${rs}.\n\n", + state->xdev_arg[0], state->mount_arg[0]); } if (state->ctx->warn && state->depth_arg && state->prune_arg) { parse_conflict_warning(state, state->depth_arg, 1, state->prune_arg, 1, - "${blu}%s${rs} does not work in the presence of ${blu}%s${rs}.\n", - state->prune_arg[0], state->depth_arg[0]); + "${blu}%s${rs} does not work in the presence of ${blu}%s${rs}.\n", + state->prune_arg[0], state->depth_arg[0]); if (state->interactive) { bfs_warning(state->ctx, "Do you want to continue? "); @@ -3483,8 +3482,8 @@ static struct bfs_expr *parse_whole_expr(struct parser_state *state) { if (state->ok_expr && state->files0_stdin_arg) { parse_conflict_error(state, state->ok_expr->argv, state->ok_expr->argc, state->files0_stdin_arg, 2, - "${blu}%s${rs} conflicts with ${blu}%s${rs} ${bld}%s${rs}.\n", - state->ok_expr->argv[0], state->files0_stdin_arg[0], state->files0_stdin_arg[1]); + "${blu}%s${rs} conflicts with ${blu}%s${rs} ${bld}%s${rs}.\n", + state->ok_expr->argv[0], state->files0_stdin_arg[0], state->files0_stdin_arg[1]); goto fail; } @@ -3644,7 +3643,7 @@ void bfs_ctx_dump(const struct bfs_ctx *ctx, enum debug_flags flag) { static void dump_costs(const struct bfs_ctx *ctx) { const struct bfs_expr *expr = ctx->expr; bfs_debug(ctx, DEBUG_COST, " Cost: ~${ylw}%g${rs}\n", expr->cost); - bfs_debug(ctx, DEBUG_COST, "Probability: ~${ylw}%g%%${rs}\n", 100.0*expr->probability); + bfs_debug(ctx, DEBUG_COST, "Probability: ~${ylw}%g%%${rs}\n", 100.0 * expr->probability); } struct bfs_ctx *bfs_parse_cmdline(int argc, char *argv[]) { @@ -3654,7 +3653,7 @@ struct bfs_ctx *bfs_parse_cmdline(int argc, char *argv[]) { goto fail; } - static char* default_argv[] = {BFS_COMMAND, NULL}; + static char *default_argv[] = {BFS_COMMAND, NULL}; if (argc < 1) { argc = 1; argv = default_argv; diff --git a/src/printf.c b/src/printf.c index 5de5a28..98bcb0f 100644 --- a/src/printf.c +++ b/src/printf.c @@ -113,14 +113,14 @@ static int bfs_printf_ctime(CFILE *cfile, const struct bfs_printf *directive, co } BFS_PRINTF_BUF(buf, "%s %s %2d %.2d:%.2d:%.2d.%09ld0 %4d", - days[tm.tm_wday], - months[tm.tm_mon], - tm.tm_mday, - tm.tm_hour, - tm.tm_min, - tm.tm_sec, - (long)ts->tv_nsec, - 1900 + tm.tm_year); + days[tm.tm_wday], + months[tm.tm_mon], + tm.tm_mday, + tm.tm_hour, + tm.tm_min, + tm.tm_sec, + (long)ts->tv_nsec, + 1900 + tm.tm_year); return dyn_fprintf(cfile->file, directive, buf); } @@ -152,19 +152,19 @@ static int bfs_printf_strftime(CFILE *cfile, const struct bfs_printf *directive, break; case '+': ret = snprintf(buf, sizeof(buf), "%4d-%.2d-%.2d+%.2d:%.2d:%.2d.%09ld0", - 1900 + tm.tm_year, - tm.tm_mon + 1, - tm.tm_mday, - tm.tm_hour, - tm.tm_min, - tm.tm_sec, - (long)ts->tv_nsec); + 1900 + tm.tm_year, + tm.tm_mon + 1, + tm.tm_mday, + tm.tm_hour, + tm.tm_min, + tm.tm_sec, + (long)ts->tv_nsec); break; case 'k': ret = snprintf(buf, sizeof(buf), "%2d", tm.tm_hour); break; case 'l': - ret = snprintf(buf, sizeof(buf), "%2d", (tm.tm_hour + 11)%12 + 1); + ret = snprintf(buf, sizeof(buf), "%2d", (tm.tm_hour + 11) % 12 + 1); break; case 's': ret = snprintf(buf, sizeof(buf), "%lld", (long long)ts->tv_sec); @@ -174,10 +174,10 @@ static int bfs_printf_strftime(CFILE *cfile, const struct bfs_printf *directive, break; case 'T': ret = snprintf(buf, sizeof(buf), "%.2d:%.2d:%.2d.%09ld0", - tm.tm_hour, - tm.tm_min, - tm.tm_sec, - (long)ts->tv_nsec); + tm.tm_hour, + tm.tm_min, + tm.tm_sec, + (long)ts->tv_nsec); break; // POSIX strftime() features @@ -202,7 +202,7 @@ static int bfs_printf_b(CFILE *cfile, const struct bfs_printf *directive, const return -1; } - uintmax_t blocks = ((uintmax_t)statbuf->blocks*BFS_STAT_BLKSIZE + 511)/512; + uintmax_t blocks = ((uintmax_t)statbuf->blocks * BFS_STAT_BLKSIZE + 511) / 512; BFS_PRINTF_BUF(buf, "%ju", blocks); return dyn_fprintf(cfile->file, directive, buf); } @@ -338,7 +338,7 @@ static int bfs_printf_k(CFILE *cfile, const struct bfs_printf *directive, const return -1; } - uintmax_t blocks = ((uintmax_t)statbuf->blocks*BFS_STAT_BLKSIZE + 1023)/1024; + uintmax_t blocks = ((uintmax_t)statbuf->blocks * BFS_STAT_BLKSIZE + 1023) / 1024; BFS_PRINTF_BUF(buf, "%ju", blocks); return dyn_fprintf(cfile->file, directive, buf); } @@ -452,7 +452,7 @@ static int bfs_printf_S(CFILE *cfile, const struct bfs_printf *directive, const if (statbuf->size == 0 && statbuf->blocks == 0) { sparsity = 1.0; } else { - sparsity = (double)BFS_STAT_BLKSIZE*statbuf->blocks/statbuf->size; + sparsity = (double)BFS_STAT_BLKSIZE * statbuf->blocks / statbuf->size; } return dyn_fprintf(cfile->file, directive, sparsity); } diff --git a/src/pwcache.c b/src/pwcache.c index 0e2f5c1..c728ba9 100644 --- a/src/pwcache.c +++ b/src/pwcache.c @@ -4,7 +4,6 @@ #include "pwcache.h" #include "alloc.h" #include "config.h" -#include "darray.h" #include "trie.h" #include #include diff --git a/src/stat.c b/src/stat.c index e8f48ee..d7387c6 100644 --- a/src/stat.c +++ b/src/stat.c @@ -10,8 +10,8 @@ #include #include #include -#include #include +#include #if defined(STATX_BASIC_STATS) && (!__ANDROID__ || __ANDROID_API__ >= 30) # define BFS_HAS_LIBC_STATX true diff --git a/src/trie.c b/src/trie.c index 77aa2d0..55544e6 100644 --- a/src/trie.c +++ b/src/trie.c @@ -700,7 +700,7 @@ static void trie_remove_impl(struct trie *trie, struct trie_leaf *leaf) { } if (child_index < parent_size) { - memmove(child, child + 1, (parent_size - child_index)*sizeof(*child)); + memmove(child, child + 1, (parent_size - child_index) * sizeof(*child)); } if (has_single_bit(parent_size)) { diff --git a/src/trie.h b/src/trie.h index 2f51db5..02088f1 100644 --- a/src/trie.h +++ b/src/trie.h @@ -4,8 +4,8 @@ #ifndef BFS_TRIE_H #define BFS_TRIE_H -#include "config.h" #include "alloc.h" +#include "config.h" #include "list.h" #include #include @@ -143,6 +143,6 @@ void trie_destroy(struct trie *trie); * Iterate over the leaves of a trie. */ #define for_trie(leaf, trie) \ - for_list(struct trie_leaf, leaf, trie) + for_list (struct trie_leaf, leaf, trie) #endif // BFS_TRIE_H diff --git a/src/xregex.c b/src/xregex.c index beb6676..b9c04bf 100644 --- a/src/xregex.c +++ b/src/xregex.c @@ -5,8 +5,8 @@ #include "alloc.h" #include "config.h" #include "diag.h" -#include "thread.h" #include "sanity.h" +#include "thread.h" #include #include #include diff --git a/src/xspawn.c b/src/xspawn.c index 80bafef..7fb63e0 100644 --- a/src/xspawn.c +++ b/src/xspawn.c @@ -187,7 +187,7 @@ fail: // In case of a write error, the parent will still see that we exited // unsuccessfully, but won't know why - (void) xwrite(pipefd[1], &error, sizeof(error)); + (void)xwrite(pipefd[1], &error, sizeof(error)); xclose(pipefd[1]); _Exit(127); diff --git a/src/xtime.c b/src/xtime.c index 79dafad..e90bdb1 100644 --- a/src/xtime.c +++ b/src/xtime.c @@ -81,7 +81,7 @@ static int safe_add(int *value, int delta) { static int floor_div(int n, int d) { int a = n < 0; - return (n + a)/d - a; + return (n + a) / d - a; } static int wrap(int *value, int max, int *next) { @@ -93,7 +93,7 @@ static int wrap(int *value, int max, int *next) { static int month_length(int year, int month) { static const int month_lengths[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; int ret = month_lengths[month]; - if (month == 1 && year%4 == 0 && (year%100 != 0 || (year + 300)%400 == 0)) { + if (month == 1 && year % 4 == 0 && (year % 100 != 0 || (year + 300) % 400 == 0)) { ++ret; } return ret; @@ -156,13 +156,13 @@ int xtimegm(struct tm *tm, time_t *timep) { leap_days = floor_div(tm->tm_year + 3, 4) - floor_div(tm->tm_year + 99, 100) + floor_div(tm->tm_year + 299, 400) - 17; } - long long epoch_days = 365LL*(tm->tm_year - 70) + leap_days + tm->tm_yday; - tm->tm_wday = (epoch_days + 4)%7; + long long epoch_days = 365LL * (tm->tm_year - 70) + leap_days + tm->tm_yday; + tm->tm_wday = (epoch_days + 4) % 7; if (tm->tm_wday < 0) { tm->tm_wday += 7; } - long long epoch_time = tm->tm_sec + 60*(tm->tm_min + 60*(tm->tm_hour + 24*epoch_days)); + long long epoch_time = tm->tm_sec + 60 * (tm->tm_min + 60 * (tm->tm_hour + 24 * epoch_days)); *timep = (time_t)epoch_time; if ((long long)*timep != epoch_time) { goto overflow; @@ -296,7 +296,7 @@ end: goto error; } - int offset = 60*tz_hour + tz_min; + int offset = 60 * tz_hour + tz_min; if (tz_negative) { result->tv_sec -= offset; } else { diff --git a/tests/bfstd.c b/tests/bfstd.c index 83964e5..33b3792 100644 --- a/tests/bfstd.c +++ b/tests/bfstd.c @@ -7,8 +7,8 @@ #include #include #include -#include #include +#include #include #include diff --git a/tests/mksock.c b/tests/mksock.c index 42ef322..7023b4f 100644 --- a/tests/mksock.c +++ b/tests/mksock.c @@ -9,8 +9,8 @@ #include "../src/bfstd.h" #include #include -#include #include +#include #include #include #include diff --git a/tests/trie.c b/tests/trie.c index 6ea94a2..656fd85 100644 --- a/tests/trie.c +++ b/tests/trie.c @@ -120,11 +120,11 @@ int main(void) { bfs_verify(!trie_find_mem(&trie, longstr, longsize)); bfs_verify(trie_insert_mem(&trie, longstr, longsize)); - memset(longstr + longsize/2, 0xAB, longsize/2); + memset(longstr + longsize / 2, 0xAB, longsize / 2); bfs_verify(!trie_find_mem(&trie, longstr, longsize)); bfs_verify(trie_insert_mem(&trie, longstr, longsize)); - memset(longstr, 0xAA, longsize/2); + memset(longstr, 0xAA, longsize / 2); bfs_verify(!trie_find_mem(&trie, longstr, longsize)); bfs_verify(trie_insert_mem(&trie, longstr, longsize)); diff --git a/tests/xtimegm.c b/tests/xtimegm.c index b2479b7..973b2eb 100644 --- a/tests/xtimegm.c +++ b/tests/xtimegm.c @@ -42,9 +42,9 @@ static bool tm_equal(const struct tm *tma, const struct tm *tmb) { static void tm_print(FILE *file, const struct tm *tm) { fprintf(file, "Y%d M%d D%d h%d m%d s%d wd%d yd%d%s\n", - tm->tm_year, tm->tm_mon, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec, - tm->tm_wday, tm->tm_yday, + tm->tm_year, tm->tm_mon, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec, + tm->tm_wday, tm->tm_yday, tm->tm_isdst ? (tm->tm_isdst < 0 ? " (DST?)" : " (DST)") : ""); } -- cgit v1.2.3 From 428cf9c206beee3407ea3c5480b00f4cfbea95f5 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 5 Oct 2023 12:56:36 -0400 Subject: bfstd: Add a thread-safe wrapper for strerror() --- src/bfstd.c | 43 +++++++++++++++++++++++++++++++++++++++++++ src/bfstd.h | 11 +++++++++++ src/color.c | 2 +- src/eval.c | 2 +- src/parse.c | 4 ++-- src/printf.c | 2 +- src/thread.h | 3 ++- src/xregex.c | 3 ++- tests/bfstd.c | 4 ++-- tests/mksock.c | 2 +- tests/xtouch.c | 6 +++--- 11 files changed, 69 insertions(+), 13 deletions(-) (limited to 'src/color.c') diff --git a/src/bfstd.c b/src/bfstd.c index fcf4a6d..e9214d4 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -276,6 +277,48 @@ char *xstpencpy(char *dest, char *end, const char *src, size_t n) { } } +const char *xstrerror(int errnum) { + int saved = errno; + const char *ret = NULL; + static thread_local char buf[256]; + +#if __APPLE__ + // No strerror_l() on macOS + if (strerror_r(errnum, buf, sizeof(buf)) == 0) { + ret = buf; + } +#else +# if __NetBSD__ + // NetBSD has no thread-specific locales + locale_t loc = LC_GLOBAL_LOCALE; +# else + locale_t loc = uselocale((locale_t)0); +# endif + + locale_t copy = loc; + if (copy == LC_GLOBAL_LOCALE) { + copy = duplocale(copy); + } + + if (copy != (locale_t)0) { + ret = strerror_l(errnum, loc); + } + + if (loc == LC_GLOBAL_LOCALE) { + freelocale(copy); + } +#endif + + if (!ret) { + // Fallback for strerror_[lr]() or duplocale() failures + snprintf(buf, sizeof(buf), "Unknown error %d", errnum); + ret = buf; + } + + errno = saved; + return ret; +} + void xstrmode(mode_t mode, char str[11]) { strcpy(str, "----------"); diff --git a/src/bfstd.h b/src/bfstd.h index fb77399..abde24e 100644 --- a/src/bfstd.h +++ b/src/bfstd.h @@ -166,6 +166,17 @@ char *xstpecpy(char *dest, char *end, const char *src); */ char *xstpencpy(char *dest, char *end, const char *src, size_t n); +/** + * Thread-safe strerror(). + * + * @param errnum + * An error number. + * @return + * A string describing that error, which remains valid until the next + * xstrerror() call in the same thread. + */ +const char *xstrerror(int errnum); + /** * Format a mode like ls -l (e.g. -rw-r--r--). * diff --git a/src/color.c b/src/color.c index 788d35d..fbb5edf 100644 --- a/src/color.c +++ b/src/color.c @@ -1239,7 +1239,7 @@ static int cvbuff(CFILE *cfile, const char *format, va_list args) { break; case 'm': - if (dstrcat(&cfile->buffer, strerror(error)) != 0) { + if (dstrcat(&cfile->buffer, xstrerror(error)) != 0) { return -1; } break; diff --git a/src/eval.c b/src/eval.c index 9f4896a..e0dd97b 100644 --- a/src/eval.c +++ b/src/eval.c @@ -1376,7 +1376,7 @@ static enum bftw_action eval_callback(const struct BFTW *ftwbuf, void *ptr) { if (ftwbuf->type == BFS_ERROR) { if (!eval_should_ignore(&state, ftwbuf->error)) { - eval_error(&state, "%s.\n", strerror(ftwbuf->error)); + eval_error(&state, "%s.\n", xstrerror(ftwbuf->error)); } state.action = BFTW_PRUNE; goto done; diff --git a/src/parse.c b/src/parse.c index 7766a7b..976f7cb 100644 --- a/src/parse.c +++ b/src/parse.c @@ -1127,7 +1127,7 @@ static struct bfs_expr *parse_color(struct parser_state *state, int color, int a if (color) { if (!colors) { - parse_expr_error(state, expr, "Error parsing $$LS_COLORS: %s.\n", strerror(ctx->colors_error)); + parse_expr_error(state, expr, "Error parsing $$LS_COLORS: %s.\n", xstrerror(ctx->colors_error)); bfs_expr_free(expr); return NULL; } @@ -3741,7 +3741,7 @@ struct bfs_ctx *bfs_parse_cmdline(int argc, char *argv[]) { } if (state.use_color == COLOR_AUTO && !ctx->colors) { - bfs_warning(ctx, "Error parsing $$LS_COLORS: %s.\n\n", strerror(ctx->colors_error)); + bfs_warning(ctx, "Error parsing $$LS_COLORS: %s.\n\n", xstrerror(ctx->colors_error)); } if (bfs_optimize(ctx) != 0) { diff --git a/src/printf.c b/src/printf.c index 98bcb0f..704e26d 100644 --- a/src/printf.c +++ b/src/printf.c @@ -744,7 +744,7 @@ int bfs_printf_parse(const struct bfs_ctx *ctx, struct bfs_expr *expr, const cha if (!directive.ptr) { int error = errno; bfs_expr_error(ctx, expr); - bfs_error(ctx, "Couldn't parse the mount table: %s.\n", strerror(error)); + bfs_error(ctx, "Couldn't parse the mount table: %s.\n", xstrerror(error)); goto directive_error; } break; diff --git a/src/thread.h b/src/thread.h index ab95a79..a59033c 100644 --- a/src/thread.h +++ b/src/thread.h @@ -8,6 +8,7 @@ #ifndef BFS_THREAD_H #define BFS_THREAD_H +#include "bfstd.h" #include "config.h" #include "diag.h" #include @@ -23,7 +24,7 @@ #endif #define thread_verify(expr, cond) \ - bfs_verify((errno = (expr), (cond)), "%s: %s", #expr, strerror(errno)) + bfs_verify((errno = (expr), (cond)), "%s: %s", #expr, xstrerror(errno)) /** * Wrapper for pthread_create(). diff --git a/src/xregex.c b/src/xregex.c index 87b692e..3df27f0 100644 --- a/src/xregex.c +++ b/src/xregex.c @@ -3,6 +3,7 @@ #include "xregex.h" #include "alloc.h" +#include "bfstd.h" #include "config.h" #include "diag.h" #include "sanity.h" @@ -274,7 +275,7 @@ void bfs_regfree(struct bfs_regex *regex) { char *bfs_regerror(const struct bfs_regex *regex) { if (!regex) { - return strdup(strerror(ENOMEM)); + return strdup(xstrerror(ENOMEM)); } #if BFS_USE_ONIGURUMA diff --git a/tests/bfstd.c b/tests/bfstd.c index 33b3792..c386279 100644 --- a/tests/bfstd.c +++ b/tests/bfstd.c @@ -15,12 +15,12 @@ /** Check the result of xdirname()/xbasename(). */ static void check_base_dir(const char *path, const char *dir, const char *base) { char *xdir = xdirname(path); - bfs_verify(xdir, "xdirname(): %s", strerror(errno)); + bfs_verify(xdir, "xdirname(): %s", xstrerror(errno)); bfs_verify(strcmp(xdir, dir) == 0, "xdirname('%s') == '%s' (!= '%s')", path, xdir, dir); free(xdir); char *xbase = xbasename(path); - bfs_verify(xbase, "xbasename(): %s", strerror(errno)); + bfs_verify(xbase, "xbasename(): %s", xstrerror(errno)); bfs_verify(strcmp(xbase, base) == 0, "xbasename('%s') == '%s' (!= '%s')", path, xbase, base); free(xbase); } diff --git a/tests/mksock.c b/tests/mksock.c index 7023b4f..f3b61da 100644 --- a/tests/mksock.c +++ b/tests/mksock.c @@ -19,7 +19,7 @@ * Print an error message. */ static void errmsg(const char *cmd, const char *path) { - fprintf(stderr, "%s: '%s': %s.\n", cmd, path, strerror(errno)); + fprintf(stderr, "%s: '%s': %s.\n", cmd, path, xstrerror(errno)); } /** diff --git a/tests/xtouch.c b/tests/xtouch.c index 80fad8d..a4c4d40 100644 --- a/tests/xtouch.c +++ b/tests/xtouch.c @@ -197,14 +197,14 @@ int main(int argc, char *argv[]) { if (rarg) { struct stat buf; if (fstatat(AT_FDCWD, rarg, &buf, at_flags(&args)) != 0) { - fprintf(stderr, "%s: '%s': %s\n", cmd, rarg, strerror(errno)); + fprintf(stderr, "%s: '%s': %s\n", cmd, rarg, xstrerror(errno)); return EXIT_FAILURE; } times[0] = buf.st_atim; times[1] = buf.st_mtim; } else if (darg) { if (xgetdate(darg, ×[0]) != 0) { - fprintf(stderr, "%s: Parsing time '%s' failed: %s\n", cmd, darg, strerror(errno)); + fprintf(stderr, "%s: Parsing time '%s' failed: %s\n", cmd, darg, xstrerror(errno)); return EXIT_FAILURE; } times[1] = times[0]; @@ -237,7 +237,7 @@ int main(int argc, char *argv[]) { for (; optind < argc; ++optind) { const char *path = argv[optind]; if (xtouch(&args, path) != 0) { - fprintf(stderr, "%s: '%s': %s\n", cmd, path, strerror(errno)); + fprintf(stderr, "%s: '%s': %s\n", cmd, path, xstrerror(errno)); ret = EXIT_FAILURE; } } -- cgit v1.2.3 From 026e8fbd248561396752552efa3cc04e0ac832b7 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 9 Nov 2023 12:59:20 -0500 Subject: config: s/BFS_FORMATTER/attr_format/ --- src/bar.c | 2 +- src/color.c | 4 ++-- src/color.h | 4 ++-- src/config.h | 4 ++-- src/diag.h | 14 +++++++------- src/dstring.h | 8 ++++---- src/eval.c | 2 +- src/exec.c | 2 +- src/opt.c | 4 ++-- src/parse.c | 14 +++++++------- 10 files changed, 29 insertions(+), 29 deletions(-) (limited to 'src/color.c') diff --git a/src/bar.c b/src/bar.c index 57cc4dd..2e50dbe 100644 --- a/src/bar.c +++ b/src/bar.c @@ -127,7 +127,7 @@ static void reset_before_death_by(int sig) { } /** printf() to the status bar with a single write(). */ -BFS_FORMATTER(2, 3) +attr_format(2, 3) static int bfs_bar_printf(struct bfs_bar *bar, const char *format, ...) { va_list args; va_start(args, format); diff --git a/src/color.c b/src/color.c index fbb5edf..7644ca3 100644 --- a/src/color.c +++ b/src/color.c @@ -1105,7 +1105,7 @@ static int print_link_target(CFILE *cfile, const struct BFTW *ftwbuf) { } /** Format some colored output to the buffer. */ -BFS_FORMATTER(2, 3) +attr_format(2, 3) static int cbuff(CFILE *cfile, const char *format, ...); /** Dump a parsed expression tree, for debugging. */ @@ -1177,7 +1177,7 @@ static int print_expr(CFILE *cfile, const struct bfs_expr *expr, bool verbose) { return 0; } -BFS_FORMATTER(2, 0) +attr_format(2, 0) static int cvbuff(CFILE *cfile, const char *format, va_list args) { const struct colors *colors = cfile->colors; int error = errno; diff --git a/src/color.h b/src/color.h index b118f77..8a81573 100644 --- a/src/color.h +++ b/src/color.h @@ -100,13 +100,13 @@ int cfclose(CFILE *cfile); * @return * 0 on success, -1 on failure. */ -BFS_FORMATTER(2, 3) +attr_format(2, 3) int cfprintf(CFILE *cfile, const char *format, ...); /** * cfprintf() variant that takes a va_list. */ -BFS_FORMATTER(2, 0) +attr_format(2, 0) int cvfprintf(CFILE *cfile, const char *format, va_list args); #endif // BFS_COLOR_H diff --git a/src/config.h b/src/config.h index e11941a..f19677c 100644 --- a/src/config.h +++ b/src/config.h @@ -188,9 +188,9 @@ * Adds compiler warnings for bad printf()-style function calls, if supported. */ #if __has_attribute(format) -# define BFS_FORMATTER(fmt, args) __attribute__((format(printf, fmt, args))) +# define attr_format(fmt, args) __attribute__((format(printf, fmt, args))) #else -# define BFS_FORMATTER(fmt, args) +# define attr_format(fmt, args) #endif /** diff --git a/src/diag.h b/src/diag.h index 838a794..8c7ed57 100644 --- a/src/diag.h +++ b/src/diag.h @@ -44,7 +44,7 @@ struct bfs_loc { /** * Print a message to standard error and abort. */ -BFS_FORMATTER(2, 3) +attr_format(2, 3) noreturn void bfs_abortf(const struct bfs_loc *loc, const char *format, ...); /** @@ -121,7 +121,7 @@ void bfs_perror(const struct bfs_ctx *ctx, const char *str); /** * Shorthand for printing error messages. */ -BFS_FORMATTER(2, 3) +attr_format(2, 3) void bfs_error(const struct bfs_ctx *ctx, const char *format, ...); /** @@ -129,7 +129,7 @@ void bfs_error(const struct bfs_ctx *ctx, const char *format, ...); * * @return Whether a warning was printed. */ -BFS_FORMATTER(2, 3) +attr_format(2, 3) bool bfs_warning(const struct bfs_ctx *ctx, const char *format, ...); /** @@ -137,25 +137,25 @@ bool bfs_warning(const struct bfs_ctx *ctx, const char *format, ...); * * @return Whether a debug message was printed. */ -BFS_FORMATTER(3, 4) +attr_format(3, 4) bool bfs_debug(const struct bfs_ctx *ctx, enum debug_flags flag, const char *format, ...); /** * bfs_error() variant that takes a va_list. */ -BFS_FORMATTER(2, 0) +attr_format(2, 0) void bfs_verror(const struct bfs_ctx *ctx, const char *format, va_list args); /** * bfs_warning() variant that takes a va_list. */ -BFS_FORMATTER(2, 0) +attr_format(2, 0) bool bfs_vwarning(const struct bfs_ctx *ctx, const char *format, va_list args); /** * bfs_debug() variant that takes a va_list. */ -BFS_FORMATTER(3, 0) +attr_format(3, 0) bool bfs_vdebug(const struct bfs_ctx *ctx, enum debug_flags flag, const char *format, va_list args); /** diff --git a/src/dstring.h b/src/dstring.h index 6496a4f..fd98df8 100644 --- a/src/dstring.h +++ b/src/dstring.h @@ -230,7 +230,7 @@ int dstrxcpy(dchar **dest, const char *str, size_t len); * @return * The created string, or NULL on failure. */ -BFS_FORMATTER(1, 2) +attr_format(1, 2) char *dstrprintf(const char *format, ...); /** @@ -243,7 +243,7 @@ char *dstrprintf(const char *format, ...); * @return * The created string, or NULL on failure. */ -BFS_FORMATTER(1, 0) +attr_format(1, 0) char *dstrvprintf(const char *format, va_list args); /** @@ -258,7 +258,7 @@ char *dstrvprintf(const char *format, va_list args); * @return * 0 on success, -1 on failure. */ -BFS_FORMATTER(2, 3) +attr_format(2, 3) int dstrcatf(dchar **str, const char *format, ...); /** @@ -273,7 +273,7 @@ int dstrcatf(dchar **str, const char *format, ...); * @return * 0 on success, -1 on failure. */ -BFS_FORMATTER(2, 0) +attr_format(2, 0) int dstrvcatf(dchar **str, const char *format, va_list args); /** diff --git a/src/eval.c b/src/eval.c index b511eba..eb4a0ca 100644 --- a/src/eval.c +++ b/src/eval.c @@ -58,7 +58,7 @@ struct bfs_eval { /** * Print an error message. */ -BFS_FORMATTER(2, 3) +attr_format(2, 3) static void eval_error(struct bfs_eval *state, const char *format, ...) { // By POSIX, any errors should be accompanied by a non-zero exit status *state->ret = EXIT_FAILURE; diff --git a/src/exec.c b/src/exec.c index f0730d2..ba82439 100644 --- a/src/exec.c +++ b/src/exec.c @@ -22,7 +22,7 @@ #include /** Print some debugging info. */ -BFS_FORMATTER(2, 3) +attr_format(2, 3) static void bfs_exec_debug(const struct bfs_exec *execbuf, const char *format, ...) { const struct bfs_ctx *ctx = execbuf->ctx; diff --git a/src/opt.c b/src/opt.c index 77c2798..5da73d8 100644 --- a/src/opt.c +++ b/src/opt.c @@ -305,7 +305,7 @@ struct opt_state { }; /** Log an optimization. */ -BFS_FORMATTER(3, 4) +attr_format(3, 4) static bool opt_debug(const struct opt_state *state, int level, const char *format, ...) { bfs_assert(state->ctx->optlevel >= level); @@ -321,7 +321,7 @@ static bool opt_debug(const struct opt_state *state, int level, const char *form } /** Warn about an expression. */ -BFS_FORMATTER(3, 4) +attr_format(3, 4) static void opt_warning(const struct opt_state *state, const struct bfs_expr *expr, const char *format, ...) { if (bfs_expr_warning(state->ctx, expr)) { va_list args; diff --git a/src/parse.c b/src/parse.c index d21ab40..d3938fc 100644 --- a/src/parse.c +++ b/src/parse.c @@ -247,7 +247,7 @@ static void highlight_args(const struct bfs_ctx *ctx, char **argv, size_t argc, /** * Print an error message during parsing. */ -BFS_FORMATTER(2, 3) +attr_format(2, 3) static void parse_error(const struct parser_state *state, const char *format, ...) { int error = errno; const struct bfs_ctx *ctx = state->ctx; @@ -267,7 +267,7 @@ static void parse_error(const struct parser_state *state, const char *format, .. /** * Print an error about some command line arguments. */ -BFS_FORMATTER(4, 5) +attr_format(4, 5) static void parse_argv_error(const struct parser_state *state, char **argv, size_t argc, const char *format, ...) { int error = errno; const struct bfs_ctx *ctx = state->ctx; @@ -287,7 +287,7 @@ static void parse_argv_error(const struct parser_state *state, char **argv, size /** * Print an error about conflicting command line arguments. */ -BFS_FORMATTER(6, 7) +attr_format(6, 7) static void parse_conflict_error(const struct parser_state *state, char **argv1, size_t argc1, char **argv2, size_t argc2, const char *format, ...) { int error = errno; const struct bfs_ctx *ctx = state->ctx; @@ -308,7 +308,7 @@ static void parse_conflict_error(const struct parser_state *state, char **argv1, /** * Print an error about an expression. */ -BFS_FORMATTER(3, 4) +attr_format(3, 4) static void parse_expr_error(const struct parser_state *state, const struct bfs_expr *expr, const char *format, ...) { int error = errno; const struct bfs_ctx *ctx = state->ctx; @@ -325,7 +325,7 @@ static void parse_expr_error(const struct parser_state *state, const struct bfs_ /** * Print a warning message during parsing. */ -BFS_FORMATTER(2, 3) +attr_format(2, 3) static bool parse_warning(const struct parser_state *state, const char *format, ...) { int error = errno; const struct bfs_ctx *ctx = state->ctx; @@ -348,7 +348,7 @@ static bool parse_warning(const struct parser_state *state, const char *format, /** * Print a warning about conflicting command line arguments. */ -BFS_FORMATTER(6, 7) +attr_format(6, 7) static bool parse_conflict_warning(const struct parser_state *state, char **argv1, size_t argc1, char **argv2, size_t argc2, const char *format, ...) { int error = errno; const struct bfs_ctx *ctx = state->ctx; @@ -372,7 +372,7 @@ static bool parse_conflict_warning(const struct parser_state *state, char **argv /** * Print a warning about an expression. */ -BFS_FORMATTER(3, 4) +attr_format(3, 4) static bool parse_expr_warning(const struct parser_state *state, const struct bfs_expr *expr, const char *format, ...) { int error = errno; const struct bfs_ctx *ctx = state->ctx; -- cgit v1.2.3 From 6a093a92f7e744838bf80be9555fc2163c317f75 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Sat, 25 Nov 2023 17:25:43 -0500 Subject: color: Make sure errno is non-zero if parse_colors() fails --- src/color.c | 86 ++++++++++++++++++++++++++++++------------------------------- 1 file changed, 43 insertions(+), 43 deletions(-) (limited to 'src/color.c') diff --git a/src/color.c b/src/color.c index 7644ca3..05ba1a3 100644 --- a/src/color.c +++ b/src/color.c @@ -142,12 +142,12 @@ static int init_esc(struct colors *colors, const char *name, const char *value, *field = esc; struct trie_leaf *leaf = trie_insert_str(&colors->names, name); - if (leaf) { - leaf->value = field; - return 0; - } else { + if (!leaf) { return -1; } + + leaf->value = field; + return 0; } /** Check if an escape sequence is equal to a string. */ @@ -623,58 +623,58 @@ struct colors *parse_colors(void) { trie_init(&colors->ext_trie); trie_init(&colors->iext_trie); - int ret = 0; + bool fail = false; // From man console_codes - ret |= init_esc(colors, "rs", "0", &colors->reset); - ret |= init_esc(colors, "lc", "\033[", &colors->leftcode); - ret |= init_esc(colors, "rc", "m", &colors->rightcode); - ret |= init_esc(colors, "ec", NULL, &colors->endcode); - ret |= init_esc(colors, "cl", "\033[K", &colors->clear_to_eol); - - ret |= init_esc(colors, "bld", "01;39", &colors->bold); - ret |= init_esc(colors, "gry", "01;30", &colors->gray); - ret |= init_esc(colors, "red", "01;31", &colors->red); - ret |= init_esc(colors, "grn", "01;32", &colors->green); - ret |= init_esc(colors, "ylw", "01;33", &colors->yellow); - ret |= init_esc(colors, "blu", "01;34", &colors->blue); - ret |= init_esc(colors, "mag", "01;35", &colors->magenta); - ret |= init_esc(colors, "cyn", "01;36", &colors->cyan); - ret |= init_esc(colors, "wht", "01;37", &colors->white); - - ret |= init_esc(colors, "wrn", "01;33", &colors->warning); - ret |= init_esc(colors, "err", "01;31", &colors->error); + fail = fail || init_esc(colors, "rs", "0", &colors->reset); + fail = fail || init_esc(colors, "lc", "\033[", &colors->leftcode); + fail = fail || init_esc(colors, "rc", "m", &colors->rightcode); + fail = fail || init_esc(colors, "ec", NULL, &colors->endcode); + fail = fail || init_esc(colors, "cl", "\033[K", &colors->clear_to_eol); + + fail = fail || init_esc(colors, "bld", "01;39", &colors->bold); + fail = fail || init_esc(colors, "gry", "01;30", &colors->gray); + fail = fail || init_esc(colors, "red", "01;31", &colors->red); + fail = fail || init_esc(colors, "grn", "01;32", &colors->green); + fail = fail || init_esc(colors, "ylw", "01;33", &colors->yellow); + fail = fail || init_esc(colors, "blu", "01;34", &colors->blue); + fail = fail || init_esc(colors, "mag", "01;35", &colors->magenta); + fail = fail || init_esc(colors, "cyn", "01;36", &colors->cyan); + fail = fail || init_esc(colors, "wht", "01;37", &colors->white); + + fail = fail || init_esc(colors, "wrn", "01;33", &colors->warning); + fail = fail || init_esc(colors, "err", "01;31", &colors->error); // Defaults from man dir_colors // "" means fall back to ->normal - ret |= init_esc(colors, "no", NULL, &colors->normal); + fail = fail || init_esc(colors, "no", NULL, &colors->normal); - ret |= init_esc(colors, "fi", "", &colors->file); - ret |= init_esc(colors, "mh", NULL, &colors->multi_hard); - ret |= init_esc(colors, "ex", "01;32", &colors->executable); - ret |= init_esc(colors, "ca", NULL, &colors->capable); - ret |= init_esc(colors, "sg", "30;43", &colors->setgid); - ret |= init_esc(colors, "su", "37;41", &colors->setuid); + fail = fail || init_esc(colors, "fi", "", &colors->file); + fail = fail || init_esc(colors, "mh", NULL, &colors->multi_hard); + fail = fail || init_esc(colors, "ex", "01;32", &colors->executable); + fail = fail || init_esc(colors, "ca", NULL, &colors->capable); + fail = fail || init_esc(colors, "sg", "30;43", &colors->setgid); + fail = fail || init_esc(colors, "su", "37;41", &colors->setuid); - ret |= init_esc(colors, "di", "01;34", &colors->directory); - ret |= init_esc(colors, "st", "37;44", &colors->sticky); - ret |= init_esc(colors, "ow", "34;42", &colors->other_writable); - ret |= init_esc(colors, "tw", "30;42", &colors->sticky_other_writable); + fail = fail || init_esc(colors, "di", "01;34", &colors->directory); + fail = fail || init_esc(colors, "st", "37;44", &colors->sticky); + fail = fail || init_esc(colors, "ow", "34;42", &colors->other_writable); + fail = fail || init_esc(colors, "tw", "30;42", &colors->sticky_other_writable); - ret |= init_esc(colors, "ln", "01;36", &colors->link); - ret |= init_esc(colors, "or", NULL, &colors->orphan); - ret |= init_esc(colors, "mi", NULL, &colors->missing); + fail = fail || init_esc(colors, "ln", "01;36", &colors->link); + fail = fail || init_esc(colors, "or", NULL, &colors->orphan); + fail = fail || init_esc(colors, "mi", NULL, &colors->missing); colors->link_as_target = false; - ret |= init_esc(colors, "bd", "01;33", &colors->blockdev); - ret |= init_esc(colors, "cd", "01;33", &colors->chardev); - ret |= init_esc(colors, "do", "01;35", &colors->door); - ret |= init_esc(colors, "pi", "33", &colors->pipe); - ret |= init_esc(colors, "so", "01;35", &colors->socket); + fail = fail || init_esc(colors, "bd", "01;33", &colors->blockdev); + fail = fail || init_esc(colors, "cd", "01;33", &colors->chardev); + fail = fail || init_esc(colors, "do", "01;35", &colors->door); + fail = fail || init_esc(colors, "pi", "33", &colors->pipe); + fail = fail || init_esc(colors, "so", "01;35", &colors->socket); - if (ret != 0) { + if (fail) { goto fail; } -- cgit v1.2.3 From 5b38f658ee42bef05cecb6cadec65b25d9e94993 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 16 Nov 2023 12:25:09 -0500 Subject: config: New variadic attr(...) macro --- src/alloc.c | 2 +- src/alloc.h | 10 ++++---- src/bar.c | 2 +- src/color.c | 4 ++-- src/color.h | 4 ++-- src/config.h | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/diag.h | 37 ++++++++++++------------------ src/dstring.h | 18 +++++++-------- src/eval.c | 2 +- src/exec.c | 2 +- src/fsade.c | 6 ++--- src/ioq.c | 4 ++-- src/mtab.c | 2 +- src/opt.c | 4 ++-- src/parse.c | 14 +++++------ src/trie.c | 2 +- src/xspawn.c | 2 +- 17 files changed, 127 insertions(+), 62 deletions(-) (limited to 'src/color.c') diff --git a/src/alloc.c b/src/alloc.c index 467f0f0..b65d0c5 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -176,7 +176,7 @@ void arena_init(struct arena *arena, size_t align, size_t size) { } /** Allocate a new slab. */ -attr_cold +attr(cold) static int slab_alloc(struct arena *arena) { // Make the initial allocation size ~4K size_t size = 4096; diff --git a/src/alloc.h b/src/alloc.h index 7132470..f21ddb9 100644 --- a/src/alloc.h +++ b/src/alloc.h @@ -114,8 +114,7 @@ static inline size_t flex_size(size_t align, size_t min, size_t offset, size_t s * @return * The allocated memory, or NULL on failure. */ -attr_malloc(free, 1) -attr_aligned_alloc(1, 2) +attr(malloc(free, 1), aligned_alloc(1, 2)) void *alloc(size_t align, size_t size); /** @@ -128,8 +127,7 @@ void *alloc(size_t align, size_t size); * @return * The allocated memory, or NULL on failure. */ -attr_malloc(free, 1) -attr_aligned_alloc(1, 2) +attr(malloc(free, 1), aligned_alloc(1, 2)) void *zalloc(size_t align, size_t size); /** Allocate memory for the given type. */ @@ -252,7 +250,7 @@ void arena_free(struct arena *arena, void *ptr); /** * Allocate an object out of the arena. */ -attr_malloc(arena_free, 2) +attr(malloc(arena_free, 2)) void *arena_alloc(struct arena *arena); /** @@ -334,7 +332,7 @@ void varena_free(struct varena *varena, void *ptr, size_t count); * @return * The allocated struct, or NULL on failure. */ -attr_malloc(varena_free, 2) +attr(malloc(varena_free, 2)) void *varena_alloc(struct varena *varena, size_t count); /** diff --git a/src/bar.c b/src/bar.c index 2e50dbe..babadc3 100644 --- a/src/bar.c +++ b/src/bar.c @@ -127,7 +127,7 @@ static void reset_before_death_by(int sig) { } /** printf() to the status bar with a single write(). */ -attr_format(2, 3) +attr(format(2, 3)) static int bfs_bar_printf(struct bfs_bar *bar, const char *format, ...) { va_list args; va_start(args, format); diff --git a/src/color.c b/src/color.c index 05ba1a3..4c2c8ca 100644 --- a/src/color.c +++ b/src/color.c @@ -1105,7 +1105,7 @@ static int print_link_target(CFILE *cfile, const struct BFTW *ftwbuf) { } /** Format some colored output to the buffer. */ -attr_format(2, 3) +attr(format(2, 3)) static int cbuff(CFILE *cfile, const char *format, ...); /** Dump a parsed expression tree, for debugging. */ @@ -1177,7 +1177,7 @@ static int print_expr(CFILE *cfile, const struct bfs_expr *expr, bool verbose) { return 0; } -attr_format(2, 0) +attr(format(2, 0)) static int cvbuff(CFILE *cfile, const char *format, va_list args) { const struct colors *colors = cfile->colors; int error = errno; diff --git a/src/color.h b/src/color.h index 8a81573..81f0e2a 100644 --- a/src/color.h +++ b/src/color.h @@ -100,13 +100,13 @@ int cfclose(CFILE *cfile); * @return * 0 on success, -1 on failure. */ -attr_format(2, 3) +attr(format(2, 3)) int cfprintf(CFILE *cfile, const char *format, ...); /** * cfprintf() variant that takes a va_list. */ -attr_format(2, 0) +attr(format(2, 0)) int cvfprintf(CFILE *cfile, const char *format, va_list args); #endif // BFS_COLOR_H diff --git a/src/config.h b/src/config.h index 9f95674..aa03552 100644 --- a/src/config.h +++ b/src/config.h @@ -301,4 +301,78 @@ typedef long double max_align_t; # define attr_target_clones(...) #endif +/** + * Shorthand for multiple attributes at once. attr(a, b(c), d) is equivalent to + * + * attr_a + * attr_b(c) + * attr_d + */ +#define attr(...) \ + attr__(attr_##__VA_ARGS__, none, none, none, none, none, none, none, none, none) + +/** + * attr() helper. For exposition, pretend we support only 2 args, instead of 9. + * There are a few cases: + * + * attr() + * => attr__(attr_, none, none) + * => attr_ => + * attr_none => + * attr_too_many_none() => + * + * attr(a) + * => attr__(attr_a, none, none) + * => attr_a => __attribute__((a)) + * attr_none => + * attr_too_many_none() => + * + * attr(a, b(c)) + * => attr__(attr_a, b(c), none, none) + * => attr_a => __attribute__((a)) + * attr_b(c) => __attribute__((b(c))) + * attr_too_many_none(none) => + * + * attr(a, b(c), d) + * => attr__(attr_a, b(c), d, none, none) + * => attr_a => __attribute__((a)) + * attr_b(c) => __attribute__((b(c))) + * attr_too_many_d(none, none) => error + * + * Some attribute names are the same as standard library functions, e.g. printf. + * Standard libraries are permitted to define these functions as macros, like + * + * #define printf(...) __builtin_printf(__VA_ARGS__) + * + * The token paste in + * + * #define attr(...) attr__(attr_##__VA_ARGS__, none, none) + * + * is necessary to prevent macro expansion before evaluating attr__(). + * Otherwise, we could get + * + * attr(printf(1, 2)) + * => attr__(__builtin_printf(1, 2), none, none) + * => attr____builtin_printf(1, 2) + * => error + */ +#define attr__(a1, a2, a3, a4, a5, a6, a7, a8, a9, none, ...) \ + a1 \ + attr_##a2 \ + attr_##a3 \ + attr_##a4 \ + attr_##a5 \ + attr_##a6 \ + attr_##a7 \ + attr_##a8 \ + attr_##a9 \ + attr_too_many_##none(__VA_ARGS__) + +// Ignore `attr_none` from expanding 1-9 argument attr(a1, a2, ...) +#define attr_none +// Ignore `attr_` from expanding 0-argument attr() +#define attr_ +// Only trigger an error on more than 9 arguments +#define attr_too_many_none(...) + #endif // BFS_CONFIG_H diff --git a/src/diag.h b/src/diag.h index 981419e..aa6a44f 100644 --- a/src/diag.h +++ b/src/diag.h @@ -44,8 +44,7 @@ struct bfs_loc { /** * Print a message to standard error and abort. */ -attr_cold -attr_format(2, 3) +attr(cold, format(2, 3)) noreturn void bfs_abortf(const struct bfs_loc *loc, const char *format, ...); /** @@ -117,14 +116,13 @@ const char *debug_flag_name(enum debug_flags flag); /** * Like perror(), but decorated like bfs_error(). */ -attr_cold +attr(cold) void bfs_perror(const struct bfs_ctx *ctx, const char *str); /** * Shorthand for printing error messages. */ -attr_cold -attr_format(2, 3) +attr(cold, format(2, 3)) void bfs_error(const struct bfs_ctx *ctx, const char *format, ...); /** @@ -132,8 +130,7 @@ void bfs_error(const struct bfs_ctx *ctx, const char *format, ...); * * @return Whether a warning was printed. */ -attr_cold -attr_format(2, 3) +attr(cold, format(2, 3)) bool bfs_warning(const struct bfs_ctx *ctx, const char *format, ...); /** @@ -141,71 +138,67 @@ bool bfs_warning(const struct bfs_ctx *ctx, const char *format, ...); * * @return Whether a debug message was printed. */ -attr_cold -attr_format(3, 4) +attr(cold, format(3, 4)) bool bfs_debug(const struct bfs_ctx *ctx, enum debug_flags flag, const char *format, ...); /** * bfs_error() variant that takes a va_list. */ -attr_cold -attr_format(2, 0) +attr(cold, format(2, 0)) void bfs_verror(const struct bfs_ctx *ctx, const char *format, va_list args); /** * bfs_warning() variant that takes a va_list. */ -attr_cold -attr_format(2, 0) +attr(cold, format(2, 0)) bool bfs_vwarning(const struct bfs_ctx *ctx, const char *format, va_list args); /** * bfs_debug() variant that takes a va_list. */ -attr_cold -attr_format(3, 0) +attr(cold, format(3, 0)) bool bfs_vdebug(const struct bfs_ctx *ctx, enum debug_flags flag, const char *format, va_list args); /** * Print the error message prefix. */ -attr_cold +attr(cold) void bfs_error_prefix(const struct bfs_ctx *ctx); /** * Print the warning message prefix. */ -attr_cold +attr(cold) bool bfs_warning_prefix(const struct bfs_ctx *ctx); /** * Print the debug message prefix. */ -attr_cold +attr(cold) bool bfs_debug_prefix(const struct bfs_ctx *ctx, enum debug_flags flag); /** * Highlight parts of the command line in an error message. */ -attr_cold +attr(cold) void bfs_argv_error(const struct bfs_ctx *ctx, const bool args[]); /** * Highlight parts of an expression in an error message. */ -attr_cold +attr(cold) void bfs_expr_error(const struct bfs_ctx *ctx, const struct bfs_expr *expr); /** * Highlight parts of the command line in a warning message. */ -attr_cold +attr(cold) bool bfs_argv_warning(const struct bfs_ctx *ctx, const bool args[]); /** * Highlight parts of an expression in a warning message. */ -attr_cold +attr(cold) bool bfs_expr_warning(const struct bfs_ctx *ctx, const struct bfs_expr *expr); #endif // BFS_DIAG_H diff --git a/src/dstring.h b/src/dstring.h index 2a94438..1be1185 100644 --- a/src/dstring.h +++ b/src/dstring.h @@ -41,7 +41,7 @@ void dstrfree(dchar *dstr); * @param cap * The initial capacity of the string. */ -attr_malloc(dstrfree, 1) +attr(malloc(dstrfree, 1)) dchar *dstralloc(size_t cap); /** @@ -50,7 +50,7 @@ dchar *dstralloc(size_t cap); * @param str * The NUL-terminated string to copy. */ -attr_malloc(dstrfree, 1) +attr(malloc(dstrfree, 1)) dchar *dstrdup(const char *str); /** @@ -61,7 +61,7 @@ dchar *dstrdup(const char *str); * @param n * The maximum number of characters to copy from str. */ -attr_malloc(dstrfree, 1) +attr(malloc(dstrfree, 1)) dchar *dstrndup(const char *str, size_t n); /** @@ -70,7 +70,7 @@ dchar *dstrndup(const char *str, size_t n); * @param dstr * The dynamic string to copy. */ -attr_malloc(dstrfree, 1) +attr(malloc(dstrfree, 1)) dchar *dstrddup(const dchar *dstr); /** @@ -81,7 +81,7 @@ dchar *dstrddup(const dchar *dstr); * @param len * The length of the string, which may include internal NUL bytes. */ -attr_malloc(dstrfree, 1) +attr(malloc(dstrfree, 1)) dchar *dstrxdup(const char *str, size_t len); /** @@ -243,7 +243,7 @@ int dstrxcpy(dchar **dest, const char *str, size_t len); * @return * The created string, or NULL on failure. */ -attr_format(1, 2) +attr(format(1, 2)) char *dstrprintf(const char *format, ...); /** @@ -256,7 +256,7 @@ char *dstrprintf(const char *format, ...); * @return * The created string, or NULL on failure. */ -attr_format(1, 0) +attr(format(1, 0)) char *dstrvprintf(const char *format, va_list args); /** @@ -271,7 +271,7 @@ char *dstrvprintf(const char *format, va_list args); * @return * 0 on success, -1 on failure. */ -attr_format(2, 3) +attr(format(2, 3)) int dstrcatf(dchar **str, const char *format, ...); /** @@ -286,7 +286,7 @@ int dstrcatf(dchar **str, const char *format, ...); * @return * 0 on success, -1 on failure. */ -attr_format(2, 0) +attr(format(2, 0)) int dstrvcatf(dchar **str, const char *format, va_list args); /** diff --git a/src/eval.c b/src/eval.c index a990fd4..859ad7e 100644 --- a/src/eval.c +++ b/src/eval.c @@ -57,7 +57,7 @@ struct bfs_eval { /** * Print an error message. */ -attr_format(2, 3) +attr(format(2, 3)) static void eval_error(struct bfs_eval *state, const char *format, ...) { // By POSIX, any errors should be accompanied by a non-zero exit status *state->ret = EXIT_FAILURE; diff --git a/src/exec.c b/src/exec.c index 90b3598..ba2fec8 100644 --- a/src/exec.c +++ b/src/exec.c @@ -22,7 +22,7 @@ #include /** Print some debugging info. */ -attr_format(2, 3) +attr(format(2, 3)) static void bfs_exec_debug(const struct bfs_exec *execbuf, const char *format, ...) { const struct bfs_ctx *ctx = execbuf->ctx; diff --git a/src/fsade.c b/src/fsade.c index 4d22d99..a48eeb0 100644 --- a/src/fsade.c +++ b/src/fsade.c @@ -32,7 +32,7 @@ * Many of the APIs used here don't have *at() variants, but we can try to * emulate something similar if /proc/self/fd is available. */ -attr_maybe_unused +attr(maybe_unused) static const char *fake_at(const struct BFTW *ftwbuf) { static atomic int proc_works = -1; @@ -66,7 +66,7 @@ fail: return ftwbuf->path; } -attr_maybe_unused +attr(maybe_unused) static void free_fake_at(const struct BFTW *ftwbuf, const char *path) { if (path != ftwbuf->path) { dstrfree((dchar *)path); @@ -76,7 +76,7 @@ static void free_fake_at(const struct BFTW *ftwbuf, const char *path) { /** * Check if an error was caused by the absence of support or data for a feature. */ -attr_maybe_unused +attr(maybe_unused) static bool is_absence_error(int error) { // If the OS doesn't support the feature, it's obviously not enabled for // any files diff --git a/src/ioq.c b/src/ioq.c index bd8d111..2739338 100644 --- a/src/ioq.c +++ b/src/ioq.c @@ -273,7 +273,7 @@ static struct ioq_monitor *ioq_slot_monitor(struct ioqq *ioqq, ioq_slot *slot) { } /** Atomically wait for a slot to change. */ -attr_noinline +attr(noinline) static uintptr_t ioq_slot_wait(struct ioqq *ioqq, ioq_slot *slot, uintptr_t value) { struct ioq_monitor *monitor = ioq_slot_monitor(ioqq, slot); mutex_lock(&monitor->mutex); @@ -303,7 +303,7 @@ done: } /** Wake up any threads waiting on a slot. */ -attr_noinline +attr(noinline) static void ioq_slot_wake(struct ioqq *ioqq, ioq_slot *slot) { struct ioq_monitor *monitor = ioq_slot_monitor(ioqq, slot); diff --git a/src/mtab.c b/src/mtab.c index 082150c..cc726a2 100644 --- a/src/mtab.c +++ b/src/mtab.c @@ -61,7 +61,7 @@ struct bfs_mtab { /** * Add an entry to the mount table. */ -attr_maybe_unused +attr(maybe_unused) static int bfs_mtab_add(struct bfs_mtab *mtab, const char *path, const char *type) { struct bfs_mount *mount = RESERVE(struct bfs_mount, &mtab->mounts, &mtab->nmounts); if (!mount) { diff --git a/src/opt.c b/src/opt.c index 5da73d8..3ee5e81 100644 --- a/src/opt.c +++ b/src/opt.c @@ -305,7 +305,7 @@ struct opt_state { }; /** Log an optimization. */ -attr_format(3, 4) +attr(format(3, 4)) static bool opt_debug(const struct opt_state *state, int level, const char *format, ...) { bfs_assert(state->ctx->optlevel >= level); @@ -321,7 +321,7 @@ static bool opt_debug(const struct opt_state *state, int level, const char *form } /** Warn about an expression. */ -attr_format(3, 4) +attr(format(3, 4)) static void opt_warning(const struct opt_state *state, const struct bfs_expr *expr, const char *format, ...) { if (bfs_expr_warning(state->ctx, expr)) { va_list args; diff --git a/src/parse.c b/src/parse.c index 778fc68..35d22fb 100644 --- a/src/parse.c +++ b/src/parse.c @@ -246,7 +246,7 @@ static void highlight_args(const struct bfs_ctx *ctx, char **argv, size_t argc, /** * Print an error message during parsing. */ -attr_format(2, 3) +attr(format(2, 3)) static void parse_error(const struct parser_state *state, const char *format, ...) { int error = errno; const struct bfs_ctx *ctx = state->ctx; @@ -266,7 +266,7 @@ static void parse_error(const struct parser_state *state, const char *format, .. /** * Print an error about some command line arguments. */ -attr_format(4, 5) +attr(format(4, 5)) static void parse_argv_error(const struct parser_state *state, char **argv, size_t argc, const char *format, ...) { int error = errno; const struct bfs_ctx *ctx = state->ctx; @@ -286,7 +286,7 @@ static void parse_argv_error(const struct parser_state *state, char **argv, size /** * Print an error about conflicting command line arguments. */ -attr_format(6, 7) +attr(format(6, 7)) static void parse_conflict_error(const struct parser_state *state, char **argv1, size_t argc1, char **argv2, size_t argc2, const char *format, ...) { int error = errno; const struct bfs_ctx *ctx = state->ctx; @@ -307,7 +307,7 @@ static void parse_conflict_error(const struct parser_state *state, char **argv1, /** * Print an error about an expression. */ -attr_format(3, 4) +attr(format(3, 4)) static void parse_expr_error(const struct parser_state *state, const struct bfs_expr *expr, const char *format, ...) { int error = errno; const struct bfs_ctx *ctx = state->ctx; @@ -324,7 +324,7 @@ static void parse_expr_error(const struct parser_state *state, const struct bfs_ /** * Print a warning message during parsing. */ -attr_format(2, 3) +attr(format(2, 3)) static bool parse_warning(const struct parser_state *state, const char *format, ...) { int error = errno; const struct bfs_ctx *ctx = state->ctx; @@ -347,7 +347,7 @@ static bool parse_warning(const struct parser_state *state, const char *format, /** * Print a warning about conflicting command line arguments. */ -attr_format(6, 7) +attr(format(6, 7)) static bool parse_conflict_warning(const struct parser_state *state, char **argv1, size_t argc1, char **argv2, size_t argc2, const char *format, ...) { int error = errno; const struct bfs_ctx *ctx = state->ctx; @@ -371,7 +371,7 @@ static bool parse_conflict_warning(const struct parser_state *state, char **argv /** * Print a warning about an expression. */ -attr_format(3, 4) +attr(format(3, 4)) static bool parse_expr_warning(const struct parser_state *state, const struct bfs_expr *expr, const char *format, ...) { int error = errno; const struct bfs_ctx *ctx = state->ctx; diff --git a/src/trie.c b/src/trie.c index cf55cee..bd5300d 100644 --- a/src/trie.c +++ b/src/trie.c @@ -95,7 +95,7 @@ bfs_static_assert(CHAR_WIDTH == 8); #if __i386__ || __x86_64__ -# define trie_clones attr_target_clones("popcnt", "default") +# define trie_clones attr(target_clones("popcnt", "default")) #else # define trie_clones #endif diff --git a/src/xspawn.c b/src/xspawn.c index 03287c3..40115a1 100644 --- a/src/xspawn.c +++ b/src/xspawn.c @@ -83,7 +83,7 @@ int bfs_spawn_destroy(struct bfs_spawn *ctx) { #if _POSIX_SPAWN > 0 /** Set some posix_spawnattr flags. */ -attr_maybe_unused +attr(maybe_unused) static int bfs_spawn_addflags(struct bfs_spawn *ctx, short flags) { short prev; errno = posix_spawnattr_getflags(&ctx->attr, &prev); -- cgit v1.2.3 From a85fc263a89fb89bc8b2a8166747660a177b1773 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Wed, 22 Nov 2023 09:33:49 -0500 Subject: config: s/attr_format/attr_printf/ --- src/bar.c | 2 +- src/color.c | 4 ++-- src/color.h | 4 ++-- src/config.h | 4 ++-- src/diag.h | 14 +++++++------- src/dstring.h | 8 ++++---- src/eval.c | 2 +- src/exec.c | 2 +- src/opt.c | 4 ++-- src/parse.c | 14 +++++++------- 10 files changed, 29 insertions(+), 29 deletions(-) (limited to 'src/color.c') diff --git a/src/bar.c b/src/bar.c index babadc3..8ab4112 100644 --- a/src/bar.c +++ b/src/bar.c @@ -127,7 +127,7 @@ static void reset_before_death_by(int sig) { } /** printf() to the status bar with a single write(). */ -attr(format(2, 3)) +attr(printf(2, 3)) static int bfs_bar_printf(struct bfs_bar *bar, const char *format, ...) { va_list args; va_start(args, format); diff --git a/src/color.c b/src/color.c index 4c2c8ca..5247cbf 100644 --- a/src/color.c +++ b/src/color.c @@ -1105,7 +1105,7 @@ static int print_link_target(CFILE *cfile, const struct BFTW *ftwbuf) { } /** Format some colored output to the buffer. */ -attr(format(2, 3)) +attr(printf(2, 3)) static int cbuff(CFILE *cfile, const char *format, ...); /** Dump a parsed expression tree, for debugging. */ @@ -1177,7 +1177,7 @@ static int print_expr(CFILE *cfile, const struct bfs_expr *expr, bool verbose) { return 0; } -attr(format(2, 0)) +attr(printf(2, 0)) static int cvbuff(CFILE *cfile, const char *format, va_list args) { const struct colors *colors = cfile->colors; int error = errno; diff --git a/src/color.h b/src/color.h index 81f0e2a..760aa9d 100644 --- a/src/color.h +++ b/src/color.h @@ -100,13 +100,13 @@ int cfclose(CFILE *cfile); * @return * 0 on success, -1 on failure. */ -attr(format(2, 3)) +attr(printf(2, 3)) int cfprintf(CFILE *cfile, const char *format, ...); /** * cfprintf() variant that takes a va_list. */ -attr(format(2, 0)) +attr(printf(2, 0)) int cvfprintf(CFILE *cfile, const char *format, va_list args); #endif // BFS_COLOR_H diff --git a/src/config.h b/src/config.h index aa03552..46f1efe 100644 --- a/src/config.h +++ b/src/config.h @@ -240,9 +240,9 @@ typedef long double max_align_t; * Adds compiler warnings for bad printf()-style function calls, if supported. */ #if __has_attribute(format) -# define attr_format(fmt, args) __attribute__((format(printf, fmt, args))) +# define attr_printf(fmt, args) __attribute__((format(printf, fmt, args))) #else -# define attr_format(fmt, args) +# define attr_printf(fmt, args) #endif /** diff --git a/src/diag.h b/src/diag.h index aa6a44f..791c065 100644 --- a/src/diag.h +++ b/src/diag.h @@ -44,7 +44,7 @@ struct bfs_loc { /** * Print a message to standard error and abort. */ -attr(cold, format(2, 3)) +attr(cold, printf(2, 3)) noreturn void bfs_abortf(const struct bfs_loc *loc, const char *format, ...); /** @@ -122,7 +122,7 @@ void bfs_perror(const struct bfs_ctx *ctx, const char *str); /** * Shorthand for printing error messages. */ -attr(cold, format(2, 3)) +attr(cold, printf(2, 3)) void bfs_error(const struct bfs_ctx *ctx, const char *format, ...); /** @@ -130,7 +130,7 @@ void bfs_error(const struct bfs_ctx *ctx, const char *format, ...); * * @return Whether a warning was printed. */ -attr(cold, format(2, 3)) +attr(cold, printf(2, 3)) bool bfs_warning(const struct bfs_ctx *ctx, const char *format, ...); /** @@ -138,25 +138,25 @@ bool bfs_warning(const struct bfs_ctx *ctx, const char *format, ...); * * @return Whether a debug message was printed. */ -attr(cold, format(3, 4)) +attr(cold, printf(3, 4)) bool bfs_debug(const struct bfs_ctx *ctx, enum debug_flags flag, const char *format, ...); /** * bfs_error() variant that takes a va_list. */ -attr(cold, format(2, 0)) +attr(cold, printf(2, 0)) void bfs_verror(const struct bfs_ctx *ctx, const char *format, va_list args); /** * bfs_warning() variant that takes a va_list. */ -attr(cold, format(2, 0)) +attr(cold, printf(2, 0)) bool bfs_vwarning(const struct bfs_ctx *ctx, const char *format, va_list args); /** * bfs_debug() variant that takes a va_list. */ -attr(cold, format(3, 0)) +attr(cold, printf(3, 0)) bool bfs_vdebug(const struct bfs_ctx *ctx, enum debug_flags flag, const char *format, va_list args); /** diff --git a/src/dstring.h b/src/dstring.h index 1be1185..6006199 100644 --- a/src/dstring.h +++ b/src/dstring.h @@ -243,7 +243,7 @@ int dstrxcpy(dchar **dest, const char *str, size_t len); * @return * The created string, or NULL on failure. */ -attr(format(1, 2)) +attr(printf(1, 2)) char *dstrprintf(const char *format, ...); /** @@ -256,7 +256,7 @@ char *dstrprintf(const char *format, ...); * @return * The created string, or NULL on failure. */ -attr(format(1, 0)) +attr(printf(1, 0)) char *dstrvprintf(const char *format, va_list args); /** @@ -271,7 +271,7 @@ char *dstrvprintf(const char *format, va_list args); * @return * 0 on success, -1 on failure. */ -attr(format(2, 3)) +attr(printf(2, 3)) int dstrcatf(dchar **str, const char *format, ...); /** @@ -286,7 +286,7 @@ int dstrcatf(dchar **str, const char *format, ...); * @return * 0 on success, -1 on failure. */ -attr(format(2, 0)) +attr(printf(2, 0)) int dstrvcatf(dchar **str, const char *format, va_list args); /** diff --git a/src/eval.c b/src/eval.c index 859ad7e..372fcf5 100644 --- a/src/eval.c +++ b/src/eval.c @@ -57,7 +57,7 @@ struct bfs_eval { /** * Print an error message. */ -attr(format(2, 3)) +attr(printf(2, 3)) static void eval_error(struct bfs_eval *state, const char *format, ...) { // By POSIX, any errors should be accompanied by a non-zero exit status *state->ret = EXIT_FAILURE; diff --git a/src/exec.c b/src/exec.c index ba2fec8..60bfd28 100644 --- a/src/exec.c +++ b/src/exec.c @@ -22,7 +22,7 @@ #include /** Print some debugging info. */ -attr(format(2, 3)) +attr(printf(2, 3)) static void bfs_exec_debug(const struct bfs_exec *execbuf, const char *format, ...) { const struct bfs_ctx *ctx = execbuf->ctx; diff --git a/src/opt.c b/src/opt.c index 3ee5e81..ddcd1ab 100644 --- a/src/opt.c +++ b/src/opt.c @@ -305,7 +305,7 @@ struct opt_state { }; /** Log an optimization. */ -attr(format(3, 4)) +attr(printf(3, 4)) static bool opt_debug(const struct opt_state *state, int level, const char *format, ...) { bfs_assert(state->ctx->optlevel >= level); @@ -321,7 +321,7 @@ static bool opt_debug(const struct opt_state *state, int level, const char *form } /** Warn about an expression. */ -attr(format(3, 4)) +attr(printf(3, 4)) static void opt_warning(const struct opt_state *state, const struct bfs_expr *expr, const char *format, ...) { if (bfs_expr_warning(state->ctx, expr)) { va_list args; diff --git a/src/parse.c b/src/parse.c index 35d22fb..8d9c3f0 100644 --- a/src/parse.c +++ b/src/parse.c @@ -246,7 +246,7 @@ static void highlight_args(const struct bfs_ctx *ctx, char **argv, size_t argc, /** * Print an error message during parsing. */ -attr(format(2, 3)) +attr(printf(2, 3)) static void parse_error(const struct parser_state *state, const char *format, ...) { int error = errno; const struct bfs_ctx *ctx = state->ctx; @@ -266,7 +266,7 @@ static void parse_error(const struct parser_state *state, const char *format, .. /** * Print an error about some command line arguments. */ -attr(format(4, 5)) +attr(printf(4, 5)) static void parse_argv_error(const struct parser_state *state, char **argv, size_t argc, const char *format, ...) { int error = errno; const struct bfs_ctx *ctx = state->ctx; @@ -286,7 +286,7 @@ static void parse_argv_error(const struct parser_state *state, char **argv, size /** * Print an error about conflicting command line arguments. */ -attr(format(6, 7)) +attr(printf(6, 7)) static void parse_conflict_error(const struct parser_state *state, char **argv1, size_t argc1, char **argv2, size_t argc2, const char *format, ...) { int error = errno; const struct bfs_ctx *ctx = state->ctx; @@ -307,7 +307,7 @@ static void parse_conflict_error(const struct parser_state *state, char **argv1, /** * Print an error about an expression. */ -attr(format(3, 4)) +attr(printf(3, 4)) static void parse_expr_error(const struct parser_state *state, const struct bfs_expr *expr, const char *format, ...) { int error = errno; const struct bfs_ctx *ctx = state->ctx; @@ -324,7 +324,7 @@ static void parse_expr_error(const struct parser_state *state, const struct bfs_ /** * Print a warning message during parsing. */ -attr(format(2, 3)) +attr(printf(2, 3)) static bool parse_warning(const struct parser_state *state, const char *format, ...) { int error = errno; const struct bfs_ctx *ctx = state->ctx; @@ -347,7 +347,7 @@ static bool parse_warning(const struct parser_state *state, const char *format, /** * Print a warning about conflicting command line arguments. */ -attr(format(6, 7)) +attr(printf(6, 7)) static bool parse_conflict_warning(const struct parser_state *state, char **argv1, size_t argc1, char **argv2, size_t argc2, const char *format, ...) { int error = errno; const struct bfs_ctx *ctx = state->ctx; @@ -371,7 +371,7 @@ static bool parse_conflict_warning(const struct parser_state *state, char **argv /** * Print a warning about an expression. */ -attr(format(3, 4)) +attr(printf(3, 4)) static bool parse_expr_warning(const struct parser_state *state, const struct bfs_expr *expr, const char *format, ...) { int error = errno; const struct bfs_ctx *ctx = state->ctx; -- cgit v1.2.3 From 4a36bb92a5bbdc41965a6d2c6eae6cdca5983474 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Sun, 7 Jan 2024 12:19:17 -0500 Subject: expr: Make expressions variadic Rather than only unary/binary expressions, we now support an arbitrary number of children. The optimizer has been re-written almost completely and now supports optimal reordering of longer expression chains, rather than just arm-swapping. Fixes #85. --- src/color.c | 39 +- src/ctx.c | 2 +- src/diag.c | 5 +- src/eval.c | 55 +- src/expr.c | 37 +- src/expr.h | 28 +- src/opt.c | 2468 +++++++++++++++++++++++++++++++++++++++-------------------- src/parse.c | 73 +- 8 files changed, 1768 insertions(+), 939 deletions(-) (limited to 'src/color.c') diff --git a/src/color.c b/src/color.c index 5247cbf..1f10c04 100644 --- a/src/color.c +++ b/src/color.c @@ -1109,7 +1109,11 @@ attr(printf(2, 3)) static int cbuff(CFILE *cfile, const char *format, ...); /** Dump a parsed expression tree, for debugging. */ -static int print_expr(CFILE *cfile, const struct bfs_expr *expr, bool verbose) { +static int print_expr(CFILE *cfile, const struct bfs_expr *expr, bool verbose, int depth) { + if (depth >= 2) { + return dstrcat(&cfile->buffer, "(...)"); + } + if (!expr) { return dstrcat(&cfile->buffer, "(null)"); } @@ -1118,13 +1122,7 @@ static int print_expr(CFILE *cfile, const struct bfs_expr *expr, bool verbose) { return -1; } - const struct bfs_expr *lhs = NULL; - const struct bfs_expr *rhs = NULL; - if (bfs_expr_is_parent(expr)) { - lhs = expr->lhs; - rhs = expr->rhs; - if (cbuff(cfile, "${red}%pq${rs}", expr->argv[0]) < 0) { return -1; } @@ -1152,21 +1150,20 @@ static int print_expr(CFILE *cfile, const struct bfs_expr *expr, bool verbose) { } } - if (lhs) { - if (dstrcat(&cfile->buffer, " ") != 0) { - return -1; - } - if (print_expr(cfile, lhs, verbose) != 0) { - return -1; - } - } - - if (rhs) { + int count = 0; + for (struct bfs_expr *child = bfs_expr_children(expr); child; child = child->next) { if (dstrcat(&cfile->buffer, " ") != 0) { return -1; } - if (print_expr(cfile, rhs, verbose) != 0) { - return -1; + if (++count >= 3) { + if (dstrcat(&cfile->buffer, "...") != 0) { + return -1; + } + break; + } else { + if (print_expr(cfile, child, verbose, depth + 1) != 0) { + return -1; + } } } @@ -1276,12 +1273,12 @@ static int cvbuff(CFILE *cfile, const char *format, va_list args) { break; case 'e': - if (print_expr(cfile, va_arg(args, const struct bfs_expr *), false) != 0) { + if (print_expr(cfile, va_arg(args, const struct bfs_expr *), false, 0) != 0) { return -1; } break; case 'E': - if (print_expr(cfile, va_arg(args, const struct bfs_expr *), true) != 0) { + if (print_expr(cfile, va_arg(args, const struct bfs_expr *), true, 0) != 0) { return -1; } break; diff --git a/src/ctx.c b/src/ctx.c index a3c5140..1f3e72e 100644 --- a/src/ctx.c +++ b/src/ctx.c @@ -241,7 +241,7 @@ int bfs_ctx_free(struct bfs_ctx *ctx) { free_colors(ctx->colors); - for_slist (struct bfs_expr, expr, &ctx->expr_list) { + for_slist (struct bfs_expr, expr, &ctx->expr_list, freelist) { bfs_expr_clear(expr); } arena_destroy(&ctx->expr_arena); diff --git a/src/diag.c b/src/diag.c index bf2343d..efa7ebd 100644 --- a/src/diag.c +++ b/src/diag.c @@ -158,9 +158,8 @@ static bool highlight_expr_recursive(const struct bfs_ctx *ctx, const struct bfs } } - if (bfs_expr_is_parent(expr)) { - ret |= highlight_expr_recursive(ctx, expr->lhs, args); - ret |= highlight_expr_recursive(ctx, expr->rhs, args); + for (struct bfs_expr *child = bfs_expr_children(expr); child; child = child->next) { + ret |= highlight_expr_recursive(ctx, child, args); } return ret; diff --git a/src/eval.c b/src/eval.c index 372fcf5..49c4aff 100644 --- a/src/eval.c +++ b/src/eval.c @@ -372,11 +372,10 @@ static int eval_exec_finish(const struct bfs_expr *expr, const struct bfs_ctx *c } ret = -1; } - } else if (bfs_expr_is_parent(expr)) { - if (expr->lhs && eval_exec_finish(expr->lhs, ctx) != 0) { - ret = -1; - } - if (expr->rhs && eval_exec_finish(expr->rhs, ctx) != 0) { + } + + for (struct bfs_expr *child = bfs_expr_children(expr); child; child = child->next) { + if (eval_exec_finish(child, ctx) != 0) { ret = -1; } } @@ -1045,50 +1044,48 @@ static bool eval_expr(struct bfs_expr *expr, struct bfs_eval *state) { * Evaluate a negation. */ bool eval_not(const struct bfs_expr *expr, struct bfs_eval *state) { - return !eval_expr(expr->rhs, state); + return !eval_expr(bfs_expr_children(expr), state); } /** * Evaluate a conjunction. */ bool eval_and(const struct bfs_expr *expr, struct bfs_eval *state) { - if (!eval_expr(expr->lhs, state)) { - return false; - } - - if (state->quit) { - return false; + for (struct bfs_expr *child = bfs_expr_children(expr); child; child = child->next) { + if (!eval_expr(child, state) || state->quit) { + return false; + } } - return eval_expr(expr->rhs, state); + return true; } /** * Evaluate a disjunction. */ bool eval_or(const struct bfs_expr *expr, struct bfs_eval *state) { - if (eval_expr(expr->lhs, state)) { - return true; - } - - if (state->quit) { - return false; + for (struct bfs_expr *child = bfs_expr_children(expr); child; child = child->next) { + if (eval_expr(child, state) || state->quit) { + return true; + } } - return eval_expr(expr->rhs, state); + return false; } /** * Evaluate the comma operator. */ bool eval_comma(const struct bfs_expr *expr, struct bfs_eval *state) { - eval_expr(expr->lhs, state); - - if (state->quit) { - return false; + bool ret; + for (struct bfs_expr *child = bfs_expr_children(expr); child; child = child->next) { + ret = eval_expr(child, state); + if (state->quit) { + break; + } } - return eval_expr(expr->rhs, state); + return ret; } /** Update the status bar. */ @@ -1571,12 +1568,8 @@ static bool eval_must_buffer(const struct bfs_expr *expr) { return true; } - if (bfs_expr_is_parent(expr)) { - if (expr->lhs && eval_must_buffer(expr->lhs)) { - return true; - } - - if (expr->rhs && eval_must_buffer(expr->rhs)) { + for (struct bfs_expr *child = bfs_expr_children(expr); child; child = child->next) { + if (eval_must_buffer(child)) { return true; } } diff --git a/src/expr.c b/src/expr.c index 2002fc7..3e0033f 100644 --- a/src/expr.c +++ b/src/expr.c @@ -23,7 +23,12 @@ struct bfs_expr *bfs_expr_new(struct bfs_ctx *ctx, bfs_eval_fn *eval_fn, size_t expr->argc = argc; expr->argv = argv; expr->probability = 0.5; - SLIST_PREPEND(&ctx->expr_list, expr); + SLIST_PREPEND(&ctx->expr_list, expr, freelist); + + if (bfs_expr_is_parent(expr)) { + SLIST_INIT(&expr->children); + } + return expr; } @@ -34,6 +39,36 @@ bool bfs_expr_is_parent(const struct bfs_expr *expr) { || expr->eval_fn == eval_comma; } +struct bfs_expr *bfs_expr_children(const struct bfs_expr *expr) { + if (bfs_expr_is_parent(expr)) { + return expr->children.head; + } else { + return NULL; + } +} + +void bfs_expr_append(struct bfs_expr *expr, struct bfs_expr *child) { + bfs_assert(bfs_expr_is_parent(expr)); + + SLIST_APPEND(&expr->children, child); + + if (!child->pure) { + expr->pure = false; + } + + expr->persistent_fds += child->persistent_fds; + if (expr->ephemeral_fds < child->ephemeral_fds) { + expr->ephemeral_fds = child->ephemeral_fds; + } +} + +void bfs_expr_extend(struct bfs_expr *expr, struct bfs_exprs *children) { + while (!SLIST_EMPTY(children)) { + struct bfs_expr *child = SLIST_POP(children); + bfs_expr_append(expr, child); + } +} + bool bfs_expr_never_returns(const struct bfs_expr *expr) { // Expressions that never return are vacuously both always true and always false return expr->always_true && expr->always_false; diff --git a/src/expr.h b/src/expr.h index 290f1f8..4d607a4 100644 --- a/src/expr.h +++ b/src/expr.h @@ -86,8 +86,10 @@ struct bfs_exprs { * A command line expression. */ struct bfs_expr { - /** The next allocated expression. */ + /** This expression's next sibling, if any. */ struct bfs_expr *next; + /** The next allocated expression. */ + struct { struct bfs_expr *next; } freelist; /** The function that evaluates this expression. */ bfs_eval_fn *eval_fn; @@ -123,12 +125,7 @@ struct bfs_expr { /** Auxilliary data for the evaluation function. */ union { /** Child expressions. */ - struct { - /** The left hand side of the expression. */ - struct bfs_expr *lhs; - /** The right hand side of the expression. */ - struct bfs_expr *rhs; - }; + struct bfs_exprs children; /** Integer comparisons. */ struct { @@ -218,10 +215,25 @@ struct bfs_ctx; struct bfs_expr *bfs_expr_new(struct bfs_ctx *ctx, bfs_eval_fn *eval, size_t argc, char **argv); /** - * @return Whether the expression has child expressions. + * @return Whether this type of expression has children. */ bool bfs_expr_is_parent(const struct bfs_expr *expr); +/** + * @return The first child of this expression, or NULL if it has none. + */ +struct bfs_expr *bfs_expr_children(const struct bfs_expr *expr); + +/** + * Add a child to an expression. + */ +void bfs_expr_append(struct bfs_expr *expr, struct bfs_expr *child); + +/** + * Add a list of children to an expression. + */ +void bfs_expr_extend(struct bfs_expr *expr, struct bfs_exprs *children); + /** * @return Whether expr is known to always quit. */ diff --git a/src/opt.c b/src/opt.c index 1dc985a..7203c61 100644 --- a/src/opt.c +++ b/src/opt.c @@ -21,11 +21,12 @@ * -bar is likely to return false. * * -O4/-Ofast: aggressive optimizations that may affect correctness in corner - * cases. The main effect is to use impure to determine if any side-effects are - * reachable at all, and skipping the traversal if not. + * cases. The main effect is to use opt->impure to determine if any side- + * effects are reachable at all, skipping the traversal if not. */ #include "opt.h" +#include "bit.h" #include "color.h" #include "config.h" #include "ctx.h" @@ -33,6 +34,7 @@ #include "eval.h" #include "exec.h" #include "expr.h" +#include "list.h" #include "pwcache.h" #include #include @@ -41,9 +43,9 @@ #include #include -static char *fake_and_arg = "-a"; -static char *fake_or_arg = "-o"; -static char *fake_not_arg = "!"; +static char *fake_and_arg = "-and"; +static char *fake_or_arg = "-or"; +static char *fake_not_arg = "-not"; /** * The data flow domain for predicates. @@ -69,6 +71,70 @@ static void pred_join(enum df_pred *dest, enum df_pred src) { *dest |= src; } +/** + * Types of predicates we track. + */ +enum pred_type { + /** -readable */ + READABLE_PRED, + /** -writable */ + WRITABLE_PRED, + /** -executable */ + EXECUTABLE_PRED, + /** -acl */ + ACL_PRED, + /** -capable */ + CAPABLE_PRED, + /** -empty */ + EMPTY_PRED, + /** -hidden */ + HIDDEN_PRED, + /** -nogroup */ + NOGROUP_PRED, + /** -nouser */ + NOUSER_PRED, + /** -sparse */ + SPARSE_PRED, + /** -xattr */ + XATTR_PRED, + /** The number of pred_types. */ + PRED_TYPES, +}; + +/** Get the name of a predicate type. */ +static const char *pred_type_name(enum pred_type type) { + switch (type) { + case READABLE_PRED: + return "-readable"; + case WRITABLE_PRED: + return "-writable"; + case EXECUTABLE_PRED: + return "-executable"; + case ACL_PRED: + return "-acl"; + case CAPABLE_PRED: + return "-capable"; + case EMPTY_PRED: + return "-empty"; + case HIDDEN_PRED: + return "-hidden"; + case NOGROUP_PRED: + return "-nogroup"; + case NOUSER_PRED: + return "-nouser"; + case SPARSE_PRED: + return "-sparse"; + case XATTR_PRED: + return "-xattr"; + + case PRED_TYPES: + break; + } + + bfs_bug("Unknown predicate %d", (int)type); + return "???"; +} + /** * A contrained integer range. */ @@ -97,6 +163,11 @@ static void range_init_top(struct df_range *range) { range->max = LLONG_MAX; } +/** Check for an infinite range. */ +static bool range_is_top(const struct df_range *range) { + return range->min == 0 && range->max == LLONG_MAX; +} + /** Compute the minimum of two values. */ static long long min_value(long long a, long long b) { if (a < b) { @@ -170,35 +241,29 @@ enum range_type { RANGE_TYPES, }; -/** - * Types of predicates we track. - */ -enum pred_type { - /** -readable */ - READABLE_PRED, - /** -writable */ - WRITABLE_PRED, - /** -executable */ - EXECUTABLE_PRED, - /** -acl */ - ACL_PRED, - /** -capable */ - CAPABLE_PRED, - /** -empty */ - EMPTY_PRED, - /** -hidden */ - HIDDEN_PRED, - /** -nogroup */ - NOGROUP_PRED, - /** -nouser */ - NOUSER_PRED, - /** -sparse */ - SPARSE_PRED, - /** -xattr */ - XATTR_PRED, - /** The number of pred_types. */ - PRED_TYPES, -}; +/** Get the name of a range type. */ +static const char *range_type_name(enum range_type type) { + switch (type) { + case DEPTH_RANGE: + return "-depth"; + case GID_RANGE: + return "-gid"; + case INUM_RANGE: + return "-inum"; + case LINKS_RANGE: + return "-links"; + case SIZE_RANGE: + return "-size"; + case UID_RANGE: + return "-uid"; + + case RANGE_TYPES: + break; + } + + bfs_bug("Unknown range %d", (int)type); + return "???"; +} /** * The data flow analysis domain. @@ -210,9 +275,9 @@ struct df_domain { /** The value ranges we track. */ struct df_range ranges[RANGE_TYPES]; - /** Bitmask of possible file types. */ + /** Bitmask of possible -types. */ unsigned int types; - /** Bitmask of possible link target types. */ + /** Bitmask of possible -xtypes. */ unsigned int xtypes; }; @@ -265,6 +330,31 @@ static void df_init_top(struct df_domain *value) { value->xtypes = ~0; } +/** Check for the top element. */ +static bool df_is_top(const struct df_domain *value) { + for (int i = 0; i < PRED_TYPES; ++i) { + if (value->preds[i] != PRED_TOP) { + return false; + } + } + + for (int i = 0; i < RANGE_TYPES; ++i) { + if (!range_is_top(&value->ranges[i])) { + return false; + } + } + + if (value->types != ~0U) { + return false; + } + + if (value->xtypes != ~0U) { + return false; + } + + return true; +} + /** Compute the union of two fact sets. */ static void df_join(struct df_domain *dest, const struct df_domain *src) { for (int i = 0; i < PRED_TYPES; ++i) { @@ -285,6 +375,15 @@ static void df_join(struct df_domain *dest, const struct df_domain *src) { struct bfs_opt { /** The context we're optimizing. */ struct bfs_ctx *ctx; + /** Optimization level (ctx->optlevel). */ + int level; + /** Recursion depth. */ + int depth; + + /** Whether to produce warnings. */ + bool warn; + /** Whether the result of this expression is ignored. */ + bool ignore_result; /** Data flow state before this expression is evaluated. */ struct df_domain before; @@ -296,18 +395,14 @@ struct bfs_opt { struct df_domain *impure; }; -/** Constrain the value of a predicate. */ -static void opt_constrain_pred(struct bfs_opt *opt, enum pred_type type, bool value) { - constrain_pred(&opt->after_true.preds[type], value); - constrain_pred(&opt->after_false.preds[type], !value); -} - /** Log an optimization. */ -attr(printf(3, 4)) -static bool opt_debug(const struct bfs_opt *opt, int level, const char *format, ...) { - bfs_assert(opt->ctx->optlevel >= level); +attr(printf(2, 3)) +static bool opt_debug(struct bfs_opt *opt, const char *format, ...) { + if (bfs_debug_prefix(opt->ctx, DEBUG_OPT)) { + for (int i = 0; i < opt->depth; ++i) { + cfprintf(opt->ctx->cerr, "│ "); + } - if (bfs_debug(opt->ctx, DEBUG_OPT, "${cyn}-O%d${rs}: ", level)) { va_list args; va_start(args, format); cvfprintf(opt->ctx->cerr, format, args); @@ -318,450 +413,577 @@ static bool opt_debug(const struct bfs_opt *opt, int level, const char *format, } } -/** Warn about an expression. */ -attr(printf(3, 4)) -static void opt_warning(const struct bfs_opt *opt, const struct bfs_expr *expr, const char *format, ...) { - if (bfs_expr_warning(opt->ctx, expr)) { +/** Log a recursive call. */ +attr(printf(2, 3)) +static bool opt_enter(struct bfs_opt *opt, const char *format, ...) { + int depth = opt->depth; + if (depth > 0) { + --opt->depth; + } + + bool debug = opt_debug(opt, "%s", depth > 0 ? "├─╮ " : ""); + if (debug) { va_list args; va_start(args, format); - bfs_vwarning(opt->ctx, format, args); + cvfprintf(opt->ctx->cerr, format, args); va_end(args); } -} -/** Create a constant expression. */ -static struct bfs_expr *opt_const(const struct bfs_opt *opt, bool value) { - static bfs_eval_fn *fns[] = {eval_false, eval_true}; - static char *fake_args[] = {"-false", "-true"}; - return bfs_expr_new(opt->ctx, fns[value], 1, &fake_args[value]); + opt->depth = depth + 1; + return debug; } -/** - * Negate an expression. - */ -static struct bfs_expr *negate_expr(const struct bfs_opt *opt, struct bfs_expr *rhs, char **argv) { - if (rhs->eval_fn == eval_not) { - return rhs->rhs; - } +/** Log a recursive return. */ +attr(printf(2, 3)) +static bool opt_leave(struct bfs_opt *opt, const char *format, ...) { + bool debug = false; + int depth = opt->depth; - struct bfs_expr *expr = bfs_expr_new(opt->ctx, eval_not, 1, argv); - if (!expr) { - return NULL; + if (format) { + if (depth > 1) { + opt->depth -= 2; + } + + debug = opt_debug(opt, "%s", depth > 1 ? "├─╯ " : ""); + if (debug) { + va_list args; + va_start(args, format); + cvfprintf(opt->ctx->cerr, format, args); + va_end(args); + } } - expr->lhs = NULL; - expr->rhs = rhs; - return expr; + opt->depth = depth - 1; + return debug; } -static struct bfs_expr *optimize_not_expr(const struct bfs_opt *opt, struct bfs_expr *expr); -static struct bfs_expr *optimize_and_expr(const struct bfs_opt *opt, struct bfs_expr *expr); -static struct bfs_expr *optimize_or_expr(const struct bfs_opt *opt, struct bfs_expr *expr); - -/** - * Apply De Morgan's laws. - */ -static struct bfs_expr *de_morgan(const struct bfs_opt *opt, struct bfs_expr *expr, char **argv) { - bool debug = opt_debug(opt, 1, "De Morgan's laws: %pe ", expr); - - struct bfs_expr *parent = negate_expr(opt, expr, argv); - if (!parent) { - return NULL; +/** Log a shallow visit. */ +attr(printf(2, 3)) +static bool opt_visit(struct bfs_opt *opt, const char *format, ...) { + int depth = opt->depth; + if (depth > 0) { + --opt->depth; } - bool has_parent = true; - if (parent->eval_fn != eval_not) { - expr = parent; - has_parent = false; + bool debug = opt_debug(opt, "%s", depth > 0 ? "├─◯ " : ""); + if (debug) { + va_list args; + va_start(args, format); + cvfprintf(opt->ctx->cerr, format, args); + va_end(args); } - bfs_assert(expr->eval_fn == eval_and || expr->eval_fn == eval_or); - if (expr->eval_fn == eval_and) { - expr->eval_fn = eval_or; - expr->argv = &fake_or_arg; - } else { - expr->eval_fn = eval_and; - expr->argv = &fake_and_arg; - } + opt->depth = depth; + return debug; +} - expr->lhs = negate_expr(opt, expr->lhs, argv); - expr->rhs = negate_expr(opt, expr->rhs, argv); - if (!expr->lhs || !expr->rhs) { - return NULL; +/** Log the deletion of an expression. */ +attr(printf(2, 3)) +static bool opt_delete(struct bfs_opt *opt, const char *format, ...) { + int depth = opt->depth; + + if (depth > 0) { + --opt->depth; } + bool debug = opt_debug(opt, "%s", depth > 0 ? "├─✘ " : ""); if (debug) { - cfprintf(opt->ctx->cerr, "<==> %pe\n", parent); + va_list args; + va_start(args, format); + cvfprintf(opt->ctx->cerr, format, args); + va_end(args); } - if (expr->lhs->eval_fn == eval_not) { - expr->lhs = optimize_not_expr(opt, expr->lhs); - } - if (expr->rhs->eval_fn == eval_not) { - expr->rhs = optimize_not_expr(opt, expr->rhs); - } - if (!expr->lhs || !expr->rhs) { - return NULL; - } + opt->depth = depth; + return debug; +} - if (expr->eval_fn == eval_and) { - expr = optimize_and_expr(opt, expr); - } else { - expr = optimize_or_expr(opt, expr); +typedef bool dump_fn(struct bfs_opt *opt, const char *format, ...); + +/** Print a df_pred. */ +static void pred_dump(dump_fn *dump, struct bfs_opt *opt, const struct df_domain *value, enum pred_type type) { + dump(opt, "${blu}%s${rs}: ", pred_type_name(type)); + + FILE *file = opt->ctx->cerr->file; + switch (value->preds[type]) { + case PRED_BOTTOM: + fprintf(file, "⊥\n"); + break; + case PRED_TOP: + fprintf(file, "⊤\n"); + break; + case PRED_TRUE: + fprintf(file, "true\n"); + break; + case PRED_FALSE: + fprintf(file, "false\n"); + break; } - if (has_parent) { - parent->rhs = expr; +} + +/** Print a df_range. */ +static void range_dump(dump_fn *dump, struct bfs_opt *opt, const struct df_domain *value, enum range_type type) { + dump(opt, "${blu}%s${rs}: ", range_type_name(type)); + + FILE *file = opt->ctx->cerr->file; + const struct df_range *range = &value->ranges[type]; + if (range_is_bottom(range)) { + fprintf(file, "⊥\n"); + } else if (range_is_top(range)) { + fprintf(file, "⊤\n"); + } else if (range->min == range->max) { + fprintf(file, "%lld\n", range->min); } else { - parent = expr; - } - if (!expr) { - return NULL; + if (range->min == LLONG_MIN) { + fprintf(file, "(-∞, "); + } else { + fprintf(file, "[%lld, ", range->min); + } + if (range->max == LLONG_MAX) { + fprintf(file, "∞)\n"); + } else { + fprintf(file, "%lld]\n", range->max); + } } +} - if (has_parent) { - parent = optimize_not_expr(opt, parent); +/** Print a set of types. */ +static void types_dump(dump_fn *dump, struct bfs_opt *opt, const char *name, unsigned int types) { + dump(opt, "${blu}%s${rs}: ", name); + + FILE *file = opt->ctx->cerr->file; + if (types == 0) { + fprintf(file, " ⊥\n"); + } else if (types == ~0U) { + fprintf(file, " ⊤\n"); + } else if (count_ones(types) < count_ones(~types)) { + fprintf(file, " 0x%X\n", types); + } else { + fprintf(file, "~0x%X\n", ~types); } - return parent; } -/** Optimize an expression recursively. */ -static struct bfs_expr *optimize_expr_recursive(struct bfs_opt *opt, struct bfs_expr *expr); +/** Calculate the number of lines of df_dump() output. */ +static int df_dump_lines(const struct df_domain *value) { + int lines = 0; -/** - * Optimize a negation. - */ -static struct bfs_expr *optimize_not_expr(const struct bfs_opt *opt, struct bfs_expr *expr) { - bfs_assert(expr->eval_fn == eval_not); - - struct bfs_expr *rhs = expr->rhs; - - int optlevel = opt->ctx->optlevel; - if (optlevel >= 1) { - if (rhs->eval_fn == eval_true || rhs->eval_fn == eval_false) { - struct bfs_expr *ret = opt_const(opt, rhs->eval_fn == eval_false); - opt_debug(opt, 1, "constant propagation: %pe <==> %pe\n", expr, ret); - return ret; - } else if (rhs->eval_fn == eval_not) { - opt_debug(opt, 1, "double negation: %pe <==> %pe\n", expr, rhs->rhs); - return rhs->rhs; - } else if (bfs_expr_never_returns(rhs)) { - opt_debug(opt, 1, "reachability: %pe <==> %pe\n", expr, rhs); - return expr->rhs; - } else if ((rhs->eval_fn == eval_and || rhs->eval_fn == eval_or) - && (rhs->lhs->eval_fn == eval_not || rhs->rhs->eval_fn == eval_not)) { - return de_morgan(opt, expr, expr->argv); - } + for (int i = 0; i < PRED_TYPES; ++i) { + lines += value->preds[i] != PRED_TOP; } - expr->pure = rhs->pure; - expr->always_true = rhs->always_false; - expr->always_false = rhs->always_true; - expr->cost = rhs->cost; - expr->probability = 1.0 - rhs->probability; + for (int i = 0; i < RANGE_TYPES; ++i) { + lines += !range_is_top(&value->ranges[i]); + } - return expr; + lines += value->types != ~0U; + lines += value->xtypes != ~0U; + + return lines; } -/** Optimize a negation recursively. */ -static struct bfs_expr *optimize_not_expr_recursive(struct bfs_opt *opt, struct bfs_expr *expr) { - struct bfs_opt rhs_state = *opt; - expr->rhs = optimize_expr_recursive(&rhs_state, expr->rhs); - if (!expr->rhs) { - return NULL; +/** Get the right debugging function for a df_dump() line. */ +static dump_fn *df_dump_line(int lines, int *line) { + ++*line; + + if (lines == 1) { + return opt_visit; + } else if (*line == 1) { + return opt_enter; + } else if (*line == lines) { + return opt_leave; + } else { + return opt_debug; } +} - opt->after_true = rhs_state.after_false; - opt->after_false = rhs_state.after_true; - - return optimize_not_expr(opt, expr); -} - -/** Optimize a conjunction. */ -static struct bfs_expr *optimize_and_expr(const struct bfs_opt *opt, struct bfs_expr *expr) { - bfs_assert(expr->eval_fn == eval_and); - - struct bfs_expr *lhs = expr->lhs; - struct bfs_expr *rhs = expr->rhs; - - const struct bfs_ctx *ctx = opt->ctx; - int optlevel = ctx->optlevel; - if (optlevel >= 1) { - if (lhs->eval_fn == eval_true) { - opt_debug(opt, 1, "conjunction elimination: %pe <==> %pe\n", expr, rhs); - return expr->rhs; - } else if (rhs->eval_fn == eval_true) { - opt_debug(opt, 1, "conjunction elimination: %pe <==> %pe\n", expr, lhs); - return expr->lhs; - } else if (lhs->always_false) { - opt_debug(opt, 1, "short-circuit: %pe <==> %pe\n", expr, lhs); - opt_warning(opt, expr->rhs, "This expression is unreachable.\n\n"); - return expr->lhs; - } else if (lhs->always_true && rhs->eval_fn == eval_false) { - bool debug = opt_debug(opt, 1, "strength reduction: %pe <==> ", expr); - struct bfs_expr *ret = expr->lhs; - ret = negate_expr(opt, ret, &fake_not_arg); - if (debug && ret) { - cfprintf(ctx->cerr, "%pe\n", ret); - } - return ret; - } else if (optlevel >= 2 && lhs->pure && rhs->eval_fn == eval_false) { - opt_debug(opt, 2, "purity: %pe <==> %pe\n", expr, rhs); - opt_warning(opt, expr->lhs, "The result of this expression is ignored.\n\n"); - return expr->rhs; - } else if (lhs->eval_fn == eval_not && rhs->eval_fn == eval_not) { - return de_morgan(opt, expr, expr->lhs->argv); - } +/** Print a data flow value. */ +static void df_dump(struct bfs_opt *opt, const char *str, const struct df_domain *value) { + if (df_is_bottom(value)) { + opt_debug(opt, "%s: ⊥\n", str); + return; + } else if (df_is_top(value)) { + opt_debug(opt, "%s: ⊤\n", str); + return; } - expr->pure = lhs->pure && rhs->pure; - expr->always_true = lhs->always_true && rhs->always_true; - expr->always_false = lhs->always_false || rhs->always_false; - expr->cost = lhs->cost + lhs->probability * rhs->cost; - expr->probability = lhs->probability * rhs->probability; + if (!opt_debug(opt, "%s:\n", str)) { + return; + } - return expr; -} + int lines = df_dump_lines(value); + int line = 0; -/** Optimize a conjunction recursively. */ -static struct bfs_expr *optimize_and_expr_recursive(struct bfs_opt *opt, struct bfs_expr *expr) { - struct bfs_opt lhs_state = *opt; - expr->lhs = optimize_expr_recursive(&lhs_state, expr->lhs); - if (!expr->lhs) { - return NULL; + for (int i = 0; i < PRED_TYPES; ++i) { + if (value->preds[i] != PRED_TOP) { + pred_dump(df_dump_line(lines, &line), opt, value, i); + } } - struct bfs_opt rhs_state = *opt; - rhs_state.before = lhs_state.after_true; - expr->rhs = optimize_expr_recursive(&rhs_state, expr->rhs); - if (!expr->rhs) { - return NULL; + for (int i = 0; i < RANGE_TYPES; ++i) { + if (!range_is_top(&value->ranges[i])) { + range_dump(df_dump_line(lines, &line), opt, value, i); + } } - opt->after_true = rhs_state.after_true; - opt->after_false = lhs_state.after_false; - df_join(&opt->after_false, &rhs_state.after_false); - - return optimize_and_expr(opt, expr); -} - -/** Optimize a disjunction. */ -static struct bfs_expr *optimize_or_expr(const struct bfs_opt *opt, struct bfs_expr *expr) { - bfs_assert(expr->eval_fn == eval_or); - - struct bfs_expr *lhs = expr->lhs; - struct bfs_expr *rhs = expr->rhs; - - const struct bfs_ctx *ctx = opt->ctx; - int optlevel = ctx->optlevel; - if (optlevel >= 1) { - if (lhs->always_true) { - opt_debug(opt, 1, "short-circuit: %pe <==> %pe\n", expr, lhs); - opt_warning(opt, expr->rhs, "This expression is unreachable.\n\n"); - return expr->lhs; - } else if (lhs->eval_fn == eval_false) { - opt_debug(opt, 1, "disjunctive syllogism: %pe <==> %pe\n", expr, rhs); - return expr->rhs; - } else if (rhs->eval_fn == eval_false) { - opt_debug(opt, 1, "disjunctive syllogism: %pe <==> %pe\n", expr, lhs); - return expr->lhs; - } else if (lhs->always_false && rhs->eval_fn == eval_true) { - bool debug = opt_debug(opt, 1, "strength reduction: %pe <==> ", expr); - struct bfs_expr *ret = expr->lhs; - ret = negate_expr(opt, ret, &fake_not_arg); - if (debug && ret) { - cfprintf(ctx->cerr, "%pe\n", ret); - } - return ret; - } else if (optlevel >= 2 && lhs->pure && rhs->eval_fn == eval_true) { - opt_debug(opt, 2, "purity: %pe <==> %pe\n", expr, rhs); - opt_warning(opt, expr->lhs, "The result of this expression is ignored.\n\n"); - return expr->rhs; - } else if (lhs->eval_fn == eval_not && rhs->eval_fn == eval_not) { - return de_morgan(opt, expr, expr->lhs->argv); - } + if (value->types != ~0U) { + types_dump(df_dump_line(lines, &line), opt, "-type", value->types); } - expr->pure = lhs->pure && rhs->pure; - expr->always_true = lhs->always_true || rhs->always_true; - expr->always_false = lhs->always_false && rhs->always_false; - expr->cost = lhs->cost + (1 - lhs->probability) * rhs->cost; - expr->probability = lhs->probability + rhs->probability - lhs->probability * rhs->probability; + if (value->xtypes != ~0U) { + types_dump(df_dump_line(lines, &line), opt, "-xtype", value->xtypes); + } +} - return expr; +/** Check if an expression is constant. */ +static bool is_const(const struct bfs_expr *expr) { + return expr->eval_fn == eval_true || expr->eval_fn == eval_false; } -/** Optimize a disjunction recursively. */ -static struct bfs_expr *optimize_or_expr_recursive(struct bfs_opt *opt, struct bfs_expr *expr) { - struct bfs_opt lhs_state = *opt; - expr->lhs = optimize_expr_recursive(&lhs_state, expr->lhs); - if (!expr->lhs) { - return NULL; +/** Warn about an expression. */ +attr(printf(3, 4)) +static void opt_warning(const struct bfs_opt *opt, const struct bfs_expr *expr, const char *format, ...) { + if (!opt->warn) { + return; } - struct bfs_opt rhs_state = *opt; - rhs_state.before = lhs_state.after_false; - expr->rhs = optimize_expr_recursive(&rhs_state, expr->rhs); - if (!expr->rhs) { - return NULL; + if (bfs_expr_is_parent(expr) || is_const(expr)) { + return; } - opt->after_false = rhs_state.after_false; - opt->after_true = lhs_state.after_true; - df_join(&opt->after_true, &rhs_state.after_true); - - return optimize_or_expr(opt, expr); + if (bfs_expr_warning(opt->ctx, expr)) { + va_list args; + va_start(args, format); + bfs_vwarning(opt->ctx, format, args); + va_end(args); + } } -/** Optimize an expression in an ignored-result context. */ -static struct bfs_expr *ignore_result(const struct bfs_opt *opt, struct bfs_expr *expr) { - int optlevel = opt->ctx->optlevel; +/** Remove and return an expression's children. */ +static void foster_children(struct bfs_expr *expr, struct bfs_exprs *children) { + bfs_assert(bfs_expr_is_parent(expr)); - if (optlevel >= 1) { - while (true) { - if (expr->eval_fn == eval_not) { - opt_debug(opt, 1, "ignored result: %pe --> %pe\n", expr, expr->rhs); - opt_warning(opt, expr, "The result of this expression is ignored.\n\n"); - expr = expr->rhs; - } else if (optlevel >= 2 - && (expr->eval_fn == eval_and || expr->eval_fn == eval_or || expr->eval_fn == eval_comma) - && expr->rhs->pure) { - opt_debug(opt, 2, "ignored result: %pe --> %pe\n", expr, expr->lhs); - opt_warning(opt, expr->rhs, "The result of this expression is ignored.\n\n"); - expr = expr->lhs; - } else { - break; - } - } + SLIST_INIT(children); + SLIST_EXTEND(children, &expr->children); - if (optlevel >= 2 && expr->pure && expr->eval_fn != eval_false) { - struct bfs_expr *ret = opt_const(opt, false); - opt_debug(opt, 2, "ignored result: %pe --> %pe\n", expr, ret); - opt_warning(opt, expr, "The result of this expression is ignored.\n\n"); - return ret; - } - } + expr->persistent_fds = 0; + expr->ephemeral_fds = 0; + expr->pure = true; +} - return expr; +/** Return an expression's only child. */ +static struct bfs_expr *only_child(struct bfs_expr *expr) { + bfs_assert(bfs_expr_is_parent(expr)); + struct bfs_expr *child = bfs_expr_children(expr); + bfs_assert(child && !child->next); + return child; } -/** Optimize a comma expression. */ -static struct bfs_expr *optimize_comma_expr(const struct bfs_opt *opt, struct bfs_expr *expr) { - bfs_assert(expr->eval_fn == eval_comma); +/** Foster an expression's only child. */ +static struct bfs_expr *foster_only_child(struct bfs_expr *expr) { + struct bfs_expr *child = only_child(expr); + struct bfs_exprs children; + foster_children(expr, &children); + return child; +} - struct bfs_expr *lhs = expr->lhs; - struct bfs_expr *rhs = expr->rhs; - - int optlevel = opt->ctx->optlevel; - if (optlevel >= 1) { - lhs = expr->lhs = ignore_result(opt, lhs); - - if (bfs_expr_never_returns(lhs)) { - opt_debug(opt, 1, "reachability: %pe <==> %pe\n", expr, lhs); - opt_warning(opt, expr->rhs, "This expression is unreachable.\n\n"); - return expr->lhs; - } else if ((lhs->always_true && rhs->eval_fn == eval_true) - || (lhs->always_false && rhs->eval_fn == eval_false)) { - opt_debug(opt, 1, "redundancy elimination: %pe <==> %pe\n", expr, lhs); - return expr->lhs; - } else if (optlevel >= 2 && lhs->pure) { - opt_debug(opt, 2, "purity: %pe <==> %pe\n", expr, rhs); - opt_warning(opt, expr->lhs, "The result of this expression is ignored.\n\n"); - return expr->rhs; +/** An expression visitor. */ +struct visitor; + +/** An expression-visiting function. */ +typedef struct bfs_expr *visit_fn(struct bfs_opt *opt, struct bfs_expr *expr, const struct visitor *visitor); + +/** An entry in a visitor lookup table. */ +struct visitor_table { + /** The evaluation function to match on. */ + bfs_eval_fn *eval_fn; + /** The visitor function. */ + visit_fn *visit; +}; + +/** Look up a visitor in a table. */ +static visit_fn *look_up_visitor(const struct bfs_expr *expr, const struct visitor_table table[]) { + for (size_t i = 0; table[i].eval_fn; ++i) { + if (expr->eval_fn == table[i].eval_fn) { + return table[i].visit; } } - expr->pure = lhs->pure && rhs->pure; - expr->always_true = bfs_expr_never_returns(lhs) || rhs->always_true; - expr->always_false = bfs_expr_never_returns(lhs) || rhs->always_false; - expr->cost = lhs->cost + rhs->cost; - expr->probability = rhs->probability; - - return expr; + return NULL; } -/** Optimize a comma expression recursively. */ -static struct bfs_expr *optimize_comma_expr_recursive(struct bfs_opt *opt, struct bfs_expr *expr) { - struct bfs_opt lhs_state = *opt; - expr->lhs = optimize_expr_recursive(&lhs_state, expr->lhs); - if (!expr->lhs) { - return NULL; - } +struct visitor { + /** The name of this visitor. */ + const char *name; + + /** A function to call before visiting children. */ + visit_fn *enter; + /** The default visitor. */ + visit_fn *visit; + /** A function to call after visiting children. */ + visit_fn *leave; + + /** A visitor lookup table. */ + struct visitor_table table[]; +}; - struct bfs_opt rhs_state = *opt; - rhs_state.before = lhs_state.after_true; - df_join(&rhs_state.before, &lhs_state.after_false); +/** Recursive visitor implementation. */ +static struct bfs_expr *visit_deep(struct bfs_opt *opt, struct bfs_expr *expr, const struct visitor *visitor); - expr->rhs = optimize_expr_recursive(&rhs_state, expr->rhs); - if (!expr->rhs) { +/** Visit a negation. */ +static struct bfs_expr *visit_not(struct bfs_opt *opt, struct bfs_expr *expr, const struct visitor *visitor) { + struct bfs_expr *rhs = foster_only_child(expr); + + struct bfs_opt nested = *opt; + rhs = visit_deep(&nested, rhs, visitor); + if (!rhs) { return NULL; } - return optimize_comma_expr(opt, expr); + opt->after_true = nested.after_false; + opt->after_false = nested.after_true; + + bfs_expr_append(expr, rhs); + return expr; } -/** Optimize an icmp-style ([+-]N) expression. */ -static void optimize_icmp(struct bfs_opt *opt, const struct bfs_expr *expr, enum range_type type) { - struct df_range *true_range = &opt->after_true.ranges[type]; - struct df_range *false_range = &opt->after_false.ranges[type]; - long long value = expr->num; +/** Visit a conjunction. */ +static struct bfs_expr *visit_and(struct bfs_opt *opt, struct bfs_expr *expr, const struct visitor *visitor) { + struct bfs_exprs children; + foster_children(expr, &children); - switch (expr->int_cmp) { - case BFS_INT_EQUAL: - constrain_min(true_range, value); - constrain_max(true_range, value); - range_remove(false_range, value); - break; + // Base case (-and) == (-true) + df_init_bottom(&opt->after_false); + struct bfs_opt nested = *opt; - case BFS_INT_LESS: - constrain_min(false_range, value); - constrain_max(true_range, value); - range_remove(true_range, value); - break; + while (!SLIST_EMPTY(&children)) { + struct bfs_expr *child = SLIST_POP(&children); - case BFS_INT_GREATER: - constrain_max(false_range, value); - constrain_min(true_range, value); - range_remove(true_range, value); - break; - } -} + if (SLIST_EMPTY(&children)) { + nested.ignore_result = opt->ignore_result; + } else { + nested.ignore_result = false; + } -/** Optimize -{execut,read,writ}able. */ -static struct bfs_expr *optimize_access(struct bfs_opt *opt, struct bfs_expr *expr) { - expr->probability = 1.0; + child = visit_deep(&nested, child, visitor); + if (!child) { + return NULL; + } - if (expr->num & R_OK) { - opt_constrain_pred(opt, READABLE_PRED, true); - expr->probability *= 0.99; - } + df_join(&opt->after_false, &nested.after_false); + nested.before = nested.after_true; - if (expr->num & W_OK) { - opt_constrain_pred(opt, WRITABLE_PRED, true); - expr->probability *= 0.8; + bfs_expr_append(expr, child); } - if (expr->num & X_OK) { - opt_constrain_pred(opt, EXECUTABLE_PRED, true); - expr->probability *= 0.2; - } + opt->after_true = nested.after_true; return expr; } -/** Optimize -empty. */ -static struct bfs_expr *optimize_empty(struct bfs_opt *opt, struct bfs_expr *expr) { - if (opt->ctx->optlevel >= 4) { - // Since -empty attempts to open and read directories, it may - // have side effects such as reporting permission errors, and - // thus shouldn't be re-ordered without aggressive optimizations - expr->pure = true; - } +/** Visit a disjunction. */ +static struct bfs_expr *visit_or(struct bfs_opt *opt, struct bfs_expr *expr, const struct visitor *visitor) { + struct bfs_exprs children; + foster_children(expr, &children); - return expr; -} + // Base case (-or) == (-false) + df_init_bottom(&opt->after_true); + struct bfs_opt nested = *opt; -/** Optimize -{exec,ok}{,dir}. */ -static struct bfs_expr *optimize_exec(struct bfs_opt *opt, struct bfs_expr *expr) { + while (!SLIST_EMPTY(&children)) { + struct bfs_expr *child = SLIST_POP(&children); + + if (SLIST_EMPTY(&children)) { + nested.ignore_result = opt->ignore_result; + } else { + nested.ignore_result = false; + } + + child = visit_deep(&nested, child, visitor); + if (!child) { + return NULL; + } + + df_join(&opt->after_true, &nested.after_true); + nested.before = nested.after_false; + + bfs_expr_append(expr, child); + } + + opt->after_false = nested.after_false; + + return expr; +} + +/** Visit a comma expression. */ +static struct bfs_expr *visit_comma(struct bfs_opt *opt, struct bfs_expr *expr, const struct visitor *visitor) { + struct bfs_exprs children; + foster_children(expr, &children); + + struct bfs_opt nested = *opt; + + while (!SLIST_EMPTY(&children)) { + struct bfs_expr *child = SLIST_POP(&children); + + if (SLIST_EMPTY(&children)) { + nested.ignore_result = opt->ignore_result; + } else { + nested.ignore_result = true; + } + + child = visit_deep(&nested, child, visitor); + if (!child) { + return NULL; + } + + nested.before = nested.after_true; + df_join(&nested.before, &nested.after_false); + + bfs_expr_append(expr, child); + } + + opt->after_true = nested.after_true; + opt->after_false = nested.after_false; + + return expr; +} + +/** Default enter() function. */ +static struct bfs_expr *visit_enter(struct bfs_opt *opt, struct bfs_expr *expr, const struct visitor *visitor) { + opt_enter(opt, "%pe\n", expr); + opt->after_true = opt->before; + opt->after_false = opt->before; + return expr; +} + +/** Default leave() function. */ +static struct bfs_expr *visit_leave(struct bfs_opt *opt, struct bfs_expr *expr, const struct visitor *visitor) { + opt_leave(opt, "%pe\n", expr); + return expr; +} + +static struct bfs_expr *visit_deep(struct bfs_opt *opt, struct bfs_expr *expr, const struct visitor *visitor) { + bool entered = false; + + visit_fn *enter = visitor->enter ? visitor->enter : visit_enter; + visit_fn *leave = visitor->leave ? visitor->leave : visit_leave; + + static const struct visitor_table table[] = { + {eval_not, visit_not}, + {eval_and, visit_and}, + {eval_or, visit_or}, + {eval_comma, visit_comma}, + {NULL, NULL}, + }; + visit_fn *recursive = look_up_visitor(expr, table); + if (recursive) { + if (!entered) { + expr = enter(opt, expr, visitor); + if (!expr) { + return NULL; + } + entered = true; + } + + expr = recursive(opt, expr, visitor); + if (!expr) { + return NULL; + } + } + + visit_fn *general = visitor->visit; + if (general) { + if (!entered) { + expr = enter(opt, expr, visitor); + if (!expr) { + return NULL; + } + entered = true; + } + + expr = general(opt, expr, visitor); + if (!expr) { + return NULL; + } + } + + visit_fn *specific = look_up_visitor(expr, visitor->table); + if (specific) { + if (!entered) { + expr = enter(opt, expr, visitor); + if (!expr) { + return NULL; + } + entered = true; + } + + expr = specific(opt, expr, visitor); + if (!expr) { + return NULL; + } + } + + if (entered) { + expr = leave(opt, expr, visitor); + } else { + opt_visit(opt, "%pe\n", expr); + } + + return expr; +} + +/** Visit an expression recursively. */ +static struct bfs_expr *visit(struct bfs_opt *opt, struct bfs_expr *expr, const struct visitor *visitor) { + opt_enter(opt, "%s()\n", visitor->name); + expr = visit_deep(opt, expr, visitor); + opt_leave(opt, "\n"); + return expr; +} + +/** Visit an expression non-recursively. */ +static struct bfs_expr *visit_shallow(struct bfs_opt *opt, struct bfs_expr *expr, const struct visitor *visitor) { + visit_fn *general = visitor->visit; + if (expr && general) { + expr = general(opt, expr, visitor); + } + + visit_fn *specific = look_up_visitor(expr, visitor->table); + if (expr && specific) { + expr = specific(opt, expr, visitor); + } + + return expr; +} + +/** Annotate -{execut,read,writ}able. */ +static struct bfs_expr *annotate_access(struct bfs_opt *opt, struct bfs_expr *expr, const struct visitor *visitor) { + expr->probability = 1.0; + if (expr->num & R_OK) { + expr->probability *= 0.99; + } + if (expr->num & W_OK) { + expr->probability *= 0.8; + } + if (expr->num & X_OK) { + expr->probability *= 0.2; + } + + return expr; +} + +/** Annotate -empty. */ +static struct bfs_expr *annotate_empty(struct bfs_opt *opt, struct bfs_expr *expr, const struct visitor *visitor) { + if (opt->level >= 4) { + // Since -empty attempts to open and read directories, it may + // have side effects such as reporting permission errors, and + // thus shouldn't be re-ordered without aggressive optimizations + expr->pure = true; + } + + return expr; +} + +/** Annotate -exec. */ +static struct bfs_expr *annotate_exec(struct bfs_opt *opt, struct bfs_expr *expr, const struct visitor *visitor) { if (expr->exec->flags & BFS_EXEC_MULTI) { expr->always_true = true; } else { @@ -771,33 +993,650 @@ static struct bfs_expr *optimize_exec(struct bfs_opt *opt, struct bfs_expr *expr return expr; } -/** Optimize -name/-lname/-path. */ -static struct bfs_expr *optimize_fnmatch(struct bfs_opt *opt, struct bfs_expr *expr) { - if (strchr(expr->argv[1], '*')) { +/** Annotate -name/-lname/-path. */ +static struct bfs_expr *annotate_fnmatch(struct bfs_opt *opt, struct bfs_expr *expr, const struct visitor *visitor) { + if (expr->literal) { + expr->probability = 0.1; + } else { expr->probability = 0.5; + } + + return expr; +} + +/** Estimate probability for -x?type. */ +static void estimate_type_probability(struct bfs_expr *expr) { + unsigned int types = expr->num; + + expr->probability = 0.0; + if (types & (1 << BFS_BLK)) { + expr->probability += 0.00000721183; + } + if (types & (1 << BFS_CHR)) { + expr->probability += 0.0000499855; + } + if (types & (1 << BFS_DIR)) { + expr->probability += 0.114475; + } + if (types & (1 << BFS_DOOR)) { + expr->probability += 0.000001; + } + if (types & (1 << BFS_FIFO)) { + expr->probability += 0.00000248684; + } + if (types & (1 << BFS_REG)) { + expr->probability += 0.859772; + } + if (types & (1 << BFS_LNK)) { + expr->probability += 0.0256816; + } + if (types & (1 << BFS_SOCK)) { + expr->probability += 0.0000116881; + } + if (types & (1 << BFS_WHT)) { + expr->probability += 0.000001; + } +} + +/** Annotate -type. */ +static struct bfs_expr *annotate_type(struct bfs_opt *opt, struct bfs_expr *expr, const struct visitor *visitor) { + estimate_type_probability(expr); + return expr; +} + +/** Annotate -xtype. */ +static struct bfs_expr *annotate_xtype(struct bfs_opt *opt, struct bfs_expr *expr, const struct visitor *visitor) { + if (opt->level >= 4) { + // Since -xtype dereferences symbolic links, it may have side + // effects such as reporting permission errors, and thus + // shouldn't be re-ordered without aggressive optimizations + expr->pure = true; + } + + estimate_type_probability(expr); + return expr; +} + +/** Annotate a negation. */ +static struct bfs_expr *annotate_not(struct bfs_opt *opt, struct bfs_expr *expr, const struct visitor *visitor) { + struct bfs_expr *rhs = only_child(expr); + expr->pure = rhs->pure; + expr->always_true = rhs->always_false; + expr->always_false = rhs->always_true; + expr->cost = rhs->cost; + expr->probability = 1.0 - rhs->probability; + return expr; +} + +/** Annotate a conjunction. */ +static struct bfs_expr *annotate_and(struct bfs_opt *opt, struct bfs_expr *expr, const struct visitor *visitor) { + expr->pure = true; + expr->always_true = true; + expr->always_false = false; + expr->cost = 0.0; + expr->probability = 1.0; + + for (struct bfs_expr *child = bfs_expr_children(expr); child; child = child->next) { + expr->pure &= child->pure; + expr->always_true &= child->always_true; + expr->always_false |= child->always_false; + expr->cost += expr->probability * child->cost; + expr->probability *= child->probability; + } + + return expr; +} + +/** Annotate a disjunction. */ +static struct bfs_expr *annotate_or(struct bfs_opt *opt, struct bfs_expr *expr, const struct visitor *visitor) { + expr->pure = true; + expr->always_true = false; + expr->always_false = true; + expr->cost = 0.0; + + float false_prob = 1.0; + for (struct bfs_expr *child = bfs_expr_children(expr); child; child = child->next) { + expr->pure &= child->pure; + expr->always_true |= child->always_true; + expr->always_false &= child->always_false; + expr->cost += false_prob * child->cost; + false_prob *= (1.0 - child->probability); + } + expr->probability = 1.0 - false_prob; + + return expr; +} + +/** Annotate a comma expression. */ +static struct bfs_expr *annotate_comma(struct bfs_opt *opt, struct bfs_expr *expr, const struct visitor *visitor) { + expr->pure = true; + expr->cost = 0.0; + + for (struct bfs_expr *child = bfs_expr_children(expr); child; child = child->next) { + expr->pure &= child->pure; + expr->always_true = child->always_true; + expr->always_false = child->always_false; + expr->cost += child->cost; + expr->probability = child->probability; + } + + return expr; +} + +/** Annotate an arbitrary expression. */ +static struct bfs_expr *annotate_visit(struct bfs_opt *opt, struct bfs_expr *expr, const struct visitor *visitor) { + /** Table of pure expressions. */ + static bfs_eval_fn *const pure[] = { + eval_access, + eval_acl, + eval_capable, + eval_depth, + eval_false, + eval_flags, + eval_fstype, + eval_gid, + eval_hidden, + eval_inum, + eval_links, + eval_lname, + eval_name, + eval_newer, + eval_nogroup, + eval_nouser, + eval_path, + eval_perm, + eval_regex, + eval_samefile, + eval_size, + eval_sparse, + eval_time, + eval_true, + eval_type, + eval_uid, + eval_used, + eval_xattr, + eval_xattrname, + }; + + expr->pure = false; + for (size_t i = 0; i < countof(pure); ++i) { + if (expr->eval_fn == pure[i]) { + expr->pure = true; + break; + } + } + + /** Table of always-true expressions. */ + static bfs_eval_fn *const always_true[] = { + eval_fls, + eval_fprint, + eval_fprint0, + eval_fprintf, + eval_fprintx, + eval_prune, + eval_true, + // Non-returning + eval_exit, + eval_quit, + }; + + expr->always_true = false; + for (size_t i = 0; i < countof(always_true); ++i) { + if (expr->eval_fn == always_true[i]) { + expr->always_true = true; + break; + } + } + + /** Table of always-false expressions. */ + static bfs_eval_fn *const always_false[] = { + eval_false, + // Non-returning + eval_exit, + eval_quit, + }; + + expr->always_false = false; + for (size_t i = 0; i < countof(always_false); ++i) { + if (expr->eval_fn == always_false[i]) { + expr->always_false = true; + break; + } + } + +#define FAST_COST 40.0 +#define FNMATCH_COST 400.0 +#define STAT_COST 1000.0 +#define PRINT_COST 20000.0 + + /** Table of expression costs. */ + static const struct { + bfs_eval_fn *eval_fn; + float cost; + } costs[] = { + {eval_access, STAT_COST}, + {eval_acl, STAT_COST}, + {eval_capable, STAT_COST}, + {eval_empty, 2 * STAT_COST}, // readdir() is worse than stat() + {eval_fls, PRINT_COST}, + {eval_fprint, PRINT_COST}, + {eval_fprint0, PRINT_COST}, + {eval_fprintf, PRINT_COST}, + {eval_fprintx, PRINT_COST}, + {eval_fstype, STAT_COST}, + {eval_gid, STAT_COST}, + {eval_inum, STAT_COST}, + {eval_links, STAT_COST}, + {eval_lname, FNMATCH_COST}, + {eval_name, FNMATCH_COST}, + {eval_newer, STAT_COST}, + {eval_nogroup, STAT_COST}, + {eval_nouser, STAT_COST}, + {eval_path, FNMATCH_COST}, + {eval_perm, STAT_COST}, + {eval_samefile, STAT_COST}, + {eval_size, STAT_COST}, + {eval_sparse, STAT_COST}, + {eval_time, STAT_COST}, + {eval_uid, STAT_COST}, + {eval_used, STAT_COST}, + {eval_xattr, STAT_COST}, + {eval_xattrname, STAT_COST}, + }; + + expr->cost = FAST_COST; + for (size_t i = 0; i < countof(costs); ++i) { + if (expr->eval_fn == costs[i].eval_fn) { + expr->cost = costs[i].cost; + break; + } + } + + /** Table of expression probabilities. */ + static const struct { + /** The evaluation function with this cost. */ + bfs_eval_fn *eval_fn; + /** The matching probability. */ + float probability; + } probs[] = { + {eval_acl, 0.00002}, + {eval_capable, 0.000002}, + {eval_empty, 0.01}, + {eval_false, 0.0}, + {eval_hidden, 0.01}, + {eval_nogroup, 0.01}, + {eval_nouser, 0.01}, + {eval_samefile, 0.01}, + {eval_true, 1.0}, + {eval_xattr, 0.01}, + {eval_xattrname, 0.01}, + }; + + expr->probability = 0.5; + for (size_t i = 0; i < countof(probs); ++i) { + if (expr->eval_fn == probs[i].eval_fn) { + expr->probability = probs[i].probability; + break; + } + } + + return expr; +} + +/** + * Annotating visitor. + */ +static const struct visitor annotate = { + .name = "annotate", + .visit = annotate_visit, + .table = { + {eval_access, annotate_access}, + {eval_empty, annotate_empty}, + {eval_exec, annotate_exec}, + {eval_lname, annotate_fnmatch}, + {eval_name, annotate_fnmatch}, + {eval_path, annotate_fnmatch}, + {eval_type, annotate_type}, + {eval_xtype, annotate_xtype}, + + {eval_not, annotate_not}, + {eval_and, annotate_and}, + {eval_or, annotate_or}, + {eval_comma, annotate_comma}, + + {NULL, NULL}, + }, +}; + +/** Create a constant expression. */ +static struct bfs_expr *opt_const(struct bfs_opt *opt, bool value) { + static bfs_eval_fn *const fns[] = {eval_false, eval_true}; + static char *fake_args[] = {"-false", "-true"}; + + struct bfs_expr *expr = bfs_expr_new(opt->ctx, fns[value], 1, &fake_args[value]); + return visit_shallow(opt, expr, &annotate); +} + +/** Negate an expression, keeping it canonical. */ +static struct bfs_expr *negate_expr(struct bfs_opt *opt, struct bfs_expr *expr, char **argv) { + if (expr->eval_fn == eval_not) { + return only_child(expr); + } else if (expr->eval_fn == eval_true) { + return opt_const(opt, false); + } else if (expr->eval_fn == eval_false) { + return opt_const(opt, true); + } + + struct bfs_expr *ret = bfs_expr_new(opt->ctx, eval_not, 1, argv); + if (!ret) { + return NULL; + } + + bfs_expr_append(ret, expr); + return visit_shallow(opt, ret, &annotate); +} + +/** Sink negations into a conjunction/disjunction using De Morgan's laws. */ +static struct bfs_expr *sink_not_andor(struct bfs_opt *opt, struct bfs_expr *expr) { + opt_debug(opt, "De Morgan's laws\n"); + + char **argv = expr->argv; + expr = only_child(expr); + opt_enter(opt, "%pe\n", expr); + + if (expr->eval_fn == eval_and) { + expr->eval_fn = eval_or; + expr->argv = &fake_or_arg; } else { - expr->probability = 0.1; + bfs_assert(expr->eval_fn == eval_or); + expr->eval_fn = eval_and; + expr->argv = &fake_and_arg; + } + + struct bfs_exprs children; + foster_children(expr, &children); + + struct bfs_expr *child; + while ((child = SLIST_POP(&children))) { + opt_enter(opt, "%pe\n", child); + + child = negate_expr(opt, child, argv); + if (!child) { + return NULL; + } + + opt_leave(opt, "%pe\n", child); + bfs_expr_append(expr, child); + } + + opt_leave(opt, "%pe\n", expr); + return visit_shallow(opt, expr, &annotate); +} + +/** Sink a negation into a comma expression. */ +static struct bfs_expr *sink_not_comma(struct bfs_opt *opt, struct bfs_expr *expr) { + bfs_assert(expr->eval_fn == eval_comma); + + opt_enter(opt, "%pe\n", expr); + + char **argv = expr->argv; + expr = only_child(expr); + + struct bfs_exprs children; + foster_children(expr, &children); + + struct bfs_expr *child; + while ((child = SLIST_POP(&children))) { + if (SLIST_EMPTY(&children)) { + opt_enter(opt, "%pe\n", child); + opt_debug(opt, "sink\n"); + + child = negate_expr(opt, child, argv); + if (!child) { + return NULL; + } + + opt_leave(opt, "%pe\n", child); + } else { + opt_visit(opt, "%pe\n", child); + } + + bfs_expr_append(expr, child); + } + + opt_leave(opt, "%pe\n", expr); + return visit_shallow(opt, expr, &annotate); +} + +/** Canonicalize a negation. */ +static struct bfs_expr *canonicalize_not(struct bfs_opt *opt, struct bfs_expr *expr, const struct visitor *visitor) { + struct bfs_expr *rhs = only_child(expr); + + if (rhs->eval_fn == eval_not) { + opt_debug(opt, "double negation\n"); + rhs = only_child(expr); + return only_child(rhs); + } else if (rhs->eval_fn == eval_and || rhs->eval_fn == eval_or) { + return sink_not_andor(opt, expr); + } else if (rhs->eval_fn == eval_comma) { + return sink_not_comma(opt, expr); + } else if (is_const(rhs)) { + opt_debug(opt, "constant propagation\n"); + return opt_const(opt, rhs->eval_fn == eval_false); + } else { + return expr; + } +} + +/** Canonicalize an associative operator. */ +static struct bfs_expr *canonicalize_assoc(struct bfs_opt *opt, struct bfs_expr *expr, const struct visitor *visitor) { + struct bfs_exprs children; + foster_children(expr, &children); + + struct bfs_exprs flat; + SLIST_INIT(&flat); + + struct bfs_expr *child; + while ((child = SLIST_POP(&children))) { + if (child->eval_fn == expr->eval_fn) { + struct bfs_expr *head = SLIST_HEAD(&child->children); + struct bfs_expr *tail = SLIST_TAIL(&child->children); + + if (!head) { + opt_delete(opt, "%pe [empty]\n", child); + } else { + opt_enter(opt, "%pe\n", child); + opt_debug(opt, "associativity\n"); + if (head == tail) { + opt_leave(opt, "%pe\n", head); + } else if (head->next == tail) { + opt_leave(opt, "%pe %pe\n", head, tail); + } else { + opt_leave(opt, "%pe ... %pe\n", head, tail); + } + } + + SLIST_EXTEND(&flat, &child->children); + } else { + opt_visit(opt, "%pe\n", child); + SLIST_APPEND(&flat, child); + } + } + + bfs_expr_extend(expr, &flat); + + return visit_shallow(opt, expr, &annotate); +} + +/** + * Canonicalizing visitor. + */ +static const struct visitor canonicalize = { + .name = "canonicalize", + .table = { + {eval_not, canonicalize_not}, + {eval_and, canonicalize_assoc}, + {eval_or, canonicalize_assoc}, + {eval_comma, canonicalize_assoc}, + {NULL, NULL}, + }, +}; + +/** Calculate the cost of an ordered pair of expressions. */ +static float expr_cost(const struct bfs_expr *parent, const struct bfs_expr *lhs, const struct bfs_expr *rhs) { + // https://cs.stackexchange.com/a/66921/21004 + float prob = lhs->probability; + if (parent->eval_fn == eval_or) { + prob = 1.0 - prob; + } + return lhs->cost + prob * rhs->cost; +} + +/** Sort a block of expressions. */ +static void sort_exprs(struct bfs_opt *opt, struct bfs_expr *parent, struct bfs_exprs *exprs) { + if (!exprs->head || !exprs->head->next) { + return; + } + + struct bfs_exprs left, right; + SLIST_INIT(&left); + SLIST_INIT(&right); + + // Split + for (struct bfs_expr *hare = exprs->head; hare && (hare = hare->next); hare = hare->next) { + struct bfs_expr *tortoise = SLIST_POP(exprs); + SLIST_APPEND(&left, tortoise); + } + SLIST_EXTEND(&right, exprs); + + // Recurse + sort_exprs(opt, parent, &left); + sort_exprs(opt, parent, &right); + + // Merge + while (!SLIST_EMPTY(&left) && !SLIST_EMPTY(&right)) { + struct bfs_expr *lhs = left.head; + struct bfs_expr *rhs = right.head; + + float cost = expr_cost(parent, lhs, rhs); + float swapped = expr_cost(parent, rhs, lhs); + + if (cost <= swapped) { + SLIST_POP(&left); + SLIST_APPEND(exprs, lhs); + } else { + opt_enter(opt, "%pe %pe [${ylw}%g${rs}]\n", lhs, rhs, cost); + SLIST_POP(&right); + SLIST_APPEND(exprs, rhs); + opt_leave(opt, "%pe %pe [${ylw}%g${rs}]\n", rhs, lhs, swapped); + } + } + SLIST_EXTEND(exprs, &left); + SLIST_EXTEND(exprs, &right); +} + +/** Reorder children to reduce cost. */ +static struct bfs_expr *reorder_andor(struct bfs_opt *opt, struct bfs_expr *expr, const struct visitor *visitor) { + struct bfs_exprs children; + foster_children(expr, &children); + + // Split into blocks of consecutive pure/impure expressions, and sort + // the pure blocks + struct bfs_exprs pure; + SLIST_INIT(&pure); + + struct bfs_expr *child; + while ((child = SLIST_POP(&children))) { + if (child->pure) { + SLIST_APPEND(&pure, child); + } else { + sort_exprs(opt, expr, &pure); + bfs_expr_extend(expr, &pure); + bfs_expr_append(expr, child); + } + } + sort_exprs(opt, expr, &pure); + bfs_expr_extend(expr, &pure); + + return visit_shallow(opt, expr, &annotate); +} + +/** + * Reordering visitor. + */ +static const struct visitor reorder = { + .name = "reorder", + .table = { + {eval_and, reorder_andor}, + {eval_or, reorder_andor}, + {NULL, NULL}, + }, +}; + +/** Transfer function for simple predicates. */ +static void data_flow_pred(struct bfs_opt *opt, enum pred_type pred, bool value) { + constrain_pred(&opt->after_true.preds[pred], value); + constrain_pred(&opt->after_false.preds[pred], !value); +} + +/** Transfer function for icmp-style ([+-]N) expressions. */ +static void data_flow_icmp(struct bfs_opt *opt, const struct bfs_expr *expr, enum range_type type) { + struct df_range *true_range = &opt->after_true.ranges[type]; + struct df_range *false_range = &opt->after_false.ranges[type]; + long long value = expr->num; + + switch (expr->int_cmp) { + case BFS_INT_EQUAL: + constrain_min(true_range, value); + constrain_max(true_range, value); + range_remove(false_range, value); + break; + + case BFS_INT_LESS: + constrain_min(false_range, value); + constrain_max(true_range, value); + range_remove(true_range, value); + break; + + case BFS_INT_GREATER: + constrain_max(false_range, value); + constrain_min(true_range, value); + range_remove(true_range, value); + break; + } +} + +/** Transfer function for -{execut,read,writ}able. */ +static struct bfs_expr *data_flow_access(struct bfs_opt *opt, struct bfs_expr *expr, const struct visitor *visitor) { + if (expr->num & R_OK) { + data_flow_pred(opt, READABLE_PRED, true); + } + if (expr->num & W_OK) { + data_flow_pred(opt, WRITABLE_PRED, true); + } + if (expr->num & X_OK) { + data_flow_pred(opt, EXECUTABLE_PRED, true); } return expr; } -/** Optimize -gid. */ -static struct bfs_expr *optimize_gid(struct bfs_opt *opt, struct bfs_expr *expr) { +/** Transfer function for -gid. */ +static struct bfs_expr *data_flow_gid(struct bfs_opt *opt, struct bfs_expr *expr, const struct visitor *visitor) { struct df_range *range = &opt->after_true.ranges[GID_RANGE]; if (range->min == range->max) { gid_t gid = range->min; bool nogroup = !bfs_getgrgid(opt->ctx->groups, gid); if (errno == 0) { - opt_constrain_pred(opt, NOGROUP_PRED, nogroup); + data_flow_pred(opt, NOGROUP_PRED, nogroup); } } return expr; } -/** Optimize -inum. */ -static struct bfs_expr *optimize_inum(struct bfs_opt *opt, struct bfs_expr *expr) { +/** Transfer function for -inum. */ +static struct bfs_expr *data_flow_inum(struct bfs_opt *opt, struct bfs_expr *expr, const struct visitor *visitor) { struct df_range *range = &opt->after_true.ranges[INUM_RANGE]; if (range->min == range->max) { expr->probability = 0.01; @@ -808,8 +1647,8 @@ static struct bfs_expr *optimize_inum(struct bfs_opt *opt, struct bfs_expr *expr return expr; } -/** Optimize -links. */ -static struct bfs_expr *optimize_links(struct bfs_opt *opt, struct bfs_expr *expr) { +/** Transfer function for -links. */ +static struct bfs_expr *data_flow_links(struct bfs_opt *opt, struct bfs_expr *expr, const struct visitor *visitor) { struct df_range *range = &opt->after_true.ranges[LINKS_RANGE]; if (1 >= range->min && 1 <= range->max) { expr->probability = 0.99; @@ -820,30 +1659,20 @@ static struct bfs_expr *optimize_links(struct bfs_opt *opt, struct bfs_expr *exp return expr; } -/** Optimize -uid. */ -static struct bfs_expr *optimize_uid(struct bfs_opt *opt, struct bfs_expr *expr) { - struct df_range *range = &opt->after_true.ranges[UID_RANGE]; - if (range->min == range->max) { - uid_t uid = range->min; - bool nouser = !bfs_getpwuid(opt->ctx->users, uid); - if (errno == 0) { - opt_constrain_pred(opt, NOUSER_PRED, nouser); - } - } +/** Transfer function for -samefile. */ +static struct bfs_expr *data_flow_samefile(struct bfs_opt *opt, struct bfs_expr *expr, const struct visitor *visitor) { + struct df_range *true_range = &opt->after_true.ranges[INUM_RANGE]; + constrain_min(true_range, expr->ino); + constrain_max(true_range, expr->ino); - return expr; -} + struct df_range *false_range = &opt->after_false.ranges[INUM_RANGE]; + range_remove(false_range, expr->ino); -/** Optimize -samefile. */ -static struct bfs_expr *optimize_samefile(struct bfs_opt *opt, struct bfs_expr *expr) { - struct df_range *range = &opt->after_true.ranges[INUM_RANGE]; - constrain_min(range, expr->ino); - constrain_max(range, expr->ino); return expr; } -/** Optimize -size. */ -static struct bfs_expr *optimize_size(struct bfs_opt *opt, struct bfs_expr *expr) { +/** Transfer function for -size. */ +static struct bfs_expr *data_flow_size(struct bfs_opt *opt, struct bfs_expr *expr, const struct visitor *visitor) { struct df_range *range = &opt->after_true.ranges[SIZE_RANGE]; if (range->min == range->max) { expr->probability = 0.01; @@ -854,473 +1683,449 @@ static struct bfs_expr *optimize_size(struct bfs_opt *opt, struct bfs_expr *expr return expr; } -/** Estimate probability for -x?type. */ -static void estimate_type_probability(struct bfs_expr *expr) { - unsigned int types = expr->num; - - expr->probability = 0.0; - if (types & (1 << BFS_BLK)) { - expr->probability += 0.00000721183; - } - if (types & (1 << BFS_CHR)) { - expr->probability += 0.0000499855; - } - if (types & (1 << BFS_DIR)) { - expr->probability += 0.114475; - } - if (types & (1 << BFS_DOOR)) { - expr->probability += 0.000001; - } - if (types & (1 << BFS_FIFO)) { - expr->probability += 0.00000248684; - } - if (types & (1 << BFS_REG)) { - expr->probability += 0.859772; - } - if (types & (1 << BFS_LNK)) { - expr->probability += 0.0256816; - } - if (types & (1 << BFS_SOCK)) { - expr->probability += 0.0000116881; - } - if (types & (1 << BFS_WHT)) { - expr->probability += 0.000001; - } -} - -/** Optimize -type. */ -static struct bfs_expr *optimize_type(struct bfs_opt *opt, struct bfs_expr *expr) { +/** Transfer function for -type. */ +static struct bfs_expr *data_flow_type(struct bfs_opt *opt, struct bfs_expr *expr, const struct visitor *visitor) { opt->after_true.types &= expr->num; opt->after_false.types &= ~expr->num; - - estimate_type_probability(expr); - return expr; } -/** Optimize -xtype. */ -static struct bfs_expr *optimize_xtype(struct bfs_opt *opt, struct bfs_expr *expr) { - if (opt->ctx->optlevel >= 4) { - // Since -xtype dereferences symbolic links, it may have side - // effects such as reporting permission errors, and thus - // shouldn't be re-ordered without aggressive optimizations - expr->pure = true; +/** Transfer function for -uid. */ +static struct bfs_expr *data_flow_uid(struct bfs_opt *opt, struct bfs_expr *expr, const struct visitor *visitor) { + struct df_range *range = &opt->after_true.ranges[UID_RANGE]; + if (range->min == range->max) { + uid_t uid = range->min; + bool nouser = !bfs_getpwuid(opt->ctx->users, uid); + if (errno == 0) { + data_flow_pred(opt, NOUSER_PRED, nouser); + } } + return expr; +} + +/** Transfer function for -xtype. */ +static struct bfs_expr *data_flow_xtype(struct bfs_opt *opt, struct bfs_expr *expr, const struct visitor *visitor) { opt->after_true.xtypes &= expr->num; opt->after_false.xtypes &= ~expr->num; - - estimate_type_probability(expr); - return expr; } -/** - * Table of pure expressions. - */ -static bfs_eval_fn *const opt_pure[] = { - eval_access, - eval_acl, - eval_capable, - eval_depth, - eval_false, - eval_flags, - eval_fstype, - eval_gid, - eval_hidden, - eval_inum, - eval_links, - eval_lname, - eval_name, - eval_newer, - eval_nogroup, - eval_nouser, - eval_path, - eval_perm, - eval_regex, - eval_samefile, - eval_size, - eval_sparse, - eval_time, - eval_true, - eval_type, - eval_uid, - eval_used, - eval_xattr, - eval_xattrname, -}; - -/** - * Table of always-true expressions. - */ -static bfs_eval_fn *const opt_always_true[] = { - eval_fls, - eval_fprint, - eval_fprint0, - eval_fprintf, - eval_fprintx, - eval_prune, - eval_true, - - // Non-returning - eval_exit, - eval_quit, -}; - -/** - * Table of always-false expressions. - */ -static bfs_eval_fn *const opt_always_false[] = { - eval_false, - - // Non-returning - eval_exit, - eval_quit, -}; - -#define FAST_COST 40.0 -#define FNMATCH_COST 400.0 -#define STAT_COST 1000.0 -#define PRINT_COST 20000.0 - -/** - * Table of expression costs. - */ -static const struct { - /** The evaluation function with this cost. */ - bfs_eval_fn *eval_fn; - /** The matching cost. */ - float cost; -} opt_costs[] = { - {eval_access, STAT_COST}, - {eval_acl, STAT_COST}, - {eval_capable, STAT_COST}, - {eval_empty, 2 * STAT_COST}, // readdir() is worse than stat() - {eval_fls, PRINT_COST}, - {eval_fprint, PRINT_COST}, - {eval_fprint0, PRINT_COST}, - {eval_fprintf, PRINT_COST}, - {eval_fprintx, PRINT_COST}, - {eval_fstype, STAT_COST}, - {eval_gid, STAT_COST}, - {eval_inum, STAT_COST}, - {eval_links, STAT_COST}, - {eval_lname, FNMATCH_COST}, - {eval_name, FNMATCH_COST}, - {eval_newer, STAT_COST}, - {eval_nogroup, STAT_COST}, - {eval_nouser, STAT_COST}, - {eval_path, FNMATCH_COST}, - {eval_perm, STAT_COST}, - {eval_samefile, STAT_COST}, - {eval_size, STAT_COST}, - {eval_sparse, STAT_COST}, - {eval_time, STAT_COST}, - {eval_uid, STAT_COST}, - {eval_used, STAT_COST}, - {eval_xattr, STAT_COST}, - {eval_xattrname, STAT_COST}, -}; - -/** - * Table of expression probabilities. - */ -static const struct { - /** The evaluation function with this cost. */ - bfs_eval_fn *eval_fn; - /** The matching probability. */ - float probability; -} opt_probs[] = { - {eval_acl, 0.00002}, - {eval_capable, 0.000002}, - {eval_empty, 0.01}, - {eval_false, 0.0}, - {eval_hidden, 0.01}, - {eval_nogroup, 0.01}, - {eval_nouser, 0.01}, - {eval_samefile, 0.01}, - {eval_true, 1.0}, - {eval_xattr, 0.01}, - {eval_xattrname, 0.01}, -}; +/** Data flow visitor entry. */ +static struct bfs_expr *data_flow_enter(struct bfs_opt *opt, struct bfs_expr *expr, const struct visitor *visitor) { + visit_enter(opt, expr, visitor); -/** - * Table of simple predicates. - */ -static const struct { - /** The evaluation function this optimizer applies to. */ - bfs_eval_fn *eval_fn; - /** The corresponding predicate. */ - enum pred_type pred; -} opt_preds[] = { - {eval_acl, ACL_PRED}, - {eval_capable, CAPABLE_PRED}, - {eval_empty, EMPTY_PRED}, - {eval_hidden, HIDDEN_PRED}, - {eval_nogroup, NOGROUP_PRED}, - {eval_nouser, NOUSER_PRED}, - {eval_sparse, SPARSE_PRED}, - {eval_xattr, XATTR_PRED}, -}; + df_dump(opt, "before", &opt->before); -/** - * Table of simple range comparisons. - */ -static const struct { - /** The evaluation function this optimizer applies to. */ - bfs_eval_fn *eval_fn; - /** The corresponding range. */ - enum range_type range; -} opt_ranges[] = { - {eval_depth, DEPTH_RANGE}, - {eval_gid, GID_RANGE}, - {eval_inum, INUM_RANGE}, - {eval_links, LINKS_RANGE}, - {eval_size, SIZE_RANGE}, - {eval_uid, UID_RANGE}, -}; + if (!bfs_expr_is_parent(expr) && !expr->pure) { + df_join(opt->impure, &opt->before); + df_dump(opt, "impure", opt->impure); + } -/** Signature for custom optimizer functions. */ -typedef struct bfs_expr *bfs_opt_fn(struct bfs_opt *opt, struct bfs_expr *expr); + return expr; +} -/** Table of custom optimizer functions. */ -static const struct { - /** The evaluation function this optimizer applies to. */ - bfs_eval_fn *eval_fn; - /** The corresponding optimizer function. */ - bfs_opt_fn *opt_fn; -} opt_fns[] = { - // Primaries - {eval_access, optimize_access}, - {eval_empty, optimize_empty}, - {eval_exec, optimize_exec}, - {eval_gid, optimize_gid}, - {eval_inum, optimize_inum}, - {eval_links, optimize_links}, - {eval_lname, optimize_fnmatch}, - {eval_name, optimize_fnmatch}, - {eval_path, optimize_fnmatch}, - {eval_samefile, optimize_samefile}, - {eval_size, optimize_size}, - {eval_type, optimize_type}, - {eval_uid, optimize_uid}, - {eval_xtype, optimize_xtype}, - - // Operators - {eval_and, optimize_and_expr_recursive}, - {eval_comma, optimize_comma_expr_recursive}, - {eval_not, optimize_not_expr_recursive}, - {eval_or, optimize_or_expr_recursive}, -}; +/** Data flow visitor exit. */ +static struct bfs_expr *data_flow_leave(struct bfs_opt *opt, struct bfs_expr *expr, const struct visitor *visitor) { + if (expr->always_true) { + expr->probability = 1.0; + df_init_bottom(&opt->after_false); + } -/** - * Look up the appropriate optimizer for an expression and call it. - */ -static struct bfs_expr *optimize_expr_lookup(struct bfs_opt *opt, struct bfs_expr *expr) { - for (size_t i = 0; i < countof(opt_pure); ++i) { - if (opt_pure[i] == expr->eval_fn) { - expr->pure = true; - break; - } + if (expr->always_false) { + expr->probability = 0.0; + df_init_bottom(&opt->after_true); } - for (size_t i = 0; i < countof(opt_always_true); ++i) { - if (opt_always_true[i] == expr->eval_fn) { + df_dump(opt, "after true", &opt->after_true); + df_dump(opt, "after false", &opt->after_false); + + if (df_is_bottom(&opt->after_false)) { + if (!expr->pure) { expr->always_true = true; - break; + expr->probability = 0.0; + } else if (expr->eval_fn != eval_true) { + opt_warning(opt, expr, "This expression is always true.\n\n"); + opt_debug(opt, "pure, always true\n"); + expr = opt_const(opt, true); + if (!expr) { + return NULL; + } } } - for (size_t i = 0; i < countof(opt_always_false); ++i) { - if (opt_always_false[i] == expr->eval_fn) { + if (df_is_bottom(&opt->after_true)) { + if (!expr->pure) { expr->always_false = true; - break; + expr->probability = 0.0; + } else if (expr->eval_fn != eval_false) { + opt_warning(opt, expr, "This expression is always false.\n\n"); + opt_debug(opt, "pure, always false\n"); + expr = opt_const(opt, false); + if (!expr) { + return NULL; + } } } - expr->cost = FAST_COST; - for (size_t i = 0; i < countof(opt_costs); ++i) { - if (opt_costs[i].eval_fn == expr->eval_fn) { - expr->cost = opt_costs[i].cost; - break; + return visit_leave(opt, expr, visitor); +} + +/** Data flow visitor function. */ +static struct bfs_expr *data_flow_visit(struct bfs_opt *opt, struct bfs_expr *expr, const struct visitor *visitor) { + if (opt->ignore_result && expr->pure) { + opt_debug(opt, "ignored result\n"); + opt_warning(opt, expr, "The result of this expression is ignored.\n\n"); + expr = opt_const(opt, false); + if (!expr) { + return NULL; } } - for (size_t i = 0; i < countof(opt_probs); ++i) { - if (opt_probs[i].eval_fn == expr->eval_fn) { - expr->probability = opt_probs[i].probability; - break; + if (df_is_bottom(&opt->before)) { + opt_debug(opt, "unreachable\n"); + opt_warning(opt, expr, "This expression is unreachable.\n\n"); + expr = opt_const(opt, false); + if (!expr) { + return NULL; } } - for (size_t i = 0; i < countof(opt_preds); ++i) { - if (opt_preds[i].eval_fn == expr->eval_fn) { - opt_constrain_pred(opt, opt_preds[i].pred, true); + /** Table of simple predicates. */ + static const struct { + bfs_eval_fn *eval_fn; + enum pred_type pred; + } preds[] = { + {eval_acl, ACL_PRED}, + {eval_capable, CAPABLE_PRED}, + {eval_empty, EMPTY_PRED}, + {eval_hidden, HIDDEN_PRED}, + {eval_nogroup, NOGROUP_PRED}, + {eval_nouser, NOUSER_PRED}, + {eval_sparse, SPARSE_PRED}, + {eval_xattr, XATTR_PRED}, + }; + + for (size_t i = 0; i < countof(preds); ++i) { + if (preds[i].eval_fn == expr->eval_fn) { + data_flow_pred(opt, preds[i].pred, true); break; } } - for (size_t i = 0; i < countof(opt_ranges); ++i) { - if (opt_ranges[i].eval_fn == expr->eval_fn) { - optimize_icmp(opt, expr, opt_ranges[i].range); + /** Table of simple range comparisons. */ + static const struct { + bfs_eval_fn *eval_fn; + enum range_type range; + } ranges[] = { + {eval_depth, DEPTH_RANGE}, + {eval_gid, GID_RANGE}, + {eval_inum, INUM_RANGE}, + {eval_links, LINKS_RANGE}, + {eval_size, SIZE_RANGE}, + {eval_uid, UID_RANGE}, + }; + + for (size_t i = 0; i < countof(ranges); ++i) { + if (ranges[i].eval_fn == expr->eval_fn) { + data_flow_icmp(opt, expr, ranges[i].range); break; } } - for (size_t i = 0; i < countof(opt_fns); ++i) { - if (opt_fns[i].eval_fn == expr->eval_fn) { - return opt_fns[i].opt_fn(opt, expr); - } + return expr; +} + +/** + * Data flow visitor. + */ +static const struct visitor data_flow = { + .name = "data_flow", + .enter = data_flow_enter, + .visit = data_flow_visit, + .leave = data_flow_leave, + .table = { + {eval_access, data_flow_access}, + {eval_gid, data_flow_gid}, + {eval_inum, data_flow_inum}, + {eval_links, data_flow_links}, + {eval_samefile, data_flow_samefile}, + {eval_size, data_flow_size}, + {eval_type, data_flow_type}, + {eval_uid, data_flow_uid}, + {eval_xtype, data_flow_xtype}, + {NULL, NULL}, + }, +}; + +/** Simplify a negation. */ +static struct bfs_expr *simplify_not(struct bfs_opt *opt, struct bfs_expr *expr, const struct visitor *visitor) { + if (opt->ignore_result) { + opt_debug(opt, "ignored result\n"); + expr = only_child(expr); } return expr; } -static struct bfs_expr *optimize_expr_recursive(struct bfs_opt *opt, struct bfs_expr *expr) { - int optlevel = opt->ctx->optlevel; +/** Lift negations out of a conjunction/disjunction using De Morgan's laws. */ +static struct bfs_expr *lift_andor_not(struct bfs_opt *opt, struct bfs_expr *expr) { + // Only lift negations if it would reduce the number of (-not) expressions + size_t added = 0, removed = 0; + for (struct bfs_expr *child = bfs_expr_children(expr); child; child = child->next) { + if (child->eval_fn == eval_not) { + ++removed; + } else { + ++added; + } + } + if (added >= removed) { + return visit_shallow(opt, expr, &annotate); + } - opt->after_true = opt->before; - opt->after_false = opt->before; + opt_debug(opt, "De Morgan's laws\n"); - if (optlevel >= 2 && df_is_bottom(&opt->before)) { - struct bfs_expr *ret = opt_const(opt, false); - opt_debug(opt, 2, "reachability: %pe --> %pe\n", expr, ret); - opt_warning(opt, expr, "This expression is unreachable.\n\n"); - return ret; + if (expr->eval_fn == eval_and) { + expr->eval_fn = eval_or; + expr->argv = &fake_or_arg; + } else { + bfs_assert(expr->eval_fn == eval_or); + expr->eval_fn = eval_and; + expr->argv = &fake_and_arg; + } + + struct bfs_exprs children; + foster_children(expr, &children); + + struct bfs_expr *child; + while ((child = SLIST_POP(&children))) { + opt_enter(opt, "%pe\n", child); + + child = negate_expr(opt, child, &fake_not_arg); + if (!child) { + return NULL; + } + + opt_leave(opt, "%pe\n", child); + bfs_expr_append(expr, child); } - expr = optimize_expr_lookup(opt, expr); - if (!expr) { + expr = visit_shallow(opt, expr, &annotate); + return negate_expr(opt, expr, &fake_not_arg); +} + +/** Get the first ignorable expression in a conjunction/disjunction. */ +static struct bfs_expr *first_ignorable(struct bfs_opt *opt, struct bfs_expr *expr) { + if (opt->level < 2 || !opt->ignore_result) { return NULL; } - if (bfs_expr_is_parent(expr)) { - struct bfs_expr *lhs = expr->lhs; - struct bfs_expr *rhs = expr->rhs; - if (rhs) { - expr->persistent_fds = rhs->persistent_fds; - expr->ephemeral_fds = rhs->ephemeral_fds; + struct bfs_expr *ret = NULL; + for (struct bfs_expr *child = bfs_expr_children(expr); child; child = child->next) { + if (!child->pure) { + ret = NULL; + } else if (!ret) { + ret = child; + } + } + + return ret; +} + +/** Simplify a conjunction. */ +static struct bfs_expr *simplify_and(struct bfs_opt *opt, struct bfs_expr *expr, const struct visitor *visitor) { + struct bfs_expr *ignorable = first_ignorable(opt, expr); + bool ignore = false; + + struct bfs_exprs children; + foster_children(expr, &children); + + while (!SLIST_EMPTY(&children)) { + struct bfs_expr *child = SLIST_POP(&children); + + if (child == ignorable) { + ignore = true; + } + + if (ignore) { + opt_delete(opt, "%pe [ignored result]\n", child); + opt_warning(opt, child, "The result of this expression is ignored.\n\n"); + continue; + } + + if (child->eval_fn == eval_true) { + opt_delete(opt, "%pe [conjunction elimination]\n", child); + continue; } - if (lhs) { - expr->persistent_fds += lhs->persistent_fds; - if (lhs->ephemeral_fds > expr->ephemeral_fds) { - expr->ephemeral_fds = lhs->ephemeral_fds; + + opt_visit(opt, "%pe\n", child); + bfs_expr_append(expr, child); + + if (child->always_false) { + while ((child = SLIST_POP(&children))) { + opt_delete(opt, "%pe [short-circuit]\n", child); } } - } else if (!expr->pure) { - df_join(opt->impure, &opt->before); } - if (expr->always_true) { - expr->probability = 1.0; - df_init_bottom(&opt->after_false); - } - if (expr->always_false) { - expr->probability = 0.0; - df_init_bottom(&opt->after_true); + struct bfs_expr *child = bfs_expr_children(expr); + if (!child) { + opt_debug(opt, "nullary identity\n"); + return opt_const(opt, true); + } else if (!child->next) { + opt_debug(opt, "unary identity\n"); + return only_child(expr); } - if (optlevel < 2 || expr->eval_fn == eval_true || expr->eval_fn == eval_false) { - return expr; - } + return lift_andor_not(opt, expr); +} - if (df_is_bottom(&opt->after_true)) { - if (expr->pure) { - struct bfs_expr *ret = opt_const(opt, false); - opt_warning(opt, expr, "This expression is always false.\n\n"); - opt_debug(opt, 2, "data flow: %pe --> %pe\n", expr, ret); - return ret; - } else { - expr->always_false = true; - expr->probability = 0.0; +/** Simplify a disjunction. */ +static struct bfs_expr *simplify_or(struct bfs_opt *opt, struct bfs_expr *expr, const struct visitor *visitor) { + struct bfs_expr *ignorable = first_ignorable(opt, expr); + bool ignore = false; + + struct bfs_exprs children; + foster_children(expr, &children); + + while (!SLIST_EMPTY(&children)) { + struct bfs_expr *child = SLIST_POP(&children); + + if (child == ignorable) { + ignore = true; } - } else if (df_is_bottom(&opt->after_false)) { - if (expr->pure) { - struct bfs_expr *ret = opt_const(opt, true); - opt_debug(opt, 2, "data flow: %pe --> %pe\n", expr, ret); - opt_warning(opt, expr, "This expression is always true.\n\n"); - return ret; - } else { - expr->always_true = true; - expr->probability = 1.0; + + if (ignore) { + opt_delete(opt, "%pe [ignored result]\n", child); + opt_warning(opt, child, "The result of this expression is ignored.\n\n"); + continue; } - } - return expr; -} + if (child->eval_fn == eval_false) { + opt_delete(opt, "%pe [disjunctive syllogism]\n", child); + continue; + } -/** Swap the children of a binary expression if it would reduce the cost. */ -static bool reorder_expr(const struct bfs_opt *opt, struct bfs_expr *expr, float swapped_cost) { - if (swapped_cost < expr->cost) { - bool debug = opt_debug(opt, 3, "cost: %pe <==> ", expr); - struct bfs_expr *lhs = expr->lhs; - expr->lhs = expr->rhs; - expr->rhs = lhs; - if (debug) { - cfprintf(opt->ctx->cerr, "%pe (~${ylw}%g${rs} --> ~${ylw}%g${rs})\n", expr, expr->cost, swapped_cost); + opt_visit(opt, "%pe\n", child); + bfs_expr_append(expr, child); + + if (child->always_true) { + while ((child = SLIST_POP(&children))) { + opt_delete(opt, "%pe [short-circuit]\n", child); + } } - expr->cost = swapped_cost; - return true; - } else { - return false; } -} -/** - * Recursively reorder sub-expressions to reduce the overall cost. - * - * @param expr - * The expression to optimize. - * @return - * Whether any subexpression was reordered. - */ -static bool reorder_expr_recursive(const struct bfs_opt *opt, struct bfs_expr *expr) { - if (!bfs_expr_is_parent(expr)) { - return false; + struct bfs_expr *child = bfs_expr_children(expr); + if (!child) { + opt_debug(opt, "nullary identity\n"); + return opt_const(opt, false); + } else if (!child->next) { + opt_debug(opt, "unary identity\n"); + return only_child(expr); } - struct bfs_expr *lhs = expr->lhs; - struct bfs_expr *rhs = expr->rhs; + return lift_andor_not(opt, expr); +} - bool ret = false; - if (lhs) { - ret |= reorder_expr_recursive(opt, lhs); - } - if (rhs) { - ret |= reorder_expr_recursive(opt, rhs); - } +/** Simplify a comma expression. */ +static struct bfs_expr *simplify_comma(struct bfs_opt *opt, struct bfs_expr *expr, const struct visitor *visitor) { + struct bfs_exprs children; + foster_children(expr, &children); + + while (!SLIST_EMPTY(&children)) { + struct bfs_expr *child = SLIST_POP(&children); - if (expr->eval_fn == eval_and || expr->eval_fn == eval_or) { - if (lhs->pure && rhs->pure) { - float rhs_prob = expr->eval_fn == eval_and ? rhs->probability : 1.0 - rhs->probability; - float swapped_cost = rhs->cost + rhs_prob * lhs->cost; - ret |= reorder_expr(opt, expr, swapped_cost); + if (opt->level >= 2 && child->pure && !SLIST_EMPTY(&children)) { + opt_delete(opt, "%pe [ignored result]\n", child); + opt_warning(opt, child, "The result of this expression is ignored.\n\n"); + continue; } + + opt_visit(opt, "%pe\n", child); + bfs_expr_append(expr, child); } - return ret; + struct bfs_expr *child = bfs_expr_children(expr); + if (child && !child->next) { + opt_debug(opt, "unary identity\n"); + return only_child(expr); + } + + return expr; } /** - * Optimize a top-level expression. + * Logical simplification visitor. */ -static struct bfs_expr *optimize_expr(struct bfs_opt *opt, struct bfs_expr *expr) { - struct df_domain saved_impure = *opt->impure; +static const struct visitor simplify = { + .name = "simplify", + .table = { + {eval_not, simplify_not}, + {eval_and, simplify_and}, + {eval_or, simplify_or}, + {eval_comma, simplify_comma}, + {NULL, NULL}, + }, +}; - expr = optimize_expr_recursive(opt, expr); - if (!expr) { - return NULL; - } +/** Optimize an expression. */ +static struct bfs_expr *optimize(struct bfs_opt *opt, struct bfs_expr *expr) { + opt_enter(opt, "pass 0:\n"); + expr = visit(opt, expr, &annotate); + opt_leave(opt, NULL); + + /** Table of optimization passes. */ + static const struct { + /** Minimum optlevel for this pass. */ + int level; + /** The visitor for this pass. */ + const struct visitor *visitor; + } passes[] = { + {1, &canonicalize}, + {3, &reorder}, + {2, &data_flow}, + {1, &simplify}, + }; - if (opt->ctx->optlevel >= 3 && reorder_expr_recursive(opt, expr)) { - // Re-do optimizations to account for the new ordering - *opt->impure = saved_impure; - expr = optimize_expr_recursive(opt, expr); - if (!expr) { - return NULL; + struct df_domain impure; + + for (int i = 0; i < 3; ++i) { + struct bfs_opt nested = *opt; + nested.impure = &impure; + impure = *opt->impure; + + opt_enter(&nested, "pass %d:\n", i + 1); + + for (size_t j = 0; j < countof(passes); ++j) { + if (opt->level < passes[j].level) { + continue; + } + + // Skip reordering the first time through the passes, to + // make warnings more understandable + if (passes[j].visitor == &reorder) { + if (i == 0) { + continue; + } else { + nested.warn = false; + } + } + + expr = visit(&nested, expr, passes[j].visitor); + if (!expr) { + return NULL; + } + } + + opt_leave(&nested, NULL); + + if (!bfs_expr_is_parent(expr)) { + break; } } + *opt->impure = impure; return expr; } @@ -1332,30 +2137,37 @@ int bfs_optimize(struct bfs_ctx *ctx) { struct bfs_opt opt = { .ctx = ctx, + .level = ctx->optlevel, + .depth = 0, + .warn = ctx->warn, + .ignore_result = false, .impure = &impure, }; df_init_top(&opt.before); - ctx->exclude = optimize_expr(&opt, ctx->exclude); + ctx->exclude = optimize(&opt, ctx->exclude); if (!ctx->exclude) { return -1; } // Only non-excluded files are evaluated opt.before = opt.after_false; + opt.ignore_result = true; struct df_range *depth = &opt.before.ranges[DEPTH_RANGE]; - constrain_min(depth, ctx->mindepth); - constrain_max(depth, ctx->maxdepth); + if (ctx->mindepth > 0) { + constrain_min(depth, ctx->mindepth); + } + if (ctx->maxdepth < INT_MAX) { + constrain_max(depth, ctx->maxdepth); + } - ctx->expr = optimize_expr(&opt, ctx->expr); + ctx->expr = optimize(&opt, ctx->expr); if (!ctx->expr) { return -1; } - ctx->expr = ignore_result(&opt, ctx->expr); - - if (df_is_bottom(&impure)) { + if (opt.level >= 2 && df_is_bottom(&impure)) { bfs_warning(ctx, "This command won't do anything.\n\n"); } @@ -1363,23 +2175,27 @@ int bfs_optimize(struct bfs_ctx *ctx) { long long mindepth = impure_depth->min; long long maxdepth = impure_depth->max; - int optlevel = ctx->optlevel; + opt_enter(&opt, "post-process:\n"); - if (optlevel >= 2 && mindepth > ctx->mindepth) { + if (opt.level >= 2 && mindepth > ctx->mindepth) { if (mindepth > INT_MAX) { mindepth = INT_MAX; } + opt_enter(&opt, "${blu}-mindepth${rs} ${bld}%d${rs}\n", ctx->mindepth); ctx->mindepth = mindepth; - opt_debug(&opt, 2, "data flow: mindepth --> %d\n", ctx->mindepth); + opt_leave(&opt, "${blu}-mindepth${rs} ${bld}%d${rs}\n", ctx->mindepth); } - if (optlevel >= 4 && maxdepth < ctx->maxdepth) { + if (opt.level >= 4 && maxdepth < ctx->maxdepth) { if (maxdepth < INT_MIN) { maxdepth = INT_MIN; } + opt_enter(&opt, "${blu}-maxdepth${rs} ${bld}%d${rs}\n", ctx->maxdepth); ctx->maxdepth = maxdepth; - opt_debug(&opt, 4, "data flow: maxdepth --> %d\n", ctx->maxdepth); + opt_leave(&opt, "${blu}-maxdepth${rs} ${bld}%d${rs}\n", ctx->maxdepth); } + opt_leave(&opt, NULL); + return 0; } diff --git a/src/parse.c b/src/parse.c index 17fe8ad..4212196 100644 --- a/src/parse.c +++ b/src/parse.c @@ -21,6 +21,7 @@ #include "exec.h" #include "expr.h" #include "fsade.h" +#include "list.h" #include "opt.h" #include "printf.h" #include "pwcache.h" @@ -47,10 +48,9 @@ #include // Strings printed by -D tree for "fake" expressions -static char *fake_and_arg = "-a"; -static char *fake_false_arg = "-false"; +static char *fake_and_arg = "-and"; static char *fake_hidden_arg = "-hidden"; -static char *fake_or_arg = "-o"; +static char *fake_or_arg = "-or"; static char *fake_print_arg = "-print"; static char *fake_true_arg = "-true"; @@ -319,12 +319,8 @@ static struct bfs_expr *new_unary_expr(const struct bfs_parser *parser, bfs_eval return NULL; } - expr->lhs = NULL; - expr->rhs = rhs; bfs_assert(bfs_expr_is_parent(expr)); - - expr->persistent_fds = rhs->persistent_fds; - expr->ephemeral_fds = rhs->ephemeral_fds; + bfs_expr_append(expr, rhs); return expr; } @@ -337,17 +333,9 @@ static struct bfs_expr *new_binary_expr(const struct bfs_parser *parser, bfs_eva return NULL; } - expr->lhs = lhs; - expr->rhs = rhs; bfs_assert(bfs_expr_is_parent(expr)); - - expr->persistent_fds = lhs->persistent_fds + rhs->persistent_fds; - if (lhs->ephemeral_fds > rhs->ephemeral_fds) { - expr->ephemeral_fds = lhs->ephemeral_fds; - } else { - expr->ephemeral_fds = rhs->ephemeral_fds; - } - + bfs_expr_append(expr, lhs); + bfs_expr_append(expr, rhs); return expr; } @@ -774,19 +762,6 @@ static struct bfs_expr *parse_unary_action(struct bfs_parser *parser, bfs_eval_f return parse_action(parser, eval_fn, 2); } -/** - * Add an expression to the exclusions. - */ -static int parse_exclude(struct bfs_parser *parser, struct bfs_expr *expr) { - struct bfs_ctx *ctx = parser->ctx; - ctx->exclude = new_binary_expr(parser, eval_or, ctx->exclude, expr, &fake_or_arg); - if (ctx->exclude) { - return 0; - } else { - return -1; - } -} - /** * Parse a test expression with integer data and a comparison flag. */ @@ -1839,10 +1814,7 @@ static struct bfs_expr *parse_nohidden(struct bfs_parser *parser, int arg1, int return NULL; } - if (parse_exclude(parser, hidden) != 0) { - return NULL; - } - + bfs_expr_append(parser->ctx->exclude, hidden); return parse_nullary_option(parser); } @@ -3206,10 +3178,7 @@ static struct bfs_expr *parse_factor(struct bfs_parser *parser) { parser->excluding = false; - if (parse_exclude(parser, factor) != 0) { - return NULL; - } - + bfs_expr_append(parser->ctx->exclude, factor); return parse_new_expr(parser, eval_true, parser->argv - argv, argv); } else if (strcmp(arg, "!") == 0 || strcmp(arg, "-not") == 0) { char **argv = parser_advance(parser, T_OPERATOR, 1); @@ -3428,19 +3397,29 @@ static void dump_expr_multiline(const struct bfs_ctx *ctx, enum debug_flags flag cfprintf(ctx->cerr, " "); } + bool close = true; + if (bfs_expr_is_parent(expr)) { - cfprintf(ctx->cerr, "(${red}%s${rs}\n", expr->argv[0]); - if (expr->lhs) { - dump_expr_multiline(ctx, flag, expr->lhs, indent + 1, 0); + if (SLIST_EMPTY(&expr->children)) { + cfprintf(ctx->cerr, "(${red}%s${rs}", expr->argv[0]); + ++rparens; + } else { + cfprintf(ctx->cerr, "(${red}%s${rs}\n", expr->argv[0]); + for (struct bfs_expr *child = bfs_expr_children(expr); child; child = child->next) { + int parens = child->next ? 0 : rparens + 1; + dump_expr_multiline(ctx, flag, child, indent + 1, parens); + } + close = false; } - dump_expr_multiline(ctx, flag, expr->rhs, indent + 1, rparens + 1); } else { if (flag == DEBUG_RATES) { cfprintf(ctx->cerr, "%pE", expr); } else { cfprintf(ctx->cerr, "%pe", expr); } + } + if (close) { for (int i = 0; i < rparens; ++i) { cfprintf(ctx->cerr, ")"); } @@ -3540,10 +3519,8 @@ void bfs_ctx_dump(const struct bfs_ctx *ctx, enum debug_flags flag) { fputs("\n", stderr); - if (ctx->exclude->eval_fn != eval_false) { - bfs_debug(ctx, flag, "(${red}-exclude${rs}\n"); - dump_expr_multiline(ctx, flag, ctx->exclude, 1, 1); - } + bfs_debug(ctx, flag, "(${red}-exclude${rs}\n"); + dump_expr_multiline(ctx, flag, ctx->exclude, 1, 1); dump_expr_multiline(ctx, flag, ctx->expr, 0, 0); } @@ -3638,7 +3615,7 @@ struct bfs_ctx *bfs_parse_cmdline(int argc, char *argv[]) { .now = ctx->now, }; - ctx->exclude = parse_new_expr(&parser, eval_false, 1, &fake_false_arg); + ctx->exclude = parse_new_expr(&parser, eval_or, 1, &fake_or_arg); if (!ctx->exclude) { goto fail; } -- cgit v1.2.3 From 3b82c88d1950291b1b703f082df43ec1b9654eb5 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Mon, 5 Feb 2024 14:11:38 -0500 Subject: color: New API to check if stat() is necessary --- src/color.c | 5 +++++ src/color.h | 12 ++++++------ 2 files changed, 11 insertions(+), 6 deletions(-) (limited to 'src/color.c') diff --git a/src/color.c b/src/color.c index 1f10c04..8c32a68 100644 --- a/src/color.c +++ b/src/color.c @@ -764,6 +764,11 @@ static bool is_link_broken(const struct BFTW *ftwbuf) { } } +bool colors_need_stat(const struct colors *colors) { + return colors->setuid || colors->setgid || colors->executable || colors->multi_hard + || colors->sticky_other_writable || colors->other_writable || colors->sticky; +} + /** Get the color for a file. */ static const struct esc_seq *file_color(const struct colors *colors, const char *filename, const struct BFTW *ftwbuf, enum bfs_stat_flags flags) { enum bfs_type type = bftw_type(ftwbuf, flags); diff --git a/src/color.h b/src/color.h index 760aa9d..85633a4 100644 --- a/src/color.h +++ b/src/color.h @@ -19,17 +19,17 @@ struct colors; /** - * Parse a color table. - * - * @return The parsed color table. + * Parse the color table from the environment. */ struct colors *parse_colors(void); +/** + * Check if stat() info is required to color a file correctly. + */ +bool colors_need_stat(const struct colors *colors); + /** * Free a color table. - * - * @param colors - * The color table to free. */ void free_colors(struct colors *colors); -- cgit v1.2.3 From c66379749f423413913b406609dfe9311ba6e555 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 18 Apr 2024 14:53:56 -0400 Subject: Rename config.h to prelude.h --- src/alloc.c | 2 +- src/alloc.h | 2 +- src/bar.c | 2 +- src/bfstd.c | 2 +- src/bfstd.h | 2 +- src/bftw.c | 2 +- src/bit.h | 2 +- src/color.c | 2 +- src/color.h | 2 +- src/config.h | 377 --------------------------------------------------------- src/ctx.h | 2 +- src/diag.c | 2 +- src/diag.h | 2 +- src/dir.c | 2 +- src/dstring.c | 2 +- src/dstring.h | 2 +- src/eval.c | 2 +- src/eval.h | 2 +- src/exec.c | 2 +- src/expr.h | 2 +- src/fsade.c | 2 +- src/fsade.h | 2 +- src/ioq.c | 2 +- src/ioq.h | 2 +- src/main.c | 4 +- src/mtab.c | 2 +- src/mtab.h | 2 +- src/opt.c | 2 +- src/parse.c | 2 +- src/prelude.h | 377 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/printf.c | 2 +- src/pwcache.c | 2 +- src/sanity.h | 2 +- src/stat.c | 2 +- src/stat.h | 2 +- src/thread.c | 2 +- src/thread.h | 2 +- src/trie.c | 2 +- src/xregex.c | 2 +- src/xspawn.c | 2 +- src/xspawn.h | 2 +- src/xtime.c | 2 +- tests/alloc.c | 2 +- tests/bfstd.c | 2 +- tests/bit.c | 2 +- tests/ioq.c | 2 +- tests/main.c | 2 +- tests/tests.h | 2 +- tests/trie.c | 2 +- tests/xspawn.c | 2 +- tests/xtime.c | 2 +- tests/xtouch.c | 2 +- 52 files changed, 428 insertions(+), 428 deletions(-) delete mode 100644 src/config.h create mode 100644 src/prelude.h (limited to 'src/color.c') diff --git a/src/alloc.c b/src/alloc.c index b65d0c5..ec8608f 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -1,9 +1,9 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD +#include "prelude.h" #include "alloc.h" #include "bit.h" -#include "config.h" #include "diag.h" #include "sanity.h" #include diff --git a/src/alloc.h b/src/alloc.h index ae055bc..095134a 100644 --- a/src/alloc.h +++ b/src/alloc.h @@ -8,7 +8,7 @@ #ifndef BFS_ALLOC_H #define BFS_ALLOC_H -#include "config.h" +#include "prelude.h" #include #include #include diff --git a/src/bar.c b/src/bar.c index 8ab4112..184d9a0 100644 --- a/src/bar.c +++ b/src/bar.c @@ -1,11 +1,11 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD +#include "prelude.h" #include "bar.h" #include "atomic.h" #include "bfstd.h" #include "bit.h" -#include "config.h" #include "dstring.h" #include #include diff --git a/src/bfstd.c b/src/bfstd.c index 2499f00..e1b4804 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -1,9 +1,9 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD +#include "prelude.h" #include "bfstd.h" #include "bit.h" -#include "config.h" #include "diag.h" #include "sanity.h" #include "thread.h" diff --git a/src/bfstd.h b/src/bfstd.h index fc22971..42f5d5b 100644 --- a/src/bfstd.h +++ b/src/bfstd.h @@ -8,7 +8,7 @@ #ifndef BFS_BFSTD_H #define BFS_BFSTD_H -#include "config.h" +#include "prelude.h" #include "sanity.h" #include diff --git a/src/bftw.c b/src/bftw.c index 6130c44..c4d3c17 100644 --- a/src/bftw.c +++ b/src/bftw.c @@ -18,10 +18,10 @@ * various helper functions to take fewer parameters. */ +#include "prelude.h" #include "bftw.h" #include "alloc.h" #include "bfstd.h" -#include "config.h" #include "diag.h" #include "dir.h" #include "dstring.h" diff --git a/src/bit.h b/src/bit.h index 69df21e..17cfbcf 100644 --- a/src/bit.h +++ b/src/bit.h @@ -8,7 +8,7 @@ #ifndef BFS_BIT_H #define BFS_BIT_H -#include "config.h" +#include "prelude.h" #include #include diff --git a/src/color.c b/src/color.c index 8c32a68..f004bf2 100644 --- a/src/color.c +++ b/src/color.c @@ -1,11 +1,11 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD +#include "prelude.h" #include "color.h" #include "alloc.h" #include "bfstd.h" #include "bftw.h" -#include "config.h" #include "diag.h" #include "dir.h" #include "dstring.h" diff --git a/src/color.h b/src/color.h index e3e7973..3278cd6 100644 --- a/src/color.h +++ b/src/color.h @@ -8,7 +8,7 @@ #ifndef BFS_COLOR_H #define BFS_COLOR_H -#include "config.h" +#include "prelude.h" #include "dstring.h" #include diff --git a/src/config.h b/src/config.h deleted file mode 100644 index 2eff1fc..0000000 --- a/src/config.h +++ /dev/null @@ -1,377 +0,0 @@ -// Copyright © Tavian Barnes -// SPDX-License-Identifier: 0BSD - -/** - * Configuration and feature/platform detection. - */ - -#ifndef BFS_CONFIG_H -#define BFS_CONFIG_H - -// Possible __STDC_VERSION__ values - -#define C95 199409L -#define C99 199901L -#define C11 201112L -#define C17 201710L -#define C23 202311L - -#include - -#if __STDC_VERSION__ < C23 -# include -# include -# include -#endif - -// bfs packaging configuration - -#ifndef BFS_COMMAND -# define BFS_COMMAND "bfs" -#endif -#ifndef BFS_HOMEPAGE -# define BFS_HOMEPAGE "https://tavianator.com/projects/bfs.html" -#endif - -// This is a symbol instead of a literal so we don't have to rebuild everything -// when the version number changes -extern const char bfs_version[]; - -// Check for system headers - -#ifdef __has_include - -#if __has_include() -# define BFS_HAS_MNTENT_H true -#endif -#if __has_include() -# define BFS_HAS_PATHS_H true -#endif -#if __has_include() -# define BFS_HAS_SYS_ACL_H true -#endif -#if __has_include() -# define BFS_HAS_SYS_CAPABILITY_H true -#endif -#if __has_include() -# define BFS_HAS_SYS_EXTATTR_H true -#endif -#if __has_include() -# define BFS_HAS_SYS_MKDEV_H true -#endif -#if __has_include() -# define BFS_HAS_SYS_PARAM_H true -#endif -#if __has_include() -# define BFS_HAS_SYS_SYSMACROS_H true -#endif -#if __has_include() -# define BFS_HAS_SYS_XATTR_H true -#endif -#if __has_include() -# define BFS_HAS_THREADS_H true -#endif -#if __has_include() -# define BFS_HAS_UTIL_H true -#endif - -#else // !__has_include - -#define BFS_HAS_MNTENT_H __GLIBC__ -#define BFS_HAS_PATHS_H true -#define BFS_HAS_SYS_ACL_H true -#define BFS_HAS_SYS_CAPABILITY_H __linux__ -#define BFS_HAS_SYS_EXTATTR_H __FreeBSD__ -#define BFS_HAS_SYS_MKDEV_H false -#define BFS_HAS_SYS_PARAM_H true -#define BFS_HAS_SYS_SYSMACROS_H __GLIBC__ -#define BFS_HAS_SYS_XATTR_H __linux__ -#define BFS_HAS_THREADS_H (!__STDC_NO_THREADS__) -#define BFS_HAS_UTIL_H __NetBSD__ - -#endif // !__has_include - -#ifndef BFS_USE_MNTENT_H -# define BFS_USE_MNTENT_H BFS_HAS_MNTENT_H -#endif -#ifndef BFS_USE_PATHS_H -# define BFS_USE_PATHS_H BFS_HAS_PATHS_H -#endif -#ifndef BFS_USE_SYS_ACL_H -# define BFS_USE_SYS_ACL_H (BFS_HAS_SYS_ACL_H && !__illumos__ && (!__linux__ || BFS_USE_LIBACL)) -#endif -#ifndef BFS_USE_SYS_CAPABILITY_H -# define BFS_USE_SYS_CAPABILITY_H (BFS_HAS_SYS_CAPABILITY_H && !__FreeBSD__ && (!__linux__ || BFS_USE_LIBCAP)) -#endif -#ifndef BFS_USE_SYS_EXTATTR_H -# define BFS_USE_SYS_EXTATTR_H (BFS_HAS_SYS_EXTATTR_H && !__DragonFly__) -#endif -#ifndef BFS_USE_SYS_MKDEV_H -# define BFS_USE_SYS_MKDEV_H BFS_HAS_SYS_MKDEV_H -#endif -#ifndef BFS_USE_SYS_PARAM_H -# define BFS_USE_SYS_PARAM_H BFS_HAS_SYS_PARAM_H -#endif -#ifndef BFS_USE_SYS_SYSMACROS_H -# define BFS_USE_SYS_SYSMACROS_H BFS_HAS_SYS_SYSMACROS_H -#endif -#ifndef BFS_USE_SYS_XATTR_H -# define BFS_USE_SYS_XATTR_H BFS_HAS_SYS_XATTR_H -#endif -#ifndef BFS_USE_THREADS_H -# define BFS_USE_THREADS_H BFS_HAS_THREADS_H -#endif -#ifndef BFS_USE_UTIL_H -# define BFS_USE_UTIL_H BFS_HAS_UTIL_H -#endif - -// Stub out feature detection on old/incompatible compilers - -#ifndef __has_feature -# define __has_feature(feat) false -#endif - -#ifndef __has_c_attribute -# define __has_c_attribute(attr) false -#endif - -#ifndef __has_attribute -# define __has_attribute(attr) false -#endif - -// Platform detection - -// Get the definition of BSD if available -#if BFS_USE_SYS_PARAM_H -# include -#endif - -#ifndef __GLIBC_PREREQ -# define __GLIBC_PREREQ(maj, min) false -#endif - -#ifndef __NetBSD_Prereq__ -# define __NetBSD_Prereq__(maj, min, patch) false -#endif - -// Fundamental utilities - -/** - * Get the length of an array. - */ -#define countof(array) (sizeof(array) / sizeof(0[array])) - -/** - * False sharing/destructive interference/largest cache line size. - */ -#ifdef __GCC_DESTRUCTIVE_SIZE -# define FALSE_SHARING_SIZE __GCC_DESTRUCTIVE_SIZE -#else -# define FALSE_SHARING_SIZE 64 -#endif - -/** - * True sharing/constructive interference/smallest cache line size. - */ -#ifdef __GCC_CONSTRUCTIVE_SIZE -# define TRUE_SHARING_SIZE __GCC_CONSTRUCTIVE_SIZE -#else -# define TRUE_SHARING_SIZE 64 -#endif - -/** - * Alignment specifier that avoids false sharing. - */ -#define cache_align alignas(FALSE_SHARING_SIZE) - -#if __COSMOPOLITAN__ -typedef long double max_align_t; -#endif - -// Wrappers for attributes - -/** - * Silence warnings about switch/case fall-throughs. - */ -#if __has_attribute(fallthrough) -# define fallthru __attribute__((fallthrough)) -#else -# define fallthru ((void)0) -#endif - -/** - * Silence warnings about unused declarations. - */ -#if __has_attribute(unused) -# define attr_maybe_unused __attribute__((unused)) -#else -# define attr_maybe_unused -#endif - -/** - * Warn if a value is unused. - */ -#if __has_attribute(warn_unused_result) -# define attr_nodiscard __attribute__((warn_unused_result)) -#else -# define attr_nodiscard -#endif - -/** - * Hint to avoid inlining a function. - */ -#if __has_attribute(noinline) -# define attr_noinline __attribute__((noinline)) -#else -# define attr_noinline -#endif - -/** - * Hint that a function is unlikely to be called. - */ -#if __has_attribute(cold) -# define attr_cold attr_noinline __attribute__((cold)) -#else -# define attr_cold attr_noinline -#endif - -/** - * Adds compiler warnings for bad printf()-style function calls, if supported. - */ -#if __has_attribute(format) -# define attr_printf(fmt, args) __attribute__((format(printf, fmt, args))) -#else -# define attr_printf(fmt, args) -#endif - -/** - * Annotates allocator-like functions. - */ -#if __has_attribute(malloc) -# if __GNUC__ >= 11 && !__OPTIMIZE__ // malloc(deallocator) disables inlining on GCC -# define attr_malloc(...) attr_nodiscard __attribute__((malloc(__VA_ARGS__))) -# else -# define attr_malloc(...) attr_nodiscard __attribute__((malloc)) -# endif -#else -# define attr_malloc(...) attr_nodiscard -#endif - -/** - * Specifies that a function returns allocations with a given alignment. - */ -#if __has_attribute(alloc_align) -# define attr_alloc_align(param) __attribute__((alloc_align(param))) -#else -# define attr_alloc_align(param) -#endif - -/** - * Specifies that a function returns allocations with a given size. - */ -#if __has_attribute(alloc_size) -# define attr_alloc_size(...) __attribute__((alloc_size(__VA_ARGS__))) -#else -# define attr_alloc_size(...) -#endif - -/** - * Shorthand for attr_alloc_align() and attr_alloc_size(). - */ -#define attr_aligned_alloc(align, ...) \ - attr_alloc_align(align) \ - attr_alloc_size(__VA_ARGS__) - -/** - * Check if function multiversioning via GNU indirect functions (ifunc) is supported. - */ -#ifndef BFS_USE_TARGET_CLONES -# if __has_attribute(target_clones) && (__GLIBC__ || __FreeBSD__) -# define BFS_USE_TARGET_CLONES true -# endif -#endif - -/** - * Apply the target_clones attribute, if available. - */ -#if BFS_USE_TARGET_CLONES -# define attr_target_clones(...) __attribute__((target_clones(__VA_ARGS__))) -#else -# define attr_target_clones(...) -#endif - -/** - * Shorthand for multiple attributes at once. attr(a, b(c), d) is equivalent to - * - * attr_a - * attr_b(c) - * attr_d - */ -#define attr(...) \ - attr__(attr_##__VA_ARGS__, none, none, none, none, none, none, none, none, none, ) - -/** - * attr() helper. For exposition, pretend we support only 2 args, instead of 9. - * There are a few cases: - * - * attr() - * => attr__(attr_, none, none) - * => attr_ => - * attr_none => - * attr_too_many_none() => - * - * attr(a) - * => attr__(attr_a, none, none) - * => attr_a => __attribute__((a)) - * attr_none => - * attr_too_many_none() => - * - * attr(a, b(c)) - * => attr__(attr_a, b(c), none, none) - * => attr_a => __attribute__((a)) - * attr_b(c) => __attribute__((b(c))) - * attr_too_many_none(none) => - * - * attr(a, b(c), d) - * => attr__(attr_a, b(c), d, none, none) - * => attr_a => __attribute__((a)) - * attr_b(c) => __attribute__((b(c))) - * attr_too_many_d(none, none) => error - * - * Some attribute names are the same as standard library functions, e.g. printf. - * Standard libraries are permitted to define these functions as macros, like - * - * #define printf(...) __builtin_printf(__VA_ARGS__) - * - * The token paste in - * - * #define attr(...) attr__(attr_##__VA_ARGS__, none, none) - * - * is necessary to prevent macro expansion before evaluating attr__(). - * Otherwise, we could get - * - * attr(printf(1, 2)) - * => attr__(__builtin_printf(1, 2), none, none) - * => attr____builtin_printf(1, 2) - * => error - */ -#define attr__(a1, a2, a3, a4, a5, a6, a7, a8, a9, none, ...) \ - a1 \ - attr_##a2 \ - attr_##a3 \ - attr_##a4 \ - attr_##a5 \ - attr_##a6 \ - attr_##a7 \ - attr_##a8 \ - attr_##a9 \ - attr_too_many_##none(__VA_ARGS__) - -// Ignore `attr_none` from expanding 1-9 argument attr(a1, a2, ...) -#define attr_none -// Ignore `attr_` from expanding 0-argument attr() -#define attr_ -// Only trigger an error on more than 9 arguments -#define attr_too_many_none(...) - -#endif // BFS_CONFIG_H diff --git a/src/ctx.h b/src/ctx.h index e14db21..fc3020c 100644 --- a/src/ctx.h +++ b/src/ctx.h @@ -8,9 +8,9 @@ #ifndef BFS_CTX_H #define BFS_CTX_H +#include "prelude.h" #include "alloc.h" #include "bftw.h" -#include "config.h" #include "diag.h" #include "expr.h" #include "trie.h" diff --git a/src/diag.c b/src/diag.c index cb27b92..deb6f26 100644 --- a/src/diag.c +++ b/src/diag.c @@ -1,11 +1,11 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD +#include "prelude.h" #include "diag.h" #include "alloc.h" #include "bfstd.h" #include "color.h" -#include "config.h" #include "ctx.h" #include "dstring.h" #include "expr.h" diff --git a/src/diag.h b/src/diag.h index 4054c48..2b13609 100644 --- a/src/diag.h +++ b/src/diag.h @@ -8,7 +8,7 @@ #ifndef BFS_DIAG_H #define BFS_DIAG_H -#include "config.h" +#include "prelude.h" #include /** diff --git a/src/dir.c b/src/dir.c index 98518f2..53c9be3 100644 --- a/src/dir.c +++ b/src/dir.c @@ -1,10 +1,10 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD +#include "prelude.h" #include "dir.h" #include "alloc.h" #include "bfstd.h" -#include "config.h" #include "diag.h" #include "sanity.h" #include "trie.h" diff --git a/src/dstring.c b/src/dstring.c index 10b0fad..913dda8 100644 --- a/src/dstring.c +++ b/src/dstring.c @@ -1,10 +1,10 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD +#include "prelude.h" #include "dstring.h" #include "alloc.h" #include "bit.h" -#include "config.h" #include "diag.h" #include #include diff --git a/src/dstring.h b/src/dstring.h index 6006199..9ea7eb9 100644 --- a/src/dstring.h +++ b/src/dstring.h @@ -8,8 +8,8 @@ #ifndef BFS_DSTRING_H #define BFS_DSTRING_H +#include "prelude.h" #include "bfstd.h" -#include "config.h" #include #include diff --git a/src/eval.c b/src/eval.c index d0112c2..b103912 100644 --- a/src/eval.c +++ b/src/eval.c @@ -5,12 +5,12 @@ * Implementation of all the primary expressions. */ +#include "prelude.h" #include "eval.h" #include "bar.h" #include "bfstd.h" #include "bftw.h" #include "color.h" -#include "config.h" #include "ctx.h" #include "diag.h" #include "dir.h" diff --git a/src/eval.h b/src/eval.h index ae43628..4dd7996 100644 --- a/src/eval.h +++ b/src/eval.h @@ -9,7 +9,7 @@ #ifndef BFS_EVAL_H #define BFS_EVAL_H -#include "config.h" +#include "prelude.h" struct bfs_ctx; struct bfs_expr; diff --git a/src/exec.c b/src/exec.c index 60bfd28..e782d49 100644 --- a/src/exec.c +++ b/src/exec.c @@ -1,12 +1,12 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD +#include "prelude.h" #include "exec.h" #include "alloc.h" #include "bfstd.h" #include "bftw.h" #include "color.h" -#include "config.h" #include "ctx.h" #include "diag.h" #include "dstring.h" diff --git a/src/expr.h b/src/expr.h index 75cb5fd..7bcace7 100644 --- a/src/expr.h +++ b/src/expr.h @@ -8,8 +8,8 @@ #ifndef BFS_EXPR_H #define BFS_EXPR_H +#include "prelude.h" #include "color.h" -#include "config.h" #include "eval.h" #include "stat.h" #include diff --git a/src/fsade.c b/src/fsade.c index 0810c7f..34a4d57 100644 --- a/src/fsade.c +++ b/src/fsade.c @@ -1,11 +1,11 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD +#include "prelude.h" #include "fsade.h" #include "atomic.h" #include "bfstd.h" #include "bftw.h" -#include "config.h" #include "dir.h" #include "dstring.h" #include "sanity.h" diff --git a/src/fsade.h b/src/fsade.h index 1f1dbfc..6300852 100644 --- a/src/fsade.h +++ b/src/fsade.h @@ -9,7 +9,7 @@ #ifndef BFS_FSADE_H #define BFS_FSADE_H -#include "config.h" +#include "prelude.h" #define BFS_CAN_CHECK_ACL BFS_USE_SYS_ACL_H diff --git a/src/ioq.c b/src/ioq.c index b936681..189bdac 100644 --- a/src/ioq.c +++ b/src/ioq.c @@ -118,12 +118,12 @@ * [1]: https://arxiv.org/abs/2201.02179 */ +#include "prelude.h" #include "ioq.h" #include "alloc.h" #include "atomic.h" #include "bfstd.h" #include "bit.h" -#include "config.h" #include "diag.h" #include "dir.h" #include "stat.h" diff --git a/src/ioq.h b/src/ioq.h index 818eea6..d8e1573 100644 --- a/src/ioq.h +++ b/src/ioq.h @@ -8,7 +8,7 @@ #ifndef BFS_IOQ_H #define BFS_IOQ_H -#include "config.h" +#include "prelude.h" #include "dir.h" #include "stat.h" #include diff --git a/src/main.c b/src/main.c index e120f03..9d8b206 100644 --- a/src/main.c +++ b/src/main.c @@ -26,7 +26,7 @@ * - bit.h (bit manipulation) * - bfstd.[ch] (standard library wrappers/polyfills) * - color.[ch] (for pretty terminal colors) - * - config.h (configuration and feature/platform detection) + * - prelude.h (configuration and feature/platform detection) * - diag.[ch] (formats diagnostic messages) * - dir.[ch] (a directory API facade) * - dstring.[ch] (a dynamic string library) @@ -45,8 +45,8 @@ * - xtime.[ch] (date/time handling utilities) */ +#include "prelude.h" #include "bfstd.h" -#include "config.h" #include "ctx.h" #include "diag.h" #include "eval.h" diff --git a/src/mtab.c b/src/mtab.c index 86ae151..7905d14 100644 --- a/src/mtab.c +++ b/src/mtab.c @@ -1,10 +1,10 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD +#include "prelude.h" #include "mtab.h" #include "alloc.h" #include "bfstd.h" -#include "config.h" #include "stat.h" #include "trie.h" #include diff --git a/src/mtab.h b/src/mtab.h index d99d78f..67290c2 100644 --- a/src/mtab.h +++ b/src/mtab.h @@ -8,7 +8,7 @@ #ifndef BFS_MTAB_H #define BFS_MTAB_H -#include "config.h" +#include "prelude.h" struct bfs_stat; diff --git a/src/opt.c b/src/opt.c index b74b4e1..ffc795b 100644 --- a/src/opt.c +++ b/src/opt.c @@ -25,11 +25,11 @@ * effects are reachable at all, skipping the traversal if not. */ +#include "prelude.h" #include "opt.h" #include "bftw.h" #include "bit.h" #include "color.h" -#include "config.h" #include "ctx.h" #include "diag.h" #include "dir.h" diff --git a/src/parse.c b/src/parse.c index a3e32fe..c2ae58f 100644 --- a/src/parse.c +++ b/src/parse.c @@ -8,12 +8,12 @@ * flags like always-true options, and skipping over paths wherever they appear. */ +#include "prelude.h" #include "parse.h" #include "alloc.h" #include "bfstd.h" #include "bftw.h" #include "color.h" -#include "config.h" #include "ctx.h" #include "diag.h" #include "dir.h" diff --git a/src/prelude.h b/src/prelude.h new file mode 100644 index 0000000..c3a0752 --- /dev/null +++ b/src/prelude.h @@ -0,0 +1,377 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +/** + * Configuration and feature/platform detection. + */ + +#ifndef BFS_PRELUDE_H +#define BFS_PRELUDE_H + +// Possible __STDC_VERSION__ values + +#define C95 199409L +#define C99 199901L +#define C11 201112L +#define C17 201710L +#define C23 202311L + +#include + +#if __STDC_VERSION__ < C23 +# include +# include +# include +#endif + +// bfs packaging configuration + +#ifndef BFS_COMMAND +# define BFS_COMMAND "bfs" +#endif +#ifndef BFS_HOMEPAGE +# define BFS_HOMEPAGE "https://tavianator.com/projects/bfs.html" +#endif + +// This is a symbol instead of a literal so we don't have to rebuild everything +// when the version number changes +extern const char bfs_version[]; + +// Check for system headers + +#ifdef __has_include + +#if __has_include() +# define BFS_HAS_MNTENT_H true +#endif +#if __has_include() +# define BFS_HAS_PATHS_H true +#endif +#if __has_include() +# define BFS_HAS_SYS_ACL_H true +#endif +#if __has_include() +# define BFS_HAS_SYS_CAPABILITY_H true +#endif +#if __has_include() +# define BFS_HAS_SYS_EXTATTR_H true +#endif +#if __has_include() +# define BFS_HAS_SYS_MKDEV_H true +#endif +#if __has_include() +# define BFS_HAS_SYS_PARAM_H true +#endif +#if __has_include() +# define BFS_HAS_SYS_SYSMACROS_H true +#endif +#if __has_include() +# define BFS_HAS_SYS_XATTR_H true +#endif +#if __has_include() +# define BFS_HAS_THREADS_H true +#endif +#if __has_include() +# define BFS_HAS_UTIL_H true +#endif + +#else // !__has_include + +#define BFS_HAS_MNTENT_H __GLIBC__ +#define BFS_HAS_PATHS_H true +#define BFS_HAS_SYS_ACL_H true +#define BFS_HAS_SYS_CAPABILITY_H __linux__ +#define BFS_HAS_SYS_EXTATTR_H __FreeBSD__ +#define BFS_HAS_SYS_MKDEV_H false +#define BFS_HAS_SYS_PARAM_H true +#define BFS_HAS_SYS_SYSMACROS_H __GLIBC__ +#define BFS_HAS_SYS_XATTR_H __linux__ +#define BFS_HAS_THREADS_H (!__STDC_NO_THREADS__) +#define BFS_HAS_UTIL_H __NetBSD__ + +#endif // !__has_include + +#ifndef BFS_USE_MNTENT_H +# define BFS_USE_MNTENT_H BFS_HAS_MNTENT_H +#endif +#ifndef BFS_USE_PATHS_H +# define BFS_USE_PATHS_H BFS_HAS_PATHS_H +#endif +#ifndef BFS_USE_SYS_ACL_H +# define BFS_USE_SYS_ACL_H (BFS_HAS_SYS_ACL_H && !__illumos__ && (!__linux__ || BFS_USE_LIBACL)) +#endif +#ifndef BFS_USE_SYS_CAPABILITY_H +# define BFS_USE_SYS_CAPABILITY_H (BFS_HAS_SYS_CAPABILITY_H && !__FreeBSD__ && (!__linux__ || BFS_USE_LIBCAP)) +#endif +#ifndef BFS_USE_SYS_EXTATTR_H +# define BFS_USE_SYS_EXTATTR_H (BFS_HAS_SYS_EXTATTR_H && !__DragonFly__) +#endif +#ifndef BFS_USE_SYS_MKDEV_H +# define BFS_USE_SYS_MKDEV_H BFS_HAS_SYS_MKDEV_H +#endif +#ifndef BFS_USE_SYS_PARAM_H +# define BFS_USE_SYS_PARAM_H BFS_HAS_SYS_PARAM_H +#endif +#ifndef BFS_USE_SYS_SYSMACROS_H +# define BFS_USE_SYS_SYSMACROS_H BFS_HAS_SYS_SYSMACROS_H +#endif +#ifndef BFS_USE_SYS_XATTR_H +# define BFS_USE_SYS_XATTR_H BFS_HAS_SYS_XATTR_H +#endif +#ifndef BFS_USE_THREADS_H +# define BFS_USE_THREADS_H BFS_HAS_THREADS_H +#endif +#ifndef BFS_USE_UTIL_H +# define BFS_USE_UTIL_H BFS_HAS_UTIL_H +#endif + +// Stub out feature detection on old/incompatible compilers + +#ifndef __has_feature +# define __has_feature(feat) false +#endif + +#ifndef __has_c_attribute +# define __has_c_attribute(attr) false +#endif + +#ifndef __has_attribute +# define __has_attribute(attr) false +#endif + +// Platform detection + +// Get the definition of BSD if available +#if BFS_USE_SYS_PARAM_H +# include +#endif + +#ifndef __GLIBC_PREREQ +# define __GLIBC_PREREQ(maj, min) false +#endif + +#ifndef __NetBSD_Prereq__ +# define __NetBSD_Prereq__(maj, min, patch) false +#endif + +// Fundamental utilities + +/** + * Get the length of an array. + */ +#define countof(array) (sizeof(array) / sizeof(0[array])) + +/** + * False sharing/destructive interference/largest cache line size. + */ +#ifdef __GCC_DESTRUCTIVE_SIZE +# define FALSE_SHARING_SIZE __GCC_DESTRUCTIVE_SIZE +#else +# define FALSE_SHARING_SIZE 64 +#endif + +/** + * True sharing/constructive interference/smallest cache line size. + */ +#ifdef __GCC_CONSTRUCTIVE_SIZE +# define TRUE_SHARING_SIZE __GCC_CONSTRUCTIVE_SIZE +#else +# define TRUE_SHARING_SIZE 64 +#endif + +/** + * Alignment specifier that avoids false sharing. + */ +#define cache_align alignas(FALSE_SHARING_SIZE) + +#if __COSMOPOLITAN__ +typedef long double max_align_t; +#endif + +// Wrappers for attributes + +/** + * Silence warnings about switch/case fall-throughs. + */ +#if __has_attribute(fallthrough) +# define fallthru __attribute__((fallthrough)) +#else +# define fallthru ((void)0) +#endif + +/** + * Silence warnings about unused declarations. + */ +#if __has_attribute(unused) +# define attr_maybe_unused __attribute__((unused)) +#else +# define attr_maybe_unused +#endif + +/** + * Warn if a value is unused. + */ +#if __has_attribute(warn_unused_result) +# define attr_nodiscard __attribute__((warn_unused_result)) +#else +# define attr_nodiscard +#endif + +/** + * Hint to avoid inlining a function. + */ +#if __has_attribute(noinline) +# define attr_noinline __attribute__((noinline)) +#else +# define attr_noinline +#endif + +/** + * Hint that a function is unlikely to be called. + */ +#if __has_attribute(cold) +# define attr_cold attr_noinline __attribute__((cold)) +#else +# define attr_cold attr_noinline +#endif + +/** + * Adds compiler warnings for bad printf()-style function calls, if supported. + */ +#if __has_attribute(format) +# define attr_printf(fmt, args) __attribute__((format(printf, fmt, args))) +#else +# define attr_printf(fmt, args) +#endif + +/** + * Annotates allocator-like functions. + */ +#if __has_attribute(malloc) +# if __GNUC__ >= 11 && !__OPTIMIZE__ // malloc(deallocator) disables inlining on GCC +# define attr_malloc(...) attr_nodiscard __attribute__((malloc(__VA_ARGS__))) +# else +# define attr_malloc(...) attr_nodiscard __attribute__((malloc)) +# endif +#else +# define attr_malloc(...) attr_nodiscard +#endif + +/** + * Specifies that a function returns allocations with a given alignment. + */ +#if __has_attribute(alloc_align) +# define attr_alloc_align(param) __attribute__((alloc_align(param))) +#else +# define attr_alloc_align(param) +#endif + +/** + * Specifies that a function returns allocations with a given size. + */ +#if __has_attribute(alloc_size) +# define attr_alloc_size(...) __attribute__((alloc_size(__VA_ARGS__))) +#else +# define attr_alloc_size(...) +#endif + +/** + * Shorthand for attr_alloc_align() and attr_alloc_size(). + */ +#define attr_aligned_alloc(align, ...) \ + attr_alloc_align(align) \ + attr_alloc_size(__VA_ARGS__) + +/** + * Check if function multiversioning via GNU indirect functions (ifunc) is supported. + */ +#ifndef BFS_USE_TARGET_CLONES +# if __has_attribute(target_clones) && (__GLIBC__ || __FreeBSD__) +# define BFS_USE_TARGET_CLONES true +# endif +#endif + +/** + * Apply the target_clones attribute, if available. + */ +#if BFS_USE_TARGET_CLONES +# define attr_target_clones(...) __attribute__((target_clones(__VA_ARGS__))) +#else +# define attr_target_clones(...) +#endif + +/** + * Shorthand for multiple attributes at once. attr(a, b(c), d) is equivalent to + * + * attr_a + * attr_b(c) + * attr_d + */ +#define attr(...) \ + attr__(attr_##__VA_ARGS__, none, none, none, none, none, none, none, none, none, ) + +/** + * attr() helper. For exposition, pretend we support only 2 args, instead of 9. + * There are a few cases: + * + * attr() + * => attr__(attr_, none, none) + * => attr_ => + * attr_none => + * attr_too_many_none() => + * + * attr(a) + * => attr__(attr_a, none, none) + * => attr_a => __attribute__((a)) + * attr_none => + * attr_too_many_none() => + * + * attr(a, b(c)) + * => attr__(attr_a, b(c), none, none) + * => attr_a => __attribute__((a)) + * attr_b(c) => __attribute__((b(c))) + * attr_too_many_none(none) => + * + * attr(a, b(c), d) + * => attr__(attr_a, b(c), d, none, none) + * => attr_a => __attribute__((a)) + * attr_b(c) => __attribute__((b(c))) + * attr_too_many_d(none, none) => error + * + * Some attribute names are the same as standard library functions, e.g. printf. + * Standard libraries are permitted to define these functions as macros, like + * + * #define printf(...) __builtin_printf(__VA_ARGS__) + * + * The token paste in + * + * #define attr(...) attr__(attr_##__VA_ARGS__, none, none) + * + * is necessary to prevent macro expansion before evaluating attr__(). + * Otherwise, we could get + * + * attr(printf(1, 2)) + * => attr__(__builtin_printf(1, 2), none, none) + * => attr____builtin_printf(1, 2) + * => error + */ +#define attr__(a1, a2, a3, a4, a5, a6, a7, a8, a9, none, ...) \ + a1 \ + attr_##a2 \ + attr_##a3 \ + attr_##a4 \ + attr_##a5 \ + attr_##a6 \ + attr_##a7 \ + attr_##a8 \ + attr_##a9 \ + attr_too_many_##none(__VA_ARGS__) + +// Ignore `attr_none` from expanding 1-9 argument attr(a1, a2, ...) +#define attr_none +// Ignore `attr_` from expanding 0-argument attr() +#define attr_ +// Only trigger an error on more than 9 arguments +#define attr_too_many_none(...) + +#endif // BFS_PRELUDE_H diff --git a/src/printf.c b/src/printf.c index 3b8269e..4df399b 100644 --- a/src/printf.c +++ b/src/printf.c @@ -1,12 +1,12 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD +#include "prelude.h" #include "printf.h" #include "alloc.h" #include "bfstd.h" #include "bftw.h" #include "color.h" -#include "config.h" #include "ctx.h" #include "diag.h" #include "dir.h" diff --git a/src/pwcache.c b/src/pwcache.c index 79437d8..af8c237 100644 --- a/src/pwcache.c +++ b/src/pwcache.c @@ -1,9 +1,9 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD +#include "prelude.h" #include "pwcache.h" #include "alloc.h" -#include "config.h" #include "trie.h" #include #include diff --git a/src/sanity.h b/src/sanity.h index 423e6ff..e168b8f 100644 --- a/src/sanity.h +++ b/src/sanity.h @@ -8,7 +8,7 @@ #ifndef BFS_SANITY_H #define BFS_SANITY_H -#include "config.h" +#include "prelude.h" #include #if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) diff --git a/src/stat.c b/src/stat.c index 2f2743b..eca5bab 100644 --- a/src/stat.c +++ b/src/stat.c @@ -1,10 +1,10 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD +#include "prelude.h" #include "stat.h" #include "atomic.h" #include "bfstd.h" -#include "config.h" #include "diag.h" #include "sanity.h" #include diff --git a/src/stat.h b/src/stat.h index 856a2ca..1fdd263 100644 --- a/src/stat.h +++ b/src/stat.h @@ -12,7 +12,7 @@ #ifndef BFS_STAT_H #define BFS_STAT_H -#include "config.h" +#include "prelude.h" #include #include #include diff --git a/src/thread.c b/src/thread.c index 200d8c3..3793896 100644 --- a/src/thread.c +++ b/src/thread.c @@ -1,9 +1,9 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD +#include "prelude.h" #include "thread.h" #include "bfstd.h" -#include "config.h" #include "diag.h" #include #include diff --git a/src/thread.h b/src/thread.h index 8174fe4..db11bd8 100644 --- a/src/thread.h +++ b/src/thread.h @@ -8,7 +8,7 @@ #ifndef BFS_THREAD_H #define BFS_THREAD_H -#include "config.h" +#include "prelude.h" #include #if __STDC_VERSION__ < C23 && !defined(thread_local) diff --git a/src/trie.c b/src/trie.c index f275064..808953e 100644 --- a/src/trie.c +++ b/src/trie.c @@ -81,10 +81,10 @@ * and insert intermediate singleton "jump" nodes when necessary. */ +#include "prelude.h" #include "trie.h" #include "alloc.h" #include "bit.h" -#include "config.h" #include "diag.h" #include "list.h" #include diff --git a/src/xregex.c b/src/xregex.c index 3df27f0..c2711bc 100644 --- a/src/xregex.c +++ b/src/xregex.c @@ -1,10 +1,10 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD +#include "prelude.h" #include "xregex.h" #include "alloc.h" #include "bfstd.h" -#include "config.h" #include "diag.h" #include "sanity.h" #include "thread.h" diff --git a/src/xspawn.c b/src/xspawn.c index 347625d..113d7ec 100644 --- a/src/xspawn.c +++ b/src/xspawn.c @@ -1,10 +1,10 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD +#include "prelude.h" #include "xspawn.h" #include "alloc.h" #include "bfstd.h" -#include "config.h" #include "list.h" #include #include diff --git a/src/xspawn.h b/src/xspawn.h index a20cbd0..6a8f54a 100644 --- a/src/xspawn.h +++ b/src/xspawn.h @@ -8,7 +8,7 @@ #ifndef BFS_XSPAWN_H #define BFS_XSPAWN_H -#include "config.h" +#include "prelude.h" #include #include #include diff --git a/src/xtime.c b/src/xtime.c index bcf6dd3..91ed915 100644 --- a/src/xtime.c +++ b/src/xtime.c @@ -1,9 +1,9 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD +#include "prelude.h" #include "xtime.h" #include "bfstd.h" -#include "config.h" #include "diag.h" #include #include diff --git a/tests/alloc.c b/tests/alloc.c index 54b84ba..6c0defd 100644 --- a/tests/alloc.c +++ b/tests/alloc.c @@ -1,9 +1,9 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD +#include "prelude.h" #include "tests.h" #include "alloc.h" -#include "config.h" #include "diag.h" #include #include diff --git a/tests/bfstd.c b/tests/bfstd.c index 5e408ca..07b68b0 100644 --- a/tests/bfstd.c +++ b/tests/bfstd.c @@ -1,9 +1,9 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD +#include "prelude.h" #include "tests.h" #include "bfstd.h" -#include "config.h" #include "diag.h" #include #include diff --git a/tests/bit.c b/tests/bit.c index b444e50..674d1b2 100644 --- a/tests/bit.c +++ b/tests/bit.c @@ -1,9 +1,9 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD +#include "prelude.h" #include "tests.h" #include "bit.h" -#include "config.h" #include "diag.h" #include #include diff --git a/tests/ioq.c b/tests/ioq.c index a69f2bf..ef5ee3b 100644 --- a/tests/ioq.c +++ b/tests/ioq.c @@ -1,10 +1,10 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD +#include "prelude.h" #include "tests.h" #include "ioq.h" #include "bfstd.h" -#include "config.h" #include "diag.h" #include "dir.h" #include diff --git a/tests/main.c b/tests/main.c index 281c417..429772b 100644 --- a/tests/main.c +++ b/tests/main.c @@ -5,10 +5,10 @@ * Entry point for unit tests. */ +#include "prelude.h" #include "tests.h" #include "bfstd.h" #include "color.h" -#include "config.h" #include #include #include diff --git a/tests/tests.h b/tests/tests.h index d61ffd7..9078938 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -8,7 +8,7 @@ #ifndef BFS_TESTS_H #define BFS_TESTS_H -#include "config.h" +#include "prelude.h" #include "diag.h" /** Unit test function type. */ diff --git a/tests/trie.c b/tests/trie.c index 2a6eb48..4667322 100644 --- a/tests/trie.c +++ b/tests/trie.c @@ -1,9 +1,9 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD +#include "prelude.h" #include "tests.h" #include "trie.h" -#include "config.h" #include "diag.h" #include #include diff --git a/tests/xspawn.c b/tests/xspawn.c index fd8362e..7362aa5 100644 --- a/tests/xspawn.c +++ b/tests/xspawn.c @@ -1,10 +1,10 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD +#include "prelude.h" #include "tests.h" #include "alloc.h" #include "bfstd.h" -#include "config.h" #include "dstring.h" #include "xspawn.h" #include diff --git a/tests/xtime.c b/tests/xtime.c index fd7aa0f..a7c63d2 100644 --- a/tests/xtime.c +++ b/tests/xtime.c @@ -1,10 +1,10 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD +#include "prelude.h" #include "tests.h" #include "xtime.h" #include "bfstd.h" -#include "config.h" #include "diag.h" #include #include diff --git a/tests/xtouch.c b/tests/xtouch.c index b1daec7..82d749d 100644 --- a/tests/xtouch.c +++ b/tests/xtouch.c @@ -1,8 +1,8 @@ // Copyright © Tavian Barnes // SPDX-License-Identifier: 0BSD +#include "prelude.h" #include "bfstd.h" -#include "config.h" #include "sanity.h" #include "xtime.h" #include -- cgit v1.2.3