home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 May / W2KPRK.iso / apps / posix / source / MAKE / COND.C < prev    next >
C/C++ Source or Header  |  1999-11-17  |  29KB  |  1,209 lines

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