Annotation of 43BSDReno/usr.bin/make/cond.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
        !             3:  * Copyright (c) 1988, 1989 by Adam de Boor
        !             4:  * Copyright (c) 1989 by Berkeley Softworks
        !             5:  * All rights reserved.
        !             6:  *
        !             7:  * This code is derived from software contributed to Berkeley by
        !             8:  * Adam de Boor.
        !             9:  *
        !            10:  * Redistribution and use in source and binary forms are permitted
        !            11:  * provided that: (1) source distributions retain this entire copyright
        !            12:  * notice and comment, and (2) distributions including binaries display
        !            13:  * the following acknowledgement:  ``This product includes software
        !            14:  * developed by the University of California, Berkeley and its contributors''
        !            15:  * in the documentation or other materials provided with the distribution
        !            16:  * and in all advertising materials mentioning features or use of this
        !            17:  * software. Neither the name of the University nor the names of its
        !            18:  * contributors may be used to endorse or promote products derived
        !            19:  * from this software without specific prior written permission.
        !            20:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
        !            21:  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
        !            22:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
        !            23:  */
        !            24: 
        !            25: #ifndef lint
        !            26: static char sccsid[] = "@(#)cond.c     5.6 (Berkeley) 6/1/90";
        !            27: #endif /* not lint */
        !            28: 
        !            29: /*-
        !            30:  * cond.c --
        !            31:  *     Functions to handle conditionals in a makefile.
        !            32:  *
        !            33:  * Interface:
        !            34:  *     Cond_Eval       Evaluate the conditional in the passed line.
        !            35:  *
        !            36:  */
        !            37: 
        !            38: #include    "make.h"
        !            39: #include    <buf.h>
        !            40: #include    <ctype.h>
        !            41: 
        !            42: /*
        !            43:  * The parsing of conditional expressions is based on this grammar:
        !            44:  *     E -> F || E
        !            45:  *     E -> F
        !            46:  *     F -> T && F
        !            47:  *     F -> T
        !            48:  *     T -> defined(variable)
        !            49:  *     T -> make(target)
        !            50:  *     T -> exists(file)
        !            51:  *     T -> empty(varspec)
        !            52:  *     T -> target(name)
        !            53:  *     T -> symbol
        !            54:  *     T -> $(varspec) op value
        !            55:  *     T -> $(varspec) == "string"
        !            56:  *     T -> $(varspec) != "string"
        !            57:  *     T -> ( E )
        !            58:  *     T -> ! T
        !            59:  *     op -> == | != | > | < | >= | <=
        !            60:  *
        !            61:  * 'symbol' is some other symbol to which the default function (condDefProc)
        !            62:  * is applied.
        !            63:  *
        !            64:  * Tokens are scanned from the 'condExpr' string. The scanner (CondToken)
        !            65:  * will return And for '&' and '&&', Or for '|' and '||', Not for '!',
        !            66:  * LParen for '(', RParen for ')' and will evaluate the other terminal
        !            67:  * symbols, using either the default function or the function given in the
        !            68:  * terminal, and return the result as either True or False.
        !            69:  *
        !            70:  * All Non-Terminal functions (CondE, CondF and CondT) return Err on error.
        !            71:  */
        !            72: typedef enum {
        !            73:     And, Or, Not, True, False, LParen, RParen, EndOfFile, None, Err
        !            74: } Token;
        !            75: 
        !            76: /*-
        !            77:  * Structures to handle elegantly the different forms of #if's. The
        !            78:  * last two fields are stored in condInvert and condDefProc, respectively.
        !            79:  */
        !            80: static Boolean   CondDoDefined(),
        !            81:                  CondDoMake();
        !            82: 
        !            83: static struct If {
        !            84:     char       *form;        /* Form of if */
        !            85:     int                formlen;      /* Length of form */
        !            86:     Boolean    doNot;        /* TRUE if default function should be negated */
        !            87:     Boolean    (*defProc)(); /* Default function to apply */
        !            88: } ifs[] = {
        !            89:     "ifdef",     5,      FALSE,  CondDoDefined,
        !            90:     "ifndef",    6,      TRUE,   CondDoDefined,
        !            91:     "ifmake",    6,      FALSE,  CondDoMake,
        !            92:     "ifnmake",   7,      TRUE,   CondDoMake,
        !            93:     "if",        2,      FALSE,  CondDoDefined,
        !            94:     (char *)0,   0,      FALSE,  (Boolean (*)())0,
        !            95: };
        !            96: 
        !            97: static Boolean   condInvert;           /* Invert the default function */
        !            98: static Boolean   (*condDefProc)();     /* Default function to apply */
        !            99: static char      *condExpr;            /* The expression to parse */
        !           100: static Token     condPushBack=None;    /* Single push-back token used in
        !           101:                                         * parsing */
        !           102: 
        !           103: #define        MAXIF           30        /* greatest depth of #if'ing */
        !           104: 
        !           105: static Boolean   condStack[MAXIF];     /* Stack of conditionals's values */
        !           106: static int       condTop = MAXIF;      /* Top-most conditional */
        !           107: static int       skipIfLevel=0;        /* Depth of skipped conditionals */
        !           108: static Boolean   skipLine = FALSE;     /* Whether the parse module is skipping
        !           109:                                         * lines */
        !           110: 
        !           111: static Token     CondT(), CondF(), CondE();
        !           112: 
        !           113: /*-
        !           114:  *-----------------------------------------------------------------------
        !           115:  * CondPushBack --
        !           116:  *     Push back the most recent token read. We only need one level of
        !           117:  *     this, so the thing is just stored in 'condPushback'.
        !           118:  *
        !           119:  * Results:
        !           120:  *     None.
        !           121:  *
        !           122:  * Side Effects:
        !           123:  *     condPushback is overwritten.
        !           124:  *
        !           125:  *-----------------------------------------------------------------------
        !           126:  */
        !           127: static void
        !           128: CondPushBack (t)
        !           129:     Token        t;    /* Token to push back into the "stream" */
        !           130: {
        !           131:     condPushBack = t;
        !           132: }
        !           133: 
        !           134: /*-
        !           135:  *-----------------------------------------------------------------------
        !           136:  * CondGetArg --
        !           137:  *     Find the argument of a built-in function.
        !           138:  *
        !           139:  * Results:
        !           140:  *     The length of the argument and the address of the argument.
        !           141:  *
        !           142:  * Side Effects:
        !           143:  *     The pointer is set to point to the closing parenthesis of the
        !           144:  *     function call.
        !           145:  *
        !           146:  *-----------------------------------------------------------------------
        !           147:  */
        !           148: static int
        !           149: CondGetArg (linePtr, argPtr, func, parens)
        !           150:     char         **linePtr;
        !           151:     char         **argPtr;
        !           152:     char         *func;
        !           153:     Boolean      parens;       /* TRUE if arg should be bounded by parens */
        !           154: {
        !           155:     register char *cp;
        !           156:     int                  argLen;
        !           157:     register Buffer buf;
        !           158: 
        !           159:     cp = *linePtr;
        !           160:     if (parens) {
        !           161:        while (*cp != '(' && *cp != '\0') {
        !           162:            cp++;
        !           163:        }
        !           164:        if (*cp == '(') {
        !           165:            cp++;
        !           166:        }
        !           167:     }
        !           168: 
        !           169:     if (*cp == '\0') {
        !           170:        /*
        !           171:         * No arguments whatsoever. Because 'make' and 'defined' aren't really
        !           172:         * "reserved words", we don't print a message. I think this is better
        !           173:         * than hitting the user with a warning message every time s/he uses
        !           174:         * the word 'make' or 'defined' at the beginning of a symbol...
        !           175:         */
        !           176:        *argPtr = cp;
        !           177:        return (0);
        !           178:     }
        !           179: 
        !           180:     while (*cp == ' ' || *cp == '\t') {
        !           181:        cp++;
        !           182:     }
        !           183: 
        !           184:     /*
        !           185:      * Create a buffer for the argument and start it out at 16 characters
        !           186:      * long. Why 16? Why not?
        !           187:      */
        !           188:     buf = Buf_Init(16);
        !           189:     
        !           190:     while ((index(" \t)&|", *cp) == (char *)NULL) && (*cp != '\0')) {
        !           191:        if (*cp == '$') {
        !           192:            /*
        !           193:             * Parse the variable spec and install it as part of the argument
        !           194:             * if it's valid. We tell Var_Parse to complain on an undefined
        !           195:             * variable, so we don't do it too. Nor do we return an error,
        !           196:             * though perhaps we should...
        !           197:             */
        !           198:            char        *cp2;
        !           199:            int         len;
        !           200:            Boolean     doFree;
        !           201: 
        !           202:            cp2 = Var_Parse(cp, VAR_CMD, TRUE, &len, &doFree);
        !           203: 
        !           204:            Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2);
        !           205:            if (doFree) {
        !           206:                free(cp2);
        !           207:            }
        !           208:            cp += len;
        !           209:        } else {
        !           210:            Buf_AddByte(buf, (Byte)*cp);
        !           211:            cp++;
        !           212:        }
        !           213:     }
        !           214: 
        !           215:     Buf_AddByte(buf, (Byte)'\0');
        !           216:     *argPtr = (char *)Buf_GetAll(buf, &argLen);
        !           217:     Buf_Destroy(buf, FALSE);
        !           218: 
        !           219:     while (*cp == ' ' || *cp == '\t') {
        !           220:        cp++;
        !           221:     }
        !           222:     if (parens && *cp != ')') {
        !           223:        Parse_Error (PARSE_WARNING, "Missing closing parenthesis for %s()",
        !           224:                     func);
        !           225:        return (0);
        !           226:     } else if (parens) {
        !           227:        /*
        !           228:         * Advance pointer past close parenthesis.
        !           229:         */
        !           230:        cp++;
        !           231:     }
        !           232:     
        !           233:     *linePtr = cp;
        !           234:     return (argLen);
        !           235: }
        !           236: 
        !           237: /*-
        !           238:  *-----------------------------------------------------------------------
        !           239:  * CondDoDefined --
        !           240:  *     Handle the 'defined' function for conditionals.
        !           241:  *
        !           242:  * Results:
        !           243:  *     TRUE if the given variable is defined.
        !           244:  *
        !           245:  * Side Effects:
        !           246:  *     None.
        !           247:  *
        !           248:  *-----------------------------------------------------------------------
        !           249:  */
        !           250: static Boolean
        !           251: CondDoDefined (argLen, arg)
        !           252:     int            argLen;
        !           253:     char    *arg;
        !           254: {
        !           255:     char    savec = arg[argLen];
        !           256:     Boolean result;
        !           257: 
        !           258:     arg[argLen] = '\0';
        !           259:     if (Var_Value (arg, VAR_CMD) != (char *)NULL) {
        !           260:        result = TRUE;
        !           261:     } else {
        !           262:        result = FALSE;
        !           263:     }
        !           264:     arg[argLen] = savec;
        !           265:     return (result);
        !           266: }
        !           267: 
        !           268: /*-
        !           269:  *-----------------------------------------------------------------------
        !           270:  * CondStrMatch --
        !           271:  *     Front-end for Str_Match so it returns 0 on match and non-zero
        !           272:  *     on mismatch. Callback function for CondDoMake via Lst_Find
        !           273:  *
        !           274:  * Results:
        !           275:  *     0 if string matches pattern
        !           276:  *
        !           277:  * Side Effects:
        !           278:  *     None
        !           279:  *
        !           280:  *-----------------------------------------------------------------------
        !           281:  */
        !           282: static int
        !           283: CondStrMatch(string, pattern)
        !           284:     char    *string;
        !           285:     char    *pattern;
        !           286: {
        !           287:     return(!Str_Match(string,pattern));
        !           288: }
        !           289: 
        !           290: /*-
        !           291:  *-----------------------------------------------------------------------
        !           292:  * CondDoMake --
        !           293:  *     Handle the 'make' function for conditionals.
        !           294:  *
        !           295:  * Results:
        !           296:  *     TRUE if the given target is being made.
        !           297:  *
        !           298:  * Side Effects:
        !           299:  *     None.
        !           300:  *
        !           301:  *-----------------------------------------------------------------------
        !           302:  */
        !           303: static Boolean
        !           304: CondDoMake (argLen, arg)
        !           305:     int            argLen;
        !           306:     char    *arg;
        !           307: {
        !           308:     char    savec = arg[argLen];
        !           309:     Boolean result;
        !           310: 
        !           311:     arg[argLen] = '\0';
        !           312:     if (Lst_Find (create, (ClientData)arg, CondStrMatch) == NILLNODE) {
        !           313:        result = FALSE;
        !           314:     } else {
        !           315:        result = TRUE;
        !           316:     }
        !           317:     arg[argLen] = savec;
        !           318:     return (result);
        !           319: }
        !           320: 
        !           321: /*-
        !           322:  *-----------------------------------------------------------------------
        !           323:  * CondDoExists --
        !           324:  *     See if the given file exists.
        !           325:  *
        !           326:  * Results:
        !           327:  *     TRUE if the file exists and FALSE if it does not.
        !           328:  *
        !           329:  * Side Effects:
        !           330:  *     None.
        !           331:  *
        !           332:  *-----------------------------------------------------------------------
        !           333:  */
        !           334: static Boolean
        !           335: CondDoExists (argLen, arg)
        !           336:     int            argLen;
        !           337:     char    *arg;
        !           338: {
        !           339:     char    savec = arg[argLen];
        !           340:     Boolean result;
        !           341:     char    *path;
        !           342: 
        !           343:     arg[argLen] = '\0';
        !           344:     path = Dir_FindFile(arg, dirSearchPath);
        !           345:     if (path != (char *)NULL) {
        !           346:        result = TRUE;
        !           347:        free(path);
        !           348:     } else {
        !           349:        result = FALSE;
        !           350:     }
        !           351:     arg[argLen] = savec;
        !           352:     return (result);
        !           353: }
        !           354: 
        !           355: /*-
        !           356:  *-----------------------------------------------------------------------
        !           357:  * CondDoTarget --
        !           358:  *     See if the given node exists and is an actual target.
        !           359:  *
        !           360:  * Results:
        !           361:  *     TRUE if the node exists as a target and FALSE if it does not.
        !           362:  *
        !           363:  * Side Effects:
        !           364:  *     None.
        !           365:  *
        !           366:  *-----------------------------------------------------------------------
        !           367:  */
        !           368: static Boolean
        !           369: CondDoTarget (argLen, arg)
        !           370:     int            argLen;
        !           371:     char    *arg;
        !           372: {
        !           373:     char    savec = arg[argLen];
        !           374:     Boolean result;
        !           375:     GNode   *gn;
        !           376: 
        !           377:     arg[argLen] = '\0';
        !           378:     gn = Targ_FindNode(arg, TARG_NOCREATE);
        !           379:     if ((gn != NILGNODE) && !OP_NOP(gn->type)) {
        !           380:        result = TRUE;
        !           381:     } else {
        !           382:        result = FALSE;
        !           383:     }
        !           384:     arg[argLen] = savec;
        !           385:     return (result);
        !           386: }
        !           387: 
        !           388: 
        !           389: /*-
        !           390:  *-----------------------------------------------------------------------
        !           391:  * CondCvtArg --
        !           392:  *     Convert the given number into a double. If the number begins
        !           393:  *     with 0x, or just x, it is interpreted as a hexadecimal integer
        !           394:  *     and converted to a double from there. All other strings just have
        !           395:  *     atof called on them.
        !           396:  *
        !           397:  * Results:
        !           398:  *     The double value of string.
        !           399:  *
        !           400:  * Side Effects:
        !           401:  *     
        !           402:  *
        !           403:  *-----------------------------------------------------------------------
        !           404:  */
        !           405: static double
        !           406: CondCvtArg(str)
        !           407:     register char      *str;
        !           408: {
        !           409:     int                        sign = 1;
        !           410:     double             atof();
        !           411:     
        !           412:     if (*str == '-') {
        !           413:        sign = -1;
        !           414:        str++;
        !           415:     } else if (*str == '+') {
        !           416:        str++;
        !           417:     }
        !           418:     if (((*str == '0') && (str[1] == 'x')) ||
        !           419:        (*str == 'x'))
        !           420:     {
        !           421:        register int i;
        !           422:        
        !           423:        str += (*str == 'x') ? 1 : 2;
        !           424: 
        !           425:        i = 0;
        !           426: 
        !           427:        while (isxdigit(*str)) {
        !           428:            i *= 16;
        !           429:            if (*str <= '9') {
        !           430:                i += *str - '0';
        !           431:            } else if (*str <= 'F') {
        !           432:                i += *str - 'A' + 10;
        !           433:            } else {
        !           434:                i += *str - 'a' + 10;
        !           435:            }
        !           436:            str++;
        !           437:        }
        !           438:        if (sign < 0) {
        !           439:            return((double)(-i));
        !           440:        } else {
        !           441:            return((double)i);
        !           442:        }
        !           443:     } else if (sign < 0) {
        !           444:        return(- atof(str));
        !           445:     } else {
        !           446:        return(atof(str));
        !           447:     }
        !           448: }
        !           449: 
        !           450: /*-
        !           451:  *-----------------------------------------------------------------------
        !           452:  * CondToken --
        !           453:  *     Return the next token from the input.
        !           454:  *
        !           455:  * Results:
        !           456:  *     A Token for the next lexical token in the stream.
        !           457:  *
        !           458:  * Side Effects:
        !           459:  *     condPushback will be set back to None if it is used.
        !           460:  *
        !           461:  *-----------------------------------------------------------------------
        !           462:  */
        !           463: static Token
        !           464: CondToken(doEval)
        !           465:     Boolean doEval;
        !           466: {
        !           467:     Token        t;
        !           468: 
        !           469:     if (condPushBack == None) {
        !           470:        while (*condExpr == ' ' || *condExpr == '\t') {
        !           471:            condExpr++;
        !           472:        }
        !           473:        switch (*condExpr) {
        !           474:            case '(':
        !           475:                t = LParen;
        !           476:                condExpr++;
        !           477:                break;
        !           478:            case ')':
        !           479:                t = RParen;
        !           480:                condExpr++;
        !           481:                break;
        !           482:            case '|':
        !           483:                if (condExpr[1] == '|') {
        !           484:                    condExpr++;
        !           485:                }
        !           486:                condExpr++;
        !           487:                t = Or;
        !           488:                break;
        !           489:            case '&':
        !           490:                if (condExpr[1] == '&') {
        !           491:                    condExpr++;
        !           492:                }
        !           493:                condExpr++;
        !           494:                t = And;
        !           495:                break;
        !           496:            case '!':
        !           497:                t = Not;
        !           498:                condExpr++;
        !           499:                break;
        !           500:            case '\n':
        !           501:            case '\0':
        !           502:                t = EndOfFile;
        !           503:                break;
        !           504:            case '$': {
        !           505:                char    *lhs;
        !           506:                char    *rhs;
        !           507:                char    *op;
        !           508:                int     varSpecLen;
        !           509:                Boolean doFree;
        !           510: 
        !           511:                /*
        !           512:                 * Parse the variable spec and skip over it, saving its
        !           513:                 * value in lhs.
        !           514:                 */
        !           515:                t = Err;
        !           516:                lhs = Var_Parse(condExpr, VAR_CMD, doEval,&varSpecLen,&doFree);
        !           517:                if (lhs == var_Error) {
        !           518:                    /*
        !           519:                     * Even if !doEval, we still report syntax errors, which
        !           520:                     * is what getting var_Error back with !doEval means.
        !           521:                     */
        !           522:                    return(Err);
        !           523:                }
        !           524:                condExpr += varSpecLen;
        !           525: 
        !           526:                /*
        !           527:                 * Skip whitespace to get to the operator
        !           528:                 */
        !           529:                while (isspace(*condExpr)) {
        !           530:                    condExpr++;
        !           531:                }
        !           532:                /*
        !           533:                 * Make sure the operator is a valid one. If it isn't a
        !           534:                 * known relational operator, pretend we got a
        !           535:                 * != 0 comparison.
        !           536:                 */
        !           537:                op = condExpr;
        !           538:                switch (*condExpr) {
        !           539:                    case '!':
        !           540:                    case '=':
        !           541:                    case '<':
        !           542:                    case '>':
        !           543:                        if (condExpr[1] == '=') {
        !           544:                            condExpr += 2;
        !           545:                        } else {
        !           546:                            condExpr += 1;
        !           547:                        }
        !           548:                        break;
        !           549:                    default:
        !           550:                        op = "!=";
        !           551:                        rhs = "0";
        !           552: 
        !           553:                        goto do_compare;
        !           554:                }
        !           555:                while (isspace(*condExpr)) {
        !           556:                    condExpr++;
        !           557:                }
        !           558:                if (*condExpr == '\0') {
        !           559:                    Parse_Error(PARSE_WARNING,
        !           560:                                "Missing right-hand-side of operator");
        !           561:                    goto error;
        !           562:                }
        !           563:                rhs = condExpr;
        !           564: do_compare:
        !           565:                if (*rhs == '"') {
        !           566:                    /*
        !           567:                     * Doing a string comparison. Only allow == and != for
        !           568:                     * operators.
        !           569:                     */
        !           570:                    char    *string;
        !           571:                    char    *cp, *cp2;
        !           572:                    Buffer  buf;
        !           573: 
        !           574:                    if (((*op != '!') && (*op != '=')) || (op[1] != '=')) {
        !           575:                        Parse_Error(PARSE_WARNING,
        !           576:                "String comparison operator should be either == or !=");
        !           577:                        goto error;
        !           578:                    }
        !           579: 
        !           580:                    buf = Buf_Init(0);
        !           581:                    
        !           582:                    for (cp = rhs+1; (*cp != '"') && (*cp != '\0'); cp++) {
        !           583:                        if ((*cp == '\\') && (cp[1] != '\0')) {
        !           584:                            /*
        !           585:                             * Backslash escapes things -- skip over next
        !           586:                             * character, if it exists.
        !           587:                             */
        !           588:                            cp++;
        !           589:                            Buf_AddByte(buf, (Byte)*cp);
        !           590:                        } else if (*cp == '$') {
        !           591:                            int len;
        !           592:                            Boolean freeIt;
        !           593:                            
        !           594:                            cp2 = Var_Parse(cp, VAR_CMD, doEval,&len, &freeIt);
        !           595:                            if (cp2 != var_Error) {
        !           596:                                Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2);
        !           597:                                if (freeIt) {
        !           598:                                    free(cp2);
        !           599:                                }
        !           600:                                cp += len - 1;
        !           601:                            } else {
        !           602:                                Buf_AddByte(buf, (Byte)*cp);
        !           603:                            }
        !           604:                        } else {
        !           605:                            Buf_AddByte(buf, (Byte)*cp);
        !           606:                        }
        !           607:                    }
        !           608: 
        !           609:                    Buf_AddByte(buf, (Byte)0);
        !           610: 
        !           611:                    string = (char *)Buf_GetAll(buf, (int *)0);
        !           612:                    Buf_Destroy(buf, FALSE);
        !           613: 
        !           614:                    if (DEBUG(COND)) {
        !           615:                        printf("lhs = \"%s\", rhs = \"%s\", op = %.2s\n",
        !           616:                               lhs, string, op);
        !           617:                    }
        !           618:                    /*
        !           619:                     * Null-terminate rhs and perform the comparison.
        !           620:                     * t is set to the result.
        !           621:                     */
        !           622:                    if (*op == '=') {
        !           623:                        t = strcmp(lhs, string) ? False : True;
        !           624:                    } else {
        !           625:                        t = strcmp(lhs, string) ? True : False;
        !           626:                    }
        !           627:                    free(string);
        !           628:                    if (rhs == condExpr) {
        !           629:                        condExpr = cp + 1;
        !           630:                    }
        !           631:                } else {
        !           632:                    /*
        !           633:                     * rhs is either a float or an integer. Convert both the
        !           634:                     * lhs and the rhs to a double and compare the two.
        !           635:                     */
        !           636:                    double      left, right;
        !           637:                    char        *string;
        !           638: 
        !           639:                    left = CondCvtArg(lhs);
        !           640:                    if (*rhs == '$') {
        !           641:                        int     len;
        !           642:                        Boolean freeIt;
        !           643:                        
        !           644:                        string = Var_Parse(rhs, VAR_CMD, doEval,&len,&freeIt);
        !           645:                        if (string == var_Error) {
        !           646:                            right = 0.0;
        !           647:                        } else {
        !           648:                            right = CondCvtArg(string);
        !           649:                            if (freeIt) {
        !           650:                                free(string);
        !           651:                            }
        !           652:                            if (rhs == condExpr) {
        !           653:                                condExpr += len;
        !           654:                            }
        !           655:                        }
        !           656:                    } else {
        !           657:                        right = CondCvtArg(rhs);
        !           658:                        if (rhs == condExpr) {
        !           659:                            /*
        !           660:                             * Skip over the right-hand side
        !           661:                             */
        !           662:                            while(!isspace(*condExpr) && (*condExpr != '\0')) {
        !           663:                                condExpr++;
        !           664:                            }
        !           665:                        }
        !           666:                    }
        !           667:                    
        !           668:                    if (DEBUG(COND)) {
        !           669:                        printf("left = %f, right = %f, op = %.2s\n", left,
        !           670:                               right, op);
        !           671:                    }
        !           672:                    switch(op[0]) {
        !           673:                    case '!':
        !           674:                        if (op[1] != '=') {
        !           675:                            Parse_Error(PARSE_WARNING,
        !           676:                                        "Unknown operator");
        !           677:                            goto error;
        !           678:                        }
        !           679:                        t = (left != right ? True : False);
        !           680:                        break;
        !           681:                    case '=':
        !           682:                        if (op[1] != '=') {
        !           683:                            Parse_Error(PARSE_WARNING,
        !           684:                                        "Unknown operator");
        !           685:                            goto error;
        !           686:                        }
        !           687:                        t = (left == right ? True : False);
        !           688:                        break;
        !           689:                    case '<':
        !           690:                        if (op[1] == '=') {
        !           691:                            t = (left <= right ? True : False);
        !           692:                        } else {
        !           693:                            t = (left < right ? True : False);
        !           694:                        }
        !           695:                        break;
        !           696:                    case '>':
        !           697:                        if (op[1] == '=') {
        !           698:                            t = (left >= right ? True : False);
        !           699:                        } else {
        !           700:                            t = (left > right ? True : False);
        !           701:                        }
        !           702:                        break;
        !           703:                    }
        !           704:                }
        !           705: error:
        !           706:                if (doFree) {
        !           707:                    free(lhs);
        !           708:                }
        !           709:                break;
        !           710:            }
        !           711:            default: {
        !           712:                Boolean (*evalProc)();
        !           713:                Boolean invert = FALSE;
        !           714:                char    *arg;
        !           715:                int     arglen;
        !           716:                
        !           717:                if (strncmp (condExpr, "defined", 7) == 0) {
        !           718:                    /*
        !           719:                     * Use CondDoDefined to evaluate the argument and
        !           720:                     * CondGetArg to extract the argument from the 'function
        !           721:                     * call'.
        !           722:                     */
        !           723:                    evalProc = CondDoDefined;
        !           724:                    condExpr += 7;
        !           725:                    arglen = CondGetArg (&condExpr, &arg, "defined", TRUE);
        !           726:                    if (arglen == 0) {
        !           727:                        condExpr -= 7;
        !           728:                        goto use_default;
        !           729:                    }
        !           730:                } else if (strncmp (condExpr, "make", 4) == 0) {
        !           731:                    /*
        !           732:                     * Use CondDoMake to evaluate the argument and
        !           733:                     * CondGetArg to extract the argument from the 'function
        !           734:                     * call'.
        !           735:                     */
        !           736:                    evalProc = CondDoMake;
        !           737:                    condExpr += 4;
        !           738:                    arglen = CondGetArg (&condExpr, &arg, "make", TRUE);
        !           739:                    if (arglen == 0) {
        !           740:                        condExpr -= 4;
        !           741:                        goto use_default;
        !           742:                    }
        !           743:                } else if (strncmp (condExpr, "exists", 6) == 0) {
        !           744:                    /*
        !           745:                     * Use CondDoExists to evaluate the argument and
        !           746:                     * CondGetArg to extract the argument from the
        !           747:                     * 'function call'.
        !           748:                     */
        !           749:                    evalProc = CondDoExists;
        !           750:                    condExpr += 6;
        !           751:                    arglen = CondGetArg(&condExpr, &arg, "exists", TRUE);
        !           752:                    if (arglen == 0) {
        !           753:                        condExpr -= 6;
        !           754:                        goto use_default;
        !           755:                    }
        !           756:                } else if (strncmp(condExpr, "empty", 5) == 0) {
        !           757:                    /*
        !           758:                     * Use Var_Parse to parse the spec in parens and return
        !           759:                     * True if the resulting string is empty.
        !           760:                     */
        !           761:                    int     length;
        !           762:                    Boolean doFree;
        !           763:                    char    *val;
        !           764: 
        !           765:                    condExpr += 5;
        !           766: 
        !           767:                    for (arglen = 0;
        !           768:                         condExpr[arglen] != '(' && condExpr[arglen] != '\0';
        !           769:                         arglen += 1)
        !           770:                    {
        !           771:                        /* void */ ;
        !           772:                    }
        !           773:                    if (condExpr[arglen] != '\0') {
        !           774:                        val = Var_Parse(&condExpr[arglen - 1], VAR_CMD,
        !           775:                                        doEval, &length, &doFree);
        !           776:                        if (val == var_Error) {
        !           777:                            t = Err;
        !           778:                        } else {
        !           779:                            t = (*val == '\0') ? True : False;
        !           780:                        }
        !           781:                        if (doFree) {
        !           782:                            free(val);
        !           783:                        }
        !           784:                        /*
        !           785:                         * Advance condExpr to beyond the closing ). Note that
        !           786:                         * we subtract one from arglen + length b/c length
        !           787:                         * is calculated from condExpr[arglen - 1].
        !           788:                         */
        !           789:                        condExpr += arglen + length - 1;
        !           790:                    } else {
        !           791:                        condExpr -= 5;
        !           792:                        goto use_default;
        !           793:                    }
        !           794:                    break;
        !           795:                } else if (strncmp (condExpr, "target", 6) == 0) {
        !           796:                    /*
        !           797:                     * Use CondDoTarget to evaluate the argument and
        !           798:                     * CondGetArg to extract the argument from the
        !           799:                     * 'function call'.
        !           800:                     */
        !           801:                    evalProc = CondDoTarget;
        !           802:                    condExpr += 6;
        !           803:                    arglen = CondGetArg(&condExpr, &arg, "target", TRUE);
        !           804:                    if (arglen == 0) {
        !           805:                        condExpr -= 6;
        !           806:                        goto use_default;
        !           807:                    }
        !           808:                } else {
        !           809:                    /*
        !           810:                     * The symbol is itself the argument to the default
        !           811:                     * function. We advance condExpr to the end of the symbol
        !           812:                     * by hand (the next whitespace, closing paren or
        !           813:                     * binary operator) and set to invert the evaluation
        !           814:                     * function if condInvert is TRUE.
        !           815:                     */
        !           816:                use_default:
        !           817:                    invert = condInvert;
        !           818:                    evalProc = condDefProc;
        !           819:                    arglen = CondGetArg(&condExpr, &arg, "", FALSE);
        !           820:                }
        !           821: 
        !           822:                /*
        !           823:                 * Evaluate the argument using the set function. If invert
        !           824:                 * is TRUE, we invert the sense of the function.
        !           825:                 */
        !           826:                t = (!doEval || (* evalProc) (arglen, arg) ?
        !           827:                     (invert ? False : True) :
        !           828:                     (invert ? True : False));
        !           829:                free(arg);
        !           830:                break;
        !           831:            }
        !           832:        }
        !           833:     } else {
        !           834:        t = condPushBack;
        !           835:        condPushBack = None;
        !           836:     }
        !           837:     return (t);
        !           838: }
        !           839: 
        !           840: /*-
        !           841:  *-----------------------------------------------------------------------
        !           842:  * CondT --
        !           843:  *     Parse a single term in the expression. This consists of a terminal
        !           844:  *     symbol or Not and a terminal symbol (not including the binary
        !           845:  *     operators):
        !           846:  *         T -> defined(variable) | make(target) | exists(file) | symbol
        !           847:  *         T -> ! T | ( E )
        !           848:  *
        !           849:  * Results:
        !           850:  *     True, False or Err.
        !           851:  *
        !           852:  * Side Effects:
        !           853:  *     Tokens are consumed.
        !           854:  *
        !           855:  *-----------------------------------------------------------------------
        !           856:  */
        !           857: static Token
        !           858: CondT(doEval)
        !           859:     Boolean doEval;
        !           860: {
        !           861:     Token   t;
        !           862: 
        !           863:     t = CondToken(doEval);
        !           864: 
        !           865:     if (t == EndOfFile) {
        !           866:        /*
        !           867:         * If we reached the end of the expression, the expression
        !           868:         * is malformed...
        !           869:         */
        !           870:        t = Err;
        !           871:     } else if (t == LParen) {
        !           872:        /*
        !           873:         * T -> ( E )
        !           874:         */
        !           875:        t = CondE(doEval);
        !           876:        if (t != Err) {
        !           877:            if (CondToken(doEval) != RParen) {
        !           878:                t = Err;
        !           879:            }
        !           880:        }
        !           881:     } else if (t == Not) {
        !           882:        t = CondT(doEval);
        !           883:        if (t == True) {
        !           884:            t = False;
        !           885:        } else if (t == False) {
        !           886:            t = True;
        !           887:        }
        !           888:     }
        !           889:     return (t);
        !           890: }
        !           891: 
        !           892: /*-
        !           893:  *-----------------------------------------------------------------------
        !           894:  * CondF --
        !           895:  *     Parse a conjunctive factor (nice name, wot?)
        !           896:  *         F -> T && F | T
        !           897:  *
        !           898:  * Results:
        !           899:  *     True, False or Err
        !           900:  *
        !           901:  * Side Effects:
        !           902:  *     Tokens are consumed.
        !           903:  *
        !           904:  *-----------------------------------------------------------------------
        !           905:  */
        !           906: static Token
        !           907: CondF(doEval)
        !           908:     Boolean doEval;
        !           909: {
        !           910:     Token   l, o;
        !           911: 
        !           912:     l = CondT(doEval);
        !           913:     if (l != Err) {
        !           914:        o = CondToken(doEval);
        !           915: 
        !           916:        if (o == And) {
        !           917:            /*
        !           918:             * F -> T && F
        !           919:             *
        !           920:             * If T is False, the whole thing will be False, but we have to
        !           921:             * parse the r.h.s. anyway (to throw it away).
        !           922:             * If T is True, the result is the r.h.s., be it an Err or no.
        !           923:             */
        !           924:            if (l == True) {
        !           925:                l = CondF(doEval);
        !           926:            } else {
        !           927:                (void) CondF(FALSE);
        !           928:            }
        !           929:        } else {
        !           930:            /*
        !           931:             * F -> T
        !           932:             */
        !           933:            CondPushBack (o);
        !           934:        }
        !           935:     }
        !           936:     return (l);
        !           937: }
        !           938: 
        !           939: /*-
        !           940:  *-----------------------------------------------------------------------
        !           941:  * CondE --
        !           942:  *     Main expression production.
        !           943:  *         E -> F || E | F
        !           944:  *
        !           945:  * Results:
        !           946:  *     True, False or Err.
        !           947:  *
        !           948:  * Side Effects:
        !           949:  *     Tokens are, of course, consumed.
        !           950:  *
        !           951:  *-----------------------------------------------------------------------
        !           952:  */
        !           953: static Token
        !           954: CondE(doEval)
        !           955:     Boolean doEval;
        !           956: {
        !           957:     Token   l, o;
        !           958: 
        !           959:     l = CondF(doEval);
        !           960:     if (l != Err) {
        !           961:        o = CondToken(doEval);
        !           962: 
        !           963:        if (o == Or) {
        !           964:            /*
        !           965:             * E -> F || E
        !           966:             *
        !           967:             * A similar thing occurs for ||, except that here we make sure
        !           968:             * the l.h.s. is False before we bother to evaluate the r.h.s.
        !           969:             * Once again, if l is False, the result is the r.h.s. and once
        !           970:             * again if l is True, we parse the r.h.s. to throw it away.
        !           971:             */
        !           972:            if (l == False) {
        !           973:                l = CondE(doEval);
        !           974:            } else {
        !           975:                (void) CondE(FALSE);
        !           976:            }
        !           977:        } else {
        !           978:            /*
        !           979:             * E -> F
        !           980:             */
        !           981:            CondPushBack (o);
        !           982:        }
        !           983:     }
        !           984:     return (l);
        !           985: }
        !           986: 
        !           987: /*-
        !           988:  *-----------------------------------------------------------------------
        !           989:  * Cond_Eval --
        !           990:  *     Evaluate the conditional in the passed line. The line
        !           991:  *     looks like this:
        !           992:  *         #<cond-type> <expr>
        !           993:  *     where <cond-type> is any of if, ifmake, ifnmake, ifdef,
        !           994:  *     ifndef, elif, elifmake, elifnmake, elifdef, elifndef
        !           995:  *     and <expr> consists of &&, ||, !, make(target), defined(variable)
        !           996:  *     and parenthetical groupings thereof.
        !           997:  *
        !           998:  * Results:
        !           999:  *     COND_PARSE      if should parse lines after the conditional
        !          1000:  *     COND_SKIP       if should skip lines after the conditional
        !          1001:  *     COND_INVALID    if not a valid conditional.
        !          1002:  *
        !          1003:  * Side Effects:
        !          1004:  *     None.
        !          1005:  *
        !          1006:  *-----------------------------------------------------------------------
        !          1007:  */
        !          1008: Cond_Eval (line)
        !          1009:     char           *line;    /* Line to parse */
        !          1010: {
        !          1011:     struct If      *ifp;
        !          1012:     Boolean        isElse;
        !          1013:     Boolean        value;
        !          1014:     int                    level;      /* Level at which to report errors. */
        !          1015: 
        !          1016:     level = PARSE_FATAL;
        !          1017: 
        !          1018:     for (line++; *line == ' ' || *line == '\t'; line++) {
        !          1019:        continue;
        !          1020:     }
        !          1021: 
        !          1022:     /*
        !          1023:      * Find what type of if we're dealing with. The result is left
        !          1024:      * in ifp and isElse is set TRUE if it's an elif line.
        !          1025:      */
        !          1026:     if (line[0] == 'e' && line[1] == 'l') {
        !          1027:        line += 2;
        !          1028:        isElse = TRUE;
        !          1029:     } else if (strncmp (line, "endif", 5) == 0) {
        !          1030:        /*
        !          1031:         * End of a conditional section. If skipIfLevel is non-zero, that
        !          1032:         * conditional was skipped, so lines following it should also be
        !          1033:         * skipped. Hence, we return COND_SKIP. Otherwise, the conditional
        !          1034:         * was read so succeeding lines should be parsed (think about it...)
        !          1035:         * so we return COND_PARSE, unless this endif isn't paired with
        !          1036:         * a decent if.
        !          1037:         */
        !          1038:        if (skipIfLevel != 0) {
        !          1039:            skipIfLevel -= 1;
        !          1040:            return (COND_SKIP);
        !          1041:        } else {
        !          1042:            if (condTop == MAXIF) {
        !          1043:                Parse_Error (level, "if-less endif");
        !          1044:                return (COND_INVALID);
        !          1045:            } else {
        !          1046:                skipLine = FALSE;
        !          1047:                condTop += 1;
        !          1048:                return (COND_PARSE);
        !          1049:            }
        !          1050:        }
        !          1051:     } else {
        !          1052:        isElse = FALSE;
        !          1053:     }
        !          1054:     
        !          1055:     /*
        !          1056:      * Figure out what sort of conditional it is -- what its default
        !          1057:      * function is, etc. -- by looking in the table of valid "ifs"
        !          1058:      */
        !          1059:     for (ifp = ifs; ifp->form != (char *)0; ifp++) {
        !          1060:        if (strncmp (ifp->form, line, ifp->formlen) == 0) {
        !          1061:            break;
        !          1062:        }
        !          1063:     }
        !          1064: 
        !          1065:     if (ifp->form == (char *) 0) {
        !          1066:        /*
        !          1067:         * Nothing fit. If the first word on the line is actually
        !          1068:         * "else", it's a valid conditional whose value is the inverse
        !          1069:         * of the previous if we parsed.
        !          1070:         */
        !          1071:        if (isElse && (line[0] == 's') && (line[1] == 'e')) {
        !          1072:            if (condTop == MAXIF) {
        !          1073:                Parse_Error (level, "if-less else");
        !          1074:                return (COND_INVALID);
        !          1075:            } else if (skipIfLevel == 0) {
        !          1076:                value = !condStack[condTop];
        !          1077:            } else {
        !          1078:                return (COND_SKIP);
        !          1079:            }
        !          1080:        } else {
        !          1081:            /*
        !          1082:             * Not a valid conditional type. No error...
        !          1083:             */
        !          1084:            return (COND_INVALID);
        !          1085:        }
        !          1086:     } else {
        !          1087:        if (isElse) {
        !          1088:            if (condTop == MAXIF) {
        !          1089:                Parse_Error (level, "if-less elif");
        !          1090:                return (COND_INVALID);
        !          1091:            } else if (skipIfLevel != 0) {
        !          1092:                /*
        !          1093:                 * If skipping this conditional, just ignore the whole thing.
        !          1094:                 * If we don't, the user might be employing a variable that's
        !          1095:                 * undefined, for which there's an enclosing ifdef that
        !          1096:                 * we're skipping...
        !          1097:                 */
        !          1098:                return(COND_SKIP);
        !          1099:            }
        !          1100:        } else if (skipLine) {
        !          1101:            /*
        !          1102:             * Don't even try to evaluate a conditional that's not an else if
        !          1103:             * we're skipping things...
        !          1104:             */
        !          1105:            skipIfLevel += 1;
        !          1106:            return(COND_SKIP);
        !          1107:        }
        !          1108: 
        !          1109:        /*
        !          1110:         * Initialize file-global variables for parsing
        !          1111:         */
        !          1112:        condDefProc = ifp->defProc;
        !          1113:        condInvert = ifp->doNot;
        !          1114:        
        !          1115:        line += ifp->formlen;
        !          1116:        
        !          1117:        while (*line == ' ' || *line == '\t') {
        !          1118:            line++;
        !          1119:        }
        !          1120:        
        !          1121:        condExpr = line;
        !          1122:        condPushBack = None;
        !          1123:        
        !          1124:        switch (CondE(TRUE)) {
        !          1125:            case True:
        !          1126:                if (CondToken(TRUE) == EndOfFile) {
        !          1127:                    value = TRUE;
        !          1128:                    break;
        !          1129:                }
        !          1130:                goto err;
        !          1131:                /*FALLTHRU*/
        !          1132:            case False:
        !          1133:                if (CondToken(TRUE) == EndOfFile) {
        !          1134:                    value = FALSE;
        !          1135:                    break;
        !          1136:                }
        !          1137:                /*FALLTHRU*/
        !          1138:            case Err:
        !          1139:            err:
        !          1140:                Parse_Error (level, "Malformed conditional (%s)",
        !          1141:                             line);
        !          1142:                return (COND_INVALID);
        !          1143:        }
        !          1144:     }
        !          1145:     if (!isElse) {
        !          1146:        condTop -= 1;
        !          1147:     } else if ((skipIfLevel != 0) || condStack[condTop]) {
        !          1148:        /*
        !          1149:         * If this is an else-type conditional, it should only take effect
        !          1150:         * if its corresponding if was evaluated and FALSE. If its if was
        !          1151:         * TRUE or skipped, we return COND_SKIP (and start skipping in case
        !          1152:         * we weren't already), leaving the stack unmolested so later elif's
        !          1153:         * don't screw up...
        !          1154:         */
        !          1155:        skipLine = TRUE;
        !          1156:        return (COND_SKIP);
        !          1157:     }
        !          1158: 
        !          1159:     if (condTop < 0) {
        !          1160:        /*
        !          1161:         * This is the one case where we can definitely proclaim a fatal
        !          1162:         * error. If we don't, we're hosed.
        !          1163:         */
        !          1164:        Parse_Error (PARSE_FATAL, "Too many nested if's. %d max.", MAXIF);
        !          1165:        return (COND_INVALID);
        !          1166:     } else {
        !          1167:        condStack[condTop] = value;
        !          1168:        skipLine = !value;
        !          1169:        return (value ? COND_PARSE : COND_SKIP);
        !          1170:     }
        !          1171: }
        !          1172: 
        !          1173: /*-
        !          1174:  *-----------------------------------------------------------------------
        !          1175:  * Cond_End --
        !          1176:  *     Make sure everything's clean at the end of a makefile.
        !          1177:  *
        !          1178:  * Results:
        !          1179:  *     None.
        !          1180:  *
        !          1181:  * Side Effects:
        !          1182:  *     Parse_Error will be called if open conditionals are around.
        !          1183:  *
        !          1184:  *-----------------------------------------------------------------------
        !          1185:  */
        !          1186: void
        !          1187: Cond_End()
        !          1188: {
        !          1189:     if (condTop != MAXIF) {
        !          1190:        Parse_Error(PARSE_FATAL, "%d open conditional%s", MAXIF-condTop,
        !          1191:                    MAXIF-condTop == 1 ? "" : "s");
        !          1192:     }
        !          1193:     condTop = MAXIF;
        !          1194: }

unix.superglobalmegacorp.com

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