[PATCH] Add initial version of xargs(1)

From: sin <sin_AT_2f30.org>
Date: Fri, 3 Jan 2014 11:52:47 +0000

---
 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 : Sat Jan 04 2014 - 10:12:03 CET