commit 4bdf9a9658c3de471418c47f55c1d4571a945ab1
Author: sin <[email protected]>
Date:   Fri Jan 3 11:52:47 2014 +0000

    Add initial version of xargs(1)

diff --git a/Makefile b/Makefile
index 2a72a1c..81dfaf6 100644
--- a/Makefile
+++ b/Makefile
@@ -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..6ce262f
--- /dev/null
+++ b/xargs.1
@@ -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..da505f9
--- /dev/null
+++ b/xargs.c
@@ -0,0 +1,241 @@
+/* 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 = 5000
+};
+
+static int inputc(void);
+static void deinputc(int);
+static void fillbuf(int);
+static void eatspace(void);
+static int parsequote(int);
+static void parseescape(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:");
+       /* Leave some room for environment variables */
+       argmaxsz -= 4 * 1024;
+
+       cmd = malloc(NARGS * sizeof(*cmd));
+       if (!cmd)
+               eprintf("malloc:");
+
+       argb = malloc(argbsz);
+       if (!argb)
+               eprintf("malloc:");
+
+       do {
+               argsz = 0; i = 0;
+               if (argc > 0) {
+                       for (; i < argc; i++) {
+                               cmd[i] = strdup(argv[i]);
+                               argsz += strlen(cmd[i]) + 1;
+                       }
+               } else {
+                       cmd[i] = strdup("/bin/echo");
+                       argsz += strlen(cmd[i]) + 1;
+                       i++;
+               }
+               while ((arg = poparg())) {
+                       if (argsz + strlen(arg) + 1 > argmaxsz ||
+                           i >= NARGS - 1) {
+                               pusharg(arg);
+                               break;
+                       }
+                       cmd[i] = strdup(arg);
+                       argsz += strlen(cmd[i]) + 1;
+                       i++;
+               }
+               cmd[i] = NULL;
+               if (i == 1 && rflag == 1)
+                       ;
+               else
+                       if (runcmd() == -1)
+                               arg = NULL;
+               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 '        ': case '
':
+                       break;
+               default:
+                       deinputc(ch);
+                       return;
+               }
+       }
+}
+
+static int
+parsequote(int q)
+{
+       int ch;
+
+       while ((ch = inputc()) != EOF) {
+               if (ch == q) {
+                       fillbuf('

Reply via email to