diff options
author | jmallett <jmallett@FreeBSD.org> | 2002-04-19 23:28:54 +0000 |
---|---|---|
committer | jmallett <jmallett@FreeBSD.org> | 2002-04-19 23:28:54 +0000 |
commit | 22be17968264e9796541bacb17a722aee628e8c2 (patch) | |
tree | 9d07f19a0a400de9d43a844a00d25af5890bea19 /usr.bin | |
parent | feb9b6ff6d055ca921f46f7fcd4ea49263c1af09 (diff) | |
download | FreeBSD-src-22be17968264e9796541bacb17a722aee628e8c2.zip FreeBSD-src-22be17968264e9796541bacb17a722aee628e8c2.tar.gz |
After 3 months...
Merge xargs(1) with that of xMach.
Bring in xargs(1) changes to add -L and -I as per the Single Unix Specification
version 3. Proper exit status numbers are implemented, and the manual page has
been updated to reflect reality.
The code has been ANSIfied, and a new file has been added to xargs(1) to do the
substring substitution as SUSv3 requires.
Traditional behaviour should not be affected, use of -J should be deprecated
in favor of the more portable -I (though -J has been left, for now).
Submitted by: me, tjr (the exit status stuff)
Obtained from: xMach
Diffstat (limited to 'usr.bin')
-rw-r--r-- | usr.bin/xargs/Makefile | 2 | ||||
-rw-r--r-- | usr.bin/xargs/strnsubst.c | 78 | ||||
-rw-r--r-- | usr.bin/xargs/xargs.1 | 63 | ||||
-rw-r--r-- | usr.bin/xargs/xargs.c | 173 |
4 files changed, 272 insertions, 44 deletions
diff --git a/usr.bin/xargs/Makefile b/usr.bin/xargs/Makefile index 0bfb074..642e953 100644 --- a/usr.bin/xargs/Makefile +++ b/usr.bin/xargs/Makefile @@ -1,5 +1,7 @@ # @(#)Makefile 8.1 (Berkeley) 6/6/93 +# $FreeBSD$ PROG= xargs +SRCS= xargs.c strnsubst.c .include <bsd.prog.mk> diff --git a/usr.bin/xargs/strnsubst.c b/usr.bin/xargs/strnsubst.c new file mode 100644 index 0000000..a06197e --- /dev/null +++ b/usr.bin/xargs/strnsubst.c @@ -0,0 +1,78 @@ +/* $xMach: strnsubst.c,v 1.3 2002/02/23 02:10:24 jmallett Exp $ */ + +/* + * Copyright (c) 2002 J. Mallett. All rights reserved. + * You may do whatever you want with this file as long as + * the above copyright and this notice remain intact, along + * with the following statement: + * For the man who taught me vi, and who got too old, too young. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <err.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +void strnsubst(char **, const char *, const char *, size_t); + +/* + * Replaces str with a string consisting of str with match replaced with + * replstr as many times as can be done before the constructed string is + * maxsize bytes large. It does not free the string pointed to by str, it + * is up to the calling program to be sure that the original contents of + * str as well as the new contents are handled in an appropriate manner. + * No value is returned. + */ +void +strnsubst(char **str, const char *match, const char *replstr, size_t maxsize) +{ + char *s1, *s2; + + s1 = *str; + if (s1 == NULL) + return; + s2 = calloc(maxsize, 1); + if (s2 == NULL) + err(1, "calloc"); + + for (;;) { + char *this; + + this = strstr(s1, match); + if (this == NULL) + break; + if ((strlen(s2) + ((uintptr_t)this - (uintptr_t)s1) + + (strlen(replstr) - 1)) > maxsize) { + strlcat(s2, s1, maxsize); + goto done; + } + strncat(s2, s1, (uintptr_t)this - (uintptr_t)s1); + strcat(s2, replstr); + s1 = this + strlen(match); + } + strcat(s2, s1); +done: + *str = s2; + return; +} + +#ifdef TEST +#include <stdio.h> + +int +main(void) +{ + char *x, *y; + + y = x = "{}{}{}"; + strnsubst(&x, "{}", "v ybir whyv! ", 12); + if (strcmp(x, "v ybir whyv! ") == 0) + printf("strnsubst() seems to work as expected.\n"); + printf("x: %s\ny: %s\n", x, y); + free(x); + return 0; +} +#endif diff --git a/usr.bin/xargs/xargs.1 b/usr.bin/xargs/xargs.1 index a723f0a..debda8e 100644 --- a/usr.bin/xargs/xargs.1 +++ b/usr.bin/xargs/xargs.1 @@ -35,6 +35,7 @@ .\" .\" @(#)xargs.1 8.1 (Berkeley) 6/6/93 .\" $FreeBSD$ +.\" $xMach: xargs.1,v 1.2 2002/02/23 05:23:37 tim Exp $ .\" .Dd May 7, 2001 .Dt XARGS 1 @@ -44,14 +45,16 @@ .Nd "construct argument list(s) and execute utility" .Sh SYNOPSIS .Nm -.Op Fl 0 +.Op Fl 0pt +.Op Fl E Ar eofstr +.Op Fl I Ar replstr .Op Fl J Ar replstr +.Op Fl L Ar number .Oo .Fl n Ar number .Op Fl x .Oc .Op Fl s Ar size -.Op Fl t .Op Ar utility Op Ar argument ... .Sh DESCRIPTION The @@ -92,6 +95,34 @@ This is expected to be used in concert with the .Fl print0 function in .Xr find 1 . +.It Fl E Ar eofstr +Use +.Ar eofstr +as a logical EOF marker. +.It Fl I Ar replstr +Execute +.Ar utility +for each input line, replacing one or more occurences of +.Ar replstr +in up to 5 arguments to +.Ar utility +with the entire line of input. +The resulting arguments after replacement is done will not be allowed to grow +beyond 255 bytes, this is implemented by concatenating as much of the argument +containing +.Ar replstr +as possible to the constructed arguments to +.Ar utility +up to 255 bytes. +The 255 byte limit does not apply to arguments to +.Ar utility +which do not contain +.Ar replstr , +and furthermore no replacement will be done on +.Ar utility +itself. +Implies +.Fl x . .It Fl J Ar replstr If this option is specified, .Nm @@ -124,6 +155,17 @@ directory to .Pp .Dl /bin/ls -1d [A-Z]* | xargs -J [] cp -rp [] destdir .Pp +.It Fl L Ar number +Calls +.Ar utility +for every +.Ar number +lines read. +If EOF is reached and fewer lines have been read than +.Ar number +then +.Ar utility +will be called with the available lines. .It Fl n Ar number Set the maximum number of arguments taken from standard input for each invocation of the utility. @@ -142,6 +184,13 @@ arguments remaining for the last invocation of The current default value for .Ar number is 5000. +.It Fl p +Echo each command to be executed and ask the user whether it should be +executed. +A response of +.Ql y +causes the command to be executed, any other response causes it to be +skipped. .It Fl s Ar size Set the maximum number of bytes for the command line length provided to .Ar utility . @@ -184,15 +233,19 @@ command line cannot be assembled, .Ar utility cannot be invoked, an invocation of the utility is terminated by a signal or an invocation of the utility exits with a value of 255. -.Pp +.Sh DIAGNOSTICS The .Nm utility exits with a value of 0 if no error occurs. If .Ar utility -cannot be invoked, +cannot be found, +.Nm +exits with a value of 127, otherwise if +.Ar utility +cannot be executed, .Nm -exits with a value of 127. +exits with a value of 126. If any other error occurs, .Nm exits with a value of 1. diff --git a/usr.bin/xargs/xargs.c b/usr.bin/xargs/xargs.c index 438c748..303d226 100644 --- a/usr.bin/xargs/xargs.c +++ b/usr.bin/xargs/xargs.c @@ -32,6 +32,8 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. + * + * $xMach: xargs.c,v 1.6 2002/02/23 05:27:47 tim Exp $ */ #ifndef lint @@ -61,29 +63,31 @@ __FBSDID("$FreeBSD$"); #include "pathnames.h" -int tflag, rval; -int zflag; - -void run(char **); +static void run(char **); static void usage(void); +void strnsubst(char **, const char *, const char *, size_t); static char echo[] = _PATH_ECHO; +static int pflag, tflag, rval, zflag; extern char *environ[]; int main(int argc, char **argv) { - int ch; - char *p, *bbp, **bxp, *ebp, **exp, **xp; - int cnt, jfound, indouble, insingle; - int nargs, nflag, nline, xflag, wasquoted; - char **av, **avj, *argp, **ep, *replstr; long arg_max; + int argumentc, ch, cnt, count, Iflag, indouble, insingle, jfound, lflag; + int nargs, nflag, nline, wasquoted, foundeof, xflag; + size_t linelen; + const char *eofstr; + char **av, **avj, **bxp, **ep, **exp, **xp; + char *argp, *bbp, *ebp, *inpline, *p, *replstr; ep = environ; - jfound = 0; - replstr = NULL; /* set if user requests -J */ + inpline = replstr = NULL; + eofstr = ""; + argumentc = cnt = count = Iflag = jfound = lflag = nflag = xflag = + wasquoted = 0; /* * POSIX.2 limits the exec line length to ARG_MAX - 2K. Running that @@ -106,17 +110,30 @@ main(int argc, char **argv) /* 1 byte for each '\0' */ nline -= strlen(*ep++) + 1 + sizeof(*ep); } - nflag = xflag = wasquoted = 0; - while ((ch = getopt(argc, argv, "0J:n:s:tx")) != -1) + while ((ch = getopt(argc, argv, "0E:I:J:L:n:ps:tx")) != -1) switch(ch) { + case 'E': + eofstr = optarg; + break; + case 'I': + Iflag = 1; + lflag = 1; + replstr = optarg; + break; case 'J': replstr = optarg; break; + case 'L': + lflag = atoi(optarg); + break; case 'n': nflag = 1; if ((nargs = atoi(optarg)) <= 0) errx(1, "illegal argument count"); break; + case 'p': + pflag = 1; + break; case 's': nline = atoi(optarg); break; @@ -138,15 +155,19 @@ main(int argc, char **argv) if (xflag && !nflag) usage(); + if (Iflag || lflag) + xflag = 1; + if (replstr != NULL && *replstr == '\0') + errx(1, "replstr may not be empty"); /* * Allocate pointers for the utility name, the utility arguments, * the maximum arguments to be read from stdin and the trailing * NULL. */ - if (!(av = bxp = - malloc((u_int)(1 + argc + nargs + 1) * sizeof(char **)))) - errx(1, "malloc"); + linelen = 1 + argc + nargs + 1; + if ((av = bxp = calloc(linelen * sizeof(char **), 1)) == NULL) + err(1, "calloc"); /* * Use the user's name for the utility as argv[0], just like the @@ -156,9 +177,8 @@ main(int argc, char **argv) if (!*argv) cnt = strlen((*bxp++ = echo)); else { - cnt = 0; do { - if (replstr && strcmp(*argv, replstr) == 0) { + if (!Iflag && replstr && strcmp(*argv, replstr) == 0) { jfound = 1; argv++; for (avj = argv; *avj; avj++) @@ -188,8 +208,8 @@ main(int argc, char **argv) if (nline <= 0) errx(1, "insufficient space for command"); - if (!(bbp = malloc((u_int)nline + 1))) - errx(1, "malloc"); + if ((bbp = malloc((u_int)nline + 1)) == NULL) + err(1, "malloc"); ebp = (argp = p = bbp) + nline - 1; for (insingle = indouble = 0;;) @@ -210,6 +230,7 @@ main(int argc, char **argv) goto arg2; goto addch; case '\n': + count++; if (zflag) goto addch; @@ -218,10 +239,35 @@ arg1: if (insingle || indouble) errx(1, "unterminated quote"); arg2: + foundeof = *eofstr != '\0' && + strcmp(argp, eofstr) == 0; + /* Do not make empty args unless they are quoted */ - if (argp != p || wasquoted) { + if ((argp != p || wasquoted) && !foundeof) { *p++ = '\0'; *xp++ = argp; + if (Iflag) { + char *realloc_holder; + size_t curlen; + realloc_holder = inpline; + if (realloc_holder == NULL) + curlen = 0; + else { + curlen = strlen(realloc_holder); + if (curlen) + strcat(inpline, " "); + } + curlen++; + argumentc++; + inpline = realloc(realloc_holder, strlen(argp) + + curlen); + if (inpline == NULL) + err(1, "realloc"); + if (curlen == 1) + strcpy(inpline, argp); + else + strcat(inpline, argp); + } } /* @@ -229,19 +275,58 @@ arg2: * run the command. If xflag and max'd out on buffer * but not on args, object. */ - if (xp == exp || p > ebp || ch == EOF) { + if (xp == exp || p > ebp || ch == EOF || (lflag <= count && xflag) || foundeof) { if (xflag && xp != exp && p > ebp) errx(1, "insufficient space for arguments"); if (jfound) { for (avj = argv; *avj; avj++) *xp++ = *avj; } - *xp = NULL; - run(av); - if (ch == EOF) + if (Iflag) { + char **tmp, **tmp2; + size_t repls; + + tmp = calloc(linelen * sizeof(char **), 1); + if (tmp == NULL) + err(1, "malloc"); + tmp2 = tmp; + for (repls = 5, avj = av; *avj != NULL; avj++) { + *tmp = *avj; + if (avj != av && repls > 0 && + strstr(*tmp, replstr) != NULL) { + strnsubst(tmp, replstr, + inpline, 255); + repls--; + } else { + *tmp = strdup(*avj); + if (*tmp == NULL) + err(1, + "strdup"); + } + tmp++; + } + do { + if (*tmp != NULL) + free(*tmp); + tmp--; + } while (--argumentc); + *tmp = *xp = NULL; + run(tmp2); + for (; tmp2 != tmp; tmp--) + free(*tmp); + free(tmp2); + free(inpline); + inpline = strdup(""); + argumentc = 0; + } else { + *xp = NULL; + run(av); + } + if (ch == EOF || foundeof) exit(rval); p = bbp; xp = bxp; + count = 0; } argp = p; wasquoted = 0; @@ -286,7 +371,7 @@ addch: if (p < ebp) { run(av); xp = bxp; cnt = ebp - argp; - bcopy(argp, bbp, cnt); + memcpy(bbp, argp, (size_t)cnt); p = (argp = bbp) + cnt; *p++ = ch; break; @@ -294,20 +379,32 @@ addch: if (p < ebp) { /* NOTREACHED */ } -void +static void run(char **argv) { volatile int childerr; char **p; + FILE *ttyfp; pid_t pid; - int status; + int ch, status; - if (tflag) { + if (tflag || pflag) { (void)fprintf(stderr, "%s", *argv); for (p = argv + 1; *p; ++p) (void)fprintf(stderr, " %s", *p); - (void)fprintf(stderr, "\n"); - (void)fflush(stderr); + if (pflag) { + if ((ttyfp = fopen("/dev/tty", "r")) != NULL) { + (void)fprintf(stderr, "?"); + (void)fflush(stderr); + ch = getc(ttyfp); + fclose(ttyfp); + if (ch != 'y') + return; + } + } else { + (void)fprintf(stderr, "\n"); + (void)fflush(stderr); + } } childerr = 0; switch(pid = vfork()) { @@ -321,12 +418,9 @@ run(char **argv) pid = waitpid(pid, &status, 0); if (pid == -1) err(1, "waitpid"); - /* If we couldn't invoke the utility, exit 127. */ - if (childerr != 0) { - errno = childerr; - warn("%s", argv[0]); - exit(127); - } + /* If we couldn't invoke the utility, exit. */ + if (childerr != 0) + err(childerr == ENOENT ? 127 : 126, "%s", *argv); /* If utility signaled or exited with a value of 255, exit 1-125. */ if (WIFSIGNALED(status) || WEXITSTATUS(status) == 255) exit(1); @@ -338,7 +432,8 @@ static void usage(void) { fprintf(stderr, - "usage: xargs [-0t] [-J replstr] [-n number [-x]] [-s size]\n" - " [utility [argument ...]]\n"); +"usage: xargs [-0pt] [-E eofstr] [-I replstr] [-J replstr] [-L number]\n"); + fprintf(stderr, +" [-n number [-x] [-s size] [utility [argument ...]]\n"); exit(1); } |