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