Annotation of coherent/a/usr/bob/korn/eval.c.save, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Expansion - quoting, separation, substitution, globbing
                      3:  */
                      4: 
                      5: static char *RCSid = "$Header: /newbits/usr/bin/korn/eval.c.save,v 1.1 91/04/12 10:48:22 bin Exp $";
                      6: 
                      7: #include <stddef.h>
                      8: #include <stdio.h>
                      9: #include <string.h>
                     10: #include <errno.h>
                     11: #include <setjmp.h>
                     12: #include <unistd.h>
                     13: #include <sys/types.h>
                     14: #include <dirent.h>
                     15: #include <pwd.h>
                     16: #include "sh.h"
                     17: #include "lex.h"
                     18: #include "tree.h"
                     19: #include "table.h"
                     20: #include "expand.h"
                     21: 
                     22: /*
                     23:  * string expansion
                     24:  *
                     25:  * first pass: quoting, IFS separation, ${} and $() substitution.
                     26:  * second pass: filename expansion (*?[]~).
                     27:  */
                     28: 
                     29: /* expansion generator state */
                     30: typedef struct Expand {
                     31:        /* int  type; */        /* see expand() */
                     32:        char   *str;            /* string */
                     33:        union {
                     34:                char  **strv;   /* string[] */
                     35:                FILE   *file;   /* file */
                     36:        } u;                    /* source */
                     37:        short   split;          /* split "$@"*/
                     38: } Expand;
                     39: 
                     40: #define        XBASE   0               /* scanning original */
                     41: #define        XSUB    1               /* expanding ${} string */
                     42: #define        XARGSEP 2               /* ifs0 between "$@" */
                     43: #define        XARG    3               /* expanding $*, $@ */
                     44: #define        XCOM    4               /* expanding $() */
                     45: 
                     46: static void    expand ARGS((char *, XPtrV *, int));
                     47: static int     comsub ARGS((Expand *, char *comm));
                     48: static int     varsub ARGS((Expand *, char *name, int stype));
                     49: static void    glob ARGS((char *cp, XPtrV *wp));
                     50: static void    globit ARGS((char *ds, char *dp, char *sp, XPtrV *wp, int check));
                     51: static char   *tilde ARGS((char *wp));
                     52: static char   *trimsub ARGS((char *str, char *pat, int how));
                     53: 
                     54: int    ifs0 = ' ';             /* todo: first char of $IFS */
                     55: 
                     56: /* compile and expand word */
                     57: char *
                     58: substitute(cp, f)
                     59:        char Const *cp;
                     60:        int f;
                     61: {
                     62:        struct source *s, *sold;
                     63: 
                     64:        sold = source;
                     65:        s = pushs(SWSTR);
                     66:        s->str = (char *) cp;
                     67:        source = s;
                     68:        if (yylex(ONEWORD) != LWORD)
                     69:                errorf("eval:substitute error\n");
                     70:        source = sold;
                     71:        return evalstr(yylval.cp, f);
                     72: }
                     73: 
                     74: /*
                     75:  * expand arg-list
                     76:  */
                     77: char **
                     78: eval(ap, f)
                     79:        register char **ap;
                     80: {
                     81:        XPtrV w;
                     82: 
                     83:        if (*ap == NULL)
                     84:                return ap;
                     85:        XPinit(w, 32);
                     86:        XPput(w, NULL);         /* space for shell name */
                     87:        while (*ap != NULL)
                     88:                expand(*ap++, &w, f);
                     89:        XPput(w, NULL);
                     90:        return (char **) XPclose(w) + 1;
                     91: }
                     92: 
                     93: /*
                     94:  * expand string
                     95:  */
                     96: char *
                     97: evalstr(cp, f)
                     98:        register char *cp;
                     99:        int f;
                    100: {
                    101:        XPtrV w;
                    102: 
                    103:        XPinit(w, 1);
                    104:        expand(cp, &w, f);
                    105:        cp = (XPsize(w) == 0) ? "" : (char*) *XPptrv(w);
                    106:        XPfree(w);
                    107:        return cp;
                    108: }
                    109: 
                    110: /* for nested substitution: ${var:=$var2} */
                    111: typedef struct SubType {
                    112:        short   type;           /* [=+-?%#] action after expanded word */
                    113:        short   base;           /* begin position of expanded word */
                    114:        char   *name;           /* name for ${var=word} */
                    115: } SubType;
                    116: 
                    117: static void
                    118: expand(cp, wp, f)
                    119:        char *cp;               /* input word */
                    120:        register XPtrV *wp;     /* output words */
                    121:        int f;                  /* DO* flags */
                    122: {
                    123:        register int c;
                    124:        register int type = XBASE; /* expansion type */
                    125:        register int quote = 0; /* quoted */
                    126:        XString ds;             /* destination string */
                    127:        register char *dp, *sp; /* dest., source */
                    128:        int fdo, word, combase; /* second pass flags; have word */
                    129:        Expand x;               /* expansion variables */
                    130:        SubType subtype [10];   /* substitution type stack */
                    131:        register SubType *st = subtype + 10;
                    132: 
                    133:        if (cp == NULL)
                    134:                errorf("eval:expand(NULL)\n");
                    135:        if (flag[FNOGLOB])
                    136:                f &= ~ DOGLOB;
                    137: 
                    138:        Xinit(ds, dp, 128);     /* init dest. string */
                    139:        type = XBASE;
                    140:        sp = cp;
                    141:        fdo = 0;
                    142:        word = !(f&DOBLANK);
                    143: 
                    144:        while (1) {
                    145:                Xcheck(ds, dp);
                    146: 
                    147:                switch (type) {
                    148:                  case XBASE:   /* original prefixed string */
                    149:                        c = *sp++;
                    150:                        switch (c) {
                    151:                          case EOS:
                    152:                                c = 0;
                    153:                                break;
                    154:                          case CHAR:
                    155:                                c = *sp++;
                    156:                                break;
                    157:                          case QCHAR:
                    158:                                quote |= 2; /* temporary quote */
                    159:                                c = *sp++;
                    160:                                break;
                    161:                          case OQUOTE:
                    162:                                word = quote = 1;
                    163:                                continue;
                    164:                          case CQUOTE:
                    165:                                quote = 0;
                    166:                                continue;
                    167:                          case COMSUB:
                    168:                                type = comsub(&x, sp);
                    169:                                sp = strchr(sp, 0) + 1;
                    170:                                combase = Xsavepos(ds, dp);
                    171:                                continue;
                    172:                          case OSUBST: /* ${var{:}[=+-?]word} */
                    173:                                cp = sp;                /* variable */
                    174:                                sp = strchr(sp, 0) + 1; /* skip variable */
                    175:                                c = (*sp == CSUBST) ? 0 : *sp++;
                    176:                                if ((c&0x7F) == '#' || (c&0x7F) == '%')
                    177:                                        f |= DOPAT;
                    178:                                type = varsub(&x, cp, c);
                    179:                                if (type == XBASE) {    /* expand? */
                    180:                                        if (st == subtype)
                    181:                                                errorf("ridiculous ${} nesting\n");
                    182:                                        --st;
                    183:                                        st->type = c;
                    184:                                        st->base = Xsavepos(ds, dp);
                    185:                                        st->name = cp;
                    186:                                } else
                    187:                                        /* todo: nested OSUBST/CSUBST */
                    188:                                        sp = wdscan(sp, CSUBST); /* skip word */
                    189:                                continue;
                    190:                          case CSUBST: /* only get here if expanding word */
                    191:                                *dp = 0;
                    192:                                if (f&DOGLOB)
                    193:                                        f &= ~DOPAT;
                    194:                                switch (st->type&0x7F) {
                    195:                                  case '#':
                    196:                                  case '%':
                    197:                                        *dp = 0;
                    198:                                        dp = Xrestpos(ds, dp, st->base);
                    199:                                        x.str = trimsub(x.str, dp, st->type);
                    200:                                        type = XSUB;
                    201:                                        continue;
                    202:                                  case '=':
                    203: #if 0
                    204:                                        if ((x.u.vp->flag&RDONLY))
                    205:                                                errorf("cannot set readonly %s\n", cp);
                    206: #endif
                    207:                                        setstr(global(st->name), Xrestpos(ds, dp, st->base));
                    208:                                        break;
                    209:                                  case '?':
                    210:                                        if (dp == Xrestpos(ds, dp, st->base))
                    211:                                                errorf("missing value for %s\n", cp);
                    212:                                        else
                    213:                                                errorf("%s\n", Xrestpos(ds, dp, st->base));
                    214:                                }
                    215:                                st++;
                    216:                                type = XBASE;
                    217:                                continue;
                    218:                        }
                    219:                        break;
                    220: 
                    221:                  case XSUB:
                    222:                        if ((c = *x.str++) == 0) {
                    223:                                type = XBASE;
                    224:                                continue;
                    225:                        }
                    226:                        break;
                    227: 
                    228:                  case XARGSEP:
                    229:                        type = XARG;
                    230:                        quote = 1;
                    231:                  case XARG:
                    232:                        if ((c = *x.str++) == 0) {
                    233:                                if ((x.str = *x.u.strv++) == NULL) {
                    234:                                        type = XBASE;
                    235:                                        continue;
                    236:                                } else if (quote && x.split) {
                    237:                                        /* terminate word for "$@" */
                    238:                                        type = XARGSEP;
                    239:                                        quote = 0;
                    240:                                }
                    241:                                c = ifs0;
                    242:                        }
                    243:                        break;
                    244: 
                    245:                  case XCOM:
                    246:                        c = getc(x.u.file);
                    247:                        if (quote) {
                    248:                                if (c == EOF) {
                    249:                                        cp = Xrestpos(ds, sp, combase);
                    250:                                        for (dp--; dp >= cp && *dp == '\n'; dp--)
                    251:                                                ;
                    252:                                        dp++;
                    253:                                        fclose(x.u.file);
                    254:                                        if (x.split)
                    255:                                                waitlast();
                    256:                                        type = XBASE;
                    257:                                        continue;
                    258:                                }
                    259:                        } else {        /* this part is probably redundant */
                    260:                                if (c == EOF || c == '\n') {
                    261:                                        while ((c = getc(x.u.file)) == '\n')
                    262:                                                ;
                    263:                                        if (c == EOF) {
                    264:                                                fclose(x.u.file);
                    265:                                                if (x.split)
                    266:                                                        waitlast();
                    267:                                                type = XBASE;
                    268:                                                continue;
                    269:                                        }
                    270:                                        ungetc(c, x.u.file);
                    271:                                        c = ifs0;
                    272:                                }
                    273:                        }
                    274:                        break;
                    275:                }
                    276: 
                    277:                /* check for end of word or IFS separation */
                    278:                if (c == 0 || !quote && (f&DOBLANK) && ctype(c, C_IFS)) {
                    279:                        if (word) {
                    280:                                *dp++ = 0;
                    281:                                cp = Xclose(ds, dp);
                    282:                                if (fdo&DOTILDE)
                    283:                                        cp = tilde(cp);
                    284:                                if (fdo&DOGLOB)
                    285:                                        glob(cp, wp);
                    286:                                else
                    287:                                        {XPput(*wp, cp);}
                    288:                                fdo = word = 0;
                    289:                                if (c != 0)
                    290:                                        Xinit(ds, dp, 128);
                    291:                        } else
                    292:                                ; /* ignore IFS */
                    293:                        if (c == 0)
                    294:                                return;
                    295:                } else {
                    296:                        /* mark any special second pass chars */
                    297:                        if (!quote)
                    298:                                switch (c) {
                    299:                                  case '*':
                    300:                                  case '?':
                    301:                                  case '[':
                    302:                                        if (f&(DOPAT|DOGLOB)) {
                    303:                                                fdo |= (f&DOGLOB);
                    304:                                                *dp++ = MAGIC;
                    305:                                        }
                    306:                                        break;
                    307:                                  case '~':
                    308:                                        if ((f&DOTILDE) && dp == Xstring(ds, dp) ||
                    309:                                            !(f&DOBLANK) && 
                    310:                                            (dp[-1] == '=' || dp[-1] == ':')) {
                    311:                                                fdo |= DOTILDE;
                    312:                                                *dp++ = MAGIC;
                    313:                                        }
                    314:                                        break;
                    315:                                }
                    316:                        else
                    317:                                quote &= ~2; /* undo temporary */
                    318: 
                    319:                        word = 1;
                    320:                        *dp++ = c; /* save output char */
                    321:                }
                    322:        }
                    323: }
                    324: 
                    325: /*
                    326:  * Prepare to generate the string returned by ${} substitution.
                    327:  */
                    328: static int
                    329: varsub(xp, sp, stype)
                    330:        register Expand *xp;
                    331:        register char *sp;
                    332:        int stype;
                    333: {
                    334:        register int c;
                    335:        int type;
                    336: 
                    337:        /* ${#var}, string length or argc */
                    338:        if (sp[0] == '#' && (c = sp[1]) != 0) {
                    339:                c = (c == '*' || c == '@') ? e.loc->argc :
                    340:                        strlen(strval(global(sp+1)));
                    341:                xp->str = strsave(ulton((unsigned long)c, 10), ATEMP);
                    342:                return XSUB;
                    343:        }
                    344: 
                    345:        c = sp[0];
                    346:        if (c == '*' || c == '@') {
                    347:                if (e.loc->argc == 0) {
                    348:                        xp->str = null;
                    349:                        type = XSUB;
                    350:                } else {
                    351:                        xp->u.strv = e.loc->argv + 1;
                    352:                        xp->str = *xp->u.strv++;
                    353:                        xp->split = c == '@'; /* $@ */
                    354:                        type = XARG;
                    355:                }
                    356:        } else {
                    357:                xp->str = strval(global(sp));
                    358:                type = XSUB;
                    359:        }
                    360: 
                    361:        c = stype&0x7F;
                    362:        /* test the compiler's code generator */
                    363:        if (c == '%' || c == '#' ||
                    364:            (((stype&0x80) ? *xp->str=='\0' : xp->str==null) ? /* undef? */
                    365:             c == '=' || c == '-' || c == '?' : c == '+'))
                    366:                type = XBASE;   /* expand word instead of variable value */
                    367:        if (type != XBASE && flag[FNOUNSET] && xp->str == null)
                    368:                errorf("%s: unset variable\n", sp);
                    369:        return type;
                    370: }
                    371: 
                    372: /*
                    373:  * Run the command in $(...) and read its output.
                    374:  */
                    375: static int
                    376: comsub(xp, cp)
                    377:        register Expand *xp;
                    378:        char *cp;
                    379: {
                    380:        Source *s;
                    381:        register struct op *t;
                    382:        FILE *fi;
                    383: 
                    384:        s = pushs(SSTRING);
                    385:        s->str = cp;
                    386:        t = compile(s);
                    387: 
                    388:        if (t != NULL && t->type == TCOM && /* $(<file) */
                    389:            *t->args == NULL && *t->vars == NULL && t->ioact != NULL) {
                    390:                register struct ioword *io = *t->ioact;
                    391: 
                    392:                if (io->flag != IOREAD)
                    393:                        errorf("funny $() command\n");
                    394:                fi = fopen(evalstr(io->name, DOTILDE), "r");
                    395:                if (fi != NULL)
                    396:                        fileno(fi) = savefd(fileno(fi));
                    397:                xp->split = 0;  /* no waitlast() */
                    398:        } else {
                    399:                int ofd1, pv[2];
                    400:                openpipe(pv);
                    401:                fi = fdopen(pv[0], "r");
                    402:                ofd1 = savefd(1);
                    403:                dup2(pv[1], 1);
                    404:                close(pv[1]);
                    405: #if 0
                    406:                exchild(t, XXCOM|XPIPEO);
                    407: #else
                    408:                execute(t, XFORK|XXCOM|XPIPEO);
                    409: #endif
                    410:                dup2(ofd1, 1);
                    411:                xp->split = 1;  /* waitlast() */
                    412:        }       
                    413: 
                    414:        if (fi == NULL)
                    415:                errorf("cannot open $() input\n");
                    416:        setvbuf(fi, (char *)NULL, _IOFBF, BUFSIZ);
                    417:        xp->u.file = fi;
                    418:        return XCOM;
                    419: }
                    420: 
                    421: /*
                    422:  * perform #pattern and %pattern substitution in ${}
                    423:  */
                    424: 
                    425: static char *
                    426: trimsub(str, pat, how)
                    427:        register char *str;
                    428:        char *pat;
                    429:        int how;
                    430: {
                    431:        register char *end = strchr(str, 0);
                    432:        register char *p, c;
                    433: 
                    434:        switch (how) {
                    435:          case '#':             /* shortest at begin */
                    436:                for (p = str; p <= end; p++) {
                    437:                        c = *p; *p = '\0';
                    438:                        if (gmatch(str, pat)) {
                    439:                                *p = c;
                    440:                                return p;
                    441:                        }
                    442:                        *p = c;
                    443:                }
                    444:                break;
                    445:        case '#'|0x80:          /* longest match at begin */
                    446:                for (p = end; p >= str; p--) {
                    447:                        c = *p; *p = '\0';
                    448:                        if (gmatch(str, pat)) {
                    449:                                *p = c;
                    450:                                return p;
                    451:                        }
                    452:                        *p = c;
                    453:                }
                    454:                break;
                    455:          case '%':             /* shortest match at end */
                    456:                for (p = end; p >= str; p--) {
                    457:                        if (gmatch(p, pat)) {
                    458:                                *p = '\0';
                    459:                                return str;
                    460:                        }
                    461:                }
                    462:                break;
                    463:          case '%'|0x80:        /* longest match at end */
                    464:                for (p = str; p <= end; p++) {
                    465:                        if (gmatch(p, pat)) {
                    466:                                *p = '\0';
                    467:                                return str;
                    468:                        }
                    469:                }
                    470:                break;
                    471:        }
                    472: 
                    473:        return str;             /* no match, return string */
                    474: }
                    475: 
                    476: /*
                    477:  * glob
                    478:  * Name derived from V6's /etc/glob, the program that expanded filenames.
                    479:  */
                    480: 
                    481: static char   *debunk();
                    482: 
                    483: static void 
                    484: glob(cp, wp)
                    485:        char *cp;
                    486:        register XPtrV *wp;
                    487: {
                    488:        char path [PATH];
                    489:        register char *sp = cp;
                    490:        int oldsize;
                    491: 
                    492:        oldsize = XPsize(*wp);
                    493:        globit(path, path, sp, wp, 0);
                    494: 
                    495:        if (XPsize(*wp) == oldsize)
                    496:                {XPput(*wp, debunk(cp));}
                    497:        else
                    498:                qsortp(XPptrv(*wp) + oldsize, (size_t)(XPsize(*wp) - oldsize), xstrcmp);
                    499: }
                    500: 
                    501: static void
                    502: globit(ds, dp, sp, wp, check)
                    503:        char *ds;               /* dest path */
                    504:        char *dp;               /* dest end */
                    505:        char *sp;               /* source path */
                    506:        register XPtrV *wp;     /* output list */
                    507:        int check;              /* check dest existence */
                    508: {
                    509:        register char *np;      /* next source component */
                    510:        register char *tsp, *tdp;
                    511: 
                    512:        if (sp == NULL) {       /* end of source path */
                    513:                if (check && eaccess(ds, 0) < 0)
                    514:                        return;
                    515:                XPput(*wp, strsave(ds, ATEMP));
                    516:                return;
                    517:        }
                    518: 
                    519:        if (dp > ds)
                    520:                *dp++ = '/';
                    521:        while (*sp == '/')
                    522:                *dp++ = *sp++;
                    523:        np = strchr(sp, '/');
                    524:        if (np != NULL)
                    525:                *np++ = 0;
                    526: 
                    527:        *dp = 0;
                    528:        if (strchr(sp, MAGIC) == NULL) { /* contains no pattern? */
                    529:                tdp = dp; tsp = sp;
                    530:                while ((*tdp++ = *tsp++) != 0)
                    531:                        ;
                    532:                --tdp;
                    533:                globit(ds, tdp, np, wp, check);
                    534:        } else {
                    535:                DIR *dirp;
                    536:                struct dirent *d;
                    537: 
                    538:                dirp = opendir(ds);
                    539:                if (dirp == NULL)
                    540:                        goto Nodir;
                    541:                while ((d = readdir(dirp)) != NULL) {
                    542:                        tsp = d->d_name;
                    543:                        if (tsp[0] == '.' &&
                    544:                            (tsp[1] == 0 || tsp[1] == '.' && tsp[2] == 0))
                    545:                                continue; /* always ignore . and .. */
                    546:                        if (*tsp == '.' && *sp != '.' || !gmatch(tsp, sp))
                    547:                                continue;
                    548: 
                    549:                        tdp = dp;
                    550:                        while ((*tdp++ = *tsp++) != 0)
                    551:                                ;
                    552:                        --tdp;
                    553:                        globit(ds, tdp, np, wp, np != NULL);
                    554:                }
                    555:                closedir(dirp);
                    556:          Nodir:;
                    557:        }
                    558: 
                    559:        if (np != NULL)
                    560:                *--np = '/';
                    561: }
                    562: 
                    563: /* remove MAGIC from string */
                    564: static char *
                    565: debunk(cp)
                    566:        char *cp;
                    567: {
                    568:        register char *dp, *sp;
                    569: 
                    570:        for (dp = sp = cp; *sp != 0; sp++)
                    571:                if (*sp != MAGIC)
                    572:                        *dp++ = *sp;
                    573:        *dp = 0;
                    574:        return cp;
                    575: }
                    576: 
                    577: /*
                    578:  * tilde expansion
                    579:  *
                    580:  * based on a version by Arnold Robbins
                    581:  */
                    582: 
                    583: static char *homedir();
                    584: 
                    585: static char *
                    586: tilde(acp)
                    587:        char *acp;
                    588: {
                    589:        register int c;
                    590:        char path [PATH+1];
                    591:        register char *cp = acp, *wp = path, *dp;
                    592:        char userid [16+1];
                    593: 
                    594:   Again:
                    595:        while (1) {
                    596:                if ((c = *cp++) == 0) {
                    597:                        *wp = 0;
                    598:                        afree((Void*)acp, ATEMP);
                    599:                        return strsave(path, ATEMP);
                    600:                } else if (c == MAGIC && *cp == '~')
                    601:                        break;
                    602:                else
                    603:                        *wp++ = c;
                    604:        }
                    605: 
                    606:        dp = NULL;      /* no output substitution */
                    607:        if (cp[1] == 0 || cp[1] == '/' || cp[1] == ':') /* ~ or ~/ */
                    608:                dp = strval(global("HOME")), cp += 1;
                    609:        else if (cp[1] == '+' && (cp[2] == '/' || cp[2] == ':' || cp[2] == 0))
                    610:                dp = strval(global("PWD")), cp += 2;
                    611:        else if (cp[1] == '-' && (cp[2] == '/' || cp[2] == ':' || cp[2] == 0))
                    612:                dp = strval(global("OLDPWD")), cp += 2;
                    613:        else if (letter(cp[1])) {
                    614:                char *save = cp;
                    615:                for (dp = userid, cp++; letnum(*cp) && dp < userid+16; )
                    616:                        *dp++ = *cp++;
                    617:                *dp = 0;
                    618:                dp = homedir(userid);
                    619:                if (dp == NULL)
                    620:                        cp = save;
                    621:        }
                    622:        /* substitute */
                    623:        if (dp != NULL)
                    624:                while (*dp != 0)
                    625:                        *wp++ = *dp++;
                    626:        goto Again;
                    627: }
                    628: 
                    629: /*
                    630:  * map userid to user's home directory.
                    631:  * todo: implement a cache with the "homedirs" table.
                    632:  * note that 4.3's getpw adds more than 6K to the shell,
                    633:  * and the YP version probably adds much more.
                    634:  * we might consider our own version of getpwnam() to keep the size down.
                    635:  */
                    636: 
                    637: static char *
                    638: homedir(name)
                    639:        char *name;
                    640: {
                    641:        register struct tbl *ap;
                    642:        register struct passwd *pw;
                    643: 
                    644:        ap = tsearch(&homedirs, name, hash(name));
                    645:        if ((ap != NULL && (ap->flag&ISSET)))
                    646:                return ap->val.s;
                    647:        pw = getpwnam(name);
                    648:        if (pw == NULL)
                    649:                return NULL;
                    650:        return pw->pw_dir;
                    651: }
                    652: 

unix.superglobalmegacorp.com

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