4.3BSD-Reno/src/usr.bin/xargs/xargs.c

Compare this file to the similar file:
Show the results in this format:

/*-
 * Copyright (c) 1990 The Regents of the University of California.
 * All rights reserved.
 *
 * This code is derived from software contributed to Berkeley by
 * John B. Roll Jr.
 *
 * Redistribution and use in source and binary forms are permitted provided
 * that: (1) source distributions retain this entire copyright notice and
 * comment, and (2) distributions including binaries display the following
 * acknowledgement:  ``This product includes software developed by the
 * University of California, Berkeley and its contributors'' in the
 * documentation or other materials provided with the distribution and in
 * all advertising materials mentioning features or use of this software.
 * Neither the name of the University nor the names of its contributors may
 * be used to endorse or promote products derived from this software without
 * specific prior written permission.
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#ifndef lint
char copyright[] =
"@(#) Copyright (c) 1990 The Regents of the University of California.\n\
 All rights reserved.\n";
#endif /* not lint */

#ifndef lint
static char sccsid[] = "@(#)xargs.c	5.4 (Berkeley) 6/24/90";
#endif /* not lint */

#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include "pathnames.h"

#define	DEF_ARGC	255

int tflag;

main(argc, argv)
	int argc;
	char **argv;
{
	extern int errno, optind;
	extern char *optarg;
	register int ch;
	register char *p, *bp, *endbp, **bxp, **endxp, **xp;
	int cnt, indouble, insingle, nargs, nline;
	char *mark, *prog, **xargs, *malloc();

	nargs = DEF_ARGC;
	nline = _BSD_LINE_MAX;

	while ((ch = getopt(argc, argv, "n:s:t")) != EOF)
		switch(ch) {
		case 'n':
			if ((nargs = atoi(optarg)) <= 0) {
				(void)fprintf(stderr,
				    "xargs: bad argument count.\n");
				exit(1);
			}
			break;
		case 's':
			if ((nline = atoi(optarg)) <= 0) {
				(void)fprintf(stderr,
				    "xargs: bad command length.\n");
				exit(1);
			}
			break;
		case 't':
			tflag = 1;
			break;
		case '?':
		default:
			usage();
	}
	argc -= optind;
	argv += optind;

	/* room for the command, leftover arguments and trailing NULL */
	if (!(xargs =
	    (char **)malloc((u_int)(nargs + argc + 2) * sizeof(char **))))
		enomem();

	if (!(bp = malloc((u_int)nline + 1)))
		enomem();

	xp = xargs + 1;
	if (!*argv)
		prog = _PATH_ECHO;
	else {
		prog = *argv;
		while (*++argv)
			*xp++ = *argv;
	}

	if (xargs[0] = rindex(prog, '/'))
		++xargs[0];
	else
		xargs[0] = prog;

	/* set up the pointers into the buffer and the arguments */
	*(endxp = (bxp = xp) + nargs) = NULL;
	endbp = (mark = p = bp) + nline;

	insingle = indouble = 0;
	for (;;)
		switch(ch = getchar()) {
		case EOF:
			if (p == bp)		/* nothing to display */
				exit(0);
			if (mark == p) {	/* nothing since last arg end */
				run(prog, xargs);
				exit(0);
			}
			goto addarg;
		case ' ':
		case '\t':
			if (insingle || indouble)
				goto addch;
			goto addarg;
		case '\n':
			if (mark == p)			/* empty line */
				continue;
addarg:			*xp++ = mark;
			*p++ = '\0';
			if (xp == endxp || p >= endbp || ch == EOF) {
				if (insingle || indouble) {
					(void)fprintf(stderr,
					   "xargs: unterminated quote.\n");
					exit(1);
				}
				run(prog, xargs);
				if (ch == EOF)
					exit(0);
				p = bp;
				xp = bxp;
			}
			mark = p;
			break;
		case '\'':
			if (indouble)
				goto addch;
			insingle = !insingle;
			break;
		case '"':
			if (insingle)
				goto addch;
			indouble = !indouble;
			break;
		case '\\':
			if ((ch = getchar()) == EOF)
				ch = '\\';
			if (ch == '\n') {
				(void)fprintf(stderr,
				    "xargs: newline may not be escaped.\n");
				exit(1);
			}
			/* FALLTHROUGH */
		default:
addch:			if (p != endbp) {
				*p++ = ch;
				continue;
			}
			if (xp == bxp) {
				(void)fprintf(stderr,
				    "xargs: argument too large.\n");
				exit(1);
			}
			*xp = NULL;
			run(prog, xargs);
			cnt = endbp - mark;
			bcopy(mark, bp, cnt);
			p = (mark = bp) + cnt;
			*p++ = ch;
			xp = bxp;
			break;
		}
	/* NOTREACHED */
}

run(prog, argv)
	char *prog, **argv;
{
	union wait pstat;
	pid_t pid, waitpid();
	char **p;

	if (tflag) {
		(void)fprintf(stderr, "%s", *argv);
		for (p = argv + 1; *p; ++p)
			(void)fprintf(stderr, " %s", *p);
		(void)fprintf(stderr, "\n");
		(void)fflush(stderr);
	}
	switch(pid = vfork()) {
	case -1:
		(void)fprintf(stderr,
		   "xargs: vfork: %s.\n", strerror(errno));
		exit(1);
	case 0:
		execvp(prog, argv);
		(void)fprintf(stderr,
		   "xargs: %s: %s.\n", prog, strerror(errno));
		_exit(1);
	}
	pid = waitpid(pid, &pstat, 0);
	if (pid == -1) {
		(void)fprintf(stderr,
		   "xargs: waitpid: %s.\n", strerror(errno));
		exit(1);
	}
	if (pstat.w_status)
		exit(1);
}

enomem()
{
	(void)fprintf(stderr, "xargs: %s.\n", strerror(ENOMEM));
	exit(1);
}

usage()
{
	(void)fprintf(stderr,
	    "xargs: [-t] [-n number] [-s size] [utility [argument ...]]\n");
	exit(1);
}