summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjmallett <jmallett@FreeBSD.org>2002-04-19 23:28:54 +0000
committerjmallett <jmallett@FreeBSD.org>2002-04-19 23:28:54 +0000
commit22be17968264e9796541bacb17a722aee628e8c2 (patch)
tree9d07f19a0a400de9d43a844a00d25af5890bea19
parentfeb9b6ff6d055ca921f46f7fcd4ea49263c1af09 (diff)
downloadFreeBSD-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
-rw-r--r--usr.bin/xargs/Makefile2
-rw-r--r--usr.bin/xargs/strnsubst.c78
-rw-r--r--usr.bin/xargs/xargs.163
-rw-r--r--usr.bin/xargs/xargs.c173
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);
}
OpenPOWER on IntegriCloud