Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/tw/xargs.c
1808 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1989-2012 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* Glenn Fowler <[email protected]> *
18
* *
19
***********************************************************************/
20
#pragma prototyped
21
/*
22
* Glenn Fowler
23
* AT&T Research
24
*
25
* xargs -- construct arg list and exec -- use tw instead
26
*/
27
28
static const char usage[] =
29
"[-?\n@(#)$Id: xargs (AT&T Research) 2012-04-11 $\n]"
30
USAGE_LICENSE
31
"[+NAME?xargs - construct arg list and execute command]"
32
"[+DESCRIPTION?\bxargs\b constructs a command line consisting of the"
33
" \acommand\a and \aargument\a operands specified followed by as"
34
" many arguments read in sequence from standard input as will fit"
35
" in length and number constraints specified by the options and the"
36
" local system. \axargs\a executes the constructed command and waits"
37
" for its completion. This sequence is repeated until an end-of-file"
38
" condition is detected on standard input or an invocation of a"
39
" constructed command line returns an exit status of 255. If"
40
" \acommand\a is omitted then the equivalent of \b/bin/echo\b is used.]"
41
42
"[+?Arguments in the standard input must be separated by unquoted blank"
43
" characters, or unescaped blank characters or newline characters."
44
" A string of zero or more non-double-quote and non-newline characters"
45
" can be quoted by enclosing them in double-quotes. A string of zero or"
46
" more non-apostrophe and non-newline characters can be quoted by"
47
" enclosing them in apostrophes. Any unquoted character can be escaped"
48
" by preceding it with a backslash. The utility will be executed one"
49
" or more times until the end-of-file is reached. The results are"
50
" unspecified if \acommand\a attempts to read from its standard input.]"
51
52
"[e:eof?Set the end of file string. The first input line matching this string"
53
" terminates the input list. There is no eof string if \astring\a is"
54
" omitted. The default eof string is \b_\b if neither \b--eof\b nor"
55
" \b-E\b are specified. For backwards compatibility \astring\a"
56
" must immediately follow the \b-e\b option flag; \b-E\b follows"
57
" standard option syntax.]:?[string]"
58
"[i:insert|replace?Replace occurences of \astring\a in the command"
59
" arguments with names read from the standard input. Implies"
60
" \b--exit\b and \b--lines=1\b. For backwards compatibility \astring\a"
61
" must immediately follow the \b-i\b option flag; \b-I\b follows"
62
" standard option syntax.]:?[string:={}]"
63
"[l:lines|max-lines?Use at most \alines\a lines from the standard input."
64
" Lines with trailing blanks logically continue onto the"
65
" next line. For backwards compatibility \alines\a"
66
" must immediately follow the \b-l\b option flag; \b-L\b follows"
67
" standard option syntax.]#?[lines:=1]"
68
"[n:args|max-args?Use at most \aargs\a arguments per command line."
69
" Fewer than \aargs\a will be used if \b--size\b is exceeded.]#[args]"
70
"[p:interactive|prompt?Prompt to determine if each command should execute."
71
" A \by\b or \bY\b recsponse executes, otherwise the command is skipped."
72
" Implies \b--verbose\b.]"
73
"[N|0:null?The file name list is NUL terminated; there is no other special"
74
" treatment of the list.]"
75
"[s:size|max-chars?Use at most \achars\a characters per command. The default"
76
" is as large as possible.]#[chars]"
77
"[t:trace|verbose?Print the command line on the standard error"
78
" before executing it.]"
79
"[x:exit?Exit if \b--size\b is exceeded.]"
80
"[X:exact?If \b--args=\b\aargs\a was specified then terminate before the last"
81
" command if it would run with less than \aargs\a arguments.]"
82
"[z:nonempty|no-run-if-empty?If no file names are found then do not execute"
83
" the command. By default the command is executed at least once.]"
84
"[E?Equivalent to \b--eof=string\b.]:[string]"
85
"[I?Equivalent to \b--insert=string\b.]:[string]"
86
"[L?Equivalent to \b--lines=number\b.]#[number]"
87
88
"\n"
89
"\n[ command [ argument ... ] ]\n"
90
"\n"
91
92
"[+EXIT STATUS]{"
93
" [+0?All invocations of \acommand\a returned exit status 0.]"
94
" [+1-125?A command line meeting the specified requirements could not"
95
" be assembled, one or more of the invocations of \acommand\a"
96
" returned non-0 exit status, or some other error occurred.]"
97
" [+126?\acommand\a was found but could not be executed.]"
98
" [+127?\acommand\a was not found.]"
99
"}"
100
"[+SEE ALSO?\bfind\b(1), \btw\b(1)]"
101
;
102
103
#include <ast.h>
104
#include <ctype.h>
105
#include <error.h>
106
107
#include "cmdarg.h"
108
109
int
110
main(int argc, register char** argv)
111
{
112
register int c;
113
register int q;
114
register char* s;
115
register Sfio_t* sp;
116
register Cmdarg_t* cmd;
117
118
int argmax = 0;
119
char* eof = "_";
120
char* insert = 0;
121
int lines = 0;
122
size_t size = 0;
123
int term = -1;
124
125
Cmddisc_t disc;
126
127
NoP(argc);
128
CMDDISC(&disc, CMD_EMPTY|CMD_EXIT, errorf);
129
error_info.id = "xargs";
130
for (;;)
131
{
132
switch (optget(argv, usage))
133
{
134
case 'e':
135
/*
136
* backwards compatibility requires no space between
137
* option and value
138
*/
139
140
if (opt_info.arg == argv[opt_info.index - 1])
141
{
142
opt_info.arg = 0;
143
opt_info.index--;
144
}
145
/*FALLTHROUGH*/
146
case 'E':
147
eof = opt_info.arg;
148
continue;
149
case 'i':
150
/*
151
* backwards compatibility requires no space between
152
* option and value
153
*/
154
155
if (opt_info.arg == argv[opt_info.index - 1])
156
{
157
opt_info.arg = 0;
158
opt_info.index--;
159
}
160
/*FALLTHROUGH*/
161
case 'I':
162
insert = opt_info.arg ? opt_info.arg : "{}";
163
disc.flags |= CMD_INSERT;
164
term = '\n';
165
continue;
166
case 'l':
167
/*
168
* backwards compatibility requires no space between
169
* option and value
170
*/
171
172
if (opt_info.arg == argv[opt_info.index - 1])
173
{
174
opt_info.arg = 0;
175
opt_info.index--;
176
}
177
/*FALLTHROUGH*/
178
case 'L':
179
argmax = opt_info.num ? opt_info.num : 1;
180
lines = 1;
181
continue;
182
case 'n':
183
argmax = opt_info.num;
184
continue;
185
case 'p':
186
disc.flags |= CMD_QUERY;
187
continue;
188
case 's':
189
size = opt_info.num;
190
continue;
191
case 't':
192
disc.flags |= CMD_TRACE;
193
continue;
194
case 'x':
195
disc.flags |= CMD_MINIMUM;
196
continue;
197
case 'z':
198
disc.flags &= ~CMD_EMPTY;
199
continue;
200
case 'D':
201
error_info.trace = -opt_info.num;
202
continue;
203
case 'N':
204
term = 0;
205
continue;
206
case 'X':
207
disc.flags |= CMD_EXACT;
208
continue;
209
case '?':
210
error(ERROR_USAGE|4, "%s", opt_info.arg);
211
continue;
212
case ':':
213
error(2, "%s", opt_info.arg);
214
continue;
215
}
216
break;
217
}
218
argv += opt_info.index;
219
if (error_info.errors)
220
error(ERROR_USAGE|4, "%s", optusage(NiL));
221
if (!(cmd = cmdopen(argv, argmax, size, insert, &disc)))
222
error(ERROR_SYSTEM|3, "out of space [cmd]");
223
if (!(sp = sfstropen()))
224
error(ERROR_SYSTEM|3, "out of space [arg]");
225
sfopen(sfstdin, NiL, "rt");
226
error_info.line = 1;
227
if (term >= 0)
228
{
229
while (s = sfgetr(sfstdin, term, 0))
230
{
231
error_info.line++;
232
if ((c = sfvalue(sfstdin) - 1) && (s[c-1] != '\r' || --c))
233
cmdarg(cmd, s, c);
234
}
235
if (sfvalue(sfstdin) > 0)
236
error(2, "last argument incomplete");
237
}
238
else
239
for (;;)
240
{
241
switch (c = sfgetc(sfstdin))
242
{
243
case '"':
244
case '\'':
245
q = c;
246
while ((c = sfgetc(sfstdin)) != q)
247
{
248
if (c == EOF)
249
goto arg;
250
if (c == '\n')
251
{
252
error(1, "missing %c quote", q);
253
error_info.line++;
254
goto arg;
255
}
256
sfputc(sp, c);
257
}
258
continue;
259
case '\\':
260
if ((c = sfgetc(sfstdin)) == EOF)
261
{
262
if (sfstrtell(sp))
263
goto arg;
264
break;
265
}
266
if (c == '\n')
267
error_info.line++;
268
sfputc(sp, c);
269
continue;
270
case EOF:
271
if (sfstrtell(sp))
272
goto arg;
273
break;
274
case '\n':
275
error_info.line++;
276
arg:
277
c = sfstrtell(sp);
278
if (!(s = sfstruse(sp)))
279
error(ERROR_SYSTEM|3, "out of space");
280
if (eof && streq(s, eof))
281
break;
282
if (c || insert)
283
{
284
if (lines && c > 1 && isspace(s[c - 2]))
285
cmdarg(cmd, 0, -1);
286
cmdarg(cmd, s, c);
287
}
288
continue;
289
default:
290
if (isspace(c))
291
goto arg;
292
sfputc(sp, c);
293
continue;
294
}
295
break;
296
}
297
if (sferror(sfstdin))
298
error(ERROR_SYSTEM|2, "input read error");
299
cmdclose(cmd);
300
exit(error_info.errors != 0);
301
}
302
303