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