sbase

suckless unix tools
git clone git://git.suckless.org/sbase
Log | Files | Refs | README | LICENSE

commit 8d97acc135239e7fae906e5fd3c479af240b3dea
parent f14887c76522b3a5d375351b6aa8432430447f6a
Author: sewn <sewn@disroot.org>
Date:   Fri, 28 Jul 2023 18:58:37 +0300

xargs: add replace string flag (-I)

Diffstat:
MMakefile | 1+
Alibutil/strnsubst.c | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mutil.h | 2++
Mxargs.1 | 8+++++++-
Mxargs.c | 16++++++++++++++--
5 files changed, 86 insertions(+), 3 deletions(-)

diff --git a/Makefile b/Makefile @@ -78,6 +78,7 @@ LIBUTILSRC =\ libutil/strlcat.c\ libutil/strlcpy.c\ libutil/strsep.c\ + libutil/strnsubst.c\ libutil/strtonum.c\ libutil/unescape.c\ libutil/writeall.c diff --git a/libutil/strnsubst.c b/libutil/strnsubst.c @@ -0,0 +1,62 @@ +/* + * 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 "../util.h" + +/* + * 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. + * If replstr is NULL, then that internally is changed to a nil-string, so + * that we can still pretend to do somewhat meaningful substitution. + * No value is returned. + */ +void +strnsubst(char **str, const char *match, const char *replstr, size_t maxsize) +{ + char *s1, *s2, *this; + size_t matchlen, s2len; + int n; + + if ((s1 = *str) == NULL) + return; + s2 = emalloc(maxsize); + + if (replstr == NULL) + replstr = ""; + + if (match == NULL || *match == '\0' || strlen(s1) >= maxsize) { + strlcpy(s2, s1, maxsize); + goto done; + } + + *s2 = '\0'; + s2len = 0; + matchlen = strlen(match); + for (;;) { + if ((this = strstr(s1, match)) == NULL) + break; + n = snprintf(s2 + s2len, maxsize - s2len, "%.*s%s", + (int)(this - s1), s1, replstr); + if (n == -1 || n + s2len + strlen(this + matchlen) >= maxsize) + break; /* out of room */ + s2len += n; + s1 = this + matchlen; + } + strlcpy(s2 + s2len, s1, maxsize - s2len); +done: + free(*str); + *str = s2; + return; +} diff --git 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 **, const char *, const char *, size_t); + /* regex */ int enregcomp(int, regex_t *, const char *, int); int eregcomp(regex_t *, const char *, int); diff --git a/xargs.1 b/xargs.1 @@ -1,4 +1,4 @@ -.Dd 2015-10-08 +.Dd 2023-07-30 .Dt XARGS 1 .Os sbase .Sh NAME @@ -8,6 +8,7 @@ .Nm .Op Fl rtx .Op Fl E Ar eofstr +.Op Fl I Ar replstr .Op Fl n Ar num .Op Fl s Ar num .Op Ar cmd Op Ar arg ... @@ -44,6 +45,11 @@ Normally the command is executed at least once even if there are no arguments. Use .Ar eofstr as a logical EOF marker. +.It Fl I Ar replstr +Use +.Ar replstr +as the placeholder for the argument. +Sets the arguments count to 1 per command line. .It Fl s Ar num Use at most .Ar num diff --git a/xargs.c b/xargs.c @@ -195,10 +195,11 @@ usage(void) int main(int argc, char *argv[]) { - int ret = 0, leftover = 0, i; + int ret = 0, leftover = 0, ri = 0, i; size_t argsz, argmaxsz; size_t arglen, a; char *arg = ""; + char *replstr; if ((argmaxsz = sysconf(_SC_ARG_MAX)) == (size_t)-1) argmaxsz = _POSIX_ARG_MAX; @@ -225,6 +226,11 @@ main(int argc, char *argv[]) case 'E': eofstr = EARGF(usage()); break; + case 'I': + nflag = 1; + maxargs = 1; + replstr = EARGF(usage()); + break; default: usage(); } ARGEND @@ -235,6 +241,8 @@ main(int argc, char *argv[]) for (; i < argc; i++) { cmd[i] = estrdup(argv[i]); argsz += strlen(cmd[i]) + 1; + if (!strcmp(cmd[i], replstr)) + ri = i; } } else { cmd[i] = estrdup("/bin/echo"); @@ -252,7 +260,11 @@ main(int argc, char *argv[]) leftover = 1; break; } - cmd[i] = estrdup(arg); + if (ri > 0) + strnsubst(&cmd[ri], replstr, arg, 255); + else + cmd[i] = estrdup(arg); + argsz += arglen + 1; i++; a++;