Introduction
Introduction Statistics Contact Development Disclaimer Help
xargs.c - sbase - suckless unix tools
git clone git://git.suckless.org/sbase
Log
Files
Refs
README
LICENSE
---
xargs.c (4934B)
---
1 /* See LICENSE file for copyright and license details. */
2 #include <sys/wait.h>
3
4 #include <errno.h>
5 #include <limits.h>
6 #include <stdint.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <unistd.h>
11
12 #include "util.h"
13
14 #define NARGS 10000
15
16 static int inputc(void);
17 static void fillargbuf(int);
18 static int eatspace(void);
19 static int parsequote(int);
20 static int parseescape(void);
21 static char *poparg(void);
22 static void waitchld(void);
23 static void spawn(void);
24
25 static size_t argbsz;
26 static size_t argbpos;
27 static size_t maxargs = 0;
28 static int nerrors = 0;
29 static int rflag = 0, nflag = 0, tflag = 0, xflag = 0, Iflag = 0;
30 static char *argb;
31 static char *cmd[NARGS];
32 static char *eofstr;
33
34 static int
35 inputc(void)
36 {
37 int ch;
38
39 ch = getc(stdin);
40 if (ch == EOF && ferror(stdin))
41 eprintf("getc <stdin>:");
42
43 return ch;
44 }
45
46 static void
47 fillargbuf(int ch)
48 {
49 if (argbpos >= argbsz) {
50 argbsz = argbpos == 0 ? 1 : argbsz * 2;
51 argb = erealloc(argb, argbsz);
52 }
53 argb[argbpos] = ch;
54 }
55
56 static int
57 eatspace(void)
58 {
59 int ch;
60
61 while ((ch = inputc()) != EOF) {
62 switch (ch) {
63 case ' ': case '\t': case '\n':
64 break;
65 default:
66 ungetc(ch, stdin);
67 return ch;
68 }
69 }
70 return -1;
71 }
72
73 static int
74 parsequote(int q)
75 {
76 int ch;
77
78 while ((ch = inputc()) != EOF) {
79 if (ch == q)
80 return 0;
81 if (ch != '\n') {
82 fillargbuf(ch);
83 argbpos++;
84 }
85 }
86
87 return -1;
88 }
89
90 static int
91 parseescape(void)
92 {
93 int ch;
94
95 if ((ch = inputc()) != EOF) {
96 fillargbuf(ch);
97 argbpos++;
98 return ch;
99 }
100
101 return -1;
102 }
103
104 static char *
105 poparg(void)
106 {
107 int ch;
108
109 argbpos = 0;
110 if (eatspace() < 0)
111 return NULL;
112 while ((ch = inputc()) != EOF) {
113 switch (ch) {
114 case ' ':
115 case '\t':
116 if (Iflag)
117 goto fill;
118 case '\n':
119 goto out;
120 case '\'':
121 if (parsequote('\'') < 0)
122 eprintf("unterminated single quote\n");
123 break;
124 case '\"':
125 if (parsequote('\"') < 0)
126 eprintf("unterminated double quote\n");
127 break;
128 case '\\':
129 if (parseescape() < 0)
130 eprintf("backslash at EOF\n");
131 break;
132 default:
133 fill:
134 fillargbuf(ch);
135 argbpos++;
136 break;
137 }
138 }
139 out:
140 fillargbuf('\0');
141
142 return (eofstr && !strcmp(argb, eofstr)) ? NULL : argb;
143 }
144
145 static void
146 waitchld(void)
147 {
148 int status;
149
150 wait(&status);
151 if (WIFEXITED(status)) {
152 if (WEXITSTATUS(status) == 255)
153 exit(124);
154 if (WEXITSTATUS(status) == 127 ||
155 WEXITSTATUS(status) == 126)
156 exit(WEXITSTATUS(status));
157 if (status)
158 nerrors++;
159 }
160 if (WIFSIGNALED(status))
161 exit(125);
162 }
163
164 static void
165 spawn(void)
166 {
167 int savederrno;
168 int first = 1;
169 char **p;
170
171 if (tflag) {
172 for (p = cmd; *p; p++) {
173 if (!first)
174 fputc(' ', stderr);
175 fputs(*p, stderr);
176 first = 0;
177 }
178 fputc('\n', stderr);
179 }
180
181 switch (fork()) {
182 case -1:
183 eprintf("fork:");
184 case 0:
185 execvp(*cmd, cmd);
186 savederrno = errno;
187 weprintf("execvp %s:", *cmd);
188 _exit(126 + (savederrno == ENOENT));
189 }
190 waitchld();
191 }
192
193 static void
194 usage(void)
195 {
196 eprintf("usage: %s [-rtx] [-E eofstr] [-n num] [-s num] "
197 "[cmd [arg ...]]\n", argv0);
198 }
199
200 int
201 main(int argc, char *argv[])
202 {
203 int ret = 0, leftover = 0, i, j;
204 size_t argsz, argmaxsz;
205 size_t arglen, a;
206 char *arg = "";
207 char *replstr;
208
209 if ((argmaxsz = sysconf(_SC_ARG_MAX)) == (size_t)-1)
210 argmaxsz = _POSIX_ARG_MAX;
211 /* Leave some room for environment variables */
212 argmaxsz -= 4096;
213
214 ARGBEGIN {
215 case 'n':
216 nflag = 1;
217 maxargs = estrtonum(EARGF(usage()), 1, MIN(SIZE_MAX, LLO…
218 break;
219 case 'r':
220 rflag = 1;
221 break;
222 case 's':
223 argmaxsz = estrtonum(EARGF(usage()), 1, MIN(SIZE_MAX, LL…
224 break;
225 case 't':
226 tflag = 1;
227 break;
228 case 'x':
229 xflag = 1;
230 break;
231 case 'E':
232 eofstr = EARGF(usage());
233 break;
234 case 'I':
235 Iflag = 1;
236 xflag = 1;
237 nflag = 1;
238 maxargs = 1;
239 replstr = EARGF(usage());
240 break;
241 default:
242 usage();
243 } ARGEND
244
245 do {
246 argsz = 0; i = 0; a = 0;
247 if (argc) {
248 for (; i < argc; i++) {
249 cmd[i] = estrdup(argv[i]);
250 argsz += strlen(cmd[i]) + 1;
251 }
252 } else {
253 cmd[i] = estrdup("/bin/echo");
254 argsz += strlen("/bin/echo") + 1;
255 i++;
256 }
257 while (leftover || (arg = poparg())) {
258 arglen = strlen(arg);
259 if (argsz + arglen >= argmaxsz || i >= NARGS - 1…
260 if (arglen >= argmaxsz) {
261 weprintf("insufficient argument …
262 if (xflag)
263 exit(1);
264 }
265 leftover = 1;
266 break;
267 }
268
269 if (!Iflag) {
270 cmd[i] = estrdup(arg);
271 argsz += arglen + 1;
272 } else {
273 for (j = 1; j < i; j++) {
274 char *p = cmd[j];
275 argsz -= strlen(cmd[j]);
276 strnsubst(&cmd[j], replstr, arg,…
277 argsz += strlen(cmd[j]);
278 free(p);
279 }
280 }
281
282 i++;
283 a++;
284 leftover = 0;
285 if (nflag && a >= maxargs)
286 break;
287 }
288 cmd[i] = NULL;
289 if (a >= maxargs && nflag)
290 spawn();
291 else if (!a || (i == 1 && rflag))
292 ;
293 else
294 spawn();
295 for (; i >= 0; i--)
296 free(cmd[i]);
297 } while (arg);
298
299 free(argb);
300
301 if (nerrors || (fshut(stdin, "<stdin>") | fshut(stdout, "<stdout…
302 ret = 123;
303
304 return ret;
305 }
You are viewing proxied material from suckless.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.