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