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