Annotation of 43BSD/ucb/rdist/expand.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.