Commit | Line | Data |
---|---|---|
ecc449eb KB |
1 | /*- |
2 | * Copyright (c) 1980, 1991 The Regents of the University of California. | |
3 | * All rights reserved. | |
4 | * | |
5 | * %sccs.include.redist.c% | |
b79f4fa9 DF |
6 | */ |
7 | ||
35371dec | 8 | #ifndef lint |
37999c01 | 9 | static char sccsid[] = "@(#)glob.c 5.40 (Berkeley) %G%"; |
ecc449eb | 10 | #endif /* not lint */ |
9363f20d | 11 | |
b9c4f741 KB |
12 | #include <sys/param.h> |
13 | #include <glob.h> | |
14 | #include <errno.h> | |
15 | #include <stdlib.h> | |
16 | #include <string.h> | |
17 | #include <unistd.h> | |
4df6491c CZ |
18 | #if __STDC__ |
19 | # include <stdarg.h> | |
20 | #else | |
21 | # include <varargs.h> | |
22 | #endif | |
23 | ||
4d7b2685 KB |
24 | #include "csh.h" |
25 | #include "extern.h" | |
b6e604fd | 26 | |
454c2aa3 | 27 | static int noglob; |
c8fda9bd | 28 | static int pargsiz, gargsiz; |
6e37afca | 29 | |
b6e604fd | 30 | /* |
c8fda9bd | 31 | * Values for gflag |
b6e604fd | 32 | */ |
6e37afca KB |
33 | #define G_NONE 0 /* No globbing needed */ |
34 | #define G_GLOB 1 /* string contains *?[] characters */ | |
35 | #define G_CSH 2 /* string contains ~`{ characters */ | |
36 | ||
37 | #define GLOBSPACE 100 /* Alloc increment */ | |
b6e604fd | 38 | |
c8fda9bd KB |
39 | #define LBRC '{' |
40 | #define RBRC '}' | |
41 | #define LBRK '[' | |
42 | #define RBRK ']' | |
c8fda9bd | 43 | #define EOS '\0' |
6e37afca | 44 | |
0aec749d | 45 | Char **gargv = NULL; |
6e37afca | 46 | long gargc = 0; |
0aec749d | 47 | Char **pargv = NULL; |
6e37afca | 48 | long pargc = 0; |
b6e604fd | 49 | |
291a8333 | 50 | /* |
c8fda9bd | 51 | * globbing is now done in two stages. In the first pass we expand |
6e37afca | 52 | * csh globbing idioms ~`{ and then we proceed doing the normal |
c8fda9bd KB |
53 | * globbing if needed ?*[ |
54 | * | |
55 | * Csh type globbing is handled in globexpand() and the rest is | |
1fedb07b | 56 | * handled in glob() which is part of the 4.4BSD libc. |
6e37afca | 57 | * |
291a8333 | 58 | */ |
0aec749d CZ |
59 | static Char *globtilde __P((Char **, Char *)); |
60 | static Char **libglob __P((Char **)); | |
61 | static Char **globexpand __P((Char **)); | |
62 | static int globbrace __P((Char *, Char *, Char ***)); | |
e71234c5 | 63 | static void expbrace __P((Char ***, Char ***, int)); |
1afb645a | 64 | static int pmatch __P((Char *, Char *)); |
0aec749d CZ |
65 | static void pword __P((void)); |
66 | static void psave __P((int)); | |
67 | static void backeval __P((Char *, bool)); | |
6a422336 | 68 | |
b6e604fd | 69 | |
6e37afca | 70 | static Char * |
1fedb07b | 71 | globtilde(nv, s) |
6e37afca | 72 | Char **nv, *s; |
b6e604fd | 73 | { |
6e37afca KB |
74 | Char gbuf[MAXPATHLEN], *gstart, *b, *u, *e; |
75 | ||
76 | gstart = gbuf; | |
77 | *gstart++ = *s++; | |
78 | u = s; | |
c28e64a2 | 79 | for (b = gstart, e = &gbuf[MAXPATHLEN - 1]; |
6859ab7a | 80 | *s && *s != '/' && *s != ':' && b < e; |
c28e64a2 CL |
81 | *b++ = *s++) |
82 | continue; | |
6e37afca KB |
83 | *b = EOS; |
84 | if (gethdir(gstart)) { | |
85 | blkfree(nv); | |
86 | if (*gstart) | |
abf583a4 | 87 | stderror(ERR_UNKUSER, vis_str(gstart)); |
6e37afca KB |
88 | else |
89 | stderror(ERR_NOHOME); | |
90 | } | |
91 | b = &gstart[Strlen(gstart)]; | |
92 | while (*s) | |
93 | *b++ = *s++; | |
94 | *b = EOS; | |
95 | --u; | |
96 | xfree((ptr_t) u); | |
97 | return (Strsave(gstart)); | |
b6e604fd BJ |
98 | } |
99 | ||
c8fda9bd KB |
100 | static int |
101 | globbrace(s, p, bl) | |
6e37afca | 102 | Char *s, *p, ***bl; |
b6e604fd | 103 | { |
6e37afca KB |
104 | int i, len; |
105 | Char *pm, *pe, *lm, *pl; | |
106 | Char **nv, **vl; | |
107 | Char gbuf[MAXPATHLEN]; | |
108 | int size = GLOBSPACE; | |
109 | ||
110 | nv = vl = (Char **) xmalloc((size_t) sizeof(Char *) * size); | |
0aec749d | 111 | *vl = NULL; |
6e37afca KB |
112 | |
113 | len = 0; | |
114 | /* copy part up to the brace */ | |
115 | for (lm = gbuf, p = s; *p != LBRC; *lm++ = *p++) | |
116 | continue; | |
117 | ||
118 | /* check for balanced braces */ | |
119 | for (i = 0, pe = ++p; *pe; pe++) | |
120 | if (*pe == LBRK) { | |
121 | /* Ignore everything between [] */ | |
122 | for (++pe; *pe != RBRK && *pe != EOS; pe++) | |
b6e604fd | 123 | continue; |
6e37afca | 124 | if (*pe == EOS) { |
c8fda9bd | 125 | blkfree(nv); |
e71234c5 | 126 | return (-RBRK); |
6e37afca KB |
127 | } |
128 | } | |
129 | else if (*pe == LBRC) | |
130 | i++; | |
131 | else if (*pe == RBRC) { | |
132 | if (i == 0) | |
133 | break; | |
134 | i--; | |
b6e604fd | 135 | } |
b6e604fd | 136 | |
2f3717d9 | 137 | if (i != 0 || *pe == '\0') { |
6e37afca | 138 | blkfree(nv); |
2f3717d9 | 139 | return (-RBRC); |
6e37afca KB |
140 | } |
141 | ||
142 | for (i = 0, pl = pm = p; pm <= pe; pm++) | |
c8fda9bd KB |
143 | switch (*pm) { |
144 | case LBRK: | |
6e37afca KB |
145 | for (++pm; *pm != RBRK && *pm != EOS; pm++) |
146 | continue; | |
147 | if (*pm == EOS) { | |
0aec749d | 148 | *vl = NULL; |
6e37afca KB |
149 | blkfree(nv); |
150 | return (-RBRK); | |
151 | } | |
152 | break; | |
c8fda9bd | 153 | case LBRC: |
6e37afca KB |
154 | i++; |
155 | break; | |
c8fda9bd | 156 | case RBRC: |
6e37afca KB |
157 | if (i) { |
158 | i--; | |
159 | break; | |
160 | } | |
161 | /* FALLTHROUGH */ | |
b6e604fd | 162 | case ',': |
6e37afca | 163 | if (i && *pm == ',') |
c8fda9bd | 164 | break; |
6e37afca KB |
165 | else { |
166 | Char savec = *pm; | |
167 | ||
168 | *pm = EOS; | |
169 | (void) Strcpy(lm, pl); | |
170 | (void) Strcat(gbuf, pe + 1); | |
171 | *pm = savec; | |
172 | *vl++ = Strsave(gbuf); | |
173 | len++; | |
174 | pl = pm + 1; | |
175 | if (vl == &nv[size]) { | |
176 | size += GLOBSPACE; | |
177 | nv = (Char **) xrealloc((ptr_t) nv, (size_t) | |
178 | size * sizeof(Char *)); | |
179 | vl = &nv[size - GLOBSPACE]; | |
180 | } | |
181 | } | |
182 | break; | |
e71234c5 CZ |
183 | default: |
184 | break; | |
b6e604fd | 185 | } |
0aec749d | 186 | *vl = NULL; |
6e37afca KB |
187 | *bl = nv; |
188 | return (len); | |
b6e604fd BJ |
189 | } |
190 | ||
e71234c5 CZ |
191 | |
192 | static void | |
193 | expbrace(nvp, elp, size) | |
194 | Char ***nvp, ***elp; | |
195 | int size; | |
196 | { | |
197 | Char **vl, **el, **nv, *s; | |
198 | ||
199 | vl = nv = *nvp; | |
200 | if (elp != NULL) | |
201 | el = *elp; | |
202 | else | |
203 | for (el = vl; *el; el++) | |
204 | continue; | |
205 | ||
206 | for (s = *vl; s; s = *++vl) { | |
207 | Char *b; | |
208 | Char **vp, **bp; | |
209 | ||
210 | /* leave {} untouched for find */ | |
211 | if (s[0] == '{' && (s[1] == '\0' || (s[1] == '}' && s[2] == '\0'))) | |
212 | continue; | |
37999c01 | 213 | if ((b = Strchr(s, '{')) != NULL) { |
e71234c5 CZ |
214 | Char **bl; |
215 | int len; | |
216 | ||
217 | if ((len = globbrace(s, b, &bl)) < 0) { | |
218 | xfree((ptr_t) nv); | |
219 | stderror(ERR_MISSING, -len); | |
220 | } | |
221 | xfree((ptr_t) s); | |
222 | if (len == 1) { | |
223 | *vl-- = *bl; | |
224 | xfree((ptr_t) bl); | |
225 | continue; | |
226 | } | |
227 | len = blklen(bl); | |
228 | if (&el[len] >= &nv[size]) { | |
229 | int l, e; | |
230 | ||
231 | l = &el[len] - &nv[size]; | |
232 | size += GLOBSPACE > l ? GLOBSPACE : l; | |
233 | l = vl - nv; | |
234 | e = el - nv; | |
235 | nv = (Char **) xrealloc((ptr_t) nv, (size_t) | |
236 | size * sizeof(Char *)); | |
237 | vl = nv + l; | |
238 | el = nv + e; | |
239 | } | |
240 | vp = vl--; | |
241 | *vp = *bl; | |
242 | len--; | |
243 | for (bp = el; bp != vp; bp--) | |
244 | bp[len] = *bp; | |
245 | el += len; | |
246 | vp++; | |
247 | for (bp = bl + 1; *bp; *vp++ = *bp++) | |
248 | continue; | |
249 | xfree((ptr_t) bl); | |
250 | } | |
251 | ||
252 | } | |
253 | if (elp != NULL) | |
254 | *elp = el; | |
255 | *nvp = nv; | |
256 | } | |
257 | ||
6e37afca | 258 | static Char ** |
c8fda9bd | 259 | globexpand(v) |
6e37afca | 260 | Char **v; |
b6e604fd | 261 | { |
6e37afca KB |
262 | Char *s; |
263 | Char **nv, **vl, **el; | |
264 | int size = GLOBSPACE; | |
265 | ||
266 | ||
267 | nv = vl = (Char **) xmalloc((size_t) sizeof(Char *) * size); | |
0aec749d | 268 | *vl = NULL; |
6e37afca KB |
269 | |
270 | /* | |
271 | * Step 1: expand backquotes. | |
272 | */ | |
37999c01 | 273 | while ((s = *v++) != NULL) { |
6e37afca KB |
274 | if (Strchr(s, '`')) { |
275 | int i; | |
276 | ||
277 | (void) dobackp(s, 0); | |
278 | for (i = 0; i < pargc; i++) { | |
279 | *vl++ = pargv[i]; | |
280 | if (vl == &nv[size]) { | |
281 | size += GLOBSPACE; | |
282 | nv = (Char **) xrealloc((ptr_t) nv, | |
283 | (size_t) size * sizeof(Char *)); | |
284 | vl = &nv[size - GLOBSPACE]; | |
285 | } | |
286 | } | |
287 | xfree((ptr_t) pargv); | |
0aec749d | 288 | pargv = NULL; |
6e37afca KB |
289 | } |
290 | else { | |
291 | *vl++ = Strsave(s); | |
292 | if (vl == &nv[size]) { | |
293 | size += GLOBSPACE; | |
294 | nv = (Char **) xrealloc((ptr_t) nv, (size_t) | |
295 | size * sizeof(Char *)); | |
296 | vl = &nv[size - GLOBSPACE]; | |
297 | } | |
298 | } | |
299 | } | |
0aec749d | 300 | *vl = NULL; |
6e37afca KB |
301 | |
302 | if (noglob) | |
303 | return (nv); | |
304 | ||
305 | /* | |
306 | * Step 2: expand braces | |
307 | */ | |
308 | el = vl; | |
87ea45ed | 309 | expbrace(&nv, &el, size); |
6e37afca KB |
310 | |
311 | /* | |
312 | * Step 3: expand ~ | |
313 | */ | |
314 | vl = nv; | |
315 | for (s = *vl; s; s = *++vl) | |
316 | if (*s == '~') | |
317 | *vl = globtilde(nv, s); | |
318 | vl = nv; | |
319 | return (vl); | |
320 | } | |
b6e604fd | 321 | |
6e37afca KB |
322 | static Char * |
323 | handleone(str, vl, action) | |
324 | Char *str, **vl; | |
325 | int action; | |
326 | { | |
b6e604fd | 327 | |
6e37afca KB |
328 | Char *cp, **vlp = vl; |
329 | ||
330 | switch (action) { | |
331 | case G_ERROR: | |
abf583a4 | 332 | setname(vis_str(str)); |
6e37afca KB |
333 | blkfree(vl); |
334 | stderror(ERR_NAME | ERR_AMBIG); | |
335 | break; | |
336 | case G_APPEND: | |
337 | trim(vlp); | |
338 | str = Strsave(*vlp++); | |
339 | do { | |
340 | cp = Strspl(str, STRspace); | |
341 | xfree((ptr_t) str); | |
342 | str = Strspl(cp, *vlp); | |
343 | xfree((ptr_t) cp); | |
c8fda9bd | 344 | } |
6e37afca KB |
345 | while (*++vlp); |
346 | blkfree(vl); | |
347 | break; | |
348 | case G_IGNORE: | |
349 | str = Strsave(strip(*vlp)); | |
350 | blkfree(vl); | |
351 | break; | |
e71234c5 CZ |
352 | default: |
353 | break; | |
6e37afca KB |
354 | } |
355 | return (str); | |
356 | } | |
b6e604fd | 357 | |
6e37afca KB |
358 | static Char ** |
359 | libglob(vl) | |
360 | Char **vl; | |
361 | { | |
454c2aa3 | 362 | int gflgs = GLOB_QUOTE | GLOB_NOMAGIC; |
6e37afca KB |
363 | glob_t globv; |
364 | char *ptr; | |
454c2aa3 | 365 | int nonomatch = adrof(STRnonomatch) != 0, magic = 0, match = 0; |
6e37afca | 366 | |
8c76c883 CZ |
367 | if (!vl || !vl[0]) |
368 | return (vl); | |
369 | ||
6e37afca KB |
370 | globv.gl_offs = 0; |
371 | globv.gl_pathv = 0; | |
372 | globv.gl_pathc = 0; | |
454c2aa3 CZ |
373 | |
374 | if (nonomatch) | |
375 | gflgs |= GLOB_NOCHECK; | |
376 | ||
6e37afca KB |
377 | do { |
378 | ptr = short2qstr(*vl); | |
379 | switch (glob(ptr, gflgs, 0, &globv)) { | |
380 | case GLOB_ABEND: | |
abf583a4 | 381 | setname(vis_str(*vl)); |
6e37afca KB |
382 | stderror(ERR_NAME | ERR_GLOB); |
383 | /* NOTREACHED */ | |
384 | case GLOB_NOSPACE: | |
385 | stderror(ERR_NOMEM); | |
386 | /* NOTREACHED */ | |
387 | default: | |
388 | break; | |
b6e604fd | 389 | } |
454c2aa3 CZ |
390 | if (globv.gl_flags & GLOB_MAGCHAR) { |
391 | match |= (globv.gl_matchc != 0); | |
392 | magic = 1; | |
6e37afca KB |
393 | } |
394 | gflgs |= GLOB_APPEND; | |
395 | } | |
396 | while (*++vl); | |
c28e64a2 | 397 | vl = (globv.gl_pathc == 0 || (magic && !match && !nonomatch)) ? |
454c2aa3 | 398 | NULL : blk2short(globv.gl_pathv); |
6e37afca KB |
399 | globfree(&globv); |
400 | return (vl); | |
b6e604fd BJ |
401 | } |
402 | ||
6e37afca KB |
403 | Char * |
404 | globone(str, action) | |
405 | Char *str; | |
406 | int action; | |
b6e604fd | 407 | { |
6e37afca | 408 | Char *v[2], **vl, **vo; |
4aad0a53 | 409 | int gflg; |
b6e604fd | 410 | |
6e37afca KB |
411 | noglob = adrof(STRnoglob) != 0; |
412 | gflag = 0; | |
413 | v[0] = str; | |
414 | v[1] = 0; | |
415 | tglob(v); | |
4aad0a53 CZ |
416 | gflg = gflag; |
417 | if (gflg == G_NONE) | |
6e37afca | 418 | return (strip(Strsave(str))); |
b6e604fd | 419 | |
4aad0a53 | 420 | if (gflg & G_CSH) { |
6e37afca KB |
421 | /* |
422 | * Expand back-quote, tilde and brace | |
423 | */ | |
424 | vo = globexpand(v); | |
4aad0a53 | 425 | if (noglob || (gflg & G_GLOB) == 0) { |
6cc6e21d CZ |
426 | if (vo[0] == NULL) { |
427 | xfree((ptr_t) vo); | |
428 | return (Strsave(STRNULL)); | |
429 | } | |
0aec749d | 430 | if (vo[1] != NULL) |
6e37afca KB |
431 | return (handleone(str, vo, action)); |
432 | else { | |
433 | str = strip(vo[0]); | |
434 | xfree((ptr_t) vo); | |
435 | return (str); | |
436 | } | |
c8fda9bd | 437 | } |
6e37afca | 438 | } |
4aad0a53 | 439 | else if (noglob || (gflg & G_GLOB) == 0) |
6e37afca KB |
440 | return (strip(Strsave(str))); |
441 | else | |
442 | vo = v; | |
443 | ||
444 | vl = libglob(vo); | |
d8200413 | 445 | if ((gflg & G_CSH) && vl != vo) |
6e37afca | 446 | blkfree(vo); |
0aec749d | 447 | if (vl == NULL) { |
abf583a4 | 448 | setname(vis_str(str)); |
6e37afca KB |
449 | stderror(ERR_NAME | ERR_NOMATCH); |
450 | } | |
6cc6e21d CZ |
451 | if (vl[0] == NULL) { |
452 | xfree((ptr_t) vl); | |
453 | return (Strsave(STRNULL)); | |
454 | } | |
455 | if (vl[1] != NULL) | |
6e37afca KB |
456 | return (handleone(str, vl, action)); |
457 | else { | |
458 | str = strip(*vl); | |
459 | xfree((ptr_t) vl); | |
6cc6e21d | 460 | return (str); |
6e37afca | 461 | } |
b6e604fd BJ |
462 | } |
463 | ||
6e37afca | 464 | Char ** |
c8fda9bd | 465 | globall(v) |
6e37afca | 466 | Char **v; |
b6e604fd | 467 | { |
6e37afca | 468 | Char **vl, **vo; |
4aad0a53 | 469 | int gflg = gflag; |
35371dec | 470 | |
6e37afca KB |
471 | if (!v || !v[0]) { |
472 | gargv = saveblk(v); | |
473 | gargc = blklen(gargv); | |
474 | return (gargv); | |
475 | } | |
b6e604fd | 476 | |
6e37afca | 477 | noglob = adrof(STRnoglob) != 0; |
b6e604fd | 478 | |
4aad0a53 | 479 | if (gflg & G_CSH) |
6e37afca KB |
480 | /* |
481 | * Expand back-quote, tilde and brace | |
482 | */ | |
483 | vl = vo = globexpand(v); | |
484 | else | |
485 | vl = vo = saveblk(v); | |
486 | ||
4aad0a53 | 487 | if (!noglob && (gflg & G_GLOB)) { |
6e37afca | 488 | vl = libglob(vo); |
d8200413 | 489 | if ((gflg & G_CSH) && vl != vo) |
6e37afca KB |
490 | blkfree(vo); |
491 | } | |
4f6145a9 CZ |
492 | else |
493 | trim(vl); | |
6e37afca KB |
494 | |
495 | gargc = vl ? blklen(vl) : 0; | |
496 | return (gargv = vl); | |
c8fda9bd | 497 | } |
6e37afca KB |
498 | |
499 | void | |
c8fda9bd KB |
500 | ginit() |
501 | { | |
6e37afca KB |
502 | gargsiz = GLOBSPACE; |
503 | gargv = (Char **) xmalloc((size_t) sizeof(Char *) * gargsiz); | |
504 | gargv[0] = 0; | |
505 | gargc = 0; | |
b6e604fd BJ |
506 | } |
507 | ||
6e37afca | 508 | void |
b6e604fd | 509 | rscan(t, f) |
6e37afca KB |
510 | register Char **t; |
511 | void (*f) (); | |
b6e604fd | 512 | { |
6e37afca | 513 | register Char *p; |
b6e604fd | 514 | |
37999c01 | 515 | while ((p = *t++) != NULL) |
6e37afca KB |
516 | while (*p) |
517 | (*f) (*p++); | |
b6e604fd BJ |
518 | } |
519 | ||
6e37afca | 520 | void |
35371dec | 521 | trim(t) |
6e37afca | 522 | register Char **t; |
b6e604fd | 523 | { |
6e37afca | 524 | register Char *p; |
b6e604fd | 525 | |
37999c01 | 526 | while ((p = *t++) != NULL) |
6e37afca KB |
527 | while (*p) |
528 | *p++ &= TRIM; | |
b6e604fd BJ |
529 | } |
530 | ||
6e37afca | 531 | void |
35371dec | 532 | tglob(t) |
6e37afca | 533 | register Char **t; |
b6e604fd | 534 | { |
6e37afca KB |
535 | register Char *p, c; |
536 | ||
37999c01 | 537 | while ((p = *t++) != NULL) { |
6e37afca KB |
538 | if (*p == '~' || *p == '=') |
539 | gflag |= G_CSH; | |
540 | else if (*p == '{' && | |
e71234c5 | 541 | (p[1] == '\0' || (p[1] == '}' && p[2] == '\0'))) |
6e37afca | 542 | continue; |
37999c01 | 543 | while ((c = *p++) != '\0') { |
e71234c5 CZ |
544 | /* |
545 | * eat everything inside the matching backquotes | |
546 | */ | |
547 | if (c == '`') { | |
548 | gflag |= G_CSH; | |
549 | while (*p && *p != '`') | |
550 | if (*p++ == '\\') { | |
551 | if (*p) /* Quoted chars */ | |
552 | p++; | |
553 | else | |
554 | break; | |
555 | } | |
556 | if (*p) /* The matching ` */ | |
557 | p++; | |
558 | else | |
559 | break; | |
560 | } | |
561 | else if (c == '{') | |
562 | gflag |= G_CSH; | |
563 | else if (isglob(c)) | |
564 | gflag |= G_GLOB; | |
565 | } | |
6e37afca | 566 | } |
b6e604fd BJ |
567 | } |
568 | ||
b6e604fd | 569 | /* |
c8fda9bd KB |
570 | * Command substitute cp. If literal, then this is a substitution from a |
571 | * << redirection, and so we should not crunch blanks and tabs, separating | |
572 | * words only at newlines. | |
b6e604fd | 573 | */ |
6e37afca | 574 | Char ** |
b6e604fd | 575 | dobackp(cp, literal) |
6e37afca KB |
576 | Char *cp; |
577 | bool literal; | |
b6e604fd | 578 | { |
6e37afca KB |
579 | register Char *lp, *rp; |
580 | Char *ep, word[MAXPATHLEN]; | |
581 | ||
582 | if (pargv) { | |
e71234c5 | 583 | #ifdef notdef |
6e37afca | 584 | abort(); |
e71234c5 | 585 | #endif |
6e37afca KB |
586 | blkfree(pargv); |
587 | } | |
588 | pargsiz = GLOBSPACE; | |
589 | pargv = (Char **) xmalloc((size_t) sizeof(Char *) * pargsiz); | |
590 | pargv[0] = NULL; | |
591 | pargcp = pargs = word; | |
592 | pargc = 0; | |
593 | pnleft = MAXPATHLEN - 4; | |
594 | for (;;) { | |
595 | for (lp = cp; *lp != '`'; lp++) { | |
596 | if (*lp == 0) { | |
597 | if (pargcp != pargs) | |
598 | pword(); | |
599 | return (pargv); | |
600 | } | |
601 | psave(*lp); | |
b6e604fd | 602 | } |
6e37afca KB |
603 | lp++; |
604 | for (rp = lp; *rp && *rp != '`'; rp++) | |
605 | if (*rp == '\\') { | |
606 | rp++; | |
b6e604fd | 607 | if (!*rp) |
6e37afca KB |
608 | goto oops; |
609 | } | |
610 | if (!*rp) | |
611 | oops: stderror(ERR_UNMATCHED, '`'); | |
612 | ep = Strsave(lp); | |
613 | ep[rp - lp] = 0; | |
614 | backeval(ep, literal); | |
615 | cp = rp + 1; | |
616 | } | |
b6e604fd BJ |
617 | } |
618 | ||
6e37afca | 619 | static void |
b6e604fd | 620 | backeval(cp, literal) |
6e37afca KB |
621 | Char *cp; |
622 | bool literal; | |
b6e604fd | 623 | { |
6e37afca KB |
624 | register int icnt, c; |
625 | register Char *ip; | |
626 | struct command faket; | |
627 | bool hadnl; | |
628 | int pvec[2], quoted; | |
629 | Char *fakecom[2], ibuf[BUFSIZ]; | |
630 | char tibuf[BUFSIZ]; | |
631 | ||
632 | hadnl = 0; | |
633 | icnt = 0; | |
634 | quoted = (literal || (cp[0] & QUOTE)) ? QUOTE : 0; | |
635 | faket.t_dtyp = NODE_COMMAND; | |
636 | faket.t_dflg = 0; | |
637 | faket.t_dlef = 0; | |
638 | faket.t_drit = 0; | |
639 | faket.t_dspr = 0; | |
640 | faket.t_dcom = fakecom; | |
641 | fakecom[0] = STRfakecom1; | |
642 | fakecom[1] = 0; | |
643 | ||
644 | /* | |
645 | * We do the psave job to temporarily change the current job so that the | |
646 | * following fork is considered a separate job. This is so that when | |
647 | * backquotes are used in a builtin function that calls glob the "current | |
648 | * job" is not corrupted. We only need one level of pushed jobs as long as | |
649 | * we are sure to fork here. | |
650 | */ | |
651 | psavejob(); | |
652 | ||
653 | /* | |
654 | * It would be nicer if we could integrate this redirection more with the | |
655 | * routines in sh.sem.c by doing a fake execute on a builtin function that | |
656 | * was piped out. | |
657 | */ | |
658 | mypipe(pvec); | |
659 | if (pfork(&faket, -1) == 0) { | |
660 | struct wordent paraml; | |
661 | struct command *t; | |
c8fda9bd | 662 | |
6e37afca KB |
663 | (void) close(pvec[0]); |
664 | (void) dmove(pvec[1], 1); | |
454c2aa3 | 665 | (void) dmove(SHERR, 2); |
6e37afca | 666 | initdesc(); |
b6e604fd | 667 | /* |
6e37afca KB |
668 | * Bugfix for nested backquotes by Michael Greim <greim@sbsvax.UUCP>, |
669 | * posted to comp.bugs.4bsd 12 Sep. 1989. | |
b6e604fd | 670 | */ |
6e37afca KB |
671 | if (pargv) /* mg, 21.dec.88 */ |
672 | blkfree(pargv), pargv = 0, pargsiz = 0; | |
673 | /* mg, 21.dec.88 */ | |
674 | arginp = cp; | |
675 | while (*cp) | |
676 | *cp++ &= TRIM; | |
0b4ff4ec CZ |
677 | |
678 | /* | |
679 | * In the child ``forget'' everything about current aliases or | |
680 | * eval vectors. | |
681 | */ | |
682 | alvec = NULL; | |
683 | evalvec = NULL; | |
684 | alvecp = NULL; | |
685 | evalp = NULL; | |
6e37afca KB |
686 | (void) lex(¶ml); |
687 | if (seterr) | |
688 | stderror(ERR_OLD); | |
689 | alias(¶ml); | |
690 | t = syntax(paraml.next, ¶ml, 0); | |
691 | if (seterr) | |
692 | stderror(ERR_OLD); | |
693 | if (t) | |
694 | t->t_dflg |= F_NOFORK; | |
695 | (void) signal(SIGTSTP, SIG_IGN); | |
696 | (void) signal(SIGTTIN, SIG_IGN); | |
697 | (void) signal(SIGTTOU, SIG_IGN); | |
4d7b2685 | 698 | execute(t, -1, NULL, NULL); |
6e37afca KB |
699 | exitstat(); |
700 | } | |
701 | xfree((ptr_t) cp); | |
702 | (void) close(pvec[1]); | |
703 | c = 0; | |
0aec749d | 704 | ip = NULL; |
6e37afca KB |
705 | do { |
706 | int cnt = 0; | |
c8fda9bd | 707 | |
6e37afca KB |
708 | for (;;) { |
709 | if (icnt == 0) { | |
710 | int i; | |
711 | ||
712 | ip = ibuf; | |
713 | do | |
714 | icnt = read(pvec[0], tibuf, BUFSIZ); | |
715 | while (icnt == -1 && errno == EINTR); | |
716 | if (icnt <= 0) { | |
717 | c = -1; | |
718 | break; | |
b6e604fd | 719 | } |
6e37afca KB |
720 | for (i = 0; i < icnt; i++) |
721 | ip[i] = (unsigned char) tibuf[i]; | |
722 | } | |
723 | if (hadnl) | |
724 | break; | |
725 | --icnt; | |
726 | c = (*ip++ & TRIM); | |
727 | if (c == 0) | |
728 | break; | |
729 | if (c == '\n') { | |
b6e604fd | 730 | /* |
6e37afca KB |
731 | * Continue around the loop one more time, so that we can eat |
732 | * the last newline without terminating this word. | |
b6e604fd | 733 | */ |
6e37afca KB |
734 | hadnl = 1; |
735 | continue; | |
736 | } | |
737 | if (!quoted && (c == ' ' || c == '\t')) | |
738 | break; | |
739 | cnt++; | |
740 | psave(c | quoted); | |
741 | } | |
742 | /* | |
743 | * Unless at end-of-file, we will form a new word here if there were | |
744 | * characters in the word, or in any case when we take text literally. | |
745 | * If we didn't make empty words here when literal was set then we | |
746 | * would lose blank lines. | |
747 | */ | |
748 | if (c != -1 && (cnt || literal)) | |
749 | pword(); | |
750 | hadnl = 0; | |
751 | } while (c >= 0); | |
752 | (void) close(pvec[0]); | |
753 | pwait(); | |
754 | prestjob(); | |
b6e604fd BJ |
755 | } |
756 | ||
6e37afca | 757 | static void |
b6e604fd | 758 | psave(c) |
0aec749d | 759 | int c; |
b6e604fd | 760 | { |
6e37afca KB |
761 | if (--pnleft <= 0) |
762 | stderror(ERR_WTOOLONG); | |
763 | *pargcp++ = c; | |
b6e604fd BJ |
764 | } |
765 | ||
6e37afca | 766 | static void |
b6e604fd BJ |
767 | pword() |
768 | { | |
6e37afca KB |
769 | psave(0); |
770 | if (pargc == pargsiz - 1) { | |
771 | pargsiz += GLOBSPACE; | |
772 | pargv = (Char **) xrealloc((ptr_t) pargv, | |
773 | (size_t) pargsiz * sizeof(Char *)); | |
774 | } | |
775 | pargv[pargc++] = Strsave(pargs); | |
776 | pargv[pargc] = NULL; | |
777 | pargcp = pargs; | |
778 | pnleft = MAXPATHLEN - 4; | |
c8fda9bd KB |
779 | } |
780 | ||
e71234c5 | 781 | int |
c8fda9bd | 782 | Gmatch(string, pattern) |
e71234c5 CZ |
783 | Char *string, *pattern; |
784 | { | |
785 | Char **blk, **p; | |
786 | int gpol = 1, gres = 0; | |
787 | ||
788 | if (*pattern == '^') { | |
789 | gpol = 0; | |
790 | pattern++; | |
791 | } | |
792 | ||
793 | blk = (Char **) xmalloc(GLOBSPACE * sizeof(Char *)); | |
794 | blk[0] = Strsave(pattern); | |
795 | blk[1] = NULL; | |
796 | ||
797 | expbrace(&blk, NULL, GLOBSPACE); | |
798 | ||
799 | for (p = blk; *p; p++) | |
800 | gres |= pmatch(string, *p); | |
801 | ||
802 | blkfree(blk); | |
803 | return(gres == gpol); | |
804 | } | |
805 | ||
1afb645a | 806 | static int |
e71234c5 | 807 | pmatch(string, pattern) |
6e37afca | 808 | register Char *string, *pattern; |
c8fda9bd | 809 | { |
6e37afca | 810 | register Char stringc, patternc; |
e71234c5 | 811 | int match, negate_range; |
6e37afca KB |
812 | Char rangec; |
813 | ||
814 | for (;; ++string) { | |
815 | stringc = *string & TRIM; | |
816 | patternc = *pattern++; | |
817 | switch (patternc) { | |
818 | case 0: | |
819 | return (stringc == 0); | |
820 | case '?': | |
821 | if (stringc == 0) | |
822 | return (0); | |
823 | break; | |
824 | case '*': | |
825 | if (!*pattern) | |
826 | return (1); | |
827 | while (*string) | |
828 | if (Gmatch(string++, pattern)) | |
829 | return (1); | |
830 | return (0); | |
831 | case '[': | |
832 | match = 0; | |
37999c01 | 833 | if ((negate_range = (*pattern == '^')) != 0) |
e71234c5 | 834 | pattern++; |
37999c01 | 835 | while ((rangec = *pattern++) != '\0') { |
6e37afca | 836 | if (rangec == ']') |
e71234c5 | 837 | break; |
6e37afca KB |
838 | if (match) |
839 | continue; | |
e71234c5 | 840 | if (rangec == '-' && *(pattern-2) != '[' && *pattern != ']') { |
2b00e1e7 | 841 | match = (stringc <= (*pattern & TRIM) && |
e71234c5 | 842 | (*(pattern-2) & TRIM) <= stringc); |
6e37afca | 843 | pattern++; |
c8fda9bd | 844 | } |
e71234c5 CZ |
845 | else |
846 | match = (stringc == (rangec & TRIM)); | |
6e37afca KB |
847 | } |
848 | if (rangec == 0) | |
849 | stderror(ERR_NAME | ERR_MISSING, ']'); | |
e71234c5 CZ |
850 | if (match == negate_range) |
851 | return (0); | |
6e37afca KB |
852 | break; |
853 | default: | |
854 | if ((patternc & TRIM) != stringc) | |
855 | return (0); | |
856 | break; | |
857 | ||
c8fda9bd | 858 | } |
6e37afca | 859 | } |
c8fda9bd KB |
860 | } |
861 | ||
6e37afca | 862 | void |
c8fda9bd | 863 | Gcat(s1, s2) |
6e37afca | 864 | Char *s1, *s2; |
c8fda9bd | 865 | { |
6e37afca KB |
866 | register Char *p, *q; |
867 | int n; | |
868 | ||
c28e64a2 CL |
869 | for (p = s1; *p++;) |
870 | continue; | |
871 | for (q = s2; *q++;) | |
872 | continue; | |
6e37afca KB |
873 | n = (p - s1) + (q - s2) - 1; |
874 | if (++gargc >= gargsiz) { | |
875 | gargsiz += GLOBSPACE; | |
876 | gargv = (Char **) xrealloc((ptr_t) gargv, | |
877 | (size_t) gargsiz * sizeof(Char *)); | |
878 | } | |
879 | gargv[gargc] = 0; | |
880 | p = gargv[gargc - 1] = (Char *) xmalloc((size_t) n * sizeof(Char)); | |
37999c01 | 881 | for (q = s1; (*p++ = *q++) != '\0';) |
c28e64a2 | 882 | continue; |
37999c01 | 883 | for (p--, q = s2; (*p++ = *q++) != '\0';) |
c28e64a2 | 884 | continue; |
c8fda9bd KB |
885 | } |
886 | ||
6e37afca | 887 | #ifdef FILEC |
c8fda9bd | 888 | int |
6e37afca | 889 | sortscmp(a, b) |
e71234c5 | 890 | register const ptr_t a, b; |
c8fda9bd | 891 | { |
6e37afca KB |
892 | #if defined(NLS) && !defined(NOSTRCOLL) |
893 | char buf[2048]; | |
6e37afca KB |
894 | #endif |
895 | ||
65f1755c | 896 | if (!a) /* check for NULL */ |
6e37afca KB |
897 | return (b ? 1 : 0); |
898 | if (!b) | |
899 | return (-1); | |
900 | ||
ef17137d KB |
901 | if (!*(Char **)a) /* check for NULL */ |
902 | return (*(Char **)b ? 1 : 0); | |
903 | if (!*(Char **)b) | |
6e37afca KB |
904 | return (-1); |
905 | ||
906 | #if defined(NLS) && !defined(NOSTRCOLL) | |
ef17137d KB |
907 | (void) strcpy(buf, short2str(*(Char **)a)); |
908 | return ((int) strcoll(buf, short2str(*(Char **)b))); | |
6e37afca | 909 | #else |
ef17137d | 910 | return ((int) Strcmp(*(Char **)a, *(Char **)b)); |
6e37afca | 911 | #endif |
b6e604fd | 912 | } |
6e37afca | 913 | #endif /* FILEC */ |