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