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