1 /* xargs.c - Run command with arguments taken from stdin.
3 * Copyright 2011 Rob Landley <rob@landley.net>
5 * See http://opengroup.org/onlinepubs/9699919799/utilities/xargs.html
7 * TODO: Rich's whitespace objection, env size isn't fixed anymore.
9 USE_XARGS(NEWTOY(xargs, "^I:E:L#ptxrn#<1s#0", TOYFLAG_USR|TOYFLAG_BIN))
15 usage: xargs [-ptxr0] [-s NUM] [-n NUM] [-L NUM] [-E STR] COMMAND...
17 Run command line one or more times, appending arguments from stdin.
19 If command exits with 255, don't launch another even if arguments remain.
21 -s Size in bytes per command line
22 -n Max number of arguments per command
23 -0 Each argument is NULL terminated, no whitespace or quote processing
24 #-p Prompt for y/n from tty before running each command
25 #-t Trace, print command line to stderr
26 #-x Exit if can't fit everything in one command
27 #-r Don't run command with empty input
28 #-L Max number of lines of input per command
29 -E stop at line matching string
32 bool "TODO xargs pedantic posix compatability"
36 This version supports insane posix whitespace handling rendered obsolete
54 // If out==NULL count TT.bytes and TT.entries, stopping at max.
55 // Otherwise, fill out out[]
57 // Returning NULL means need more data.
58 // Returning char * means hit data limits, start of data left over
59 // Returning 1 means hit data limits, but consumed all data
60 // Returning 2 means hit -E eofstr
62 static char *handle_entries(char *data, char **entry)
67 // Chop up whitespace delimited string into args
76 if (TT.max_entries && TT.entries >= TT.max_entries)
77 return *s ? s : (char *)1;
83 if (++TT.bytes >= TT.max_bytes && TT.max_bytes) return save;
84 if (!*s || isspace(*s)) break;
89 if (len == strlen(TT.eofstr) && !strncmp(save, TT.eofstr, len))
92 if (entry) entry[TT.entries] = save;
98 TT.bytes += strlen(data)+1;
99 if (TT.max_bytes && TT.bytes >= TT.max_bytes) return data;
100 if (TT.max_entries && TT.entries >= TT.max_entries)
102 if (entry) entry[TT.entries] = data;
109 void xargs_main(void)
111 struct double_list *dlist = NULL, *dtemp;
112 int entries, bytes, done = 0, status;
113 char *data = NULL, **out;
116 if (!(toys.optflags & FLAG_0)) TT.delim = '\n';
118 // If no optargs, call echo.
121 *(toys.optargs = xzalloc(2*sizeof(char *)))="echo";
125 for (entries = 0, bytes = -1; entries < toys.optc; entries++, bytes++)
126 bytes += strlen(toys.optargs[entries]);
128 // Loop through exec chunks.
129 while (data || !done) {
133 // Loop reading input
139 l = getdelim(&data, (size_t *)&l, TT.delim, stdin);
147 dlist_add(&dlist, data);
150 data = handle_entries(data, NULL);
152 if (data == (char *)2) done++;
153 if ((long)data <= 2) data = 0;
154 else data = xstrdup(data);
159 // Accumulate cally thing
161 if (data && !TT.entries) error_exit("argument too long");
162 out = xzalloc((entries+TT.entries+1)*sizeof(char *));
164 // Fill out command line to exec
165 memcpy(out, toys.optargs, entries*sizeof(char *));
168 if (dlist) dlist->prev->next = 0;
169 for (dtemp = dlist; dtemp; dtemp = dtemp->next)
170 handle_entries(dtemp->data, out+entries);
172 if (!(pid = XVFORK())) {
174 open("/dev/null", O_RDONLY);
177 waitpid(pid, &status, 0);
178 status = WIFEXITED(status) ? WEXITSTATUS(status) : WTERMSIG(status)+127;
180 // Abritrary number of execs, can't just leak memory each time...
182 struct double_list *dtemp = dlist->next;