diff options
author | Tavian Barnes <tavianator@tavianator.com> | 2021-05-08 11:58:09 -0400 |
---|---|---|
committer | Tavian Barnes <tavianator@tavianator.com> | 2021-09-15 13:56:20 -0400 |
commit | b6b7a68190703d30912d2a1c3d8d64e3de81a612 (patch) | |
tree | d99e0b9dd0060deed2980b43a99fd2f359f9ad30 /parse.c | |
parent | b2d85ea84c930ebcfefc6449414ed64cd80e2f89 (diff) | |
download | bfs-b6b7a68190703d30912d2a1c3d8d64e3de81a612.tar.xz |
Implement -files0-from FILE
See https://savannah.gnu.org/bugs/?60383 for the development of the
corresponding GNU find feature.
Diffstat (limited to 'parse.c')
-rw-r--r-- | parse.c | 93 |
1 files changed, 89 insertions, 4 deletions
@@ -237,10 +237,14 @@ struct parser_state { bool stdout_tty; /** Whether this session is interactive (stdin and stderr are each a terminal). */ bool interactive; + /** Whether stdin has been consumed by -files0-from -. */ + bool stdin_consumed; /** Whether -color or -nocolor has been passed. */ 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 any non-option arguments have been encountered. */ @@ -260,6 +264,8 @@ struct parser_state { const char *mount_arg; /** An "-xdev"-type argument if any. */ const char *xdev_arg; + /** An "-ok"-type argument if any. */ + const char *ok_arg; /** The current time. */ struct timespec now; @@ -383,12 +389,21 @@ static char **parser_advance(struct parser_state *state, enum token_type type, s * Parse a root path. */ static int parse_root(struct parser_state *state, const char *path) { + char *copy = strdup(path); + if (!copy) { + parse_perror(state, "strdup()"); + return -1; + } + struct bfs_ctx *ctx = state->ctx; - int ret = DARRAY_PUSH(&ctx->paths, &path); - if (ret != 0) { + if (DARRAY_PUSH(&ctx->paths, ©) != 0) { parse_perror(state, "DARRAY_PUSH()"); + free(copy); + return -1; } - return ret; + + state->implicit_root = false; + return 0; } /** @@ -1189,6 +1204,10 @@ static struct expr *parse_exec(struct parser_state *state, int flags, int arg2) } } + if (execbuf->flags & BFS_EXEC_CONFIRM) { + state->ok_arg = expr->argv[0]; + } + return expr; } @@ -1233,6 +1252,58 @@ static struct expr *parse_f(struct parser_state *state, int arg1, int arg2) { } /** + * Parse -files0-from PATH. + */ +static struct expr *parse_files0_from(struct parser_state *state, int arg1, int arg2) { + const char *arg = state->argv[0]; + const char *from = state->argv[1]; + if (!from) { + parse_error(state, "${blu}%s${rs} requires a path.\n", arg); + return NULL; + } + + FILE *file; + if (strcmp(from, "-") == 0) { + file = stdin; + } else { + file = fopen(from, "rb"); + } + if (!file) { + parse_error(state, "${blu}%s${rs} ${bld}%s${rs}: %m.\n", arg, from); + return NULL; + } + + struct expr *expr = parse_unary_positional_option(state); + + while (true) { + char *path = xgetdelim(file, '\0'); + if (!path) { + if (errno) { + parse_error(state, "${blu}%s${rs} ${bld}%s${rs}: %m.\n", arg, from); + expr = NULL; + } + break; + } + + int ret = parse_root(state, path); + free(path); + if (ret != 0) { + expr = NULL; + break; + } + } + + if (file == stdin) { + state->stdin_consumed = true; + } else { + fclose(file); + } + + state->implicit_root = false; + return expr; +} + +/** * Parse -flags FLAGS. */ static struct expr *parse_flags(struct parser_state *state, int arg1, int arg2) { @@ -2736,6 +2807,8 @@ static struct expr *parse_help(struct parser_state *state, int arg1, int arg2) { cfprintf(cout, " Measure times relative to the start of today\n"); cfprintf(cout, " ${blu}-depth${rs}\n"); cfprintf(cout, " Search in post-order (descendents first)\n"); + cfprintf(cout, " ${blu}-files0-from${rs} ${bld}FILE${rs}\n"); + cfprintf(cout, " Search the NUL ('\\0')-separated paths from ${bld}FILE${rs} (${bld}-${rs} for standard input).\n"); cfprintf(cout, " ${blu}-follow${rs}\n"); cfprintf(cout, " Follow all symbolic links (same as ${cyn}-L${rs})\n"); cfprintf(cout, " ${blu}-ignore_readdir_race${rs}\n"); @@ -2988,6 +3061,7 @@ static const struct table_entry parse_table[] = { {"-exit", T_ACTION, parse_exit}, {"-f", T_FLAG, parse_f}, {"-false", T_TEST, parse_const, false}, + {"-files0-from", T_OPTION, parse_files0_from}, {"-flags", T_TEST, parse_flags}, {"-fls", T_ACTION, parse_fls}, {"-follow", T_OPTION, parse_follow, BFTW_FOLLOW_ALL, true}, @@ -3408,6 +3482,11 @@ static struct expr *parse_whole_expr(struct parser_state *state) { fprintf(stderr, "\n"); } + if (state->ok_arg && state->stdin_consumed) { + parse_error(state, "${blu}%s${rs} conflicts with ${blu}-files0-from${rs} ${bld}-${rs}.\n", state->ok_arg); + goto fail; + } + return expr; fail: @@ -3627,8 +3706,10 @@ struct bfs_ctx *bfs_parse_cmdline(int argc, char *argv[]) { .regex_flags = 0, .stdout_tty = stdout_tty, .interactive = stdin_tty && stderr_tty, + .stdin_consumed = false, .use_color = use_color, .implicit_print = true, + .implicit_root = true, .non_option_seen = false, .just_info = false, .excluding = false, @@ -3637,6 +3718,7 @@ struct bfs_ctx *bfs_parse_cmdline(int argc, char *argv[]) { .prune_arg = NULL, .mount_arg = NULL, .xdev_arg = NULL, + .ok_arg = NULL, }; if (strcmp(xbasename(state.command), "find") == 0) { @@ -3663,7 +3745,10 @@ struct bfs_ctx *bfs_parse_cmdline(int argc, char *argv[]) { } if (darray_length(ctx->paths) == 0) { - if (parse_root(&state, ".") != 0) { + if (!state.implicit_root) { + parse_error(&state, "No root paths specified.\n"); + goto fail; + } else if (parse_root(&state, ".") != 0) { goto fail; } } |