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