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