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