--- Makefile | 1 + xargs.1 | 28 +++++++ xargs.c | 258 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 287 insertions(+) create mode 100644 xargs.1 create mode 100644 xargs.c diff --git a/Makefile b/Makefile index 2a72a1c..81dfaf6 100644 --- a/Makefile +++ b/Makefile _AT_@ -93,6 +93,7 @@ SRC = \ stat.c \ wc.c \ who.c \ + xargs.c \ yes.c OBJ = $(SRC:.c=.o) $(LIB) diff --git a/xargs.1 b/xargs.1 new file mode 100644 index 0000000..87ce6f8 --- /dev/null +++ b/xargs.1 _AT_@ -0,0 +1,28 @@ +.TH XARGS 1 sbase\-VERSION +.SH NAME +xargs \- constuct argument list(s) and execute command +.SH SYNOPSIS +.B xargs +.RB [ \-r ] +.RI [ cmd +.RI [arg... ] ] +.SH DESCRIPTION +xargs reads space, tab, newline and EOF delimited strings from stdin +and executes the specified cmd with the strings as arguments. + +Any arguments specified on the command line are given to the command upon +each invocation, followed by some number of the arguments read from +stdin. The command is repeatedly executed one or more times until stdin +is exhausted. + +Spaces, tabs and newlines may be embedded in arguments using single (`'') +or double (`#') quotes or backslashes ('\\'). Single quotes escape all +non-single quote characters, excluding newlines, up to the matching single +quote. Double quotes escape all non-double quote characters, excluding +newlines, up to the matching double quote. Any single character, including +newlines, may be escaped by a backslash. +.SH OPTIONS +.TP +.BI \-r +Do not run the command if there are no arguments. Normally the command is +executed at least once even if there are no arguments. diff --git a/xargs.c b/xargs.c new file mode 100644 index 0000000..7de5fec --- /dev/null +++ b/xargs.c _AT_@ -0,0 +1,258 @@ +/* See LICENSE file for copyright and license details. */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/wait.h> +#include <unistd.h> +#include "text.h" +#include "util.h" + +enum { + NARGS = 2048 +}; + +extern char **environ; + +static int inputc(void); +static void deinputc(int); +static void fillbuf(int); +static void eatspace(void); +static char *poparg(void); +static int parsesquote(void); +static int parsedquote(void); +static char *poparg(void); +static void pusharg(char *); +static int runcmd(void); + +static char **cmd; +static char *argb; +static size_t argbsz = 1; +static size_t argbpos; +static int rflag = 0; + +static void +usage(void) +{ + eprintf("usage: %s [-r] [cmd [arg...]]", argv0); +} + +int +main(int argc, char *argv[]) +{ + long argsz, argmaxsz; + char *arg; + int i; + + ARGBEGIN { + case 'r': + rflag = 1; + break; + default: + usage(); + } ARGEND; + + argmaxsz = sysconf(_SC_ARG_MAX); + if (argmaxsz < 0) + eprintf("sysconf:"); + + cmd = malloc(NARGS * sizeof(*cmd)); + if (!cmd) + eprintf("malloc:"); + + argb = malloc(argbsz); + if (!argb) + eprintf("malloc:"); + + do { + argsz = 0; + for (i = 0; environ[i]; i++) + argsz += strlen(environ[i]); + i = 0; + if (argc > 0) { + for (; i < argc; i++) { + cmd[i] = strdup(argv[i]); + argsz += strlen(cmd[i]); + } + } else { + cmd[i] = strdup("/bin/echo"); + argsz += strlen(cmd[i]); + i++; + } + while ((arg = poparg())) { + if (argsz + strlen(arg) >= argmaxsz || + i >= NARGS - 1) { + pusharg(arg); + break; + } + cmd[i] = strdup(arg); + argsz += strlen(cmd[i]); + i++; + } + cmd[i] = NULL; + if (i == 1 && rflag == 1); else runcmd(); + for (; i >= 0; i--) + free(cmd[i]); + } while (arg); + + free(argb); + free(cmd); + return 0; +} + +static int +inputc(void) +{ + int ch; + + ch = getc(stdin); + if (ch == EOF && ferror(stdin)) + eprintf("stdin: read error:"); + return ch; +} + +static void +deinputc(int ch) +{ + ungetc(ch, stdin); +} + +static void +fillbuf(int ch) +{ + if (argbpos >= argbsz) { + argbsz *= 2; + argb = realloc(argb, argbsz); + if (!argb) + eprintf("realloc:"); + } + argb[argbpos] = ch; +} + +static void +eatspace(void) +{ + int ch; + + while ((ch = inputc()) != EOF) { + switch (ch) { + case ' ': case '\t': case '\n': + break; + default: + deinputc(ch); + return; + } + } +} + +static int +parsesquote(void) +{ + int ch; + + while ((ch = inputc()) != EOF) { + switch (ch) { + case '\'': + fillbuf('\0'); + return 0; + default: + if (ch != '\n') { + fillbuf(ch); + argbpos++; + } + break; + } + } + return -1; +} + +static int +parsedquote(void) +{ + int ch; + + while ((ch = inputc()) != EOF) { + switch (ch) { + case '\"': + fillbuf('\0'); + return 0; + default: + if (ch != '\n') { + fillbuf(ch); + argbpos++; + } + break; + } + } + return -1; +} + +static char * +poparg(void) +{ + int ch; + int escape = 0; + + argbpos = 0; + eatspace(); + while ((ch = inputc()) != EOF) { + switch (ch) { + case ' ': case '\t': case '\n': + if (escape == 1) { + escape = !escape; + fillbuf(ch); + argbpos++; + break; + } + fillbuf('\0'); + deinputc(ch); + return argb; + case '\'': + if (parsesquote() == -1) + enprintf(EXIT_FAILURE, + "unterminated single quote\n"); + break; + case '\"': + if (parsedquote() == -1) + enprintf(EXIT_FAILURE, + "unterminated double quote\n"); + break; + case '\\': + escape = !escape; + break; + default: + fillbuf(ch); + argbpos++; + break; + } + } + if (argbpos > 0) { + fillbuf('\0'); + return argb; + } + return NULL; +} + +static void +pusharg(char *arg) +{ + char *p; + + for (p = &arg[strlen(arg) - 1]; p >= arg; p--) + deinputc(*p); +} + +static int +runcmd(void) +{ + pid_t pid; + + pid = fork(); + if (pid < 0) + eprintf("fork:"); + if (pid == 0) { + execvp(*cmd, cmd); + eprintf("execvp %s:", *cmd); + } + wait(NULL); + return 0; +} -- 1.8.4.5 --82I3+IH0IqGh5yIs--Received on Mon Sep 17 2001 - 00:00:00 CEST
This archive was generated by hypermail 2.3.0 : Sun Jan 05 2014 - 18:48:03 CET