|
|
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.