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: }

Defined functions

Cat defined in line 538; used 10 times
addpath defined in line 558; used 3 times
amatch defined in line 392; used 3 times
argcmp defined in line 207; used 2 times
execbrc defined in line 296; used 2 times
expsh defined in line 219; used 3 times
expstr defined in line 107; used 3 times
match defined in line 375; used 1 times
matchdir defined in line 256; used 1 times
smatch defined in line 480; used 1 times

Defined variables

eargc defined in line 20; used 9 times
eargv defined in line 21; used 7 times
entp defined in line 30; used 4 times
expany defined in line 29; used 6 times
lastpathp defined in line 24; used 2 times
nleft defined in line 27; used 3 times
path defined in line 22; used 14 times
pathp defined in line 23; used 22 times
sccsid defined in line 8; never used
shchars defined in line 17; used 1 times
sortbase defined in line 31; used 5 times
tilde defined in line 25; used 8 times
tpathp defined in line 26; used 6 times
which defined in line 19; used 8 times

Defined macros

GAVSIZ defined in line 13; used 2 times
LC defined in line 14; used 1 times
RC defined in line 15; used 1 times
sort defined in line 36; used 4 times
Last modified: 1986-03-28
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2040
Valid CSS Valid XHTML 1.0 Strict