|
|
1.1 root 1: static char *sccsid = "@(#)sh.glob.c 4.2 3/11/81";
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 || eq(as, "{") || eq(as, "{}")) {
79: Gcat(as, "");
80: sort();
81: } else
82: acollect(as);
83: }
84:
85: acollect(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:
101: sort()
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:
117: expand(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);
164: endit:
165: gpathp = sgpathp;
166: *gpathp = 0;
167: }
168:
169: matchdir(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:
205: patherr:
206: Perror(gpath);
207: }
208:
209: copdent(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:
220: execbrc(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: }
250: pend:
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;
271: doit:
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:
298: match(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:
315: amatch(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);
380: slash:
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:
399: Gmatch(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:
455: Gcat(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:
466: addpath(c)
467: char c;
468: {
469:
470: if (gpathp >= lastgpathp)
471: error("Pathname too long");
472: *gpathp++ = c;
473: *gpathp = 0;
474: }
475:
476: rscan(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:
493: scan(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:
504: tglob(c)
505: register char c;
506: {
507:
508: if (any(c, globchars))
509: gflag |= c == '{' ? 2 : 1;
510: return (c);
511: }
512:
513: trim(c)
514: char c;
515: {
516:
517: return (c & TRIM);
518: }
519:
520: tback(c)
521: char c;
522: {
523:
524: if (c == '`')
525: gflag = 1;
526: }
527:
528: char *
529: globone(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: */
573: char **
574: dobackp(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)
612: oops:
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:
624: backeval(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(¶ml);
672: if (err)
673: error(err);
674: alias(¶ml);
675: t = syntax(paraml.next, ¶ml, 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:
737: psave(c)
738: char c;
739: {
740:
741: if (--pnleft <= 0)
742: error("Word too long");
743: *pargcp++ = c;
744: }
745:
746: pword()
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.