Support the SysV-style -exec utility args.. {} + function, required by
SUSv3. This is similar to find foo -print0 | xargs -0 utility args.
This commit is contained in:
parent
148aadf8bc
commit
5e25d888a8
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=97736
@ -294,6 +294,15 @@ and
|
||||
.Ar arguments
|
||||
are not subject to the further expansion of shell patterns
|
||||
and constructs.
|
||||
.It Ic -exec Ar utility Oo Ar argument ... Oc {} +
|
||||
Same as
|
||||
.Ic -exec ,
|
||||
except that
|
||||
.Dq Li {}
|
||||
is replaced with as many pathnames as possible for each invocation of
|
||||
.Ar utility .
|
||||
This behaviour is similar to that of
|
||||
.Xr xargs 1 .
|
||||
.It Ic -execdir Ar utility Op Ar argument ... ;
|
||||
The
|
||||
.Ic -execdir
|
||||
|
@ -235,6 +235,10 @@ find_execute(plan, paths)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
/* Finish any pending -exec ... {} + functions. */
|
||||
for (p = plan; p != NULL; p = p->next)
|
||||
if (p->execute == f_exec && p->flags & F_EXECPLUS)
|
||||
(p->execute)(p, NULL);
|
||||
if (errno)
|
||||
err(1, "fts_read");
|
||||
return (rval);
|
||||
|
@ -70,6 +70,7 @@ typedef struct _plandata *creat_f(struct _option *, char ***);
|
||||
#define F_MTUNKNOWN 0x00002000
|
||||
#define F_IGNCASE 0x00010000 /* iname ipath iregex */
|
||||
#define F_EXACTTIME F_IGNCASE /* -[acm]time units syntax */
|
||||
#define F_EXECPLUS 0x00020000 /* -exec ... {} + */
|
||||
|
||||
/* node definition */
|
||||
typedef struct _plandata {
|
||||
@ -94,6 +95,12 @@ typedef struct _plandata {
|
||||
char **_e_argv; /* argv array */
|
||||
char **_e_orig; /* original strings */
|
||||
int *_e_len; /* allocated length */
|
||||
int _e_pbnum; /* base num. of args. used */
|
||||
int _e_ppos; /* number of arguments used */
|
||||
int _e_pnummax; /* max. number of arguments */
|
||||
int _e_psize; /* number of bytes of args. */
|
||||
int _e_pbsize; /* base num. of bytes of args */
|
||||
int _e_psizemax; /* max num. of bytes of args */
|
||||
} ex;
|
||||
char *_a_data[2]; /* array of char pointers */
|
||||
char *_c_data; /* char pointer */
|
||||
@ -117,6 +124,12 @@ typedef struct _plandata {
|
||||
#define e_argv p_un.ex._e_argv
|
||||
#define e_orig p_un.ex._e_orig
|
||||
#define e_len p_un.ex._e_len
|
||||
#define e_pbnum p_un.ex._e_pbnum
|
||||
#define e_ppos p_un.ex._e_ppos
|
||||
#define e_pnummax p_un.ex._e_pnummax
|
||||
#define e_psize p_un.ex._e_psize
|
||||
#define e_pbsize p_un.ex._e_pbsize
|
||||
#define e_psizemax p_un.ex._e_psizemax
|
||||
|
||||
typedef struct _option {
|
||||
const char *name; /* option name */
|
||||
|
@ -55,6 +55,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <fnmatch.h>
|
||||
#include <fts.h>
|
||||
#include <grp.h>
|
||||
#include <limits.h>
|
||||
#include <pwd.h>
|
||||
#include <regex.h>
|
||||
#include <stdio.h>
|
||||
@ -528,6 +529,13 @@ f_exec(plan, entry)
|
||||
int status;
|
||||
char *file;
|
||||
|
||||
if (entry == NULL && plan->flags & F_EXECPLUS) {
|
||||
if (plan->e_ppos == plan->e_pbnum)
|
||||
return (1);
|
||||
plan->e_argv[plan->e_ppos] = NULL;
|
||||
goto doexec;
|
||||
}
|
||||
|
||||
/* XXX - if file/dir ends in '/' this will not work -- can it? */
|
||||
if ((plan->flags & F_EXECDIR) && \
|
||||
(file = strrchr(entry->fts_path, '/')))
|
||||
@ -535,12 +543,24 @@ f_exec(plan, entry)
|
||||
else
|
||||
file = entry->fts_path;
|
||||
|
||||
for (cnt = 0; plan->e_argv[cnt]; ++cnt)
|
||||
if (plan->e_len[cnt])
|
||||
brace_subst(plan->e_orig[cnt], &plan->e_argv[cnt],
|
||||
file, plan->e_len[cnt]);
|
||||
if (plan->flags & F_EXECPLUS) {
|
||||
if ((plan->e_argv[plan->e_ppos] = strdup(file)) == NULL)
|
||||
err(1, NULL);
|
||||
plan->e_len[plan->e_ppos] = strlen(file);
|
||||
plan->e_psize += plan->e_len[plan->e_ppos];
|
||||
if (++plan->e_ppos < plan->e_pnummax &&
|
||||
plan->e_psize < plan->e_psizemax)
|
||||
return (1);
|
||||
plan->e_argv[plan->e_ppos] = NULL;
|
||||
} else {
|
||||
for (cnt = 0; plan->e_argv[cnt]; ++cnt)
|
||||
if (plan->e_len[cnt])
|
||||
brace_subst(plan->e_orig[cnt],
|
||||
&plan->e_argv[cnt], file,
|
||||
plan->e_len[cnt]);
|
||||
}
|
||||
|
||||
if ((plan->flags & F_NEEDOK) && !queryuser(plan->e_argv))
|
||||
doexec: if ((plan->flags & F_NEEDOK) && !queryuser(plan->e_argv))
|
||||
return 0;
|
||||
|
||||
/* make sure find output is interspersed correctly with subprocesses */
|
||||
@ -561,6 +581,12 @@ f_exec(plan, entry)
|
||||
warn("%s", plan->e_argv[0]);
|
||||
_exit(1);
|
||||
}
|
||||
if (plan->flags & F_EXECPLUS) {
|
||||
while (--plan->e_ppos >= plan->e_pbnum)
|
||||
free(plan->e_argv[plan->e_ppos]);
|
||||
plan->e_ppos = plan->e_pbnum;
|
||||
plan->e_psize = plan->e_pbsize;
|
||||
}
|
||||
pid = waitpid(pid, &status, 0);
|
||||
return (pid != -1 && WIFEXITED(status) && !WEXITSTATUS(status));
|
||||
}
|
||||
@ -578,7 +604,8 @@ c_exec(option, argvp)
|
||||
char ***argvp;
|
||||
{
|
||||
PLAN *new; /* node returned */
|
||||
int cnt;
|
||||
long argmax;
|
||||
int cnt, i;
|
||||
char **argv, **ap, *p;
|
||||
|
||||
/* XXX - was in c_execdir, but seems unnecessary!?
|
||||
@ -595,12 +622,32 @@ c_exec(option, argvp)
|
||||
"%s: no terminating \";\"", option->name);
|
||||
if (**ap == ';')
|
||||
break;
|
||||
if (**ap == '+' && ap != argv && strcmp(*(ap - 1), "{}") == 0) {
|
||||
new->flags |= F_EXECPLUS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ap == argv)
|
||||
errx(1, "%s: no command specified", option->name);
|
||||
|
||||
cnt = ap - *argvp + 1;
|
||||
if (new->flags & F_EXECPLUS) {
|
||||
new->e_ppos = new->e_pbnum = cnt - 2;
|
||||
if ((argmax = sysconf(_SC_ARG_MAX)) == -1) {
|
||||
warn("sysconf(_SC_ARG_MAX)");
|
||||
argmax = _POSIX_ARG_MAX;
|
||||
}
|
||||
/*
|
||||
* Estimate the maximum number of arguments as {ARG_MAX}/10,
|
||||
* and the maximum number of bytes to use for arguments as
|
||||
* {ARG_MAX}*(3/4).
|
||||
*/
|
||||
new->e_pnummax = argmax / 10;
|
||||
new->e_psizemax = (argmax / 4) * 3;
|
||||
new->e_pbsize = 0;
|
||||
cnt += new->e_pnummax + 1;
|
||||
}
|
||||
if ((new->e_argv = malloc(cnt * sizeof(char *))) == NULL)
|
||||
err(1, NULL);
|
||||
if ((new->e_orig = malloc(cnt * sizeof(char *))) == NULL)
|
||||
@ -610,8 +657,11 @@ c_exec(option, argvp)
|
||||
|
||||
for (argv = *argvp, cnt = 0; argv < ap; ++argv, ++cnt) {
|
||||
new->e_orig[cnt] = *argv;
|
||||
if (new->flags & F_EXECPLUS)
|
||||
new->e_pbsize += strlen(*argv) + 1;
|
||||
for (p = *argv; *p; ++p)
|
||||
if (p[0] == '{' && p[1] == '}') {
|
||||
if (!(new->flags & F_EXECPLUS) && p[0] == '{' &&
|
||||
p[1] == '}') {
|
||||
if ((new->e_argv[cnt] =
|
||||
malloc(MAXPATHLEN)) == NULL)
|
||||
err(1, NULL);
|
||||
@ -623,9 +673,20 @@ c_exec(option, argvp)
|
||||
new->e_len[cnt] = 0;
|
||||
}
|
||||
}
|
||||
if (new->flags & F_EXECPLUS) {
|
||||
new->e_psize = new->e_pbsize;
|
||||
cnt--;
|
||||
for (i = 0; i < new->e_pnummax; i++) {
|
||||
new->e_argv[cnt] = NULL;
|
||||
new->e_len[cnt] = 0;
|
||||
cnt++;
|
||||
}
|
||||
argv = ap;
|
||||
goto done;
|
||||
}
|
||||
new->e_argv[cnt] = new->e_orig[cnt] = NULL;
|
||||
|
||||
*argvp = argv + 1;
|
||||
done: *argvp = argv + 1;
|
||||
return new;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user