Annotation of coherent/b/bin/sh.420/eval.c, revision 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.