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