From fcd08ee02a660e7c3013b073e7122be5094e8d47 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Wed, 8 Jun 2016 23:26:48 -0400 Subject: Implement -fprint and -fprint0. --- bfs.h | 8 ++++++ eval.c | 22 +++++++++++----- parse.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- tests.sh | 14 ++++++++++- 4 files changed, 123 insertions(+), 9 deletions(-) diff --git a/bfs.h b/bfs.h index f6f120d..a6c7264 100644 --- a/bfs.h +++ b/bfs.h @@ -15,6 +15,7 @@ #include "color.h" #include #include +#include #include #include @@ -91,6 +92,9 @@ struct cmdline { /** The command line expression. */ struct expr *expr; + + /** The number of open files used by the expression tree. */ + int nopen_files; }; /** @@ -192,6 +196,9 @@ struct expr { /** Optional inode number for a target file. */ ino_t ino; + /** File to output to. */ + FILE *file; + /** Optional -exec flags. */ enum execflags execflags; @@ -247,6 +254,7 @@ bool eval_delete(const struct expr *expr, struct eval_state *state); bool eval_exec(const struct expr *expr, struct eval_state *state); bool eval_nohidden(const struct expr *expr, struct eval_state *state); bool eval_print(const struct expr *expr, struct eval_state *state); +bool eval_fprint(const struct expr *expr, struct eval_state *state); bool eval_print0(const struct expr *expr, struct eval_state *state); bool eval_prune(const struct expr *expr, struct eval_state *state); bool eval_quit(const struct expr *expr, struct eval_state *state); diff --git a/eval.c b/eval.c index 828a33f..c3e29d2 100644 --- a/eval.c +++ b/eval.c @@ -626,11 +626,21 @@ bool eval_print(const struct expr *expr, struct eval_state *state) { } /** - * -print0 action. + * -fprint action. + */ +bool eval_fprint(const struct expr *expr, struct eval_state *state) { + const char *path = state->ftwbuf->path; + fputs(path, expr->file); + fputc('\n', expr->file); + return true; +} + +/** + * -f?print0 action. */ bool eval_print0(const struct expr *expr, struct eval_state *state) { const char *path = state->ftwbuf->path; - fwrite(path, 1, strlen(path) + 1, stdout); + fwrite(path, 1, strlen(path) + 1, expr->file); return true; } @@ -857,7 +867,7 @@ static enum bftw_action cmdline_callback(struct BFTW *ftwbuf, void *ptr) { /** * Infer the number of open file descriptors we're allowed to have. */ -static int infer_fdlimit() { +static int infer_fdlimit(const struct cmdline *cmdline) { int ret = 4096; struct rlimit rl; @@ -867,8 +877,8 @@ static int infer_fdlimit() { } } - // std{in,out,err} - int nopen = 3; + // 3 for std{in,out,err} + int nopen = 3 + cmdline->nopen_files; // Check /dev/fd for the current number of open fds, if possible (we may // have inherited more than just the standard ones) @@ -914,7 +924,7 @@ int eval_cmdline(const struct cmdline *cmdline) { return 0; } - int nopenfd = infer_fdlimit(); + int nopenfd = infer_fdlimit(cmdline); struct callback_args args = { .cmdline = cmdline, diff --git a/parse.c b/parse.c index cccdacf..4101c36 100644 --- a/parse.c +++ b/parse.c @@ -62,6 +62,12 @@ static struct expr expr_false = { */ static void free_expr(struct expr *expr) { if (expr && expr != &expr_true && expr != &expr_false) { + if (expr->file && expr->file != stdout && expr->file != stderr) { + if (fclose(expr->file) != 0) { + perror("fclose()"); + } + } + free_expr(expr->lhs); free_expr(expr->rhs); free(expr); @@ -80,6 +86,7 @@ static struct expr *new_expr(eval_fn *eval, bool pure, size_t argc, char **argv) expr->pure = pure; expr->argc = argc; expr->argv = argv; + expr->file = NULL; } return expr; } @@ -259,7 +266,7 @@ static int stat_arg(const struct parser_state *state, struct expr *expr, struct int ret = fstatat(AT_FDCWD, expr->sdata, sb, flags); if (ret != 0) { pretty_error(cmdline->stderr_colors, - "'%s': %s\n", expr->sdata, strerror(errno)); + "error: '%s': %s\n", expr->sdata, strerror(errno)); free_expr(expr); } return ret; @@ -507,6 +514,25 @@ static struct expr *parse_nullary_action(struct parser_state *state, eval_fn *ev return parse_action(state, eval, 1); } +/** + * Parse an action that takes one argument. + */ +static struct expr *parse_unary_action(struct parser_state *state, eval_fn *eval) { + const char *arg = state->argv[0]; + const char *value = state->argv[1]; + if (!value) { + pretty_error(state->cmdline->stderr_colors, + "error: %s needs a value.\n", arg); + return NULL; + } + + struct expr *expr = parse_action(state, eval, 2); + if (expr) { + expr->sdata = value; + } + return expr; +} + /** * Parse a test expression with integer data and a comparison flag. */ @@ -702,6 +728,59 @@ static struct expr *parse_exec(struct parser_state *state, enum execflags flags) return expr; } +/** + * Open a file for an expression. + */ +static int expr_open(struct parser_state *state, struct expr *expr, const char *path) { + expr->file = fopen(path, "wb"); + if (!expr->file) { + pretty_error(state->cmdline->stderr_colors, + "error: '%s': %s\n", path, strerror(errno)); + free_expr(expr); + return -1; + } + + ++state->cmdline->nopen_files; + return 0; +} + +/** + * Parse -fprint FILE. + */ +static struct expr *parse_fprint(struct parser_state *state) { + struct expr *expr = parse_unary_action(state, eval_fprint); + if (expr) { + if (expr_open(state, expr, expr->sdata) != 0) { + return NULL; + } + } + return expr; +} + +/** + * Parse -fprint0 FILE. + */ +static struct expr *parse_fprint0(struct parser_state *state) { + struct expr *expr = parse_unary_action(state, eval_print0); + if (expr) { + if (expr_open(state, expr, expr->sdata) != 0) { + return NULL; + } + } + return expr; +} + +/** + * Parse -print0. + */ +static struct expr *parse_print0(struct parser_state *state) { + struct expr *expr = parse_nullary_action(state, eval_print0); + if (expr) { + expr->file = stdout; + } + return expr; +} + /** * Parse -group. */ @@ -1176,6 +1255,10 @@ static struct expr *parse_literal(struct parser_state *state) { } else if (strcmp(arg, "-follow") == 0) { cmdline->flags |= BFTW_FOLLOW | BFTW_DETECT_CYCLES; return parse_nullary_positional_option(state); + } else if (strcmp(arg, "-fprint") == 0) { + return parse_fprint(state); + } else if (strcmp(arg, "-fprint0") == 0) { + return parse_fprint0(state); } break; @@ -1265,7 +1348,7 @@ static struct expr *parse_literal(struct parser_state *state) { } else if (strcmp(arg, "-print") == 0) { return parse_nullary_action(state, eval_print); } else if (strcmp(arg, "-print0") == 0) { - return parse_nullary_action(state, eval_print0); + return parse_print0(state); } else if (strcmp(arg, "-prune") == 0) { return parse_nullary_action(state, eval_prune); } @@ -1756,6 +1839,7 @@ struct cmdline *parse_cmdline(int argc, char *argv[]) { cmdline->optlevel = 2; cmdline->debug = 0; cmdline->expr = &expr_true; + cmdline->nopen_files = 0; cmdline->colors = parse_colors(getenv("LS_COLORS")); cmdline->stdout_colors = isatty(STDOUT_FILENO) ? cmdline->colors : NULL; diff --git a/tests.sh b/tests.sh index d4ac7fc..ead81f6 100755 --- a/tests.sh +++ b/tests.sh @@ -62,8 +62,11 @@ function make_weirdnames() { weirdnames="$(mktemp -d "${TMPDIR:-/tmp}"/bfs.weirdnames.XXXXXXXXXX)" make_weirdnames "$weirdnames" +out="$(mktemp -d "${TMPDIR:-/tmp}"/bfs.out.XXXXXXXXXX)" + # Clean up temporary directories on exit function cleanup() { + rm -rf "$out" rm -rf "$weirdnames" rm -rf "$links" rm -rf "$perms" @@ -340,7 +343,16 @@ function test_0061() { find_diff '-' '(-' '!-' ',' ')' './(' './!' \( \! -print , -print \) } -for i in {1..61}; do +function test_0062() { + find "$basic" -fprint "$out/out.find" + "$BFS" "$basic" -fprint "$out/out.bfs" + + sort -o "$out/out.find" "$out/out.find" + sort -o "$out/out.bfs" "$out/out.bfs" + diff -u "$out/out.find" "$out/out.bfs" +} + +for i in {1..62}; do test="test_$(printf '%04d' $i)" ("$test" "$dir") status=$? -- cgit v1.2.3