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