Subject: Re: upgrade to mv
To: None <greywolf@starwolf.com>
From: Masao Uebayashi <masao@plala.or.jp>
List: tech-userlevel
Date: 08/16/2001 02:13:24
----Next_Part(Thu_Aug_16_02:13:24_2001_163)--
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

> What really needs to happen is for xargs(1) to be brought in-line with
> spec.

I'am looking into xargs(1)'s source and tring to implement the insert
mode (-I/-i) feature.  The following patch at least works for me.  But
I've not written the manual, but the spec is supposed to be compliant
to the SUSv2's -I/-i.

  http://thibs.menloschool.org/help/susv2/xcu/xargs.html

(-E/-e implementation also seems not that hard.)

Regards,
Masao

----Next_Part(Thu_Aug_16_02:13:24_2001_163)--
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="xargs.patch"

Index: xargs.c
===================================================================
RCS file: /cvsroot/basesrc/usr.bin/xargs/xargs.c,v
retrieving revision 1.12
diff -u -r1.12 xargs.c
--- xargs.c	1999/12/22 14:41:01	1.12
+++ xargs.c	2001/08/15 17:08:31
@@ -65,23 +65,23 @@
 #include <unistd.h>
 #include "pathnames.h"
 
-static int pflag, tflag, zflag, rval;
+static int Iflag, pflag, tflag, zflag, rval;
 static FILE *promptfile;
 static regex_t yesexpr;
 
-static void	run __P((char **));
-int		main __P((int, char **));
-static void	usage __P((void));
+int main(int, char **);
+static void	run(char **);
+static void	usage(void);
 
 int
-main(argc, argv)
-	int argc;
-	char **argv;
+main(int argc, char *argv[])
 {
-	int ch;
 	char *p, *bbp, *ebp, **bxp, **exp, **xp;
-	int cnt, indouble, insingle, nargs, nflag, nline, xflag;
 	char **av, *argp;
+	char *rpltmp, **rplarg, **rplp;
+	int ch, cnt, indouble, iflag, insingle, nargs, nflag, nline, xflag;
+	extern int optind;
+	extern char *optarg;
 
 	setlocale(LC_ALL, "");
 
@@ -100,12 +100,24 @@
 	 */
 	nargs = 5000;
 	nline = ARG_MAX - 4 * 1024;
-	nflag = xflag = 0;
-	while ((ch = getopt(argc, argv, "0n:ps:tx")) != -1)
+	iflag = nflag = xflag = 0;
+	while ((ch = getopt(argc, argv, "0I:i:n:ps:tx")) != -1)
 		switch(ch) {
 		case '0':
 			zflag = 1;
 			break;
+		case 'I':
+			Iflag = 1;
+			/* Template of replaced string. */
+			rpltmp = optarg;
+			break;
+		case 'i':
+			iflag = 1;
+			if (optarg != NULL)
+				rpltmp = optarg;
+			else
+				rpltmp = "{}";
+			break;
 		case 'n':
 			nflag = 1;
 			if ((nargs = atoi(optarg)) <= 0)
@@ -115,7 +127,8 @@
 			pflag = tflag = 1;
 			break;
 		case 's':
-			nline = atoi(optarg);
+			if ((nline = atoi(optarg)) <= 0)
+				errx(1, "illegal argument count");
 			break;
 		case 't':
 			tflag = 1;
@@ -138,8 +151,8 @@
 	 * the maximum arguments to be read from stdin and the trailing
 	 * NULL.
 	 */
-	if (!(av = bxp =
-	    malloc((u_int)(1 + argc + nargs + 1) * sizeof(char **))))
+	if ((av = bxp =
+	    malloc((u_int)(1 + (argc - 1) + nargs + 1) * sizeof(char **))) == NULL)
 		err(1, "malloc");
 
 	/*
@@ -147,13 +160,15 @@
 	 * shell.  Echo is the default.  Set up pointers for the user's
 	 * arguments.
 	 */
-	if (!*argv)
-		cnt = strlen(*bxp++ = _PATH_ECHO);
-	else {
+	if (*argv == NULL) {
+		cnt = strlen(*bxp = _PATH_ECHO);
+		bxp++;
+	} else {
 		cnt = 0;
 		do {
-			cnt += strlen(*bxp++ = *argv) + 1;
-		} while (*++argv);
+			cnt += strlen(*bxp = *argv) + 1;
+			bxp++;
+		} while (*++argv != NULL);
 	}
 
 	/*
@@ -161,7 +176,8 @@
 	 * count doesn't include the trailing NULL pointer, so the malloc
 	 * added in an extra slot.
 	 */
-	exp = (xp = bxp) + nargs;
+	xp = bxp;
+	exp = bxp + nargs;
 
 	/*
 	 * Allocate buffer space for the arguments read from stdin and the
@@ -175,9 +191,26 @@
 	if (nline <= 0)
 		errx(1, "insufficient space for command");
 
-	if (!(bbp = malloc((u_int)nline + 1)))
+	if ((bbp = malloc((u_int)nline + 1)) == NULL)
 		err(1, "malloc");
-	ebp = (argp = p = bbp) + nline - 1;
+	argp = p = bbp;
+	ebp = bbp + nline - 1;
+
+	if (Iflag || iflag) {
+		int n = 0;
+		/* It's senseless to replace the utility's name. */
+		for (xp = av + 1; xp < bxp; ++xp) {
+			/* printf("TRY: %s\t%s\n", rpltmp, *xp); */
+			if (strcmp((const char *)rpltmp, (const char *)*xp) == 0) {
+				/* printf("RPL: %s\t%s\n", rpltmp, *xp); */
+				*xp = bbp;
+				++n;
+			}
+			if (n == 5)
+				break;
+		}
+		xp = bxp;
+	}
 
 	if (pflag) {
 		int error;
@@ -188,7 +221,7 @@
 		    != 0) {
 			char msg[NL_TEXTMAX];
 
-			(void)regerror(error, NULL, msg, sizeof (msg));
+			(void)regerror(error, NULL, msg, sizeof(msg));
 			err(1, "cannot compile yesexpr: %s", msg);
 		}
 	}
@@ -218,6 +251,7 @@
 				goto arg2;
 			goto addch;
 		case '\n':
+			/* Read newline as normal character.  (zflag is not documented?) */
 			if (zflag)
 				goto addch;
 			/* Empty lines are skipped. */
@@ -225,12 +259,21 @@
 				continue;
 
 			/* Quotes do not escape newlines. */
-arg1:			if (insingle || indouble)
-				 errx(1, "unterminated quote");
+arg1:		if (insingle || indouble)
+				errx(1, "unterminated quote");
 
-arg2:			*p = '\0';
+arg2:		*p = '\0';
 			*xp++ = argp;
 
+			/* Run a command per line. */
+			if (Iflag || iflag) {
+				*bxp = NULL;
+				run(av);
+				argp = p = bbp;
+				xp = bxp;
+				break;
+			}
+
 			/*
 			 * If max'd out on args or buffer, or reached EOF,
 			 * run the command.  If xflag and max'd out on buffer
@@ -267,12 +310,14 @@
 				errx(1, "backslash at EOF");
 			/* FALLTHROUGH */
 		default:
-addch:			if (p < ebp) {
+addch:		if (p < ebp) {
 				*p++ = ch;
 				break;
 			}
 
-			/* If only one argument, not enough buffer space. */
+			/*
+			 * Buffer is full.  If only one argument, not enough buffer space.
+			 */
 			if (bxp == xp)
 				errx(1, "insufficient space for argument");
 			/* Didn't hit argument limit, so if xflag object. */
@@ -281,10 +326,12 @@
 
 			*xp = NULL;
 			run(av);
+
 			xp = bxp;
 			cnt = ebp - argp;
 			memmove(bbp, argp, cnt);
-			p = (argp = bbp) + cnt;
+			argp = bbp;
+			p = bbp + cnt;
 			*p++ = ch;
 			break;
 		}
@@ -292,8 +339,7 @@
 }
 
 static void
-run(argv)
-	char **argv;
+run(char **argv)
 {
 	volatile int noinvoke;
 	char **p;
@@ -302,14 +348,14 @@
 
 	if (tflag) {
 		(void)fprintf(stderr, "%s", *argv);
-		for (p = argv + 1; *p; ++p)
+		for (p = argv + 1; *p != NULL; ++p)
 			(void)fprintf(stderr, " %s", *p);
 		if (pflag) {
 			char buf[LINE_MAX + 1];
 
 			(void)fprintf(stderr, "?...");
 			fflush(stderr);
-			if (fgets(buf, sizeof (buf), promptfile) == NULL) {
+			if (fgets(buf, sizeof(buf), promptfile) == NULL) {
 				rval = 1;
 				return;
 			}
@@ -350,17 +396,15 @@
 		if (WEXITSTATUS (status) == 255) {
 			warnx ("%s exited with status 255", argv[0]);
 			exit(124);
-		} else if (WEXITSTATUS (status) != 0) {
+		} else if (WEXITSTATUS (status) != 0)
 			rval = 123;
-		}
 	} else if (WIFSIGNALED (status)) {
-		if (WTERMSIG(status) < NSIG) {
+		if (WTERMSIG(status) < NSIG)
 			warnx("%s terminated by SIG%s", argv[0],
 				sys_signame[WTERMSIG(status)]);
-		} else {
+		else
 			warnx("%s terminated by signal %d", argv[0],
 				WTERMSIG(status));
-		}
 		exit(125);
 	}
 }

----Next_Part(Thu_Aug_16_02:13:24_2001_163)----