Hi,

This is a quick hack implementing xargs(1).  Many features
are currently missing and there is a known issue with overflowing
the `argb' buffer.

Any comments?

bye,
sin
>From 731875ba179abbe8604d8979510195fa8d85ac20 Mon Sep 17 00:00:00 2001
From: sin <s...@2f30.org>
Date: Fri, 3 Jan 2014 11:52:47 +0000
Subject: [PATCH] Add initial version of xargs(1)

---
 Makefile |   1 +
 xargs.c  | 213 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 214 insertions(+)
 create mode 100644 xargs.c

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.c b/xargs.c
new file mode 100644
index 0000000..72159ef
--- /dev/null
+++ b/xargs.c
@@ -0,0 +1,213 @@
+/* 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"
+
+static int inputc(void);
+static void deinputc(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 void
+usage(void)
+{
+       eprintf("usage: %s [-r] [cmd [arg...]]", argv0);
+}
+
+static char **cmd;
+static char argb[BUFSIZ];
+static size_t argbpos;
+static int rflag = 0;
+
+int
+main(int argc, char *argv[])
+{
+       char *arg;
+       int i = 0;
+
+       ARGBEGIN {
+       case 'r':
+               rflag = 1;
+               break;
+       default:
+               usage();
+       } ARGEND;
+
+       cmd = malloc(sysconf(_SC_ARG_MAX) * sizeof(*cmd));
+       if (!cmd)
+               eprintf("malloc:");
+
+       do {
+               if (argc > 0)
+                       for (i = 0; i < argc; i++)
+                               cmd[i] = strdup(argv[i]);
+               else
+                       cmd[i++] = strdup("/bin/echo");
+               while ((arg = poparg())) {
+                       if (i < sysconf(_SC_ARG_MAX) - 1) {
+                               cmd[i++] = strdup(arg);
+                       } else {
+                               pusharg(arg);
+                               break;
+                       }
+               }
+               cmd[i] = NULL;
+               runcmd();
+               for (; i >= 0; i--)
+                       free(cmd[i]);
+       } while (arg);
+
+       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
+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;
+       int ok = -1;
+
+       while ((ch = inputc()) != EOF) {
+               switch (ch) {
+               case '\'':
+                       argb[argbpos] = '\0';
+                       ok = 0;
+                       break;
+               default:
+                       if (ch != '\n')
+                               argb[argbpos++] = ch;
+                       break;
+               }
+       }
+       return ok;
+}
+
+static int
+parsedquote(void)
+{
+       int ch;
+       int ok = -1;
+
+       while ((ch = inputc()) != EOF) {
+               switch (ch) {
+               case '\"':
+                       argb[argbpos] = '\0';
+                       ok = 0;
+                       break;
+               default:
+                       if (ch != '\n')
+                               argb[argbpos++] = ch;
+                       break;
+               }
+       }
+       return ok;
+}
+
+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;
+                               if (ch != '\n') {
+                                       argb[argbpos++] = ch;
+                                       break;
+                               }
+                       }
+                       argb[argbpos] = '\0';
+                       deinputc(ch);
+                       return argb;
+               case '\'':
+                       if (parsesquote() == -1)
+                               enprintf(EXIT_FAILURE, "unterminated quote\n");
+                       break;
+               case '\"':
+                       if (parsedquote() == -1)
+                               enprintf(EXIT_FAILURE, "unterminated quote\n");
+                       break;
+               case '\\':
+                       escape = !escape;
+                       break;
+               default:
+                       argb[argbpos++] = ch;
+                       break;
+               }
+       }
+       if (argbpos > 0) {
+               argb[argbpos] = '\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);
+       wait(NULL);
+       return 0;
+}
-- 
1.8.4.5

Reply via email to