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