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