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