[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.2

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