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