summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bfs.h8
-rw-r--r--eval.c22
-rw-r--r--parse.c88
-rwxr-xr-xtests.sh14
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 <stdbool.h>
#include <stddef.h>
+#include <stdio.h>
#include <sys/types.h>
#include <time.h>
@@ -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;
@@ -508,6 +515,25 @@ static struct expr *parse_nullary_action(struct parser_state *state, eval_fn *ev
}
/**
+ * 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.
*/
static struct expr *parse_test_icmp(struct parser_state *state, eval_fn *eval) {
@@ -703,6 +729,59 @@ static struct expr *parse_exec(struct parser_state *state, enum execflags flags)
}
/**
+ * 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.
*/
static struct expr *parse_group(struct parser_state *state) {
@@ -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=$?