Hi, On Sun, Jul 30, 2023 at 10:15:49AM +0300, sewn wrote: > From 9f4be567ff25fee986976c6afa193223496013a6 Mon Sep 17 00:00:00 2001 > From: sewn <s...@disroot.org> > Date: Fri, 28 Jul 2023 18:58:37 +0300 > Subject: [PATCH] xargs: add replace string flag (-I)
I have applied the patch with some small modifications that I am going to elaborate in the mail. There is still pending work to have a correct -I implementation. > diff --git a/libutil/strnsubst.c b/libutil/strnsubst.c > new file mode 100644 > index 0000000..a76d484 > --- /dev/null > +++ b/libutil/strnsubst.c > @@ -0,0 +1,63 @@ > +/* > + * 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 <stdio.h> > +#include <stdlib.h> > +#include <string.h> > +#include <unistd.h> unistd.h is not needed and it was removed. > +void > +strnsubst(char **str, const char *match, const char *replstr, size_t maxsize) > +{ > + char *s1, *s2, *this; > + size_t matchlen, repllen, s2len; > + int n; replen was set but it was not used, thus I remove it. > +done: > + *str = s2; *str is holding a previously allocated string, so we have to free it. > diff --git a/util.h b/util.h > index 8d5004b..d6911bd 100644 > --- a/util.h > +++ b/util.h > @@ -63,6 +63,8 @@ size_t estrlcpy(char *, const char *, size_t); > #define strsep xstrsep > char *strsep(char **, const char *); > > +void strnsubst(char **str, const char *match, const char *replstr, size_t > maxsize); > + We don't use parameter names in prototypes. > @@ -252,7 +260,11 @@ main(int argc, char *argv[]) > leftover = 1; > break; > } > - cmd[i] = estrdup(arg); > + if (ri > 0) > + strnsubst(&cmd[ri], replstr, arg, (size_t)255); > + else > + cmd[i] = estrdup(arg); > + > argsz += arglen + 1; > i++; > a++; the cast to size_t is not required because the prototype already does the work. The problems with this implementation is that POSIX mandates that when -I is used then spaces don't break arguments and they are just separated by newlines. I tried something like: - case ' ': case '\t': case '\n': + case ' ': + case '\t': + if (Iflag) + goto fill; + case '\n': goto out; case '\'': if (parsequote('\'') < 0) @@ -126,6 +130,7 @@ poparg(void) eprintf("backslash at EOF\n"); break; default: + fill: fillargbuf(ch); argbpos++; break; @@ -227,6 +232,7 @@ main(int argc, char *argv[]) eofstr = EARGF(usage()); break; case 'I': + Iflag = 1; xflag = 1; nflag = 1; maxargs = 1; but we pass the full line (after removing leading spaces) to exec, being a single parameter instead of being split. For example: xargs -I x ls x <<EOF . .. EOF will execute ls '. ..' that is wrong, but addapting the code to change that is really complex. Also, POSIX says: At least five arguments in arguments can each contain one or more instances of replstr But we are allowing only one. I think we should go trought all the elements of cmd[] and apply the substitution. Regards,