Commit | Line | Data |
---|---|---|
401149be | 1 | static char *sccsid = "@(#)glob.c 4.2 %G%"; |
b6e604fd BJ |
2 | #include "sh.h" |
3 | ||
4 | /* | |
5 | * C Shell | |
6 | */ | |
7 | ||
8 | int globcnt; | |
9 | ||
10 | char *globchars = "`{[*?"; | |
11 | ||
12 | char *gpath, *gpathp, *lastgpathp; | |
13 | int globbed; | |
14 | bool noglob; | |
15 | bool nonomatch; | |
16 | char *entp; | |
17 | char **sortbas; | |
18 | ||
19 | char ** | |
20 | glob(v) | |
21 | register char **v; | |
22 | { | |
23 | char agpath[BUFSIZ]; | |
24 | char *agargv[GAVSIZ]; | |
25 | ||
26 | gpath = agpath; gpathp = gpath; *gpathp = 0; | |
27 | lastgpathp = &gpath[sizeof agpath - 2]; | |
28 | ginit(agargv); globcnt = 0; | |
29 | #ifdef GDEBUG | |
30 | printf("glob entered: "); blkpr(v); printf("\n"); | |
31 | #endif | |
32 | noglob = adrof("noglob") != 0; | |
33 | nonomatch = adrof("nonomatch") != 0; | |
34 | globcnt = noglob | nonomatch; | |
35 | while (*v) | |
36 | collect(*v++); | |
37 | #ifdef GDEBUG | |
38 | printf("glob done, globcnt=%d, gflag=%d: ", globcnt, gflag); blkpr(gargv); printf("\n"); | |
39 | #endif | |
40 | if (globcnt == 0 && (gflag&1)) { | |
41 | blkfree(gargv), gargv = 0; | |
42 | return (0); | |
43 | } else | |
44 | return (gargv = copyblk(gargv)); | |
45 | } | |
46 | ||
47 | ginit(agargv) | |
48 | char **agargv; | |
49 | { | |
50 | ||
51 | agargv[0] = 0; gargv = agargv; sortbas = agargv; gargc = 0; | |
52 | gnleft = NCARGS - 4; | |
53 | } | |
54 | ||
55 | collect(as) | |
56 | register char *as; | |
57 | { | |
58 | register int i; | |
59 | ||
60 | if (any('`', as)) { | |
61 | #ifdef GDEBUG | |
62 | printf("doing backp of %s\n", as); | |
63 | #endif | |
64 | dobackp(as, 0); | |
65 | #ifdef GDEBUG | |
66 | printf("backp done, acollect'ing\n"); | |
67 | #endif | |
68 | for (i = 0; i < pargc; i++) | |
69 | if (noglob) | |
70 | Gcat(pargv[i], ""); | |
71 | else | |
72 | acollect(pargv[i]); | |
73 | if (pargv) | |
74 | blkfree(pargv), pargv = 0; | |
75 | #ifdef GDEBUG | |
76 | printf("acollect done\n"); | |
77 | #endif | |
401149be | 78 | } else if (noglob || eq(as, "{") || eq(as, "{}")) { |
b6e604fd | 79 | Gcat(as, ""); |
401149be BJ |
80 | sort(); |
81 | } else | |
b6e604fd BJ |
82 | acollect(as); |
83 | } | |
84 | ||
85 | acollect(as) | |
86 | register char *as; | |
87 | { | |
88 | register int ogargc = gargc; | |
89 | ||
90 | gpathp = gpath; *gpathp = 0; globbed = 0; | |
91 | expand(as); | |
92 | if (gargc == ogargc) { | |
93 | if (nonomatch) { | |
94 | Gcat(as, ""); | |
95 | sort(); | |
96 | } | |
97 | } else | |
98 | sort(); | |
99 | } | |
100 | ||
101 | sort() | |
102 | { | |
103 | register char **p1, **p2, *c; | |
104 | char **Gvp = &gargv[gargc]; | |
105 | ||
106 | p1 = sortbas; | |
107 | while (p1 < Gvp-1) { | |
108 | p2 = p1; | |
109 | while (++p2 < Gvp) | |
110 | if (strcmp(*p1, *p2) > 0) | |
111 | c = *p1, *p1 = *p2, *p2 = c; | |
112 | p1++; | |
113 | } | |
114 | sortbas = Gvp; | |
115 | } | |
116 | ||
117 | expand(as) | |
118 | char *as; | |
119 | { | |
120 | register char *cs; | |
121 | register char *sgpathp, *oldcs; | |
122 | struct stat stb; | |
123 | ||
124 | sgpathp = gpathp; | |
125 | cs = as; | |
126 | if (*cs == '~' && gpathp == gpath) { | |
127 | addpath('~'); | |
128 | for (cs++; letter(*cs) || digit(*cs) || *cs == '-';) | |
129 | addpath(*cs++); | |
130 | if (!*cs || *cs == '/') { | |
131 | if (gpathp != gpath + 1) { | |
132 | *gpathp = 0; | |
133 | if (gethdir(gpath + 1)) | |
134 | error("Unknown user: %s", gpath + 1); | |
135 | strcpy(gpath, gpath + 1); | |
136 | } else | |
137 | strcpy(gpath, value("home")); | |
138 | gpathp = strend(gpath); | |
139 | } | |
140 | } | |
141 | while (!any(*cs, globchars)) { | |
142 | if (*cs == 0) { | |
143 | if (!globbed) | |
144 | Gcat(gpath, ""); | |
145 | else if (stat(gpath, &stb) >= 0) { | |
146 | Gcat(gpath, ""); | |
147 | globcnt++; | |
148 | } | |
149 | goto endit; | |
150 | } | |
151 | addpath(*cs++); | |
152 | } | |
153 | oldcs = cs; | |
154 | while (cs > as && *cs != '/') | |
155 | cs--, gpathp--; | |
156 | if (*cs == '/') | |
157 | cs++, gpathp++; | |
158 | *gpathp = 0; | |
159 | if (*oldcs == '{') { | |
160 | execbrc(cs, NOSTR); | |
161 | return; | |
162 | } | |
163 | matchdir(cs); | |
164 | endit: | |
165 | gpathp = sgpathp; | |
166 | *gpathp = 0; | |
167 | } | |
168 | ||
169 | matchdir(pattern) | |
170 | char *pattern; | |
171 | { | |
172 | struct stat stb; | |
173 | struct direct dirbuf[BUFSIZ / sizeof (struct direct)]; | |
174 | char d_name[DIRSIZ+1]; | |
175 | register int dirf, cnt; | |
176 | ||
177 | dirf = open(gpath, 0); | |
178 | if (dirf < 0) { | |
179 | if (globbed) | |
180 | return; | |
181 | goto patherr; | |
182 | } | |
183 | if (fstat(dirf, &stb) < 0) | |
184 | goto patherr; | |
185 | if (!isdir(stb)) { | |
186 | errno = ENOTDIR; | |
187 | goto patherr; | |
188 | } | |
189 | while ((cnt = read(dirf, (char *) dirbuf, sizeof dirbuf)) >= sizeof dirbuf[0]) { | |
190 | register struct direct *ep = dirbuf; | |
191 | ||
192 | for (cnt /= sizeof (struct direct); cnt > 0; cnt--, ep++) { | |
193 | if (ep->d_ino == 0) | |
194 | continue; | |
195 | copdent(d_name, ep->d_name); | |
196 | if (match(d_name, pattern)) { | |
197 | Gcat(gpath, d_name); | |
198 | globcnt++; | |
199 | } | |
200 | } | |
201 | } | |
202 | close(dirf); | |
203 | return; | |
204 | ||
205 | patherr: | |
206 | Perror(gpath); | |
207 | } | |
208 | ||
209 | copdent(to, from) | |
210 | register char *to, *from; | |
211 | { | |
212 | register int cnt = DIRSIZ; | |
213 | ||
214 | do | |
215 | *to++ = *from++; | |
216 | while (--cnt); | |
217 | *to = 0; | |
218 | } | |
219 | ||
220 | execbrc(p, s) | |
221 | char *p, *s; | |
222 | { | |
223 | char restbuf[BUFSIZ + 2]; | |
224 | register char *pe, *pm, *pl; | |
225 | int brclev = 0; | |
226 | char *lm, savec, *sgpathp; | |
227 | ||
228 | for (lm = restbuf; *p != '{'; *lm++ = *p++) | |
229 | continue; | |
230 | for (pe = ++p; *pe; pe++) | |
231 | switch (*pe) { | |
232 | ||
233 | case '{': | |
234 | brclev++; | |
235 | continue; | |
236 | ||
237 | case '}': | |
238 | if (brclev == 0) | |
239 | goto pend; | |
240 | brclev--; | |
241 | continue; | |
242 | ||
243 | case '[': | |
244 | for (pe++; *pe && *pe != ']'; pe++) | |
245 | continue; | |
246 | if (!*pe) | |
247 | error("Missing ]"); | |
248 | continue; | |
249 | } | |
250 | pend: | |
251 | if (brclev || !*pe) | |
252 | error("Missing }"); | |
253 | for (pl = pm = p; pm <= pe; pm++) | |
254 | switch (*pm & (QUOTE|TRIM)) { | |
255 | ||
256 | case '{': | |
257 | brclev++; | |
258 | continue; | |
259 | ||
260 | case '}': | |
261 | if (brclev) { | |
262 | brclev--; | |
263 | continue; | |
264 | } | |
265 | goto doit; | |
266 | ||
267 | case ','|QUOTE: | |
268 | case ',': | |
269 | if (brclev) | |
270 | continue; | |
271 | doit: | |
272 | savec = *pm; | |
273 | *pm = 0; | |
274 | strcpy(lm, pl); | |
275 | strcat(restbuf, pe + 1); | |
276 | *pm = savec; | |
277 | if (s == 0) { | |
278 | sgpathp = gpathp; | |
279 | expand(restbuf); | |
280 | gpathp = sgpathp; | |
281 | *gpathp = 0; | |
282 | } else if (amatch(s, restbuf)) | |
283 | return (1); | |
284 | sort(); | |
285 | pl = pm + 1; | |
286 | continue; | |
287 | ||
288 | case '[': | |
289 | for (pm++; *pm && *pm != ']'; pm++) | |
290 | continue; | |
291 | if (!*pm) | |
292 | error("Missing ]"); | |
293 | continue; | |
294 | } | |
295 | return (0); | |
296 | } | |
297 | ||
298 | match(s, p) | |
299 | char *s, *p; | |
300 | { | |
301 | register int c; | |
302 | register char *sentp; | |
303 | char sglobbed = globbed; | |
304 | ||
305 | if (*s == '.' && *p != '.') | |
306 | return (0); | |
307 | sentp = entp; | |
308 | entp = s; | |
309 | c = amatch(s, p); | |
310 | entp = sentp; | |
311 | globbed = sglobbed; | |
312 | return (c); | |
313 | } | |
314 | ||
315 | amatch(s, p) | |
316 | register char *s, *p; | |
317 | { | |
318 | register int scc; | |
319 | int ok, lc; | |
320 | char *sgpathp; | |
321 | struct stat stb; | |
322 | int c, cc; | |
323 | ||
324 | globbed = 1; | |
325 | for (;;) { | |
326 | scc = *s++ & TRIM; | |
327 | switch (c = *p++) { | |
328 | ||
329 | case '{': | |
330 | return (execbrc(p - 1, s - 1)); | |
331 | ||
332 | case '[': | |
333 | ok = 0; | |
334 | lc = 077777; | |
335 | while (cc = *p++) { | |
336 | if (cc == ']') { | |
337 | if (ok) | |
338 | break; | |
339 | return (0); | |
340 | } | |
341 | if (cc == '-') { | |
342 | if (lc <= scc && scc <= *p++) | |
343 | ok++; | |
344 | } else | |
345 | if (scc == (lc = cc)) | |
346 | ok++; | |
347 | } | |
348 | if (cc == 0) | |
349 | error("Missing ]"); | |
350 | continue; | |
351 | ||
352 | case '*': | |
353 | if (!*p) | |
354 | return (1); | |
355 | if (*p == '/') { | |
356 | p++; | |
357 | goto slash; | |
358 | } | |
359 | for (s--; *s; s++) | |
360 | if (amatch(s, p)) | |
361 | return (1); | |
362 | return (0); | |
363 | ||
364 | case 0: | |
365 | return (scc == 0); | |
366 | ||
367 | default: | |
368 | if (c != scc) | |
369 | return (0); | |
370 | continue; | |
371 | ||
372 | case '?': | |
373 | if (scc == 0) | |
374 | return (0); | |
375 | continue; | |
376 | ||
377 | case '/': | |
378 | if (scc) | |
379 | return (0); | |
380 | slash: | |
381 | s = entp; | |
382 | sgpathp = gpathp; | |
383 | while (*s) | |
384 | addpath(*s++); | |
385 | addpath('/'); | |
386 | if (stat(gpath, &stb) == 0 && isdir(stb)) | |
387 | if (*p == 0) { | |
388 | Gcat(gpath, ""); | |
389 | globcnt++; | |
390 | } else | |
391 | expand(p); | |
392 | gpathp = sgpathp; | |
393 | *gpathp = 0; | |
394 | return (0); | |
395 | } | |
396 | } | |
397 | } | |
398 | ||
399 | Gmatch(s, p) | |
400 | register char *s, *p; | |
401 | { | |
402 | register int scc; | |
403 | int ok, lc; | |
404 | int c, cc; | |
405 | ||
406 | for (;;) { | |
407 | scc = *s++ & TRIM; | |
408 | switch (c = *p++) { | |
409 | ||
410 | case '[': | |
411 | ok = 0; | |
412 | lc = 077777; | |
413 | while (cc = *p++) { | |
414 | if (cc == ']') { | |
415 | if (ok) | |
416 | break; | |
417 | return (0); | |
418 | } | |
419 | if (cc == '-') { | |
420 | if (lc <= scc && scc <= *p++) | |
421 | ok++; | |
422 | } else | |
423 | if (scc == (lc = cc)) | |
424 | ok++; | |
425 | } | |
426 | if (cc == 0) | |
427 | bferr("Missing ]"); | |
428 | continue; | |
429 | ||
430 | case '*': | |
431 | if (!*p) | |
432 | return (1); | |
433 | for (s--; *s; s++) | |
434 | if (Gmatch(s, p)) | |
435 | return (1); | |
436 | return (0); | |
437 | ||
438 | case 0: | |
439 | return (scc == 0); | |
440 | ||
441 | default: | |
442 | if ((c & TRIM) != scc) | |
443 | return (0); | |
444 | continue; | |
445 | ||
446 | case '?': | |
447 | if (scc == 0) | |
448 | return (0); | |
449 | continue; | |
450 | ||
451 | } | |
452 | } | |
453 | } | |
454 | ||
455 | Gcat(s1, s2) | |
456 | register char *s1, *s2; | |
457 | { | |
458 | ||
459 | gnleft -= strlen(s1) + strlen(s2) + 1; | |
460 | if (gnleft <= 0 || ++gargc >= GAVSIZ) | |
461 | error("Arguments too long"); | |
462 | gargv[gargc] = 0; | |
463 | gargv[gargc - 1] = strspl(s1, s2); | |
464 | } | |
465 | ||
466 | addpath(c) | |
467 | char c; | |
468 | { | |
469 | ||
470 | if (gpathp >= lastgpathp) | |
471 | error("Pathname too long"); | |
472 | *gpathp++ = c; | |
473 | *gpathp = 0; | |
474 | } | |
475 | ||
476 | rscan(t, f) | |
477 | register char **t; | |
478 | int (*f)(); | |
479 | { | |
480 | register char *p, c; | |
481 | ||
482 | while (p = *t++) { | |
483 | if (f == tglob) | |
484 | if (*p == '~') | |
485 | gflag |= 2; | |
486 | else if (eq(p, "{") || eq(p, "{}")) | |
487 | continue; | |
488 | while (c = *p++) | |
489 | (*f)(c); | |
490 | } | |
491 | } | |
492 | ||
493 | scan(t, f) | |
494 | register char **t; | |
495 | int (*f)(); | |
496 | { | |
497 | register char *p, c; | |
498 | ||
499 | while (p = *t++) | |
500 | while (c = *p) | |
501 | *p++ = (*f)(c); | |
502 | } | |
503 | ||
504 | tglob(c) | |
505 | register char c; | |
506 | { | |
507 | ||
508 | if (any(c, globchars)) | |
509 | gflag |= c == '{' ? 2 : 1; | |
510 | return (c); | |
511 | } | |
512 | ||
513 | trim(c) | |
514 | char c; | |
515 | { | |
516 | ||
517 | return (c & TRIM); | |
518 | } | |
519 | ||
520 | tback(c) | |
521 | char c; | |
522 | { | |
523 | ||
524 | if (c == '`') | |
525 | gflag = 1; | |
526 | } | |
527 | ||
528 | char * | |
529 | globone(str) | |
530 | register char *str; | |
531 | { | |
532 | char *gv[2]; | |
533 | register char **gvp; | |
534 | register char *cp; | |
535 | ||
536 | gv[0] = str; | |
537 | gv[1] = 0; | |
538 | gflag = 0; | |
539 | rscan(gv, tglob); | |
540 | if (gflag) { | |
541 | gvp = glob(gv); | |
542 | if (gvp == 0) { | |
543 | setname(str); | |
544 | bferr("No match"); | |
545 | } | |
546 | cp = *gvp++; | |
547 | if (cp == 0) | |
548 | cp = ""; | |
549 | else if (*gvp) { | |
550 | setname(str); | |
551 | bferr("Ambiguous"); | |
552 | } else | |
553 | cp = strip(cp); | |
554 | /* | |
555 | if (cp == 0 || *gvp) { | |
556 | setname(str); | |
557 | bferr(cp ? "Ambiguous" : "No output"); | |
558 | } | |
559 | */ | |
560 | xfree((char *)gargv); gargv = 0; | |
561 | } else { | |
562 | scan(gv, trim); | |
563 | cp = savestr(gv[0]); | |
564 | } | |
565 | return (cp); | |
566 | } | |
567 | ||
568 | /* | |
569 | * Command substitute cp. If literal, then this is | |
570 | * a substitution from a << redirection, and so we should | |
571 | * not crunch blanks and tabs, separating words only at newlines. | |
572 | */ | |
573 | char ** | |
574 | dobackp(cp, literal) | |
575 | char *cp; | |
576 | bool literal; | |
577 | { | |
578 | register char *lp, *rp; | |
579 | char *ep; | |
580 | char word[BUFSIZ]; | |
581 | char *apargv[GAVSIZ + 2]; | |
582 | ||
583 | if (pargv) { | |
584 | abort(); | |
585 | blkfree(pargv); | |
586 | } | |
587 | pargv = apargv; | |
588 | pargv[0] = NOSTR; | |
589 | pargcp = pargs = word; | |
590 | pargc = 0; | |
591 | pnleft = BUFSIZ - 4; | |
592 | for (;;) { | |
593 | for (lp = cp; *lp != '`'; lp++) { | |
594 | if (*lp == 0) { | |
595 | if (pargcp != pargs) | |
596 | pword(); | |
597 | #ifdef GDEBUG | |
598 | printf("leaving dobackp\n"); | |
599 | #endif | |
600 | return (pargv = copyblk(pargv)); | |
601 | } | |
602 | psave(*lp); | |
603 | } | |
604 | lp++; | |
605 | for (rp = lp; *rp && *rp != '`'; rp++) | |
606 | if (*rp == '\\') { | |
607 | rp++; | |
608 | if (!*rp) | |
609 | goto oops; | |
610 | } | |
611 | if (!*rp) | |
612 | oops: | |
613 | error("Unmatched `"); | |
614 | ep = savestr(lp); | |
615 | ep[rp - lp] = 0; | |
616 | backeval(ep, literal); | |
617 | #ifdef GDEBUG | |
618 | printf("back from backeval\n"); | |
619 | #endif | |
620 | cp = rp + 1; | |
621 | } | |
622 | } | |
623 | ||
624 | backeval(cp, literal) | |
625 | char *cp; | |
626 | bool literal; | |
627 | { | |
628 | int pvec[2]; | |
629 | int quoted = (literal || (cp[0] & QUOTE)) ? QUOTE : 0; | |
630 | char ibuf[BUFSIZ]; | |
631 | register int icnt = 0, c; | |
632 | register char *ip; | |
633 | bool hadnl = 0; | |
634 | char *fakecom[2]; | |
635 | struct command faket; | |
636 | ||
637 | faket.t_dtyp = TCOM; | |
638 | faket.t_dflg = 0; | |
639 | faket.t_dlef = 0; | |
640 | faket.t_drit = 0; | |
641 | faket.t_dspr = 0; | |
642 | faket.t_dcom = fakecom; | |
643 | fakecom[0] = "` ... `"; | |
644 | fakecom[1] = 0; | |
645 | /* | |
646 | * We do the psave job to temporarily change the current job | |
647 | * so that the following fork is considered a separate job. | |
648 | * This is so that when backquotes are used in a | |
649 | * builtin function that calls glob the "current job" is not corrupted. | |
650 | * We only need one level of pushed jobs as long as we are sure to | |
651 | * fork here. | |
652 | */ | |
653 | psavejob(); | |
654 | /* | |
655 | * It would be nicer if we could integrate this redirection more | |
656 | * with the routines in sh.sem.c by doing a fake execute on a builtin | |
657 | * function that was piped out. | |
658 | */ | |
659 | mypipe(pvec); | |
660 | if (pfork(&faket, -1) == 0) { | |
661 | struct wordent paraml; | |
662 | struct command *t; | |
663 | ||
664 | close(pvec[0]); | |
665 | dmove(pvec[1], 1); | |
666 | dmove(SHDIAG, 2); | |
667 | initdesc(); | |
668 | arginp = cp; | |
669 | while (*cp) | |
670 | *cp++ &= TRIM; | |
671 | lex(¶ml); | |
672 | if (err) | |
673 | error(err); | |
674 | alias(¶ml); | |
675 | t = syntax(paraml.next, ¶ml, 0); | |
676 | if (err) | |
677 | error(err); | |
678 | if (t) | |
679 | t->t_dflg |= FPAR; | |
680 | execute(t, -1); | |
681 | exitstat(); | |
682 | } | |
683 | xfree(cp); | |
684 | close(pvec[1]); | |
685 | do { | |
686 | int cnt = 0; | |
687 | for (;;) { | |
688 | if (icnt == 0) { | |
689 | ip = ibuf; | |
690 | icnt = read(pvec[0], ip, BUFSIZ); | |
691 | if (icnt <= 0) { | |
692 | c = -1; | |
693 | break; | |
694 | } | |
695 | } | |
696 | if (hadnl) | |
697 | break; | |
698 | --icnt; | |
699 | c = (*ip++ & TRIM); | |
700 | if (c == 0) | |
701 | break; | |
702 | if (c == '\n') { | |
703 | /* | |
704 | * Continue around the loop one | |
705 | * more time, so that we can eat | |
706 | * the last newline without terminating | |
707 | * this word. | |
708 | */ | |
709 | hadnl = 1; | |
710 | continue; | |
711 | } | |
712 | if (!quoted && (c == ' ' || c == '\t')) | |
713 | break; | |
714 | cnt++; | |
715 | psave(c | quoted); | |
716 | } | |
717 | /* | |
718 | * Unless at end-of-file, we will form a new word | |
719 | * here if there were characters in the word, or in | |
720 | * any case when we take text literally. If | |
721 | * we didn't make empty words here when literal was | |
722 | * set then we would lose blank lines. | |
723 | */ | |
724 | if (c != -1 && (cnt || literal)) | |
725 | pword(); | |
726 | hadnl = 0; | |
727 | } while (c >= 0); | |
728 | #ifdef GDEBUG | |
729 | printf("done in backeval, pvec: %d %d\n", pvec[0], pvec[1]); | |
730 | printf("also c = %c <%o>\n", c, c); | |
731 | #endif | |
732 | close(pvec[0]); | |
733 | pwait(); | |
734 | prestjob(); | |
735 | } | |
736 | ||
737 | psave(c) | |
738 | char c; | |
739 | { | |
740 | ||
741 | if (--pnleft <= 0) | |
742 | error("Word too long"); | |
743 | *pargcp++ = c; | |
744 | } | |
745 | ||
746 | pword() | |
747 | { | |
748 | ||
749 | psave(0); | |
750 | if (pargc == GAVSIZ) | |
751 | error("Too many words from ``"); | |
752 | pargv[pargc++] = savestr(pargs); | |
753 | pargv[pargc] = NOSTR; | |
754 | #ifdef GDEBUG | |
755 | printf("got word %s\n", pargv[pargc-1]); | |
756 | #endif | |
757 | pargcp = pargs; | |
758 | pnleft = BUFSIZ - 4; | |
759 | } |