|
|
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.4 (Berkeley) 5/13/86";
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 ','|QUOTE:
261: case ',':
262: if (brclev)
263: continue;
264: doit:
265: savec = *pm;
266: *pm = 0;
267: (void) strcpy(lm, pl);
268: (void) strcat(restbuf, pe + 1);
269: *pm = savec;
270: if (s == 0) {
271: sgpathp = gpathp;
272: expand(restbuf);
273: gpathp = sgpathp;
274: *gpathp = 0;
275: } else if (amatch(s, restbuf))
276: return (1);
277: sort();
278: pl = pm + 1;
279: continue;
280:
281: case '[':
282: for (pm++; *pm && *pm != ']'; pm++)
283: continue;
284: if (!*pm)
285: error("Missing ]");
286: continue;
287: }
288: return (0);
289: }
290:
291: match(s, p)
292: char *s, *p;
293: {
294: register int c;
295: register char *sentp;
296: char sglobbed = globbed;
297:
298: if (*s == '.' && *p != '.')
299: return (0);
300: sentp = entp;
301: entp = s;
302: c = amatch(s, p);
303: entp = sentp;
304: globbed = sglobbed;
305: return (c);
306: }
307:
308: amatch(s, p)
309: register char *s, *p;
310: {
311: register int scc;
312: int ok, lc;
313: char *sgpathp;
314: struct stat stb;
315: int c, cc;
316:
317: globbed = 1;
318: for (;;) {
319: scc = *s++ & TRIM;
320: switch (c = *p++) {
321:
322: case '{':
323: return (execbrc(p - 1, s - 1));
324:
325: case '[':
326: ok = 0;
327: lc = 077777;
328: while (cc = *p++) {
329: if (cc == ']') {
330: if (ok)
331: break;
332: return (0);
333: }
334: if (cc == '-') {
335: if (lc <= scc && scc <= *p++)
336: ok++;
337: } else
338: if (scc == (lc = cc))
339: ok++;
340: }
341: if (cc == 0)
342: error("Missing ]");
343: continue;
344:
345: case '*':
346: if (!*p)
347: return (1);
348: if (*p == '/') {
349: p++;
350: goto slash;
351: }
352: for (s--; *s; s++)
353: if (amatch(s, p))
354: return (1);
355: return (0);
356:
357: case 0:
358: return (scc == 0);
359:
360: default:
361: if ((c & TRIM) != scc)
362: return (0);
363: continue;
364:
365: case '?':
366: if (scc == 0)
367: return (0);
368: continue;
369:
370: case '/':
371: if (scc)
372: return (0);
373: slash:
374: s = entp;
375: sgpathp = gpathp;
376: while (*s)
377: addpath(*s++);
378: addpath('/');
379: if (stat(gpath, &stb) == 0 && isdir(stb))
380: if (*p == 0) {
381: Gcat(gpath, "");
382: globcnt++;
383: } else
384: expand(p);
385: gpathp = sgpathp;
386: *gpathp = 0;
387: return (0);
388: }
389: }
390: }
391:
392: Gmatch(s, p)
393: register char *s, *p;
394: {
395: register int scc;
396: int ok, lc;
397: int c, cc;
398:
399: for (;;) {
400: scc = *s++ & TRIM;
401: switch (c = *p++) {
402:
403: case '[':
404: ok = 0;
405: lc = 077777;
406: while (cc = *p++) {
407: if (cc == ']') {
408: if (ok)
409: break;
410: return (0);
411: }
412: if (cc == '-') {
413: if (lc <= scc && scc <= *p++)
414: ok++;
415: } else
416: if (scc == (lc = cc))
417: ok++;
418: }
419: if (cc == 0)
420: bferr("Missing ]");
421: continue;
422:
423: case '*':
424: if (!*p)
425: return (1);
426: for (s--; *s; s++)
427: if (Gmatch(s, p))
428: return (1);
429: return (0);
430:
431: case 0:
432: return (scc == 0);
433:
434: default:
435: if ((c & TRIM) != scc)
436: return (0);
437: continue;
438:
439: case '?':
440: if (scc == 0)
441: return (0);
442: continue;
443:
444: }
445: }
446: }
447:
448: Gcat(s1, s2)
449: char *s1, *s2;
450: {
451: register char *p, *q;
452: int n;
453:
454: for (p = s1; *p++;)
455: ;
456: for (q = s2; *q++;)
457: ;
458: gnleft -= (n = (p - s1) + (q - s2) - 1);
459: if (gnleft <= 0 || ++gargc >= GAVSIZ)
460: error("Arguments too long");
461: gargv[gargc] = 0;
462: p = gargv[gargc - 1] = xalloc((unsigned)n);
463: for (q = s1; *p++ = *q++;)
464: ;
465: for (p--, q = s2; *p++ = *q++;)
466: ;
467: }
468:
469: addpath(c)
470: char c;
471: {
472:
473: if (gpathp >= lastgpathp)
474: error("Pathname too long");
475: *gpathp++ = c & TRIM;
476: *gpathp = 0;
477: }
478:
479: rscan(t, f)
480: register char **t;
481: int (*f)();
482: {
483: register char *p;
484:
485: while (p = *t++)
486: while (*p)
487: (*f)(*p++);
488: }
489:
490: trim(t)
491: register char **t;
492: {
493: register char *p;
494:
495: while (p = *t++)
496: while (*p)
497: *p++ &= TRIM;
498: }
499:
500: tglob(t)
501: register char **t;
502: {
503: register char *p, c;
504:
505: while (p = *t++) {
506: if (*p == '~')
507: gflag |= 2;
508: else if (*p == '{' && (p[1] == '\0' || p[1] == '}' && p[2] == '\0'))
509: continue;
510: while (c = *p++)
511: if (isglob(c))
512: gflag |= c == '{' ? 2 : 1;
513: }
514: }
515:
516: char *
517: globone(str)
518: register char *str;
519: {
520: char *gv[2];
521: register char **gvp;
522: register char *cp;
523:
524: gv[0] = str;
525: gv[1] = 0;
526: gflag = 0;
527: tglob(gv);
528: if (gflag) {
529: gvp = glob(gv);
530: if (gvp == 0) {
531: setname(str);
532: bferr("No match");
533: }
534: cp = *gvp++;
535: if (cp == 0)
536: cp = "";
537: else if (*gvp) {
538: setname(str);
539: bferr("Ambiguous");
540: } else
541: cp = strip(cp);
542: /*
543: if (cp == 0 || *gvp) {
544: setname(str);
545: bferr(cp ? "Ambiguous" : "No output");
546: }
547: */
548: xfree((char *)gargv); gargv = 0;
549: } else {
550: trim(gv);
551: cp = savestr(gv[0]);
552: }
553: return (cp);
554: }
555:
556: /*
557: * Command substitute cp. If literal, then this is
558: * a substitution from a << redirection, and so we should
559: * not crunch blanks and tabs, separating words only at newlines.
560: */
561: char **
562: dobackp(cp, literal)
563: char *cp;
564: bool literal;
565: {
566: register char *lp, *rp;
567: char *ep;
568: char word[BUFSIZ];
569: char *apargv[GAVSIZ + 2];
570:
571: if (pargv) {
572: abort();
573: blkfree(pargv);
574: }
575: pargv = apargv;
576: pargv[0] = NOSTR;
577: pargcp = pargs = word;
578: pargc = 0;
579: pnleft = BUFSIZ - 4;
580: for (;;) {
581: for (lp = cp; *lp != '`'; lp++) {
582: if (*lp == 0) {
583: if (pargcp != pargs)
584: pword();
585: #ifdef GDEBUG
586: printf("leaving dobackp\n");
587: #endif
588: return (pargv = copyblk(pargv));
589: }
590: psave(*lp);
591: }
592: lp++;
593: for (rp = lp; *rp && *rp != '`'; rp++)
594: if (*rp == '\\') {
595: rp++;
596: if (!*rp)
597: goto oops;
598: }
599: if (!*rp)
600: oops:
601: error("Unmatched `");
602: ep = savestr(lp);
603: ep[rp - lp] = 0;
604: backeval(ep, literal);
605: #ifdef GDEBUG
606: printf("back from backeval\n");
607: #endif
608: cp = rp + 1;
609: }
610: }
611:
612: backeval(cp, literal)
613: char *cp;
614: bool literal;
615: {
616: int pvec[2];
617: int quoted = (literal || (cp[0] & QUOTE)) ? QUOTE : 0;
618: char ibuf[BUFSIZ];
619: register int icnt = 0, c;
620: register char *ip;
621: bool hadnl = 0;
622: char *fakecom[2];
623: struct command faket;
624:
625: faket.t_dtyp = TCOM;
626: faket.t_dflg = 0;
627: faket.t_dlef = 0;
628: faket.t_drit = 0;
629: faket.t_dspr = 0;
630: faket.t_dcom = fakecom;
631: fakecom[0] = "` ... `";
632: fakecom[1] = 0;
633: /*
634: * We do the psave job to temporarily change the current job
635: * so that the following fork is considered a separate job.
636: * This is so that when backquotes are used in a
637: * builtin function that calls glob the "current job" is not corrupted.
638: * We only need one level of pushed jobs as long as we are sure to
639: * fork here.
640: */
641: psavejob();
642: /*
643: * It would be nicer if we could integrate this redirection more
644: * with the routines in sh.sem.c by doing a fake execute on a builtin
645: * function that was piped out.
646: */
647: mypipe(pvec);
648: if (pfork(&faket, -1) == 0) {
649: struct wordent paraml;
650: struct command *t;
651:
652: (void) close(pvec[0]);
653: (void) dmove(pvec[1], 1);
654: (void) dmove(SHDIAG, 2);
655: initdesc();
656: arginp = cp;
657: while (*cp)
658: *cp++ &= TRIM;
659: (void) lex(¶ml);
660: if (err)
661: error(err);
662: alias(¶ml);
663: t = syntax(paraml.next, ¶ml, 0);
664: if (err)
665: error(err);
666: if (t)
667: t->t_dflg |= FPAR;
668: (void) signal(SIGTSTP, SIG_IGN);
669: (void) signal(SIGTTIN, SIG_IGN);
670: (void) signal(SIGTTOU, SIG_IGN);
671: execute(t, -1);
672: exitstat();
673: }
674: xfree(cp);
675: (void) close(pvec[1]);
676: do {
677: int cnt = 0;
678: for (;;) {
679: if (icnt == 0) {
680: ip = ibuf;
681: icnt = read(pvec[0], ip, BUFSIZ);
682: if (icnt <= 0) {
683: c = -1;
684: break;
685: }
686: }
687: if (hadnl)
688: break;
689: --icnt;
690: c = (*ip++ & TRIM);
691: if (c == 0)
692: break;
693: if (c == '\n') {
694: /*
695: * Continue around the loop one
696: * more time, so that we can eat
697: * the last newline without terminating
698: * this word.
699: */
700: hadnl = 1;
701: continue;
702: }
703: if (!quoted && (c == ' ' || c == '\t'))
704: break;
705: cnt++;
706: psave(c | quoted);
707: }
708: /*
709: * Unless at end-of-file, we will form a new word
710: * here if there were characters in the word, or in
711: * any case when we take text literally. If
712: * we didn't make empty words here when literal was
713: * set then we would lose blank lines.
714: */
715: if (c != -1 && (cnt || literal))
716: pword();
717: hadnl = 0;
718: } while (c >= 0);
719: #ifdef GDEBUG
720: printf("done in backeval, pvec: %d %d\n", pvec[0], pvec[1]);
721: printf("also c = %c <%o>\n", c, c);
722: #endif
723: (void) close(pvec[0]);
724: pwait();
725: prestjob();
726: }
727:
728: psave(c)
729: char c;
730: {
731:
732: if (--pnleft <= 0)
733: error("Word too long");
734: *pargcp++ = c;
735: }
736:
737: pword()
738: {
739:
740: psave(0);
741: if (pargc == GAVSIZ)
742: error("Too many words from ``");
743: pargv[pargc++] = savestr(pargs);
744: pargv[pargc] = NOSTR;
745: #ifdef GDEBUG
746: printf("got word %s\n", pargv[pargc-1]);
747: #endif
748: pargcp = pargs;
749: pnleft = BUFSIZ - 4;
750: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.