diff options
author | Tavian Barnes <tavianator@tavianator.com> | 2025-04-01 06:50:26 -0400 |
---|---|---|
committer | Tavian Barnes <tavianator@tavianator.com> | 2025-04-01 07:28:02 -0400 |
commit | a662fda2642e17478bc8e78adb4c6642a8505cdb (patch) | |
tree | 95107aed722b822a72856f75bd2746b0318885b8 | |
parent | b1fe97289315cfb6278eec4554b92776df98f28d (diff) | |
download | bfs-a662fda2642e17478bc8e78adb4c6642a8505cdb.tar.xz |
parse: Only process the last -files0-from
GNU find intentionally makes later -files0-from options override earlier
ones, for symmetry with similar features like du --files0-from. Change
bfs to match.
Link: https://savannah.gnu.org/bugs/?66965
-rw-r--r-- | src/parse.c | 122 | ||||
-rw-r--r-- | tests/bfs/files0_from_stdin_twice.sh | 1 | ||||
-rw-r--r-- | tests/gnu/files0_from_empty.sh | 2 | ||||
-rw-r--r-- | tests/gnu/files0_from_file_file.out (renamed from tests/bfs/files0_from_twice.out) | 2 | ||||
-rw-r--r-- | tests/gnu/files0_from_file_file.sh (renamed from tests/bfs/files0_from_twice.sh) | 0 | ||||
-rw-r--r-- | tests/gnu/files0_from_ok.sh | 1 | ||||
-rw-r--r-- | tests/gnu/files0_from_stdin_ok.sh | 1 | ||||
-rw-r--r-- | tests/gnu/files0_from_stdin_ok_file.out | 45 | ||||
-rw-r--r-- | tests/gnu/files0_from_stdin_ok_file.sh | 4 | ||||
-rw-r--r-- | tests/gnu/files0_from_stdin_stdin.out | 45 | ||||
-rw-r--r-- | tests/gnu/files0_from_stdin_stdin.sh | 2 | ||||
-rw-r--r-- | tests/gnu/ok_files0_from.sh | 1 | ||||
-rw-r--r-- | tests/gnu/ok_files0_from_stdin.sh | 1 | ||||
-rw-r--r-- | tests/gnu/ok_flush.sh | 2 |
14 files changed, 168 insertions, 61 deletions
diff --git a/src/parse.c b/src/parse.c index 9631b91..a19e689 100644 --- a/src/parse.c +++ b/src/parse.c @@ -84,8 +84,6 @@ struct bfs_parser { enum use_color use_color; /** Whether a -print action is implied. */ bool implicit_print; - /** Whether the default root "." should be used. */ - bool implicit_root; /** Whether the expression has started. */ bool expr_started; /** Whether an information option like -help or -version was passed. */ @@ -105,6 +103,8 @@ struct bfs_parser { const struct bfs_expr *mount_expr; /** An "-xdev" expression, if any. */ const struct bfs_expr *xdev_expr; + /** A "-files0-from" expression, if any. */ + const struct bfs_expr *files0_expr; /** An expression that consumes stdin, if any. */ const struct bfs_expr *stdin_expr; @@ -427,7 +427,6 @@ static int parse_root(struct bfs_parser *parser, const char *path) { return -1; } - parser->implicit_root = false; return 0; } @@ -1351,51 +1350,14 @@ static struct bfs_expr *parse_files0_from(struct bfs_parser *parser, int arg1, i return NULL; } - const char *from = expr->argv[1]; - - FILE *file; - if (strcmp(from, "-") == 0) { - if (!consume_stdin(parser, expr)) { - return NULL; - } - file = stdin; - } else { - file = xfopen(from, O_RDONLY | O_CLOEXEC); - } - if (!file) { - parse_expr_error(parser, expr, "%s.\n", errstr()); - return NULL; - } - - while (true) { - char *path = xgetdelim(file, '\0'); - if (!path) { - if (errno) { - goto fail; - } else { - break; - } - } - - int ret = parse_root(parser, path); - free(path); - if (ret != 0) { - goto fail; - } - } - - if (file != stdin) { - fclose(file); - } - - parser->implicit_root = false; + // For compatibility with GNU find, + // + // bfs -files0-from a -files0-from b + // + // should *only* use b, not a. So stash the expression here and only + // process the last one at the end of parsing. + parser->files0_expr = expr; return expr; - -fail: - if (file != stdin) { - fclose(file); - } - return NULL; } /** @@ -3546,6 +3508,55 @@ static struct bfs_expr *parse_expr(struct bfs_parser *parser) { return expr; } +/** Handle -files0-from after parsing. */ +static int parse_files0_roots(struct bfs_parser *parser) { + const struct bfs_expr *expr = parser->files0_expr; + const char *from = expr->argv[1]; + + FILE *file; + if (strcmp(from, "-") == 0) { + if (!consume_stdin(parser, expr)) { + return -1; + } + file = stdin; + } else { + file = xfopen(from, O_RDONLY | O_CLOEXEC); + } + if (!file) { + parse_expr_error(parser, expr, "%s.\n", errstr()); + return -1; + } + + while (true) { + char *path = xgetdelim(file, '\0'); + if (!path) { + if (errno) { + goto fail; + } else { + break; + } + } + + int ret = parse_root(parser, path); + free(path); + if (ret != 0) { + goto fail; + } + } + + if (file != stdin) { + fclose(file); + } + + return 0; + +fail: + if (file != stdin) { + fclose(file); + } + return -1; +} + /** * Parse the top-level expression. */ @@ -3571,6 +3582,16 @@ static struct bfs_expr *parse_whole_expr(struct bfs_parser *parser) { return NULL; } + if (parser->files0_expr) { + if (parse_files0_roots(parser) != 0) { + return NULL; + } + } else if (ctx->npaths == 0) { + if (parse_root(parser, ".") != 0) { + return NULL; + } + } + if (parser->implicit_print) { const struct bfs_expr *limit = parser->limit_expr; if (limit) { @@ -3842,7 +3863,6 @@ struct bfs_ctx *bfs_parse_cmdline(int argc, char *argv[]) { .stdout_tty = stdout_tty, .use_color = use_color, .implicit_print = true, - .implicit_root = true, .just_info = false, .excluding = false, .last_arg = NULL, @@ -3879,12 +3899,6 @@ struct bfs_ctx *bfs_parse_cmdline(int argc, char *argv[]) { goto fail; } - if (ctx->npaths == 0 && parser.implicit_root) { - if (parse_root(&parser, ".") != 0) { - goto fail; - } - } - if ((ctx->flags & BFTW_FOLLOW_ALL) && !ctx->unique) { // We need bftw() to detect cycles unless -unique does it for us ctx->flags |= BFTW_DETECT_CYCLES; diff --git a/tests/bfs/files0_from_stdin_twice.sh b/tests/bfs/files0_from_stdin_twice.sh deleted file mode 100644 index 752e9de..0000000 --- a/tests/bfs/files0_from_stdin_twice.sh +++ /dev/null @@ -1 +0,0 @@ -! invoke_bfs -files0-from - -files0-from - </dev/null diff --git a/tests/gnu/files0_from_empty.sh b/tests/gnu/files0_from_empty.sh index 85eee8f..7b42772 100644 --- a/tests/gnu/files0_from_empty.sh +++ b/tests/gnu/files0_from_empty.sh @@ -1 +1 @@ -! printf "\0" | invoke_bfs -files0-from - +! printf '\0' | invoke_bfs -files0-from - diff --git a/tests/bfs/files0_from_twice.out b/tests/gnu/files0_from_file_file.out index 5087ae9..fb683c7 100644 --- a/tests/bfs/files0_from_twice.out +++ b/tests/gnu/files0_from_file_file.out @@ -1,4 +1,2 @@ -basic/c -basic/c/d basic/g basic/g/h diff --git a/tests/bfs/files0_from_twice.sh b/tests/gnu/files0_from_file_file.sh index 1119952..1119952 100644 --- a/tests/bfs/files0_from_twice.sh +++ b/tests/gnu/files0_from_file_file.sh diff --git a/tests/gnu/files0_from_ok.sh b/tests/gnu/files0_from_ok.sh deleted file mode 100644 index 8e145ce..0000000 --- a/tests/gnu/files0_from_ok.sh +++ /dev/null @@ -1 +0,0 @@ -! printf "basic\0" | invoke_bfs -files0-from - -ok echo {} \; diff --git a/tests/gnu/files0_from_stdin_ok.sh b/tests/gnu/files0_from_stdin_ok.sh new file mode 100644 index 0000000..0283c8d --- /dev/null +++ b/tests/gnu/files0_from_stdin_ok.sh @@ -0,0 +1 @@ +! printf 'basic\0' | invoke_bfs -files0-from - -ok echo {} \; diff --git a/tests/gnu/files0_from_stdin_ok_file.out b/tests/gnu/files0_from_stdin_ok_file.out new file mode 100644 index 0000000..0f6b00d --- /dev/null +++ b/tests/gnu/files0_from_stdin_ok_file.out @@ -0,0 +1,45 @@ + + + + + + /j + /j +! +!- +!-/e +!-/e +!/d +!/d +( +(- +(-/c +(-/c +(/b +(/b +) +)/g +)/g +* +*/m +*/m +, +,/f +,/f +- +-/a +-/a +... +.../h +.../h +/n +/n +[ +[/k +[/k +\ +\/i +\/i +{ +{/l +{/l diff --git a/tests/gnu/files0_from_stdin_ok_file.sh b/tests/gnu/files0_from_stdin_ok_file.sh new file mode 100644 index 0000000..028df0c --- /dev/null +++ b/tests/gnu/files0_from_stdin_ok_file.sh @@ -0,0 +1,4 @@ +FILE="$TMP/$TEST.in" +cd weirdnames +invoke_bfs -mindepth 1 -fprintf "$FILE" "%P\0" +yes | bfs_diff -files0-from - -ok printf '%s\n' {} \; -files0-from "$FILE" diff --git a/tests/gnu/files0_from_stdin_stdin.out b/tests/gnu/files0_from_stdin_stdin.out new file mode 100644 index 0000000..0f6b00d --- /dev/null +++ b/tests/gnu/files0_from_stdin_stdin.out @@ -0,0 +1,45 @@ + + + + + + /j + /j +! +!- +!-/e +!-/e +!/d +!/d +( +(- +(-/c +(-/c +(/b +(/b +) +)/g +)/g +* +*/m +*/m +, +,/f +,/f +- +-/a +-/a +... +.../h +.../h +/n +/n +[ +[/k +[/k +\ +\/i +\/i +{ +{/l +{/l diff --git a/tests/gnu/files0_from_stdin_stdin.sh b/tests/gnu/files0_from_stdin_stdin.sh new file mode 100644 index 0000000..8f6368f --- /dev/null +++ b/tests/gnu/files0_from_stdin_stdin.sh @@ -0,0 +1,2 @@ +cd weirdnames +invoke_bfs -mindepth 1 -printf "%P\0" | bfs_diff -files0-from - -files0-from - diff --git a/tests/gnu/ok_files0_from.sh b/tests/gnu/ok_files0_from.sh deleted file mode 100644 index 0e2818b..0000000 --- a/tests/gnu/ok_files0_from.sh +++ /dev/null @@ -1 +0,0 @@ -! printf "basic\0" | invoke_bfs -ok echo {} \; -files0-from - diff --git a/tests/gnu/ok_files0_from_stdin.sh b/tests/gnu/ok_files0_from_stdin.sh new file mode 100644 index 0000000..2c4de7b --- /dev/null +++ b/tests/gnu/ok_files0_from_stdin.sh @@ -0,0 +1 @@ +! printf 'basic\0' | invoke_bfs -ok echo {} \; -files0-from - diff --git a/tests/gnu/ok_flush.sh b/tests/gnu/ok_flush.sh index 87c7298..a5dc0d0 100644 --- a/tests/gnu/ok_flush.sh +++ b/tests/gnu/ok_flush.sh @@ -1,4 +1,4 @@ # I/O streams should be flushed before -ok prompts -yes | invoke_bfs basic -printf '%p ? ' -ok echo found \; 2>&1 | tr '\0' ' ' | sed 's/?.*?/?/' >"$OUT" +yes | invoke_bfs basic -printf '%p ? ' -ok echo found \; 2>&1 | sed 's/?.*?/?/' >"$OUT" sort_output diff_output |