[BACK]Return to expand.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / oldrdist

Annotation of src/usr.bin/oldrdist/expand.c, Revision 1.14

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