|
|
1.1 root 1: /* expand.c -- various expanisions of shell type patterns */
2:
3: /*
4: * $Header: /f/osi/others/idist/RCS/expand.c,v 7.0 89/11/23 21:58:25 mrose Rel $
5: *
6: * Expansion primitives for wild card names. The tilde expansion stuff
7: * has been moved out as both sides require that whilst only the
8: * client requires this stuff.
9: *
10: * Julian Onions <[email protected]>
11: * Nottingham University Computer Science
12: *
13: *
14: * $Log: expand.c,v $
15: * Revision 7.0 89/11/23 21:58:25 mrose
16: * Release 6.0
17: *
18: */
19:
20: /*
21: * Copyright (c) 1983 Regents of the University of California.
22: * All rights reserved. The Berkeley software License Agreement
23: * specifies the terms and conditions for redistribution.
24: */
25:
26: #ifndef lint
27: static char sccsid[] = "@(#)expand.c 5.2 (Berkeley) 3/28/86";
28: static char *rcsid = "$Header: /f/osi/others/idist/RCS/expand.c,v 7.0 89/11/23 21:58:25 mrose Rel $";
29: #endif
30:
31: #include "defs.h"
32:
33: #define GAVSIZ NCARGS / 6
34: #define LC '{'
35: #define RC '}'
36:
37: static char shchars[] = "${[*?";
38:
39: int which; /* bit mask of types to expand */
40: int eargc; /* expanded arg count */
41: char **eargv; /* expanded arg vectors */
42: char *path;
43: char *pathp;
44: char *lastpathp;
45: char *tilde; /* "~user" if not expanding tilde, else "" */
46: char *tpathp;
47: int nleft;
48:
49: int expany; /* any expansions done? */
50: char *entp;
51: char **sortbase;
52:
53: char *index();
54: int argcmp();
55:
56: #define sort() qsort((char *)sortbase, &eargv[eargc] - sortbase, \
57: sizeof(*sortbase), argcmp), sortbase = &eargv[eargc]
58:
59: /*
60: * Take a list of names and expand any macros, etc.
61: * wh = E_VARS if expanding variables.
62: * wh = E_SHELL if expanding shell characters.
63: * wh = E_TILDE if expanding `~'.
64: * or any of these or'ed together.
65: *
66: * Major portions of this were snarfed from csh/sh.glob.c.
67: */
68: struct namelist *
69: expand(list, wh)
70: struct namelist *list;
71: int wh;
72: {
73: register struct namelist *nl, *prev;
74: register int n;
75: char pathbuf[BUFSIZ];
76: char *argvbuf[GAVSIZ];
77:
78: if (debug) {
79: printf("expand(%x, %d)\nlist = ", list, wh);
80: prnames(list);
81: }
82:
83: if (wh == 0) {
84: register char *cp;
85:
86: for (nl = list; nl != NULL; nl = nl->n_next)
87: for (cp = nl->n_name; *cp; cp++)
88: *cp = *cp & TRIM;
89: return(list);
90: }
91:
92: which = wh;
93: path = tpathp = pathp = pathbuf;
94: *pathp = '\0';
95: lastpathp = &path[sizeof pathbuf - 2];
96: tilde = "";
97: eargc = 0;
98: eargv = sortbase = argvbuf;
99: *eargv = 0;
100: nleft = NCARGS - 4;
101: /*
102: * Walk the name list and expand names into eargv[];
103: */
104: for (nl = list; nl != NULL; nl = nl->n_next)
105: expstr(nl->n_name);
106: /*
107: * Take expanded list of names from eargv[] and build a new list.
108: */
109: list = prev = NULL;
110: for (n = 0; n < eargc; n++) {
111: nl = makenl((char *)NULL);
112: nl->n_name = eargv[n];
113: if (prev == NULL)
114: list = prev = nl;
115: else {
116: prev->n_next = nl;
117: prev = nl;
118: }
119: }
120: if (debug) {
121: printf("expanded list = ");
122: prnames(list);
123: }
124: return(list);
125: }
126:
127: expstr(s)
128: char *s;
129: {
130: register char *cp, *cp1;
131: register struct namelist *tp;
132: char *tail;
133: char buf[BUFSIZ];
134: int savec, oeargc;
135: extern char homedir[];
136:
137: if (s == NULL || *s == '\0')
138: return;
139:
140: if ((which & E_VARS) && (cp = index(s, '$')) != NULL) {
141: *cp++ = '\0';
142: if (*cp == '\0') {
143: yyerror("no variable name after '$'");
144: return;
145: }
146: if (*cp == LC) {
147: cp++;
148: if ((tail = index(cp, RC)) == NULL) {
149: yyerror("unmatched '{'");
150: return;
151: }
152: *tail++ = savec = '\0';
153: if (*cp == '\0') {
154: yyerror("no variable name after '$'");
155: return;
156: }
157: } else {
158: tail = cp + 1;
159: savec = *tail;
160: *tail = '\0';
161: }
162: tp = lookup(cp, NULL, (struct namelist *)0);
163: if (savec != '\0')
164: *tail = savec;
165: if (tp != NULL) {
166: for (; tp != NULL; tp = tp->n_next) {
167: (void) sprintf(buf, "%s%s%s",
168: s, tp->n_name, tail);
169: expstr(buf);
170: }
171: return;
172: }
173: (void) sprintf(buf, "%s%s", s, tail);
174: expstr(buf);
175: return;
176: }
177: if ((which & ~E_VARS) == 0 || !strcmp(s, "{") || !strcmp(s, "{}")) {
178: Cat(s, "");
179: sort();
180: return;
181: }
182: if (*s == '~') {
183: cp = ++s;
184: if (*cp == '\0' || *cp == '/') {
185: tilde = "~";
186: cp1 = homedir;
187: } else {
188: tilde = cp1 = buf;
189: *cp1++ = '~';
190: do
191: *cp1++ = *cp++;
192: while (*cp && *cp != '/');
193: *cp1 = '\0';
194: if (pw == NULL || strcmp(pw->pw_name, buf+1) != 0) {
195: if ((pw = getpwnam(buf+1)) == NULL) {
196: (void) strcat(buf, ": unknown user name");
197: yyerror(buf+1);
198: return;
199: }
200: }
201: cp1 = pw->pw_dir;
202: s = cp;
203: }
204: for (cp = path; *cp++ = *cp1++; )
205: ;
206: tpathp = pathp = cp - 1;
207: } else {
208: tpathp = pathp = path;
209: tilde = "";
210: }
211: *pathp = '\0';
212: if (!(which & E_SHELL)) {
213: if (which & E_TILDE)
214: Cat(path, s);
215: else
216: Cat(tilde, s);
217: sort();
218: return;
219: }
220: oeargc = eargc;
221: expany = 0;
222: expsh(s);
223: if (eargc == oeargc)
224: Cat(s, ""); /* "nonomatch" is set */
225: sort();
226: }
227:
228: static
229: argcmp(a1, a2)
230: char **a1, **a2;
231: {
232:
233: return (strcmp(*a1, *a2));
234: }
235:
236: /*
237: * If there are any Shell meta characters in the name,
238: * expand into a list, after searching directory
239: */
240: expsh(s)
241: char *s;
242: {
243: register char *cp;
244: register char *spathp, *oldcp;
245: struct stat stb;
246:
247: spathp = pathp;
248: cp = s;
249: while (!any(*cp, shchars)) {
250: if (*cp == '\0') {
251: if (!expany || stat(path, &stb) >= 0) {
252: if (which & E_TILDE)
253: Cat(path, "");
254: else
255: Cat(tilde, tpathp);
256: }
257: goto endit;
258: }
259: addpath(*cp++);
260: }
261: oldcp = cp;
262: while (cp > s && *cp != '/')
263: cp--, pathp--;
264: if (*cp == '/')
265: cp++, pathp++;
266: *pathp = '\0';
267: if (*oldcp == '{') {
268: (void) execbrc(cp, (char *)NULL);
269: return;
270: }
271: matchdir(cp);
272: endit:
273: pathp = spathp;
274: *pathp = '\0';
275: }
276:
277: matchdir(pattern)
278: char *pattern;
279: {
280: struct stat stb;
281: register struct direct *dp;
282: DIR *dirp;
283:
284: dirp = opendir(path);
285: if (dirp == NULL) {
286: if (expany)
287: return;
288: goto patherr2;
289: }
290: if (fstat(dirp->dd_fd, &stb) < 0)
291: goto patherr1;
292: if (!ISDIR(stb.st_mode)) {
293: errno = ENOTDIR;
294: goto patherr1;
295: }
296: while ((dp = readdir(dirp)) != NULL)
297: if (match(dp->d_name, pattern)) {
298: if (which & E_TILDE)
299: Cat(path, dp->d_name);
300: else {
301: (void) strcpy(pathp, dp->d_name);
302: Cat(tilde, tpathp);
303: *pathp = '\0';
304: }
305: }
306: closedir(dirp);
307: return;
308:
309: patherr1:
310: closedir(dirp);
311: patherr2:
312: (void) strcat(path, ": ");
313: (void) strcat(path, sys_errlist[errno]);
314: yyerror(path);
315: }
316:
317: execbrc(p, s)
318: char *p, *s;
319: {
320: char restbuf[BUFSIZ + 2];
321: register char *pe, *pm, *pl;
322: int brclev = 0;
323: char *lm, savec, *spathp;
324:
325: for (lm = restbuf; *p != '{'; *lm++ = *p++)
326: continue;
327: for (pe = ++p; *pe; pe++)
328: switch (*pe) {
329:
330: case '{':
331: brclev++;
332: continue;
333:
334: case '}':
335: if (brclev == 0)
336: goto pend;
337: brclev--;
338: continue;
339:
340: case '[':
341: for (pe++; *pe && *pe != ']'; pe++)
342: continue;
343: if (!*pe)
344: yyerror("Missing ']'");
345: continue;
346: }
347: pend:
348: if (brclev || !*pe) {
349: yyerror("Missing '}'");
350: return (0);
351: }
352: for (pl = pm = p; pm <= pe; pm++)
353: switch (*pm & (QUOTE|TRIM)) {
354:
355: case '{':
356: brclev++;
357: continue;
358:
359: case '}':
360: if (brclev) {
361: brclev--;
362: continue;
363: }
364: goto doit;
365:
366: case ',':
367: if (brclev)
368: continue;
369: doit:
370: savec = *pm;
371: *pm = 0;
372: (void) strcpy(lm, pl);
373: (void) strcat(restbuf, pe + 1);
374: *pm = savec;
375: if (s == 0) {
376: spathp = pathp;
377: expsh(restbuf);
378: pathp = spathp;
379: *pathp = 0;
380: } else if (amatch(s, restbuf))
381: return (1);
382: sort();
383: pl = pm + 1;
384: continue;
385:
386: case '[':
387: for (pm++; *pm && *pm != ']'; pm++)
388: continue;
389: if (!*pm)
390: yyerror("Missing ']'");
391: continue;
392: }
393: return (0);
394: }
395:
396: match(s, p)
397: char *s, *p;
398: {
399: register int c;
400: register char *sentp;
401: char sexpany = expany;
402:
403: if (*s == '.' && *p != '.')
404: return (0);
405: sentp = entp;
406: entp = s;
407: c = amatch(s, p);
408: entp = sentp;
409: expany = sexpany;
410: return (c);
411: }
412:
413: amatch(s, p)
414: register char *s, *p;
415: {
416: register int scc;
417: int ok, lc;
418: char *spathp;
419: struct stat stb;
420: int c, cc;
421:
422: expany = 1;
423: for (;;) {
424: scc = *s++ & TRIM;
425: switch (c = *p++) {
426:
427: case '{':
428: return (execbrc(p - 1, s - 1));
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: yyerror("Missing ']'");
448: return (0);
449: }
450: continue;
451:
452: case '*':
453: if (!*p)
454: return (1);
455: if (*p == '/') {
456: p++;
457: goto slash;
458: }
459: for (s--; *s; s++)
460: if (amatch(s, p))
461: return (1);
462: return (0);
463:
464: case '\0':
465: return (scc == '\0');
466:
467: default:
468: if ((c & TRIM) != scc)
469: return (0);
470: continue;
471:
472: case '?':
473: if (scc == '\0')
474: return (0);
475: continue;
476:
477: case '/':
478: if (scc)
479: return (0);
480: slash:
481: s = entp;
482: spathp = pathp;
483: while (*s)
484: addpath(*s++);
485: addpath('/');
486: if (stat(path, &stb) == 0 && ISDIR(stb.st_mode))
487: if (*p == '\0') {
488: if (which & E_TILDE)
489: Cat(path, "");
490: else
491: Cat(tilde, tpathp);
492: } else
493: expsh(p);
494: pathp = spathp;
495: *pathp = '\0';
496: return (0);
497: }
498: }
499: }
500:
501: smatch(s, p)
502: register char *s, *p;
503: {
504: register int scc;
505: int ok, lc;
506: int c, cc;
507:
508: for (;;) {
509: scc = *s++ & TRIM;
510: switch (c = *p++) {
511:
512: case '[':
513: ok = 0;
514: lc = 077777;
515: while (cc = *p++) {
516: if (cc == ']') {
517: if (ok)
518: break;
519: return (0);
520: }
521: if (cc == '-') {
522: if (lc <= scc && scc <= *p++)
523: ok++;
524: } else
525: if (scc == (lc = cc))
526: ok++;
527: }
528: if (cc == 0) {
529: yyerror("Missing ']'");
530: return (0);
531: }
532: continue;
533:
534: case '*':
535: if (!*p)
536: return (1);
537: for (s--; *s; s++)
538: if (smatch(s, p))
539: return (1);
540: return (0);
541:
542: case '\0':
543: return (scc == '\0');
544:
545: default:
546: if ((c & TRIM) != scc)
547: return (0);
548: continue;
549:
550: case '?':
551: if (scc == 0)
552: return (0);
553: continue;
554:
555: }
556: }
557: }
558:
559: Cat(s1, s2)
560: register char *s1, *s2;
561: {
562: int len = strlen(s1) + strlen(s2) + 1;
563: register char *s;
564:
565: nleft -= len;
566: if (nleft <= 0 || ++eargc >= GAVSIZ)
567: yyerror("Arguments too long");
568: eargv[eargc] = 0;
569: eargv[eargc - 1] = s = malloc((unsigned)len);
570: if (s == NULL)
571: adios (NULLCP, "ran out of memory");
572: while (*s++ = *s1++ & TRIM)
573: ;
574: s--;
575: while (*s++ = *s2++ & TRIM)
576: ;
577: }
578:
579: addpath(c)
580: char c;
581: {
582:
583: if (pathp >= lastpathp)
584: yyerror("Pathname too long");
585: else {
586: *pathp++ = c & TRIM;
587: *pathp = '\0';
588: }
589: }
590:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.