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