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