1N/A/***********************************************************************
1N/A* *
1N/A* This software is part of the ast package *
1N/A* Copyright (c) 1989-2011 AT&T Intellectual Property *
1N/A* and is licensed under the *
1N/A* Common Public License, Version 1.0 *
1N/A* by AT&T Intellectual Property *
1N/A* *
1N/A* A copy of the License is available at *
1N/A* http://www.opensource.org/licenses/cpl1.0.txt *
1N/A* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
1N/A* *
1N/A* Information and Software Systems Research *
1N/A* AT&T Research *
1N/A* Florham Park NJ *
1N/A* *
1N/A* Glenn Fowler <gsf@research.att.com> *
1N/A* *
1N/A***********************************************************************/
1N/A#pragma prototyped
1N/A/*
1N/A * Glenn Fowler
1N/A * AT&T Research
1N/A *
1N/A * xargs -- construct arg list and exec -- use tw instead
1N/A */
1N/A
1N/Astatic const char usage[] =
1N/A"[-?\n@(#)$Id: xargs (AT&T Research) 2005-03-07 $\n]"
1N/AUSAGE_LICENSE
1N/A"[+NAME?xargs - construct arg list and execute command]"
1N/A"[+DESCRIPTION?\bxargs\b constructs a command line consisting of the"
1N/A" \acommand\a and \aargument\a operands specified followed by as"
1N/A" many arguments read in sequence from standard input as will fit"
1N/A" in length and number constraints specified by the options and the"
1N/A" local system. \axargs\a executes the constructed command and waits"
1N/A" for its completion. This sequence is repeated until an end-of-file"
1N/A" condition is detected on standard input or an invocation of a"
1N/A" constructed command line returns an exit status of 255. If"
1N/A" \acommand\a is omitted then the equivalent of \b/bin/echo\b is used.]"
1N/A
1N/A"[+?Arguments in the standard input must be separated by unquoted blank"
1N/A" characters, or unescaped blank characters or newline characters."
1N/A" A string of zero or more non-double-quote and non-newline characters"
1N/A" can be quoted by enclosing them in double-quotes. A string of zero or"
1N/A" more non-apostrophe and non-newline characters can be quoted by"
1N/A" enclosing them in apostrophes. Any unquoted character can be escaped"
1N/A" by preceding it with a backslash. The utility will be executed one"
1N/A" or more times until the end-of-file is reached. The results are"
1N/A" unspecified if \acommand\a attempts to read from its standard input.]"
1N/A
1N/A"[e:eof?Set the end of file string. The first input line matching this string"
1N/A" terminates the input list. There is no eof string if \astring\a is"
1N/A" omitted. The default eof string is \b_\b if neither \b--eof\b nor"
1N/A" \b-E\b are specified. For backwards compatibility \astring\a"
1N/A" must immediately follow the \b-e\b option flag; \b-E\b follows"
1N/A" standard option syntax.]:?[string]"
1N/A"[i:insert|replace?Replace occurences of \astring\a in the command"
1N/A" arguments with names read from the standard input. Implies"
1N/A" \b--exit\b and \b--lines=1\b. For backwards compatibility \astring\a"
1N/A" must immediately follow the \b-i\b option flag; \b-I\b follows"
1N/A" standard option syntax.]:?[string:={}]"
1N/A"[l:lines|max-lines?Use at most \alines\a lines from the standard input."
1N/A" Lines with trailing blanks logically continue onto the"
1N/A" next line. For backwards compatibility \alines\a"
1N/A" must immediately follow the \b-l\b option flag; \b-L\b follows"
1N/A" standard option syntax.]#?[lines:=1]"
1N/A"[n:args|max-args?Use at most \aargs\a arguments per command line."
1N/A" Fewer than \aargs\a will be used if \b--size\b is exceeded.]#[args]"
1N/A"[p:interactive|prompt?Prompt to determine if each command should execute."
1N/A" A \by\b or \bY\b recsponse executes, otherwise the command is skipped."
1N/A" Implies \b--verbose\b.]"
1N/A"[N|0:null?The file name list is NUL terminated; there is no other special"
1N/A" treatment of the list.]"
1N/A"[s:size|max-chars?Use at most \achars\a characters per command. The default"
1N/A" is as large as possible.]#[chars]"
1N/A"[t:trace|verbose?Print the command line on the standard error"
1N/A" before executing it.]"
1N/A"[x:exit?Exit if \b--size\b is exceeded.]"
1N/A"[X:exact?If \b--args=\b\aargs\a was specified then terminate before the last"
1N/A" command if it would run with less than \aargs\a arguments.]"
1N/A"[z:nonempty|no-run-if-empty?If no file names are found then do not execute"
1N/A" the command. By default the command is executed at least once.]"
1N/A"[E?Equivalent to \b--eof=string\b.]:[string]"
1N/A"[I?Equivalent to \b--insert=string\b.]:[string]"
1N/A"[L?Equivalent to \b--lines=number\b.]#[number]"
1N/A
1N/A"\n"
1N/A"\n[ command [ argument ... ] ]\n"
1N/A"\n"
1N/A
1N/A"[+EXIT STATUS]{"
1N/A" [+0?All invocations of \acommand\a returned exit status 0.]"
1N/A" [+1-125?A command line meeting the specified requirements could not"
1N/A" be assembled, one or more of the invocations of \acommand\a"
1N/A" returned non-0 exit status, or some other error occurred.]"
1N/A" [+126?\acommand\a was found but could not be executed.]"
1N/A" [+127?\acommand\a was not found.]"
1N/A"}"
1N/A"[+SEE ALSO?\bfind\b(1), \btw\b(1)]"
1N/A;
1N/A
1N/A#include <ast.h>
1N/A#include <ctype.h>
1N/A#include <error.h>
1N/A
1N/A#include "cmdarg.h"
1N/A
1N/Aint
1N/Ab_xargs(int argc,register char *argv[], void* context)
1N/A{
1N/A register int c;
1N/A register int q;
1N/A register char* s;
1N/A register Sfio_t* sp;
1N/A register Cmdarg_t* cmd;
1N/A
1N/A int argmax = 0;
1N/A char* eof = "_";
1N/A int flags = CMD_EMPTY;
1N/A char* insert = 0;
1N/A int lines = 0;
1N/A size_t size = 0;
1N/A int term = -1;
1N/A
1N/A NoP(argc);
1N/A error_info.id = "xargs";
1N/A for (;;)
1N/A {
1N/A switch (optget(argv, usage))
1N/A {
1N/A case 'e':
1N/A /*
1N/A * backwards compatibility requires no space between
1N/A * option and value
1N/A */
1N/A
1N/A if (opt_info.arg == argv[opt_info.index - 1])
1N/A {
1N/A opt_info.arg = 0;
1N/A opt_info.index--;
1N/A }
1N/A /*FALLTHROUGH*/
1N/A case 'E':
1N/A eof = opt_info.arg;
1N/A continue;
1N/A case 'i':
1N/A /*
1N/A * backwards compatibility requires no space between
1N/A * option and value
1N/A */
1N/A
1N/A if (opt_info.arg == argv[opt_info.index - 1])
1N/A {
1N/A opt_info.arg = 0;
1N/A opt_info.index--;
1N/A }
1N/A /*FALLTHROUGH*/
1N/A case 'I':
1N/A insert = opt_info.arg ? opt_info.arg : "{}";
1N/A flags |= CMD_INSERT;
1N/A term = '\n';
1N/A continue;
1N/A case 'l':
1N/A /*
1N/A * backwards compatibility requires no space between
1N/A * option and value
1N/A */
1N/A
1N/A if (opt_info.arg == argv[opt_info.index - 1])
1N/A {
1N/A opt_info.arg = 0;
1N/A opt_info.index--;
1N/A }
1N/A /*FALLTHROUGH*/
1N/A case 'L':
1N/A argmax = opt_info.num ? opt_info.num : 1;
1N/A lines = 1;
1N/A continue;
1N/A case 'n':
1N/A argmax = opt_info.num;
1N/A continue;
1N/A case 'p':
1N/A flags |= CMD_QUERY;
1N/A continue;
1N/A case 's':
1N/A size = opt_info.num;
1N/A continue;
1N/A case 't':
1N/A flags |= CMD_TRACE;
1N/A continue;
1N/A case 'x':
1N/A flags |= CMD_MINIMUM;
1N/A continue;
1N/A case 'z':
1N/A flags &= ~CMD_EMPTY;
1N/A continue;
1N/A case 'D':
1N/A error_info.trace = -opt_info.num;
1N/A continue;
1N/A case 'N':
1N/A term = 0;
1N/A continue;
1N/A case 'X':
1N/A flags |= CMD_EXACT;
1N/A continue;
1N/A case '?':
1N/A error(ERROR_USAGE|4, "%s", opt_info.arg);
1N/A continue;
1N/A case ':':
1N/A error(2, "%s", opt_info.arg);
1N/A continue;
1N/A }
1N/A break;
1N/A }
1N/A argv += opt_info.index;
1N/A if (error_info.errors)
1N/A error(ERROR_USAGE|4, "%s", optusage(NiL));
1N/A if (!(cmd = cmdopen(argv, argmax, size, insert, flags)))
1N/A error(ERROR_SYSTEM|3, "out of space [cmd]");
1N/A if (!(sp = sfstropen()))
1N/A error(ERROR_SYSTEM|3, "out of space [arg]");
1N/A sfopen(sfstdin, NiL, "rt");
1N/A error_info.line = 1;
1N/A if (term >= 0)
1N/A {
1N/A while (s = sfgetr(sfstdin, term, 0))
1N/A {
1N/A error_info.line++;
1N/A if ((c = sfvalue(sfstdin) - 1) && (s[c-1] != '\r' || --c))
1N/A cmdarg(cmd, s, c);
1N/A }
1N/A if (sfvalue(sfstdin) > 0)
1N/A error(2, "last argument incomplete");
1N/A }
1N/A else
1N/A for (;;)
1N/A {
1N/A switch (c = sfgetc(sfstdin))
1N/A {
1N/A case '"':
1N/A case '\'':
1N/A q = c;
1N/A while ((c = sfgetc(sfstdin)) != q)
1N/A {
1N/A if (c == EOF)
1N/A goto arg;
1N/A if (c == '\n')
1N/A {
1N/A error(1, "missing %c quote", q);
1N/A error_info.line++;
1N/A goto arg;
1N/A }
1N/A sfputc(sp, c);
1N/A }
1N/A continue;
1N/A case '\\':
1N/A if ((c = sfgetc(sfstdin)) == EOF)
1N/A {
1N/A if (sfstrtell(sp))
1N/A goto arg;
1N/A break;
1N/A }
1N/A if (c == '\n')
1N/A error_info.line++;
1N/A sfputc(sp, c);
1N/A continue;
1N/A case EOF:
1N/A if (sfstrtell(sp))
1N/A goto arg;
1N/A break;
1N/A case '\n':
1N/A error_info.line++;
1N/A arg:
1N/A c = sfstrtell(sp);
1N/A if (!(s = sfstruse(sp)))
1N/A error(ERROR_SYSTEM|3, "out of space");
1N/A if (eof && streq(s, eof))
1N/A break;
1N/A if (c || insert)
1N/A {
1N/A if (lines && c > 1 && isspace(s[c - 2]))
1N/A cmd->argcount--;
1N/A cmdarg(cmd, s, c);
1N/A }
1N/A continue;
1N/A default:
1N/A if (isspace(c))
1N/A goto arg;
1N/A sfputc(sp, c);
1N/A continue;
1N/A }
1N/A break;
1N/A }
1N/A if (sferror(sfstdin))
1N/A error(ERROR_SYSTEM|2, "input read error");
1N/A cmdclose(cmd);
1N/A return(error_info.errors != 0);
1N/A}