Commit | Line | Data |
---|---|---|
c599959c KB |
1 | /*- |
2 | * Copyright (c) 1990 The Regents of the University of California. | |
3 | * All rights reserved. | |
4 | * | |
5 | * This code is derived from software contributed to Berkeley by | |
6 | * John B. Roll Jr. | |
7 | * | |
8 | * %sccs.include.redist.c% | |
9 | */ | |
10 | ||
11 | #ifndef lint | |
12 | char copyright[] = | |
13 | "@(#) Copyright (c) 1990 The Regents of the University of California.\n\ | |
14 | All rights reserved.\n"; | |
15 | #endif /* not lint */ | |
16 | ||
17 | #ifndef lint | |
d777ab9d | 18 | static char sccsid[] = "@(#)xargs.c 5.5 (Berkeley) %G%"; |
c599959c KB |
19 | #endif /* not lint */ |
20 | ||
21 | #include <sys/types.h> | |
22 | #include <sys/wait.h> | |
23 | #include <errno.h> | |
24 | #include <stdio.h> | |
38dde0cd | 25 | #include <string.h> |
c599959c KB |
26 | #include <limits.h> |
27 | #include "pathnames.h" | |
28 | ||
29 | #define DEF_ARGC 255 | |
30 | ||
31 | int tflag; | |
32 | ||
33 | main(argc, argv) | |
34 | int argc; | |
35 | char **argv; | |
36 | { | |
37 | extern int errno, optind; | |
38 | extern char *optarg; | |
39 | register int ch; | |
40 | register char *p, *bp, *endbp, **bxp, **endxp, **xp; | |
41 | int cnt, indouble, insingle, nargs, nline; | |
42 | char *mark, *prog, **xargs, *malloc(); | |
43 | ||
44 | nargs = DEF_ARGC; | |
d777ab9d | 45 | nline = _POSIX2_LINE_MAX; |
c599959c KB |
46 | |
47 | while ((ch = getopt(argc, argv, "n:s:t")) != EOF) | |
48 | switch(ch) { | |
49 | case 'n': | |
50 | if ((nargs = atoi(optarg)) <= 0) { | |
51 | (void)fprintf(stderr, | |
52 | "xargs: bad argument count.\n"); | |
53 | exit(1); | |
54 | } | |
55 | break; | |
56 | case 's': | |
57 | if ((nline = atoi(optarg)) <= 0) { | |
58 | (void)fprintf(stderr, | |
59 | "xargs: bad command length.\n"); | |
60 | exit(1); | |
61 | } | |
62 | break; | |
63 | case 't': | |
64 | tflag = 1; | |
65 | break; | |
66 | case '?': | |
67 | default: | |
68 | usage(); | |
69 | } | |
70 | argc -= optind; | |
71 | argv += optind; | |
72 | ||
73 | /* room for the command, leftover arguments and trailing NULL */ | |
74 | if (!(xargs = | |
75 | (char **)malloc((u_int)(nargs + argc + 2) * sizeof(char **)))) | |
76 | enomem(); | |
77 | ||
78 | if (!(bp = malloc((u_int)nline + 1))) | |
79 | enomem(); | |
80 | ||
81 | xp = xargs + 1; | |
82 | if (!*argv) | |
83 | prog = _PATH_ECHO; | |
84 | else { | |
85 | prog = *argv; | |
86 | while (*++argv) | |
87 | *xp++ = *argv; | |
88 | } | |
89 | ||
90 | if (xargs[0] = rindex(prog, '/')) | |
91 | ++xargs[0]; | |
92 | else | |
93 | xargs[0] = prog; | |
94 | ||
95 | /* set up the pointers into the buffer and the arguments */ | |
96 | *(endxp = (bxp = xp) + nargs) = NULL; | |
97 | endbp = (mark = p = bp) + nline; | |
98 | ||
99 | insingle = indouble = 0; | |
100 | for (;;) | |
101 | switch(ch = getchar()) { | |
102 | case EOF: | |
8add0d2b | 103 | if (p == bp) /* nothing to display */ |
c599959c | 104 | exit(0); |
8add0d2b KB |
105 | if (mark == p) { /* nothing since last arg end */ |
106 | run(prog, xargs); | |
107 | exit(0); | |
108 | } | |
c599959c KB |
109 | goto addarg; |
110 | case ' ': | |
111 | case '\t': | |
112 | if (insingle || indouble) | |
113 | goto addch; | |
114 | goto addarg; | |
115 | case '\n': | |
116 | if (mark == p) /* empty line */ | |
117 | continue; | |
118 | addarg: *xp++ = mark; | |
119 | *p++ = '\0'; | |
120 | if (xp == endxp || p >= endbp || ch == EOF) { | |
121 | if (insingle || indouble) { | |
122 | (void)fprintf(stderr, | |
123 | "xargs: unterminated quote.\n"); | |
124 | exit(1); | |
125 | } | |
126 | run(prog, xargs); | |
127 | if (ch == EOF) | |
128 | exit(0); | |
129 | p = bp; | |
130 | xp = bxp; | |
131 | } | |
132 | mark = p; | |
133 | break; | |
134 | case '\'': | |
135 | if (indouble) | |
136 | goto addch; | |
137 | insingle = !insingle; | |
138 | break; | |
139 | case '"': | |
140 | if (insingle) | |
141 | goto addch; | |
142 | indouble = !indouble; | |
143 | break; | |
144 | case '\\': | |
145 | if ((ch = getchar()) == EOF) | |
146 | ch = '\\'; | |
147 | if (ch == '\n') { | |
148 | (void)fprintf(stderr, | |
149 | "xargs: newline may not be escaped.\n"); | |
150 | exit(1); | |
151 | } | |
152 | /* FALLTHROUGH */ | |
153 | default: | |
154 | addch: if (p != endbp) { | |
155 | *p++ = ch; | |
156 | continue; | |
157 | } | |
158 | if (xp == bxp) { | |
159 | (void)fprintf(stderr, | |
160 | "xargs: argument too large.\n"); | |
161 | exit(1); | |
162 | } | |
163 | *xp = NULL; | |
164 | run(prog, xargs); | |
165 | cnt = endbp - mark; | |
166 | bcopy(mark, bp, cnt); | |
167 | p = (mark = bp) + cnt; | |
168 | *p++ = ch; | |
169 | xp = bxp; | |
170 | break; | |
171 | } | |
172 | /* NOTREACHED */ | |
173 | } | |
174 | ||
175 | run(prog, argv) | |
176 | char *prog, **argv; | |
177 | { | |
178 | union wait pstat; | |
179 | pid_t pid, waitpid(); | |
180 | char **p; | |
181 | ||
182 | if (tflag) { | |
183 | (void)fprintf(stderr, "%s", *argv); | |
184 | for (p = argv + 1; *p; ++p) | |
185 | (void)fprintf(stderr, " %s", *p); | |
186 | (void)fprintf(stderr, "\n"); | |
187 | (void)fflush(stderr); | |
188 | } | |
189 | switch(pid = vfork()) { | |
190 | case -1: | |
191 | (void)fprintf(stderr, | |
192 | "xargs: vfork: %s.\n", strerror(errno)); | |
193 | exit(1); | |
194 | case 0: | |
195 | execvp(prog, argv); | |
196 | (void)fprintf(stderr, | |
197 | "xargs: %s: %s.\n", prog, strerror(errno)); | |
198 | _exit(1); | |
199 | } | |
200 | pid = waitpid(pid, &pstat, 0); | |
201 | if (pid == -1) { | |
202 | (void)fprintf(stderr, | |
203 | "xargs: waitpid: %s.\n", strerror(errno)); | |
204 | exit(1); | |
205 | } | |
206 | if (pstat.w_status) | |
207 | exit(1); | |
208 | } | |
209 | ||
210 | enomem() | |
211 | { | |
212 | (void)fprintf(stderr, "xargs: %s.\n", strerror(ENOMEM)); | |
213 | exit(1); | |
214 | } | |
215 | ||
216 | usage() | |
217 | { | |
218 | (void)fprintf(stderr, | |
219 | "xargs: [-t] [-n number] [-s size] [utility [argument ...]]\n"); | |
220 | exit(1); | |
221 | } |