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,



Reply via email to