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