mail back errors (perhaps this is why mail gets lost.....)
[unix-history] / usr / src / bin / csh / glob.c
CommitLineData
401149be 1static char *sccsid = "@(#)glob.c 4.2 %G%";
b6e604fd
BJ
2#include "sh.h"
3
4/*
5 * C Shell
6 */
7
8int globcnt;
9
10char *globchars = "`{[*?";
11
12char *gpath, *gpathp, *lastgpathp;
13int globbed;
14bool noglob;
15bool nonomatch;
16char *entp;
17char **sortbas;
18
19char **
20glob(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
47ginit(agargv)
48 char **agargv;
49{
50
51 agargv[0] = 0; gargv = agargv; sortbas = agargv; gargc = 0;
52 gnleft = NCARGS - 4;
53}
54
55collect(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
85acollect(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
101sort()
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
117expand(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);
164endit:
165 gpathp = sgpathp;
166 *gpathp = 0;
167}
168
169matchdir(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
205patherr:
206 Perror(gpath);
207}
208
209copdent(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
220execbrc(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 }
250pend:
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;
271doit:
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
298match(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
315amatch(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);
380slash:
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
399Gmatch(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
455Gcat(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
466addpath(c)
467 char c;
468{
469
470 if (gpathp >= lastgpathp)
471 error("Pathname too long");
472 *gpathp++ = c;
473 *gpathp = 0;
474}
475
476rscan(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
493scan(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
504tglob(c)
505 register char c;
506{
507
508 if (any(c, globchars))
509 gflag |= c == '{' ? 2 : 1;
510 return (c);
511}
512
513trim(c)
514 char c;
515{
516
517 return (c & TRIM);
518}
519
520tback(c)
521 char c;
522{
523
524 if (c == '`')
525 gflag = 1;
526}
527
528char *
529globone(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 */
573char **
574dobackp(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)
612oops:
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
624backeval(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(&paraml);
672 if (err)
673 error(err);
674 alias(&paraml);
675 t = syntax(paraml.next, &paraml, 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
737psave(c)
738 char c;
739{
740
741 if (--pnleft <= 0)
742 error("Word too long");
743 *pargcp++ = c;
744}
745
746pword()
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}