aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--toys/posix/find.c92
1 files changed, 50 insertions, 42 deletions
diff --git a/toys/posix/find.c b/toys/posix/find.c
index 3b5810ee..663d2e2f 100644
--- a/toys/posix/find.c
+++ b/toys/posix/find.c
@@ -57,6 +57,7 @@ config FIND
// add -print if no action (-exec, -ok, -print)
// find . -print -xdev (should xdev before print)
// -exec {} + accepts any + after {}, not just immediately after. ";" optional
+// posix wants loop detection?
#define FOR_find
#include "toys.h"
@@ -88,7 +89,7 @@ static int flush_exec(struct dirtree *new, struct exec_range *aa)
if (aa->dir && new->parent) dl = (void *)&new->parent->extra;
else dl = &aa->names;
- dlist_terminate(dl);
+ dlist_terminate(*dl);
// switch to directory for -execdir, or back to top if we have an -execdir
// _and_ a normal -exec, or are at top of tree in -execdir
@@ -97,25 +98,26 @@ static int flush_exec(struct dirtree *new, struct exec_range *aa)
// execdir: accumulated execs in this directory's children.
newargs = xmalloc(sizeof(char *)*(aa->arglen+aa->namecount+1));
- if (!aa->curly) {
- memcpy(newargs, aa->argstart+1, sizeof(char *)*aa->arglen);
+ if (aa->curly < 0) {
+ memcpy(newargs, aa->argstart, sizeof(char *)*aa->arglen);
newargs[aa->arglen] = 0;
} else {
struct double_list *dl2 = *dl;
int pos = aa->curly, rest = aa->arglen - aa->curly;
// Collate argument list
- memcpy(newargs, aa->argstart+1, sizeof(char *)*pos);
+ memcpy(newargs, aa->argstart, sizeof(char *)*pos);
for (dl2 = *dl; dl2; dl2 = dl2->next) newargs[pos++] = dl2->data;
- rest = aa->arglen - aa->curly;
- memcpy(newargs+pos, aa->argstart+aa->curly+1,
- sizeof(char *)*(rest-1));
+ rest = aa->arglen - aa->curly - 1;
+ memcpy(newargs+pos, aa->argstart+aa->curly+1, sizeof(char *)*rest);
newargs[pos+rest] = 0;
}
rc = xpclose(xpopen(newargs, 0), 0);
- llist_traverse(dl, llist_free_double);
+ llist_traverse(*dl, llist_free_double);
+ *dl = 0;
+ aa->namecount = 0;
return rc;
}
@@ -353,49 +355,51 @@ static int do_find(struct dirtree *new)
// Initial argument parsing pass
if (!new) {
- // special case "-exec \;" to fall through to "needs 1 arg" error.
- if (!strcmp(ss[1], ";")) {
- int len;
-
- dlist_add_nomalloc(&TT.argdata,(void *)(aa = xzalloc(sizeof(*aa))));
- aa->argstart = ++ss;
-
- // Record command line arguments to -exec
- for (len = 0; ss[len]; len++) {
- if (!strcmp(ss[len], ";")) break;
- else if (!strcmp(ss[len], "{}")) {
- aa->curly = len;
- if (!strcmp(ss[len+1], "+")) {
-
- // Measure environment space
- if (!TT.envsize) {
- char **env;
-
- for (env = environ; *env; env++)
- TT.envsize += sizeof(char *) + strlen(*env) + 1;
- TT.envsize += sizeof(char *);
- }
- aa->plus++;
- len++;
- break;
+ int len;
+
+ // catch "-exec" with no args and "-exec \;"
+ if (!ss[1] || !strcmp(ss[1], ";")) error_exit("'%s' needs 1 arg", s);
+
+ dlist_add_nomalloc(&TT.argdata, (void *)(aa = xzalloc(sizeof(*aa))));
+ aa->argstart = ++ss;
+ aa->curly = -1;
+
+ // Record command line arguments to -exec
+ for (len = 0; ss[len]; len++) {
+ if (!strcmp(ss[len], ";")) break;
+ else if (!strcmp(ss[len], "{}")) {
+ aa->curly = len;
+ if (!strcmp(ss[len+1], "+")) {
+
+ // Measure environment space
+ if (!TT.envsize) {
+ char **env;
+
+ for (env = environ; *env; env++)
+ TT.envsize += sizeof(char *) + strlen(*env) + 1;
+ TT.envsize += sizeof(char *);
}
- } else aa->argsize += sizeof(char *) + strlen(ss[len]) + 1;
- }
- if (!ss[len]) error_exit("-exec without \\;");
- ss += len-1;
- aa->arglen = len;
- aa->dir = !!strchr(s, 'd');
- if (aa->dir && TT.topdir == -1) TT.topdir = xopen(".", 0);
+ aa->plus++;
+ len++;
+ break;
+ }
+ } else aa->argsize += sizeof(char *) + strlen(ss[len]) + 1;
}
+ if (!ss[len]) error_exit("-exec without \\;");
+ ss += len;
+ aa->arglen = len;
+ aa->dir = !!strchr(s, 'd');
+ if (aa->dir && TT.topdir == -1) TT.topdir = xopen(".", 0);
// collect names and execute commands
} else {
if (check) {
- char *name;
+ char *name, *ss1 = ss[1];
struct double_list **dl;
// Grab command line exec argument list
aa = (void *)llist_pop(&argdata);
+ ss += aa->arglen + 1;
// name is always a new malloc, so we can always free it.
name = aa->dir ? xstrdup(new->name) : dirtree_path(new, 0);
@@ -405,7 +409,7 @@ static int do_find(struct dirtree *new)
if (aa->dir) aa->prev = (void *)1;
if (*s == 'o') {
- char *prompt = xmprintf("[%s] %s", ss[1], name);
+ char *prompt = xmprintf("[%s] %s", ss1, name);
if(!(test = yesno(prompt, 0))) goto cont;
}
@@ -426,9 +430,13 @@ static int do_find(struct dirtree *new)
aa->namesize += size;
}
dlist_add(dl, name);
+ aa->namecount++;
if (!aa->plus) test = flush_exec(new, aa);
}
}
+
+ // Argument consumed, skip the check.
+ goto cont;
} else goto error;
// This test can go at the end because we do a syntax checking