Annotation of coherent/b/bin/sh.420/eval.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * sh/eval.c
                      3:  * Bourne shell.
                      4:  * Evaluation of parameter substitution, command substitution,
                      5:  * blank interpretation, and file name generation.
                      6:  */
                      7: 
                      8: #include <sys/compat.h>
                      9: #include <sys/stat.h>
                     10: #include <fcntl.h>
                     11: #include "sh.h"
                     12: 
                     13: struct eval_context {
                     14:        char    * arcp;         /* character position in argument */
                     15:        int     argf;           /* First character of argument flag */
                     16:        int     argg;           /* Glob seek, escape quoted glob chars */
                     17:        int     argq;           /* Quotation flag, no blanks or glob */
                     18: } _eval [1];
                     19: 
                     20: LOCAL  void    variable        ();
                     21: LOCAL  void    special         ();
                     22: LOCAL  void    graves          ();
                     23: 
                     24: LOCAL  void    add_char        ();
                     25: LOCAL  void    add_quoted      ();
                     26: LOCAL  void    add_arg         ();
                     27: LOCAL  void    end_arg         ();
                     28: 
                     29: #define        EVAL_NO_QUOTE                   0
                     30: #define        EVAL_QUOTED                     1
                     31: #define        EVAL_FORCE_QUOTE                2
                     32: 
                     33: #define        EVAL_INPUT_SOURCE(eval,cp)      (void) ((eval)->arcp = (cp))
                     34: #define        EVAL_NEXT_CHAR(eval)            (* (eval)->arcp ++)
                     35: #define        EVAL_UNGET_CHAR(eval,ch)        (void) ((eval)->arcp --)
                     36: 
                     37: #define        EVAL_SET_QUOTING(eval,q)        (void) ((eval)->argq = (q))
                     38: #define        EVAL_ADD_QUOTE(eval,q)  \
                     39:                (void) ((eval)->argq = ((eval)->argq & ~ EVAL_QUOTED)  | (q))
                     40: #define        EVAL_IS_QUOTED(eval)            ((eval)->argq)
                     41: 
                     42: #define        EVAL_SET_GLOB(eval,g)           (void) ((eval)->argg = (g))
                     43: #define        EVAL_IS_GLOBSEEK(eval)          ((eval)->argg != 0)
                     44: 
                     45: #define        EVAL_MADE_ARGUMENT(eval)        (void) ((eval)->argf = 0)
                     46: #define        EVAL_ARGUMENT_IF_QUOTED(eval)   (void) ((eval)->argf &= \
                     47:                                                ~ (eval)->argq)
                     48: #define        EVAL_NO_ARGUMENT(eval)          (void) ((eval)->argf = 1, strp = strt)
                     49: #define        EVAL_IS_NO_ARGUMENT(eval)       ((eval)->argf != 0)
                     50: 
                     51: 
                     52: /*
                     53:  * Evaluate a string.
                     54:  */
                     55: 
                     56: void
                     57: eval(cp, f)
                     58: char *cp;
                     59: {
                     60:        register int m, c;
                     61: 
                     62:        EVAL_INPUT_SOURCE (_eval, cp);
                     63:        EVAL_NO_ARGUMENT (_eval);
                     64: 
                     65:        if (f == EHERE) {
                     66:                m = MHERE;
                     67:                EVAL_SET_QUOTING (_eval, EVAL_FORCE_QUOTE);
                     68:        } else if (f == EWORD) {
                     69:                m = MNQUO;
                     70:                EVAL_SET_QUOTING (_eval, EVAL_FORCE_QUOTE);
                     71:        } else {
                     72:                m = MNQUO;
                     73:                EVAL_SET_QUOTING (_eval, EVAL_NO_QUOTE);
                     74:        }
                     75:        EVAL_SET_GLOB (_eval, f == EARGS || f == EPATT);
                     76: 
                     77:        while ((c = EVAL_NEXT_CHAR (_eval)) != '\0') {
                     78:                if (! class (c, m)) {
                     79:                        add_char (c);
                     80:                        continue;
                     81:                }
                     82:                switch (c) {
                     83:                case '"':       /* m == MNQUO || m == MDQUO */
                     84:                        if ((m ^= (MDQUO ^ MNQUO)) == MDQUO) {
                     85: 
                     86:                                EVAL_ADD_QUOTE (_eval, EVAL_QUOTED);
                     87: 
                     88:                                if ((c = EVAL_NEXT_CHAR (_eval)) == '\"')
                     89:                                        EVAL_MADE_ARGUMENT (_eval);
                     90: 
                     91:                                EVAL_UNGET_CHAR (_eval, c);
                     92:                        } else
                     93:                                EVAL_ADD_QUOTE (_eval, 0);
                     94:                        continue;
                     95: 
                     96:                case '\'':      /* m == MNQUO */
                     97:                        while ((c = EVAL_NEXT_CHAR (_eval)) != '\'' && c != 0)
                     98:                                add_quoted (c);
                     99:                        EVAL_MADE_ARGUMENT (_eval);
                    100:                        continue;
                    101: 
                    102:                case '\\':      /* m == MDQUO || m == MNQUO */
                    103:                        c = EVAL_NEXT_CHAR (_eval);
                    104:                        if (m != MNQUO && ! class (c, m)) {
                    105:                                add_char ('\\');
                    106:                                add_char (c);
                    107:                        } else
                    108:                                add_quoted (c);
                    109:                        EVAL_MADE_ARGUMENT (_eval);
                    110:                        continue;
                    111: 
                    112:                case '$':       /* m == MNQUO || m = MDQUO */
                    113:                        variable ();
                    114:                        continue;
                    115: 
                    116:                case '`':       /* m == MNQUO || m = MDQUO */
                    117:                        graves (m);
                    118:                        continue;
                    119: 
                    120:                default:
                    121:                        add_char (c);
                    122:                        continue;
                    123:                }
                    124:        }
                    125: 
                    126:        if (f == EARGS)
                    127:                end_arg ();
                    128:        else
                    129:                * strp ++ = '\0';
                    130: }
                    131: 
                    132: 
                    133: /*
                    134:  * Read the name of a shell variable and perform the appropriate substitution.
                    135:  */
                    136: 
                    137: LOCAL void
                    138: variable()
                    139: {
                    140:        VAR *vp;
                    141:        int s;
                    142:        char *sav;
                    143:        register int c, count, quote;
                    144:        register char * pp;
                    145:        char          * name_start = strp;
                    146:        char          * alternate_value;
                    147:        int             colon_test = 0;
                    148: 
                    149:        s = '\0';
                    150:        c = EVAL_NEXT_CHAR (_eval);
                    151: 
                    152:        if (strchr (SPECIAL_VAR_CHARS, c) != 0) {
                    153:                special (c);
                    154:                return;
                    155:        } else if (class (c, MRVAR)) {
                    156:                do {
                    157:                        add_arg (c);
                    158:                        c = EVAL_NEXT_CHAR (_eval);
                    159:                } while (class (c, MRVAR));
                    160: 
                    161:                EVAL_UNGET_CHAR (_eval, c);
                    162:        } else if (c != '{') {
                    163:                /* Not a legal variable name, put it back. */
                    164:                add_char ('$');
                    165:                add_char (c);
                    166:                return;
                    167:        } else {
                    168:                /* c == '{' */
                    169: 
                    170:                c = EVAL_NEXT_CHAR (_eval);
                    171: 
                    172:                if (strchr (SPECIAL_VAR_CHARS, c) != NULL) {
                    173:                        int             peek;
                    174: 
                    175:                        if ((peek = EVAL_NEXT_CHAR (_eval)) == '}') {
                    176: 
                    177:                                /* Allow specials of the form "${?}" etc. */
                    178:                                special (c);
                    179:                                return;
                    180:                        }
                    181:                        EVAL_UNGET_CHAR (_eval, peek);
                    182:                }
                    183: 
                    184:                for (;;) {
                    185:                        if (! class (c, MRVAR))
                    186:                                break;
                    187:                        add_arg (c);
                    188:                        c = EVAL_NEXT_CHAR (_eval);
                    189:                }
                    190: 
                    191:                if ((colon_test = c == ':') != 0)
                    192:                        c = EVAL_NEXT_CHAR (_eval);
                    193: 
                    194:                if (strchr ("-=?+", c) != NULL) {
                    195:                        /*
                    196:                         * ${VAR [-=?+] word}
                    197:                         * Stash away the value of the intemediate character
                    198:                         * and store a '=' character to stroke the variable-
                    199:                         * storage machinery.
                    200:                         */
                    201: 
                    202:                        s = c;
                    203:                        add_arg ('=');
                    204:                        alternate_value = strp;
                    205:                        if ((quote = EVAL_NEXT_CHAR (_eval)) != '"' &&
                    206:                            quote != '\'') {
                    207: 
                    208:                                EVAL_UNGET_CHAR (_eval, quote);
                    209:                                quote = 0;
                    210:                        }
                    211: 
                    212:                        for (count = 1; ; ) {
                    213:                                c = EVAL_NEXT_CHAR (_eval);
                    214:                                if (c == '}' && count -- == 1)
                    215:                                        break;
                    216:                                else if (c == '$' && quote != '\'') {
                    217: /*
                    218:  * steve 6/24/92
                    219:  * This truly sleazy hack handles e.g. "${V1-$V2}", oy.
                    220:  * It doesn't do it very well, paying no attention to quotes (for example).
                    221:  */
                    222:                                        variable ();
                    223:                                        continue;
                    224:                                } else if (c == '{')
                    225:                                        ++ count;
                    226:                                else if (quote != 0 && c == quote) {
                    227:                                        quote = 0;
                    228:                                        continue;
                    229:                                }
                    230:                                add_arg (c);
                    231:                        }
                    232:                } else if (colon_test || c != '}') {
                    233:                        eillvar (strp = name_start);
                    234:                        return;
                    235:                }
                    236:        }
                    237:        add_arg ('\0');
                    238: 
                    239:        c = * name_start;
                    240: 
                    241:        if (class (c, MDIGI)) {
                    242:                if ((c -= '1') >= sargc)
                    243:                        pp = NULL;
                    244:                else
                    245:                        pp = sargp [c];
                    246:        } else if (namevar (name_start) == 0) {
                    247:                eillvar (strp = name_start);
                    248:                return;
                    249:        } else {
                    250:                pp = NULL;
                    251:                if ((vp = findvar (name_start)) != NULL) {
                    252:                        pp = convvar (vp);
                    253:                        if (* pp == '\0' && colon_test)
                    254:                                pp = NULL;      /* regard value "" as not set */
                    255:                }
                    256:        }
                    257: 
                    258:        switch (s) {
                    259:        case '\0':
                    260:                if (uflag != 0 && pp == NULL)
                    261:                        enotdef (name_start);
                    262:                break;
                    263: 
                    264:        case '-':
                    265:                if (pp == NULL)
                    266:                        pp = alternate_value;
                    267:                break;
                    268: 
                    269:        case '=':
                    270:                if (pp == NULL) {
                    271:                        if (class (* name_start, MDIGI) ||
                    272:                            strchr (SPECIAL_VAR_CHARS,
                    273:                                    * name_start) != NULL) {
                    274: 
                    275:                                printe ("Illegal substitution");
                    276:                                strp = name_start;
                    277:                                return;
                    278:                        }
                    279:                        setsvar (name_start);
                    280:                        pp = alternate_value;
                    281:                }
                    282:                break;
                    283: 
                    284:        case '?':
                    285:                if (pp != NULL)
                    286:                        break;
                    287:                if (* alternate_value != '\0')
                    288:                        prints ("%s\n", alternate_value);
                    289:                else {
                    290:                        alternate_value [-1] = '\0';
                    291:                        enotdef (name_start);
                    292:                }
                    293:                reset (RUABORT);
                    294:                NOTREACHED;
                    295: 
                    296:        case '+':
                    297:                if (pp != NULL)
                    298:                        pp = alternate_value;
                    299:                break;
                    300:        }
                    301: 
                    302:        strp = name_start;
                    303: 
                    304:        if (pp != NULL)
                    305:                while ((c = * pp ++) != '\0')
                    306:                        add_char (c);
                    307: 
                    308:        EVAL_ARGUMENT_IF_QUOTED (_eval);
                    309: }
                    310: 
                    311: 
                    312: /*
                    313:  * Return the value of the special shell variables.
                    314:  * No check for end of buffer.
                    315:  */
                    316: 
                    317: LOCAL void
                    318: special(n)
                    319: int            n;
                    320: {
                    321:        int             flag;
                    322:        char          * sp;
                    323: 
                    324:        switch (n) {
                    325:        case '#':
                    326:                n = sargc;
                    327:                goto maked;
                    328: 
                    329:        case '?':
                    330:                n = slret;
                    331:                goto maked;
                    332: 
                    333:        case '$':
                    334:                n = shpid;
                    335:                goto maked;
                    336: 
                    337:        case '!':
                    338:                n = sback;
                    339:                goto maked;
                    340: 
                    341:        maked:
                    342:                sprintf (strp, "%d", n);
                    343:                sp = strp;
                    344:                break;
                    345: 
                    346:        case '-':
                    347: 
                    348:                for (sp = & eflag; sp <= & xflag ; sp ++)
                    349:                        if (* sp)
                    350:                                add_char (* sp);
                    351: 
                    352:                EVAL_ARGUMENT_IF_QUOTED (_eval);
                    353:                return;
                    354: 
                    355:        case '@':
                    356:        case '*':
                    357:                flag = EVAL_IS_QUOTED (_eval) == EVAL_QUOTED && n == '@';
                    358:                for (n = 0; n < sargc; n++) {
                    359:                        if (n) {
                    360:                                if (flag)
                    361:                                        end_arg ();
                    362:                                else
                    363:                                        add_char (' ');
                    364:                        }
                    365: 
                    366:                        sp = sargp [n];
                    367:                        while (* sp)
                    368:                                add_char (* sp ++);
                    369: 
                    370:                        /*
                    371:                         * Make sure that arguments like "" get handled
                    372:                         * properly when expanding "$@"
                    373:                         */
                    374: 
                    375:                        if (flag)
                    376:                                EVAL_ARGUMENT_IF_QUOTED (_eval);
                    377:                }
                    378:                return;
                    379: 
                    380:        case '0':
                    381:                sp = sarg0;
                    382:                break;
                    383: 
                    384:        default:
                    385:                if (n - '1' >= sargc) {
                    386:                        if (uflag)
                    387:                                printe ("Unset parameter: %c", n);
                    388:                        EVAL_ARGUMENT_IF_QUOTED (_eval);
                    389:                        return;
                    390:                }
                    391:                sp = sargp [n - '1'];
                    392:                break;
                    393:        }
                    394: 
                    395:        while (* sp)
                    396:                add_char (* sp ++);
                    397: 
                    398:        EVAL_ARGUMENT_IF_QUOTED (_eval);
                    399: }
                    400: 
                    401: 
                    402: /*
                    403:  * Read and evaluate a command found between graves.
                    404:  *
                    405:  * NB : Backslash-quoting inside graves was not supported properly before,
                    406:  * and I'm not sure that I've got it right. The idea is that before passing
                    407:  * things off to session (), we process the appropriate backslash-escapes.
                    408:  * What consists of an "appropriate" escape depends on whether the graves
                    409:  * appeared within a double-quoted section (in which case we recognise the
                    410:  * specials appropriate to that) or not (in which case we recognised the
                    411:  * characters $`\ as specials. We also process '$'-expansions in graves now,
                    412:  * but not globs.
                    413:  *
                    414:  * Since we are removing some bashslashes here, we should be building into
                    415:  * a temporary buffer. We append our work onto the global "strp" buffer and
                    416:  * cut it back once we have finished.
                    417:  */
                    418: 
                    419: LOCAL void
                    420: graves (quotemode)
                    421: int            quotemode;
                    422: {
                    423:        int pipev[2], f, oslret;
                    424:        char          * ostrp;
                    425:        register FILE *fp;
                    426:        register int c;
                    427:        register int nnl;
                    428: 
                    429:        ostrp = strp;
                    430:        oslret = slret;
                    431: 
                    432:        while ((c = EVAL_NEXT_CHAR (_eval)) != '`') {
                    433:                if (c != '\\') {
                    434:                        add_arg (c);
                    435:                        continue;
                    436:                }
                    437:                c = EVAL_NEXT_CHAR (_eval);
                    438: 
                    439:                if (! (quotemode == MDQUO && class (c, MDQUO)) &&
                    440:                    (c != '$' && c != '\\' && c != '`'))
                    441:                        add_arg ('\\');
                    442: 
                    443:                add_arg (c);
                    444:        }
                    445:        * strp = 0;
                    446: 
                    447:        if ((f = pipeline (pipev)) == 0) {
                    448:                slret = oslret;         /* in case grave command uses $? */
                    449:                dup2 (pipev [1], 1);
                    450:                close (pipev [0]);
                    451:                close (pipev [1]);
                    452:                exit (session (SARGS, ostrp));
                    453:                NOTREACHED;
                    454:        }
                    455: 
                    456:        close (pipev [1]);
                    457:        if ((fp = fdopen (pipev [0], "r")) == NULL) {
                    458:                close (pipev [0]);
                    459:                ecantfdop ();
                    460:                return;
                    461:        }
                    462:        strp = ostrp;
                    463:        nnl = 0;
                    464: 
                    465:        while ((c = getc (fp)) != EOF) {
                    466:                if (! recover (IEVAL)) {
                    467: #ifdef VERBOSE
                    468:                        if (xflag) prints ("Interrupt in eval\n");
                    469: #endif
                    470:                        errflag ++;
                    471:                        break;
                    472:                }
                    473:                if (c == '\n')
                    474:                        ++ nnl;
                    475:                else {
                    476:                        while (nnl) {
                    477:                                nnl --;
                    478:                                add_char ('\n');
                    479:                        }
                    480:                        add_char (c);
                    481:                }
                    482:        }
                    483: 
                    484:        /*
                    485:         * If we expanded to something, we have an arg. If we are in double-
                    486:         * quotes, we have an arg. Otherwise, we have an arg if we had an arg
                    487:         * before.
                    488:         */
                    489: 
                    490:        EVAL_ARGUMENT_IF_QUOTED (_eval);
                    491:        fclose (fp);
                    492:        waitc (f);
                    493: }
                    494: 
                    495: 
                    496: /*
                    497:  * Add a character to the current argument.
                    498:  * If no quotation is set, pick off blanks and globs.
                    499:  */
                    500: 
                    501: LOCAL void
                    502: add_char(c)
                    503: register int c;
                    504: {
                    505:        if (EVAL_IS_QUOTED (_eval) == 0) {
                    506:                if (strchr (vifs, c) != NULL) {
                    507:                        end_arg ();
                    508:                        return;
                    509:                }
                    510:                if (EVAL_IS_GLOBSEEK (_eval) && class (c, MGLOB)) {
                    511:                        add_arg (c);
                    512:                        EVAL_MADE_ARGUMENT (_eval);
                    513:                        return;
                    514:                }
                    515:        }
                    516:        add_quoted (c);
                    517: }
                    518: 
                    519: 
                    520: /*
                    521:  * Add a quoted character to the current argument.
                    522:  * if argg is set, then glob characters are quoted with a \,
                    523:  * as well as \ itself.
                    524:  */
                    525: 
                    526: LOCAL void
                    527: add_quoted(c) register int c;
                    528: {
                    529:        if (EVAL_IS_GLOBSEEK (_eval) && (class (c, MGLOB) || c == '\\'))
                    530:                add_arg ('\\');
                    531: 
                    532:        add_arg (c);
                    533:        EVAL_MADE_ARGUMENT (_eval);
                    534: }
                    535: 
                    536: 
                    537: /*
                    538:  * Add a character to the current argument
                    539:  * and check for end of buffer.
                    540:  */
                    541: 
                    542: LOCAL void
                    543: add_arg (c) register int c;
                    544: {
                    545:        if (strp >= strt + STRSIZE)     /* Should do more */
                    546:                etoolong ("in add_arg ()");
                    547:        else
                    548:                * strp ++ = c;
                    549: }
                    550: 
                    551: 
                    552: /*
                    553:  * Terminate the current argument if it is non-empty.
                    554:  * If argg is set, then glob the argument to expand globs
                    555:  * or to simply remove any quotes.
                    556:  */
                    557: 
                    558: LOCAL void
                    559: end_arg ()
                    560: {
                    561:        if (EVAL_IS_NO_ARGUMENT (_eval))
                    562:                return;
                    563: 
                    564:        * strp ++ = '\0';
                    565:        if (EVAL_IS_GLOBSEEK (_eval))
                    566:                glob1 (duplstr (strt, 0));
                    567:        else {
                    568:                nargv = addargl (nargv, duplstr (strt, 0));
                    569:                nargc += 1;
                    570:        }
                    571: 
                    572:        EVAL_NO_ARGUMENT (_eval);
                    573: }
                    574: 
                    575: 
                    576: /*
                    577:  * Evaluate a here document.
                    578:  */
                    579: 
                    580: int
                    581: evalhere(u2)
                    582: {
                    583:        register int u1;
                    584:        register FILE *f2;
                    585:        char buf[128];
                    586:        char *tmp;
                    587: 
                    588:        tmp = shtmp ();
                    589:        if ((u1 = creat (tmp, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) {
                    590:                ecantmake (tmp);
                    591:                return -1;
                    592:        }
                    593:        if ((f2 = fdopen (u2, "r")) == NULL) {
                    594:                ecantfdop ();
                    595:                close (u1);
                    596:                close (u2);
                    597:                return -1;
                    598:        }
                    599:        while (fgets (buf, sizeof (buf), f2) != NULL) {
                    600:                eval (buf, EHERE);
                    601:                write (u1, strt, strp - 1 - strt);
                    602:        }
                    603:        close (u1);
                    604:        fclose (f2);
                    605:        if ((u2 = open (tmp, O_RDONLY)) < 0) {
                    606:                ecantopen (tmp);
                    607:                u2 = -1;
                    608:        }
                    609:        unlink (tmp);
                    610:        return u2;
                    611: }

unix.superglobalmegacorp.com

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