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