Hi,
On Sun, Jul 30, 2023 at 10:15:49AM +0300, sewn wrote:
> From 9f4be567ff25fee986976c6afa193223496013a6 Mon Sep 17 00:00:00 2001
> From: sewn <[email protected]>
> 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,