|
|
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[] = "@(#)glob.c 5.2 (Berkeley) 3/7/86";
9: #endif not lint
10:
11: /*
12: * C-shell glob for random programs.
13: */
14:
15: #include <sys/param.h>
16: #include <sys/stat.h>
17: #include <sys/dir.h>
18:
19: #include <stdio.h>
20: #include <errno.h>
21: #include <pwd.h>
22:
23: #define QUOTE 0200
24: #define TRIM 0177
25: #define eq(a,b) (strcmp(a, b)==0)
26: #define GAVSIZ (NCARGS/6)
27: #define isdir(d) ((d.st_mode & S_IFMT) == S_IFDIR)
28:
29: static char **gargv; /* Pointer to the (stack) arglist */
30: static short gargc; /* Number args in gargv */
31: static short gnleft;
32: static short gflag;
33: static int tglob();
34: char **glob();
35: char *globerr;
36: char *home;
37: struct passwd *getpwnam();
38: extern int errno;
39: static char *strspl(), *strend();
40: char *malloc(), *strcpy(), *strcat();
41: char **copyblk();
42:
43: static int globcnt;
44:
45: char *globchars = "`{[*?";
46:
47: static char *gpath, *gpathp, *lastgpathp;
48: static int globbed;
49: static char *entp;
50: static char **sortbas;
51:
52: char **
53: glob(v)
54: register char *v;
55: {
56: char agpath[BUFSIZ];
57: char *agargv[GAVSIZ];
58: char *vv[2];
59: vv[0] = v;
60: vv[1] = 0;
61: gflag = 0;
62: rscan(vv, tglob);
63: if (gflag == 0)
64: return (copyblk(vv));
65:
66: globerr = 0;
67: gpath = agpath; gpathp = gpath; *gpathp = 0;
68: lastgpathp = &gpath[sizeof agpath - 2];
69: ginit(agargv); globcnt = 0;
70: collect(v);
71: if (globcnt == 0 && (gflag&1)) {
72: blkfree(gargv), gargv = 0;
73: return (0);
74: } else
75: return (gargv = copyblk(gargv));
76: }
77:
78: static
79: ginit(agargv)
80: char **agargv;
81: {
82:
83: agargv[0] = 0; gargv = agargv; sortbas = agargv; gargc = 0;
84: gnleft = NCARGS - 4;
85: }
86:
87: static
88: collect(as)
89: register char *as;
90: {
91: if (eq(as, "{") || eq(as, "{}")) {
92: Gcat(as, "");
93: sort();
94: } else
95: acollect(as);
96: }
97:
98: static
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: sort();
108: }
109:
110: static
111: sort()
112: {
113: register char **p1, **p2, *c;
114: char **Gvp = &gargv[gargc];
115:
116: p1 = sortbas;
117: while (p1 < Gvp-1) {
118: p2 = p1;
119: while (++p2 < Gvp)
120: if (strcmp(*p1, *p2) > 0)
121: c = *p1, *p1 = *p2, *p2 = c;
122: p1++;
123: }
124: sortbas = Gvp;
125: }
126:
127: static
128: expand(as)
129: char *as;
130: {
131: register char *cs;
132: register char *sgpathp, *oldcs;
133: struct stat stb;
134:
135: sgpathp = gpathp;
136: cs = as;
137: if (*cs == '~' && gpathp == gpath) {
138: addpath('~');
139: for (cs++; letter(*cs) || digit(*cs) || *cs == '-';)
140: addpath(*cs++);
141: if (!*cs || *cs == '/') {
142: if (gpathp != gpath + 1) {
143: *gpathp = 0;
144: if (gethdir(gpath + 1))
145: globerr = "Unknown user name after ~";
146: (void) strcpy(gpath, gpath + 1);
147: } else
148: (void) strcpy(gpath, home);
149: gpathp = strend(gpath);
150: }
151: }
152: while (!any(*cs, globchars)) {
153: if (*cs == 0) {
154: if (!globbed)
155: Gcat(gpath, "");
156: else if (stat(gpath, &stb) >= 0) {
157: Gcat(gpath, "");
158: globcnt++;
159: }
160: goto endit;
161: }
162: addpath(*cs++);
163: }
164: oldcs = cs;
165: while (cs > as && *cs != '/')
166: cs--, gpathp--;
167: if (*cs == '/')
168: cs++, gpathp++;
169: *gpathp = 0;
170: if (*oldcs == '{') {
171: (void) execbrc(cs, ((char *)0));
172: return;
173: }
174: matchdir(cs);
175: endit:
176: gpathp = sgpathp;
177: *gpathp = 0;
178: }
179:
180: static
181: matchdir(pattern)
182: char *pattern;
183: {
184: struct stat stb;
185: register struct direct *dp;
186: DIR *dirp;
187:
188: dirp = opendir(gpath);
189: if (dirp == NULL) {
190: if (globbed)
191: return;
192: goto patherr2;
193: }
194: if (fstat(dirp->dd_fd, &stb) < 0)
195: goto patherr1;
196: if (!isdir(stb)) {
197: errno = ENOTDIR;
198: goto patherr1;
199: }
200: while ((dp = readdir(dirp)) != NULL) {
201: if (dp->d_ino == 0)
202: continue;
203: if (match(dp->d_name, pattern)) {
204: Gcat(gpath, dp->d_name);
205: globcnt++;
206: }
207: }
208: closedir(dirp);
209: return;
210:
211: patherr1:
212: closedir(dirp);
213: patherr2:
214: globerr = "Bad directory components";
215: }
216:
217: static
218: execbrc(p, s)
219: char *p, *s;
220: {
221: char restbuf[BUFSIZ + 2];
222: register char *pe, *pm, *pl;
223: int brclev = 0;
224: char *lm, savec, *sgpathp;
225:
226: for (lm = restbuf; *p != '{'; *lm++ = *p++)
227: continue;
228: for (pe = ++p; *pe; pe++)
229: switch (*pe) {
230:
231: case '{':
232: brclev++;
233: continue;
234:
235: case '}':
236: if (brclev == 0)
237: goto pend;
238: brclev--;
239: continue;
240:
241: case '[':
242: for (pe++; *pe && *pe != ']'; pe++)
243: continue;
244: continue;
245: }
246: pend:
247: brclev = 0;
248: for (pl = pm = p; pm <= pe; pm++)
249: switch (*pm & (QUOTE|TRIM)) {
250:
251: case '{':
252: brclev++;
253: continue;
254:
255: case '}':
256: if (brclev) {
257: brclev--;
258: continue;
259: }
260: goto doit;
261:
262: case ','|QUOTE:
263: case ',':
264: if (brclev)
265: continue;
266: doit:
267: savec = *pm;
268: *pm = 0;
269: (void) strcpy(lm, pl);
270: (void) strcat(restbuf, pe + 1);
271: *pm = savec;
272: if (s == 0) {
273: sgpathp = gpathp;
274: expand(restbuf);
275: gpathp = sgpathp;
276: *gpathp = 0;
277: } else if (amatch(s, restbuf))
278: return (1);
279: sort();
280: pl = pm + 1;
281: if (brclev)
282: return (0);
283: continue;
284:
285: case '[':
286: for (pm++; *pm && *pm != ']'; pm++)
287: continue;
288: if (!*pm)
289: pm--;
290: continue;
291: }
292: if (brclev)
293: goto doit;
294: return (0);
295: }
296:
297: static
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: static
316: amatch(s, p)
317: register char *s, *p;
318: {
319: register int scc;
320: int ok, lc;
321: char *sgpathp;
322: struct stat stb;
323: int c, cc;
324:
325: globbed = 1;
326: for (;;) {
327: scc = *s++ & TRIM;
328: switch (c = *p++) {
329:
330: case '{':
331: return (execbrc(p - 1, s - 1));
332:
333: case '[':
334: ok = 0;
335: lc = 077777;
336: while (cc = *p++) {
337: if (cc == ']') {
338: if (ok)
339: break;
340: return (0);
341: }
342: if (cc == '-') {
343: if (lc <= scc && scc <= *p++)
344: ok++;
345: } else
346: if (scc == (lc = cc))
347: ok++;
348: }
349: if (cc == 0)
350: if (ok)
351: p--;
352: else
353: return 0;
354: continue;
355:
356: case '*':
357: if (!*p)
358: return (1);
359: if (*p == '/') {
360: p++;
361: goto slash;
362: }
363: s--;
364: do {
365: if (amatch(s, p))
366: return (1);
367: } while (*s++);
368: return (0);
369:
370: case 0:
371: return (scc == 0);
372:
373: default:
374: if (c != scc)
375: return (0);
376: continue;
377:
378: case '?':
379: if (scc == 0)
380: return (0);
381: continue;
382:
383: case '/':
384: if (scc)
385: return (0);
386: slash:
387: s = entp;
388: sgpathp = gpathp;
389: while (*s)
390: addpath(*s++);
391: addpath('/');
392: if (stat(gpath, &stb) == 0 && isdir(stb))
393: if (*p == 0) {
394: Gcat(gpath, "");
395: globcnt++;
396: } else
397: expand(p);
398: gpathp = sgpathp;
399: *gpathp = 0;
400: return (0);
401: }
402: }
403: }
404:
405: static
406: Gmatch(s, p)
407: register char *s, *p;
408: {
409: register int scc;
410: int ok, lc;
411: int c, cc;
412:
413: for (;;) {
414: scc = *s++ & TRIM;
415: switch (c = *p++) {
416:
417: case '[':
418: ok = 0;
419: lc = 077777;
420: while (cc = *p++) {
421: if (cc == ']') {
422: if (ok)
423: break;
424: return (0);
425: }
426: if (cc == '-') {
427: if (lc <= scc && scc <= *p++)
428: ok++;
429: } else
430: if (scc == (lc = cc))
431: ok++;
432: }
433: if (cc == 0)
434: if (ok)
435: p--;
436: else
437: return 0;
438: continue;
439:
440: case '*':
441: if (!*p)
442: return (1);
443: for (s--; *s; s++)
444: if (Gmatch(s, p))
445: return (1);
446: return (0);
447:
448: case 0:
449: return (scc == 0);
450:
451: default:
452: if ((c & TRIM) != scc)
453: return (0);
454: continue;
455:
456: case '?':
457: if (scc == 0)
458: return (0);
459: continue;
460:
461: }
462: }
463: }
464:
465: static
466: Gcat(s1, s2)
467: register char *s1, *s2;
468: {
469: register int len = strlen(s1) + strlen(s2) + 1;
470:
471: if (len >= gnleft || gargc >= GAVSIZ - 1)
472: globerr = "Arguments too long";
473: else {
474: gargc++;
475: gnleft -= len;
476: gargv[gargc] = 0;
477: gargv[gargc - 1] = strspl(s1, s2);
478: }
479: }
480:
481: static
482: addpath(c)
483: char c;
484: {
485:
486: if (gpathp >= lastgpathp)
487: globerr = "Pathname too long";
488: else {
489: *gpathp++ = c;
490: *gpathp = 0;
491: }
492: }
493:
494: static
495: rscan(t, f)
496: register char **t;
497: int (*f)();
498: {
499: register char *p, c;
500:
501: while (p = *t++) {
502: if (f == tglob)
503: if (*p == '~')
504: gflag |= 2;
505: else if (eq(p, "{") || eq(p, "{}"))
506: continue;
507: while (c = *p++)
508: (*f)(c);
509: }
510: }
511: /*
512: static
513: scan(t, f)
514: register char **t;
515: int (*f)();
516: {
517: register char *p, c;
518:
519: while (p = *t++)
520: while (c = *p)
521: *p++ = (*f)(c);
522: } */
523:
524: static
525: tglob(c)
526: register char c;
527: {
528:
529: if (any(c, globchars))
530: gflag |= c == '{' ? 2 : 1;
531: return (c);
532: }
533: /*
534: static
535: trim(c)
536: char c;
537: {
538:
539: return (c & TRIM);
540: } */
541:
542:
543: letter(c)
544: register char c;
545: {
546:
547: return (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '_');
548: }
549:
550: digit(c)
551: register char c;
552: {
553:
554: return (c >= '0' && c <= '9');
555: }
556:
557: any(c, s)
558: register int c;
559: register char *s;
560: {
561:
562: while (*s)
563: if (*s++ == c)
564: return(1);
565: return(0);
566: }
567: blklen(av)
568: register char **av;
569: {
570: register int i = 0;
571:
572: while (*av++)
573: i++;
574: return (i);
575: }
576:
577: char **
578: blkcpy(oav, bv)
579: char **oav;
580: register char **bv;
581: {
582: register char **av = oav;
583:
584: while (*av++ = *bv++)
585: continue;
586: return (oav);
587: }
588:
589: blkfree(av0)
590: char **av0;
591: {
592: register char **av = av0;
593:
594: while (*av)
595: free(*av++);
596: free((char *)av0);
597: }
598:
599: static
600: char *
601: strspl(cp, dp)
602: register char *cp, *dp;
603: {
604: register char *ep = malloc((unsigned)(strlen(cp) + strlen(dp) + 1));
605:
606: if (ep == (char *)0)
607: fatal("Out of memory");
608: (void) strcpy(ep, cp);
609: (void) strcat(ep, dp);
610: return (ep);
611: }
612:
613: char **
614: copyblk(v)
615: register char **v;
616: {
617: register char **nv = (char **)malloc((unsigned)((blklen(v) + 1) *
618: sizeof(char **)));
619: if (nv == (char **)0)
620: fatal("Out of memory");
621:
622: return (blkcpy(nv, v));
623: }
624:
625: static
626: char *
627: strend(cp)
628: register char *cp;
629: {
630:
631: while (*cp)
632: cp++;
633: return (cp);
634: }
635: /*
636: * Extract a home directory from the password file
637: * The argument points to a buffer where the name of the
638: * user whose home directory is sought is currently.
639: * We write the home directory of the user back there.
640: */
641: gethdir(home)
642: char *home;
643: {
644: register struct passwd *pp = getpwnam(home);
645:
646: if (pp == 0)
647: return (1);
648: (void) strcpy(home, pp->pw_dir);
649: return (0);
650: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.