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