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