diff options
-rw-r--r-- | bfs.h | 1 | ||||
-rw-r--r-- | eval.c | 38 | ||||
-rw-r--r-- | parse.c | 16 | ||||
-rwxr-xr-x | tests.sh | 5 | ||||
-rw-r--r-- | tests/test_printx.out | 21 |
5 files changed, 81 insertions, 0 deletions
@@ -326,6 +326,7 @@ bool eval_fls(const struct expr *expr, struct eval_state *state); bool eval_fprint(const struct expr *expr, struct eval_state *state); bool eval_fprint0(const struct expr *expr, struct eval_state *state); bool eval_fprintf(const struct expr *expr, struct eval_state *state); +bool eval_fprintx(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); @@ -670,6 +670,44 @@ done: } /** + * -printx action. + */ +bool eval_fprintx(const struct expr *expr, struct eval_state *state) { + FILE *file = expr->cfile->file; + const char *path = state->ftwbuf->path; + + while (true) { + size_t span = strcspn(path, " \t\n\\$'\"`"); + if (fwrite(path, 1, span, file) != span) { + goto error; + } + path += span; + + char c = path[0]; + if (!c) { + break; + } + + char escaped[] = {'\\', c}; + if (fwrite(escaped, 1, sizeof(escaped), file) != sizeof(escaped)) { + goto error; + } + ++path; + } + + + if (fputc('\n', file) == EOF) { + goto error; + } + + return true; + +error: + eval_error(state); + return true; +} + +/** * -prune action. */ bool eval_prune(const struct expr *expr, struct eval_state *state) { @@ -1699,6 +1699,18 @@ static struct expr *parse_printf(struct parser_state *state, int arg1, int arg2) } /** + * Parse -printx. + */ +static struct expr *parse_printx(struct parser_state *state, int arg1, int arg2) { + struct expr *expr = parse_nullary_action(state, eval_fprintx); + if (expr) { + expr->always_true = true; + expr->cfile = state->cmdline->cout; + } + return expr; +} + +/** * Parse -prune. */ static struct expr *parse_prune(struct parser_state *state, int arg1, int arg2) { @@ -2178,6 +2190,9 @@ static struct expr *parse_help(struct parser_state *state, int arg1, int arg2) { cfprintf(cout, " %{blu}-exit%{rs} %{bld}[STATUS]%{rs}\n"); cfprintf(cout, " Exit immediately with the given status (%d if unspecified)\n", EXIT_SUCCESS); + cfprintf(cout, " %{blu}-printx%{rs}\n"); + cfprintf(cout, " Like %{blu}-print%{rs}, but escape whitespace and quotation characters, to make the\n"); + cfprintf(cout, " output safe for %{ex}xargs%{rs}. Consider using %{blu}-print0%{rs} and %{ex}xargs%{rs} %{bld}-0%{rs} instead.\n"); cfprintf(cout, " %{blu}-rm%{rs}\n"); cfprintf(cout, " Delete any found files (same as %{blu}-delete%{rs}; implies %{blu}-depth%{rs})\n\n"); @@ -2299,6 +2314,7 @@ static const struct table_entry parse_table[] = { {"-print", false, parse_print}, {"-print0", false, parse_print0}, {"-printf", false, parse_printf}, + {"-printx", false, parse_printx}, {"-prune", false, parse_prune}, {"-quit", false, parse_quit}, {"-readable", false, parse_access, R_OK}, @@ -256,6 +256,7 @@ bsd_tests=( test_nogroup test_nouser test_exit + test_printx ) gnu_tests=( @@ -1227,6 +1228,10 @@ function test_exit() { bfs_diff basic -name bar -exit -o -print } +function test_printx() { + bfs_diff weirdnames -printx +} + passed=0 failed=0 diff --git a/tests/test_printx.out b/tests/test_printx.out new file mode 100644 index 0000000..53c7547 --- /dev/null +++ b/tests/test_printx.out @@ -0,0 +1,21 @@ +weirdnames +weirdnames/! +weirdnames/!- +weirdnames/( +weirdnames/(- +weirdnames/) +weirdnames/, +weirdnames/- +weirdnames/... +weirdnames/\ +weirdnames/\\ +weirdnames/!-/e +weirdnames/!/d +weirdnames/(-/c +weirdnames/(/b +weirdnames/)/g +weirdnames/,/f +weirdnames/-/a +weirdnames/.../h +weirdnames/\ /j +weirdnames/\\/i |