[BACK]Return to cond.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / usr.bin / make

Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.

Diff for /src/usr.bin/make/cond.c between version 1.12 and 1.46

version 1.12, 2001/01/14 20:44:26 version 1.46, 2008/11/23 10:52:58
Line 2 
Line 2 
   
 /*  /*
  * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.   * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
    * All rights reserved.
    *
    * This code is derived from software contributed to Berkeley by
    * Adam de Boor.
    *
    * Redistribution and use in source and binary forms, with or without
    * modification, are permitted provided that the following conditions
    * are met:
    * 1. Redistributions of source code must retain the above copyright
    *    notice, this list of conditions and the following disclaimer.
    * 2. Redistributions in binary form must reproduce the above copyright
    *    notice, this list of conditions and the following disclaimer in the
    *    documentation and/or other materials provided with the distribution.
    * 3. Neither the name of the University nor the names of its contributors
    *    may be used to endorse or promote products derived from this software
    *    without specific prior written permission.
    *
    * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
    * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
    * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    * SUCH DAMAGE.
    */
   
   /*
  * Copyright (c) 1988, 1989 by Adam de Boor   * Copyright (c) 1988, 1989 by Adam de Boor
  * Copyright (c) 1989 by Berkeley Softworks   * Copyright (c) 1989 by Berkeley Softworks
  * All rights reserved.   * All rights reserved.
Line 38 
Line 69 
  * SUCH DAMAGE.   * SUCH DAMAGE.
  */   */
   
 #ifdef MAKE_BOOTSTRAP  #ifndef MAKE_NATIVE
 static char rcsid[] = "$NetBSD$";  static char rcsid[] = "$NetBSD$";
 #else  #else
 #include <sys/cdefs.h>  #include <sys/cdefs.h>
Line 61  __RCSID("$NetBSD$");
Line 92  __RCSID("$NetBSD$");
  */   */
   
 #include    <ctype.h>  #include    <ctype.h>
 #include    <math.h>  #include    <errno.h>    /* For strtoul() error checking */
   
 #include    "make.h"  #include    "make.h"
 #include    "hash.h"  #include    "hash.h"
 #include    "dir.h"  #include    "dir.h"
Line 83  __RCSID("$NetBSD$");
Line 115  __RCSID("$NetBSD$");
  *      T -> $(varspec) op value   *      T -> $(varspec) op value
  *      T -> $(varspec) == "string"   *      T -> $(varspec) == "string"
  *      T -> $(varspec) != "string"   *      T -> $(varspec) != "string"
    *      T -> "string"
  *      T -> ( E )   *      T -> ( E )
  *      T -> ! T   *      T -> ! T
  *      op -> == | != | > | < | >= | <=   *      op -> == | != | > | < | >= | <=
Line 106  typedef enum {
Line 139  typedef enum {
  * Structures to handle elegantly the different forms of #if's. The   * Structures to handle elegantly the different forms of #if's. The
  * last two fields are stored in condInvert and condDefProc, respectively.   * last two fields are stored in condInvert and condDefProc, respectively.
  */   */
 static void CondPushBack __P((Token));  static void CondPushBack(Token);
 static int CondGetArg __P((char **, char **, char *, Boolean));  static int CondGetArg(char **, char **, const char *, Boolean);
 static Boolean CondDoDefined __P((int, char *));  static Boolean CondDoDefined(int, char *);
 static int CondStrMatch __P((ClientData, ClientData));  static int CondStrMatch(ClientData, ClientData);
 static Boolean CondDoMake __P((int, char *));  static Boolean CondDoMake(int, char *);
 static Boolean CondDoExists __P((int, char *));  static Boolean CondDoExists(int, char *);
 static Boolean CondDoTarget __P((int, char *));  static Boolean CondDoTarget(int, char *);
 static Boolean CondDoCommands __P((int, char *));  static Boolean CondDoCommands(int, char *);
 static Boolean CondCvtArg __P((char *, double *));  static Boolean CondCvtArg(char *, double *);
 static Token CondToken __P((Boolean));  static Token CondToken(Boolean);
 static Token CondT __P((Boolean));  static Token CondT(Boolean);
 static Token CondF __P((Boolean));  static Token CondF(Boolean);
 static Token CondE __P((Boolean));  static Token CondE(Boolean);
   
 static struct If {  static const struct If {
     char        *form;        /* Form of if */      const char  *form;        /* Form of if */
     int         formlen;      /* Length of form */      int         formlen;      /* Length of form */
     Boolean     doNot;        /* TRUE if default function should be negated */      Boolean     doNot;        /* TRUE if default function should be negated */
     Boolean     (*defProc) __P((int, char *)); /* Default function to apply */      Boolean     (*defProc)(int, char *); /* Default function to apply */
 } ifs[] = {  } ifs[] = {
     { "ifdef",    5,      FALSE,  CondDoDefined },      { "def",      3,      FALSE,  CondDoDefined },
     { "ifndef",   6,      TRUE,   CondDoDefined },      { "ndef",     4,      TRUE,   CondDoDefined },
     { "ifmake",   6,      FALSE,  CondDoMake },      { "make",     4,      FALSE,  CondDoMake },
     { "ifnmake",  7,      TRUE,   CondDoMake },      { "nmake",    5,      TRUE,   CondDoMake },
     { "if",       2,      FALSE,  CondDoDefined },      { "",         0,      FALSE,  CondDoDefined },
     { NULL,       0,      FALSE,  NULL }      { NULL,       0,      FALSE,  NULL }
 };  };
   
 static Boolean    condInvert;           /* Invert the default function */  static Boolean    condInvert;           /* Invert the default function */
 static Boolean    (*condDefProc)        /* Default function to apply */  static Boolean    (*condDefProc)(int, char *);  /* Default function to apply */
                     __P((int, char *));  
 static char       *condExpr;            /* The expression to parse */  static char       *condExpr;            /* The expression to parse */
 static Token      condPushBack=None;    /* Single push-back token used in  static Token      condPushBack=None;    /* Single push-back token used in
                                          * parsing */                                           * parsing */
   
 #define MAXIF           30        /* greatest depth of #if'ing */  static unsigned int     cond_depth = 0;         /* current .if nesting level */
   static unsigned int     cond_min_depth = 0;     /* depth at makefile open */
   
 static Boolean    condStack[MAXIF];     /* Stack of conditionals's values */  static int
 static int        condTop = MAXIF;      /* Top-most conditional */  istoken(const char *str, const char *tok, size_t len)
 static int        skipIfLevel=0;        /* Depth of skipped conditionals */  {
 static Boolean    skipLine = FALSE;     /* Whether the parse module is skipping          return strncmp(str, tok, len) == 0 && !isalpha((unsigned char)str[len]);
                                          * lines */  }
   
 /*-  /*-
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
Line 155  static Boolean   skipLine = FALSE;  /* W
Line 188  static Boolean   skipLine = FALSE;  /* W
  *      Push back the most recent token read. We only need one level of   *      Push back the most recent token read. We only need one level of
  *      this, so the thing is just stored in 'condPushback'.   *      this, so the thing is just stored in 'condPushback'.
  *   *
    * Input:
    *      t               Token to push back into the "stream"
    *
  * Results:   * Results:
  *      None.   *      None.
  *   *
Line 164  static Boolean   skipLine = FALSE;  /* W
Line 200  static Boolean   skipLine = FALSE;  /* W
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 static void  static void
 CondPushBack (t)  CondPushBack(Token t)
     Token         t;    /* Token to push back into the "stream" */  
 {  {
     condPushBack = t;      condPushBack = t;
 }  }
Line 175  CondPushBack (t)
Line 210  CondPushBack (t)
  * CondGetArg --   * CondGetArg --
  *      Find the argument of a built-in function.   *      Find the argument of a built-in function.
  *   *
    * Input:
    *      parens          TRUE if arg should be bounded by parens
    *
  * Results:   * Results:
  *      The length of the argument and the address of the argument.   *      The length of the argument and the address of the argument.
  *   *
Line 185  CondPushBack (t)
Line 223  CondPushBack (t)
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 static int  static int
 CondGetArg (linePtr, argPtr, func, parens)  CondGetArg(char **linePtr, char **argPtr, const char *func, Boolean parens)
     char          **linePtr;  
     char          **argPtr;  
     char          *func;  
     Boolean       parens;       /* TRUE if arg should be bounded by parens */  
 {  {
     register char *cp;      char          *cp;
     int           argLen;      int           argLen;
     register Buffer buf;      Buffer        buf;
   
     cp = *linePtr;      cp = *linePtr;
     if (parens) {      if (parens) {
Line 212  CondGetArg (linePtr, argPtr, func, paren
Line 246  CondGetArg (linePtr, argPtr, func, paren
          * than hitting the user with a warning message every time s/he uses           * than hitting the user with a warning message every time s/he uses
          * the word 'make' or 'defined' at the beginning of a symbol...           * the word 'make' or 'defined' at the beginning of a symbol...
          */           */
         *argPtr = cp;          *argPtr = NULL;
         return (0);          return (0);
     }      }
   
Line 226  CondGetArg (linePtr, argPtr, func, paren
Line 260  CondGetArg (linePtr, argPtr, func, paren
      */       */
     buf = Buf_Init(16);      buf = Buf_Init(16);
   
     while ((strchr(" \t)&|", *cp) == (char *)NULL) && (*cp != '\0')) {      while ((strchr(" \t)&|", *cp) == NULL) && (*cp != '\0')) {
         if (*cp == '$') {          if (*cp == '$') {
             /*              /*
              * Parse the variable spec and install it as part of the argument               * Parse the variable spec and install it as part of the argument
Line 236  CondGetArg (linePtr, argPtr, func, paren
Line 270  CondGetArg (linePtr, argPtr, func, paren
              */               */
             char        *cp2;              char        *cp2;
             int         len;              int         len;
             Boolean     doFree;              void        *freeIt;
   
             cp2 = Var_Parse(cp, VAR_CMD, TRUE, &len, &doFree);  
   
               cp2 = Var_Parse(cp, VAR_CMD, TRUE, &len, &freeIt);
             Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2);              Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2);
             if (doFree) {              if (freeIt)
                 free(cp2);                  free(freeIt);
             }  
             cp += len;              cp += len;
         } else {          } else {
             Buf_AddByte(buf, (Byte)*cp);              Buf_AddByte(buf, (Byte)*cp);
Line 259  CondGetArg (linePtr, argPtr, func, paren
Line 291  CondGetArg (linePtr, argPtr, func, paren
         cp++;          cp++;
     }      }
     if (parens && *cp != ')') {      if (parens && *cp != ')') {
         Parse_Error (PARSE_WARNING, "Missing closing parenthesis for %s()",          Parse_Error(PARSE_WARNING, "Missing closing parenthesis for %s()",
                      func);                       func);
         return (0);          return (0);
     } else if (parens) {      } else if (parens) {
Line 287  CondGetArg (linePtr, argPtr, func, paren
Line 319  CondGetArg (linePtr, argPtr, func, paren
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 static Boolean  static Boolean
 CondDoDefined (argLen, arg)  CondDoDefined(int argLen, char *arg)
     int     argLen;  
     char    *arg;  
 {  {
     char    savec = arg[argLen];      char    savec = arg[argLen];
     char    *p1;      char    *p1;
     Boolean result;      Boolean result;
   
     arg[argLen] = '\0';      arg[argLen] = '\0';
     if (Var_Value (arg, VAR_CMD, &p1) != (char *)NULL) {      if (Var_Value(arg, VAR_CMD, &p1) != NULL) {
         result = TRUE;          result = TRUE;
     } else {      } else {
         result = FALSE;          result = FALSE;
Line 322  CondDoDefined (argLen, arg)
Line 352  CondDoDefined (argLen, arg)
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 static int  static int
 CondStrMatch(string, pattern)  CondStrMatch(ClientData string, ClientData pattern)
     ClientData    string;  
     ClientData    pattern;  
 {  {
     return(!Str_Match((char *) string,(char *) pattern));      return(!Str_Match((char *)string,(char *)pattern));
 }  }
   
 /*-  /*-
Line 343  CondStrMatch(string, pattern)
Line 371  CondStrMatch(string, pattern)
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 static Boolean  static Boolean
 CondDoMake (argLen, arg)  CondDoMake(int argLen, char *arg)
     int     argLen;  
     char    *arg;  
 {  {
     char    savec = arg[argLen];      char    savec = arg[argLen];
     Boolean result;      Boolean result;
   
     arg[argLen] = '\0';      arg[argLen] = '\0';
     if (Lst_Find (create, (ClientData)arg, CondStrMatch) == NILLNODE) {      if (Lst_Find(create, arg, CondStrMatch) == NILLNODE) {
         result = FALSE;          result = FALSE;
     } else {      } else {
         result = TRUE;          result = TRUE;
Line 374  CondDoMake (argLen, arg)
Line 400  CondDoMake (argLen, arg)
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 static Boolean  static Boolean
 CondDoExists (argLen, arg)  CondDoExists(int argLen, char *arg)
     int     argLen;  
     char    *arg;  
 {  {
     char    savec = arg[argLen];      char    savec = arg[argLen];
     Boolean result;      Boolean result;
Line 384  CondDoExists (argLen, arg)
Line 408  CondDoExists (argLen, arg)
   
     arg[argLen] = '\0';      arg[argLen] = '\0';
     path = Dir_FindFile(arg, dirSearchPath);      path = Dir_FindFile(arg, dirSearchPath);
     if (path != (char *)NULL) {      if (path != NULL) {
         result = TRUE;          result = TRUE;
         free(path);          free(path);
     } else {      } else {
         result = FALSE;          result = FALSE;
     }      }
     arg[argLen] = savec;      arg[argLen] = savec;
       if (DEBUG(COND)) {
           fprintf(debug_file, "exists(%s) result is \"%s\"\n",
                  arg, path ? path : "");
       }
     return (result);      return (result);
 }  }
   
Line 408  CondDoExists (argLen, arg)
Line 436  CondDoExists (argLen, arg)
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 static Boolean  static Boolean
 CondDoTarget (argLen, arg)  CondDoTarget(int argLen, char *arg)
     int     argLen;  
     char    *arg;  
 {  {
     char    savec = arg[argLen];      char    savec = arg[argLen];
     Boolean result;      Boolean result;
Line 443  CondDoTarget (argLen, arg)
Line 469  CondDoTarget (argLen, arg)
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 static Boolean  static Boolean
 CondDoCommands (argLen, arg)  CondDoCommands(int argLen, char *arg)
     int     argLen;  
     char    *arg;  
 {  {
     char    savec = arg[argLen];      char    savec = arg[argLen];
     Boolean result;      Boolean result;
Line 465  CondDoCommands (argLen, arg)
Line 489  CondDoCommands (argLen, arg)
 /*-  /*-
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  * CondCvtArg --   * CondCvtArg --
  *      Convert the given number into a double. If the number begins   *      Convert the given number into a double.
  *      with 0x, it is interpreted as a hexadecimal integer   *      We try a base 10 or 16 integer conversion first, if that fails
  *      and converted to a double from there. All other strings just have   *      then we try a floating point conversion instead.
  *      strtod called on them.  
  *   *
  * Results:   * Results:
  *      Sets 'value' to double value of string.   *      Sets 'value' to double value of string.
  *      Returns true if the string was a valid number, false o.w.   *      Returns 'true' if the convertion suceeded
    *
    *-----------------------------------------------------------------------
    */
   static Boolean
   CondCvtArg(char *str, double *value)
   {
       char *eptr, ech;
       unsigned long l_val;
       double d_val;
   
       errno = 0;
       l_val = strtoul(str, &eptr, str[1] == 'x' ? 16 : 10);
       ech = *eptr;
       if (ech == 0 && errno != ERANGE) {
           d_val = str[0] == '-' ? -(double)-l_val : (double)l_val;
       } else {
           if (ech != 0 && ech != '.' && ech != 'e' && ech != 'E')
               return FALSE;
           d_val = strtod(str, &eptr);
           if (*eptr)
               return FALSE;
       }
   
       *value = d_val;
       return TRUE;
   }
   
   /*-
    *-----------------------------------------------------------------------
    * CondGetString --
    *      Get a string from a variable reference or an optionally quoted
    *      string.  This is called for the lhs and rhs of string compares.
    *
    * Results:
    *      Sets freeIt if needed,
    *      Sets quoted if string was quoted,
    *      Returns NULL on error,
    *      else returns string - absent any quotes.
  *   *
  * Side Effects:   * Side Effects:
  *      Can change 'value' even if string is not a valid number.   *      Moves condExpr to end of this token.
  *   *
  *   *
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 static Boolean  /* coverity:[+alloc : arg-*2] */
 CondCvtArg(str, value)  static char *
     register char       *str;  CondGetString(Boolean doEval, Boolean *quoted, void **freeIt)
     double              *value;  {
 {      Buffer buf;
     if ((*str == '0') && (str[1] == 'x')) {      char *cp;
         register long i;      char *str;
       int len;
         for (str += 2, i = 0; *str; str++) {      int qt;
             int x;      char *start;
             if (isdigit((unsigned char) *str))  
                 x  = *str - '0';      buf = Buf_Init(0);
             else if (isxdigit((unsigned char) *str))      str = NULL;
                 x = 10 + *str - isupper((unsigned char) *str) ? 'A' : 'a';      *freeIt = NULL;
       *quoted = qt = *condExpr == '"' ? 1 : 0;
       if (qt)
           condExpr++;
       for (start = condExpr; *condExpr && str == NULL; condExpr++) {
           switch (*condExpr) {
           case '\\':
               if (condExpr[1] != '\0') {
                   condExpr++;
                   Buf_AddByte(buf, (Byte)*condExpr);
               }
               break;
           case '"':
               if (qt) {
                   condExpr++;             /* we don't want the quotes */
                   goto got_str;
               } else
                   Buf_AddByte(buf, (Byte)*condExpr); /* likely? */
               break;
           case ')':
           case '!':
           case '=':
           case '>':
           case '<':
           case ' ':
           case '\t':
               if (!qt)
                   goto got_str;
             else              else
                 return FALSE;                  Buf_AddByte(buf, (Byte)*condExpr);
             i = (i << 4) + x;              break;
           case '$':
               /* if we are in quotes, then an undefined variable is ok */
               str = Var_Parse(condExpr, VAR_CMD, (qt ? 0 : doEval),
                               &len, freeIt);
               if (str == var_Error) {
                   if (*freeIt) {
                       free(*freeIt);
                       *freeIt = NULL;
                   }
                   /*
                    * Even if !doEval, we still report syntax errors, which
                    * is what getting var_Error back with !doEval means.
                    */
                   str = NULL;
                   goto cleanup;
               }
               condExpr += len;
               /*
                * If the '$' was first char (no quotes), and we are
                * followed by space, the operator or end of expression,
                * we are done.
                */
               if ((condExpr == start + len) &&
                   (*condExpr == '\0' ||
                    isspace((unsigned char) *condExpr) ||
                    strchr("!=><)", *condExpr))) {
                   goto cleanup;
               }
               /*
                * Nope, we better copy str to buf
                */
               for (cp = str; *cp; cp++) {
                   Buf_AddByte(buf, (Byte)*cp);
               }
               if (*freeIt) {
                   free(*freeIt);
                   *freeIt = NULL;
               }
               str = NULL;                 /* not finished yet */
               condExpr--;                 /* don't skip over next char */
               break;
           default:
               Buf_AddByte(buf, (Byte)*condExpr);
               break;
         }          }
         *value = (double) i;  
         return TRUE;  
     }  
     else {  
         char *eptr;  
         *value = strtod(str, &eptr);  
         return *eptr == '\0';  
     }      }
    got_str:
       Buf_AddByte(buf, (Byte)'\0');
       str = (char *)Buf_GetAll(buf, NULL);
       *freeIt = str;
    cleanup:
       Buf_Destroy(buf, FALSE);
       return str;
 }  }
   
 /*-  /*-
Line 522  CondCvtArg(str, value)
Line 654  CondCvtArg(str, value)
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 static Token  static Token
 CondToken(doEval)  compare_expression(Boolean doEval)
     Boolean doEval;  {
       Token       t;
       char        *lhs;
       char        *rhs;
       char        *op;
       void        *lhsFree;
       void        *rhsFree;
       Boolean lhsQuoted;
       Boolean rhsQuoted;
   
       rhs = NULL;
       lhsFree = rhsFree = FALSE;
       lhsQuoted = rhsQuoted = FALSE;
   
       /*
        * Parse the variable spec and skip over it, saving its
        * value in lhs.
        */
       t = Err;
       lhs = CondGetString(doEval, &lhsQuoted, &lhsFree);
       if (!lhs) {
           if (lhsFree)
               free(lhsFree);
           return Err;
       }
       /*
        * Skip whitespace to get to the operator
        */
       while (isspace((unsigned char) *condExpr))
           condExpr++;
   
       /*
        * Make sure the operator is a valid one. If it isn't a
        * known relational operator, pretend we got a
        * != 0 comparison.
        */
       op = condExpr;
       switch (*condExpr) {
           case '!':
           case '=':
           case '<':
           case '>':
               if (condExpr[1] == '=') {
                   condExpr += 2;
               } else {
                   condExpr += 1;
               }
               break;
           default:
               op = UNCONST("!=");
               if (lhsQuoted)
                   rhs = UNCONST("");
               else
                   rhs = UNCONST("0");
   
               goto do_compare;
       }
       while (isspace((unsigned char) *condExpr)) {
           condExpr++;
       }
       if (*condExpr == '\0') {
           Parse_Error(PARSE_WARNING,
                       "Missing right-hand-side of operator");
           goto error;
       }
       rhs = CondGetString(doEval, &rhsQuoted, &rhsFree);
       if (!rhs) {
           if (lhsFree)
               free(lhsFree);
           if (rhsFree)
               free(rhsFree);
           return Err;
       }
   do_compare:
       if (rhsQuoted || lhsQuoted) {
   do_string_compare:
           if (((*op != '!') && (*op != '=')) || (op[1] != '=')) {
               Parse_Error(PARSE_WARNING,
       "String comparison operator should be either == or !=");
               goto error;
           }
   
           if (DEBUG(COND)) {
               fprintf(debug_file, "lhs = \"%s\", rhs = \"%s\", op = %.2s\n",
                      lhs, rhs, op);
           }
           /*
            * Null-terminate rhs and perform the comparison.
            * t is set to the result.
            */
           if (*op == '=') {
               t = strcmp(lhs, rhs) ? False : True;
           } else {
               t = strcmp(lhs, rhs) ? True : False;
           }
       } else {
           /*
            * rhs is either a float or an integer. Convert both the
            * lhs and the rhs to a double and compare the two.
            */
           double          left, right;
   
           if (!CondCvtArg(lhs, &left) || !CondCvtArg(rhs, &right))
               goto do_string_compare;
   
           if (DEBUG(COND)) {
               fprintf(debug_file, "left = %f, right = %f, op = %.2s\n", left,
                      right, op);
           }
           switch(op[0]) {
           case '!':
               if (op[1] != '=') {
                   Parse_Error(PARSE_WARNING,
                               "Unknown operator");
                   goto error;
               }
               t = (left != right ? True : False);
               break;
           case '=':
               if (op[1] != '=') {
                   Parse_Error(PARSE_WARNING,
                               "Unknown operator");
                   goto error;
               }
               t = (left == right ? True : False);
               break;
           case '<':
               if (op[1] == '=') {
                   t = (left <= right ? True : False);
               } else {
                   t = (left < right ? True : False);
               }
               break;
           case '>':
               if (op[1] == '=') {
                   t = (left >= right ? True : False);
               } else {
                   t = (left > right ? True : False);
               }
               break;
           }
       }
   error:
       if (lhsFree)
           free(lhsFree);
       if (rhsFree)
           free(rhsFree);
       return t;
   }
   
   static Token
   compare_function(Boolean doEval)
   {
       Token       t;
       Boolean (*evalProc)(int, char *);
       Boolean invert = FALSE;
       char        *arg = NULL;
       int arglen = 0;
   
       if (istoken(condExpr, "defined", 7)) {
           /*
            * Use CondDoDefined to evaluate the argument and
            * CondGetArg to extract the argument from the 'function
            * call'.
            */
           evalProc = CondDoDefined;
           condExpr += 7;
           arglen = CondGetArg(&condExpr, &arg, "defined", TRUE);
           if (arglen == 0) {
               condExpr -= 7;
               goto use_default;
           }
       } else if (istoken(condExpr, "make", 4)) {
           /*
            * Use CondDoMake to evaluate the argument and
            * CondGetArg to extract the argument from the 'function
            * call'.
            */
           evalProc = CondDoMake;
           condExpr += 4;
           arglen = CondGetArg(&condExpr, &arg, "make", TRUE);
           if (arglen == 0) {
               condExpr -= 4;
               goto use_default;
           }
       } else if (istoken(condExpr, "exists", 6)) {
           /*
            * Use CondDoExists to evaluate the argument and
            * CondGetArg to extract the argument from the
            * 'function call'.
            */
           evalProc = CondDoExists;
           condExpr += 6;
           arglen = CondGetArg(&condExpr, &arg, "exists", TRUE);
           if (arglen == 0) {
               condExpr -= 6;
               goto use_default;
           }
       } else if (istoken(condExpr, "empty", 5)) {
           /*
            * Use Var_Parse to parse the spec in parens and return
            * True if the resulting string is empty.
            */
           int         did_warn, length;
           void    *freeIt;
           char    *val;
   
           condExpr += 5;
   
           did_warn = 0;
           for (arglen = 0; condExpr[arglen] != '\0'; arglen += 1) {
               if (condExpr[arglen] == '(')
                   break;
               if (!isspace((unsigned char)condExpr[arglen]) &&
                   !did_warn) {
   
                   Parse_Error(PARSE_WARNING,
                       "Extra characters after \"empty\"");
                   did_warn = 1;
               }
           }
   
           if (condExpr[arglen] != '\0') {
               val = Var_Parse(&condExpr[arglen - 1], VAR_CMD,
                               FALSE, &length, &freeIt);
               if (val == var_Error) {
                   t = Err;
               } else {
                   /*
                    * A variable is empty when it just contains
                    * spaces... 4/15/92, christos
                    */
                   char *p;
                   for (p = val; *p && isspace((unsigned char)*p); p++)
                       continue;
                   t = (*p == '\0') ? True : False;
               }
               if (freeIt) {
                   free(freeIt);
               }
               /*
                * Advance condExpr to beyond the closing ). Note that
                * we subtract one from arglen + length b/c length
                * is calculated from condExpr[arglen - 1].
                */
               condExpr += arglen + length - 1;
           } else {
               condExpr -= 5;
               goto use_default;
           }
           return t;
       } else if (istoken(condExpr, "target", 6)) {
           /*
            * Use CondDoTarget to evaluate the argument and
            * CondGetArg to extract the argument from the
            * 'function call'.
            */
           evalProc = CondDoTarget;
           condExpr += 6;
           arglen = CondGetArg(&condExpr, &arg, "target", TRUE);
           if (arglen == 0) {
               condExpr -= 6;
               goto use_default;
           }
       } else if (istoken(condExpr, "commands", 8)) {
           /*
            * Use CondDoCommands to evaluate the argument and
            * CondGetArg to extract the argument from the
            * 'function call'.
            */
           evalProc = CondDoCommands;
           condExpr += 8;
           arglen = CondGetArg(&condExpr, &arg, "commands", TRUE);
           if (arglen == 0) {
               condExpr -= 8;
               goto use_default;
           }
       } else {
           /*
            * The symbol is itself the argument to the default
            * function. We advance condExpr to the end of the symbol
            * by hand (the next whitespace, closing paren or
            * binary operator) and set to invert the evaluation
            * function if condInvert is TRUE.
            */
           if (isdigit((unsigned char)condExpr[0]) || strchr("+-", condExpr[0])) {
               /*
                * Variables may already be substituted
                * by the time we get here.
                */
               return compare_expression(doEval);
           }
       use_default:
           invert = condInvert;
           evalProc = condDefProc;
           arglen = CondGetArg(&condExpr, &arg, "", FALSE);
       }
   
       /*
        * Evaluate the argument using the set function. If invert
        * is TRUE, we invert the sense of the function.
        */
       t = (!doEval || (* evalProc) (arglen, arg) ?
            (invert ? False : True) :
            (invert ? True : False));
       if (arg)
           free(arg);
       return t;
   }
   
   static Token
   CondToken(Boolean doEval)
 {  {
     Token         t;      Token         t;
   
Line 558  CondToken(doEval)
Line 1001  CondToken(doEval)
                 t = Not;                  t = Not;
                 condExpr++;                  condExpr++;
                 break;                  break;
               case '#':
             case '\n':              case '\n':
             case '\0':              case '\0':
                 t = EndOfFile;                  t = EndOfFile;
                 break;                  break;
             case '$': {              case '"':
                 char    *lhs;              case '$':
                 char    *rhs;                  return compare_expression(doEval);
                 char    *op;  
                 int     varSpecLen;  
                 Boolean doFree;  
   
                 /*  
                  * Parse the variable spec and skip over it, saving its  
                  * value in lhs.  
                  */  
                 t = Err;  
                 lhs = Var_Parse(condExpr, VAR_CMD, doEval,&varSpecLen,&doFree);  
                 if (lhs == var_Error) {  
                     /*  
                      * Even if !doEval, we still report syntax errors, which  
                      * is what getting var_Error back with !doEval means.  
                      */  
                     return(Err);  
                 }  
                 condExpr += varSpecLen;  
   
                 if (!isspace((unsigned char) *condExpr) &&  
                     strchr("!=><", *condExpr) == NULL) {  
                     Buffer buf;  
                     char *cp;  
   
                     buf = Buf_Init(0);  
   
                     for (cp = lhs; *cp; cp++)  
                         Buf_AddByte(buf, (Byte)*cp);  
   
                     if (doFree)  
                         free(lhs);  
   
                     for (;*condExpr && !isspace((unsigned char) *condExpr);  
                          condExpr++)  
                         Buf_AddByte(buf, (Byte)*condExpr);  
   
                     Buf_AddByte(buf, (Byte)'\0');              default:
                     lhs = (char *)Buf_GetAll(buf, &varSpecLen);                  return compare_function(doEval);
                     Buf_Destroy(buf, FALSE);  
   
                     doFree = TRUE;  
                 }  
   
                 /*  
                  * Skip whitespace to get to the operator  
                  */  
                 while (isspace((unsigned char) *condExpr))  
                     condExpr++;  
   
                 /*  
                  * Make sure the operator is a valid one. If it isn't a  
                  * known relational operator, pretend we got a  
                  * != 0 comparison.  
                  */  
                 op = condExpr;  
                 switch (*condExpr) {  
                     case '!':  
                     case '=':  
                     case '<':  
                     case '>':  
                         if (condExpr[1] == '=') {  
                             condExpr += 2;  
                         } else {  
                             condExpr += 1;  
                         }  
                         break;  
                     default:  
                         op = "!=";  
                         rhs = "0";  
   
                         goto do_compare;  
                 }  
                 while (isspace((unsigned char) *condExpr)) {  
                     condExpr++;  
                 }  
                 if (*condExpr == '\0') {  
                     Parse_Error(PARSE_WARNING,  
                                 "Missing right-hand-side of operator");  
                     goto error;  
                 }  
                 rhs = condExpr;  
 do_compare:  
                 if (*rhs == '"') {  
                     /*  
                      * Doing a string comparison. Only allow == and != for  
                      * operators.  
                      */  
                     char    *string;  
                     char    *cp, *cp2;  
                     int     qt;  
                     Buffer  buf;  
   
 do_string_compare:  
                     if (((*op != '!') && (*op != '=')) || (op[1] != '=')) {  
                         Parse_Error(PARSE_WARNING,  
                 "String comparison operator should be either == or !=");  
                         goto error;  
                     }  
   
                     buf = Buf_Init(0);  
                     qt = *rhs == '"' ? 1 : 0;  
   
                     for (cp = &rhs[qt];  
                          ((qt && (*cp != '"')) ||  
                           (!qt && strchr(" \t)", *cp) == NULL)) &&  
                          (*cp != '\0'); cp++) {  
                         if ((*cp == '\\') && (cp[1] != '\0')) {  
                             /*  
                              * Backslash escapes things -- skip over next  
                              * character, if it exists.  
                              */  
                             cp++;  
                             Buf_AddByte(buf, (Byte)*cp);  
                         } else if (*cp == '$') {  
                             int len;  
                             Boolean freeIt;  
   
                             cp2 = Var_Parse(cp, VAR_CMD, doEval,&len, &freeIt);  
                             if (cp2 != var_Error) {  
                                 Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2);  
                                 if (freeIt) {  
                                     free(cp2);  
                                 }  
                                 cp += len - 1;  
                             } else {  
                                 Buf_AddByte(buf, (Byte)*cp);  
                             }  
                         } else {  
                             Buf_AddByte(buf, (Byte)*cp);  
                         }  
                     }  
   
                     Buf_AddByte(buf, (Byte)0);  
   
                     string = (char *)Buf_GetAll(buf, (int *)0);  
                     Buf_Destroy(buf, FALSE);  
   
                     if (DEBUG(COND)) {  
                         printf("lhs = \"%s\", rhs = \"%s\", op = %.2s\n",  
                                lhs, string, op);  
                     }  
                     /*  
                      * Null-terminate rhs and perform the comparison.  
                      * t is set to the result.  
                      */  
                     if (*op == '=') {  
                         t = strcmp(lhs, string) ? False : True;  
                     } else {  
                         t = strcmp(lhs, string) ? True : False;  
                     }  
                     free(string);  
                     if (rhs == condExpr) {  
                         if (!qt && *cp == ')')  
                             condExpr = cp;  
                         else  
                             condExpr = cp + 1;  
                     }  
                 } else {  
                     /*  
                      * rhs is either a float or an integer. Convert both the  
                      * lhs and the rhs to a double and compare the two.  
                      */  
                     double      left, right;  
                     char        *string;  
   
                     if (!CondCvtArg(lhs, &left))  
                         goto do_string_compare;  
                     if (*rhs == '$') {  
                         int     len;  
                         Boolean freeIt;  
   
                         string = Var_Parse(rhs, VAR_CMD, doEval,&len,&freeIt);  
                         if (string == var_Error) {  
                             right = 0.0;  
                         } else {  
                             if (!CondCvtArg(string, &right)) {  
                                 if (freeIt)  
                                     free(string);  
                                 goto do_string_compare;  
                             }  
                             if (freeIt)  
                                 free(string);  
                             if (rhs == condExpr)  
                                 condExpr += len;  
                         }  
                     } else {  
                         if (!CondCvtArg(rhs, &right))  
                             goto do_string_compare;  
                         if (rhs == condExpr) {  
                             /*  
                              * Skip over the right-hand side  
                              */  
                             while(!isspace((unsigned char) *condExpr) &&  
                                   (*condExpr != '\0')) {  
                                 condExpr++;  
                             }  
                         }  
                     }  
   
                     if (DEBUG(COND)) {  
                         printf("left = %f, right = %f, op = %.2s\n", left,  
                                right, op);  
                     }  
                     switch(op[0]) {  
                     case '!':  
                         if (op[1] != '=') {  
                             Parse_Error(PARSE_WARNING,  
                                         "Unknown operator");  
                             goto error;  
                         }  
                         t = (left != right ? True : False);  
                         break;  
                     case '=':  
                         if (op[1] != '=') {  
                             Parse_Error(PARSE_WARNING,  
                                         "Unknown operator");  
                             goto error;  
                         }  
                         t = (left == right ? True : False);  
                         break;  
                     case '<':  
                         if (op[1] == '=') {  
                             t = (left <= right ? True : False);  
                         } else {  
                             t = (left < right ? True : False);  
                         }  
                         break;  
                     case '>':  
                         if (op[1] == '=') {  
                             t = (left >= right ? True : False);  
                         } else {  
                             t = (left > right ? True : False);  
                         }  
                         break;  
                     }  
                 }  
 error:  
                 if (doFree)  
                     free(lhs);  
                 break;  
             }  
             default: {  
                 Boolean (*evalProc) __P((int, char *));  
                 Boolean invert = FALSE;  
                 char    *arg;  
                 int     arglen;  
   
                 if (strncmp (condExpr, "defined", 7) == 0) {  
                     /*  
                      * Use CondDoDefined to evaluate the argument and  
                      * CondGetArg to extract the argument from the 'function  
                      * call'.  
                      */  
                     evalProc = CondDoDefined;  
                     condExpr += 7;  
                     arglen = CondGetArg (&condExpr, &arg, "defined", TRUE);  
                     if (arglen == 0) {  
                         condExpr -= 7;  
                         goto use_default;  
                     }  
                 } else if (strncmp (condExpr, "make", 4) == 0) {  
                     /*  
                      * Use CondDoMake to evaluate the argument and  
                      * CondGetArg to extract the argument from the 'function  
                      * call'.  
                      */  
                     evalProc = CondDoMake;  
                     condExpr += 4;  
                     arglen = CondGetArg (&condExpr, &arg, "make", TRUE);  
                     if (arglen == 0) {  
                         condExpr -= 4;  
                         goto use_default;  
                     }  
                 } else if (strncmp (condExpr, "exists", 6) == 0) {  
                     /*  
                      * Use CondDoExists to evaluate the argument and  
                      * CondGetArg to extract the argument from the  
                      * 'function call'.  
                      */  
                     evalProc = CondDoExists;  
                     condExpr += 6;  
                     arglen = CondGetArg(&condExpr, &arg, "exists", TRUE);  
                     if (arglen == 0) {  
                         condExpr -= 6;  
                         goto use_default;  
                     }  
                 } else if (strncmp(condExpr, "empty", 5) == 0) {  
                     /*  
                      * Use Var_Parse to parse the spec in parens and return  
                      * True if the resulting string is empty.  
                      */  
                     int     length;  
                     Boolean doFree;  
                     char    *val;  
   
                     condExpr += 5;  
   
                     for (arglen = 0;  
                          condExpr[arglen] != '(' && condExpr[arglen] != '\0';  
                          arglen += 1)  
                         continue;  
   
                     if (condExpr[arglen] != '\0') {  
                         val = Var_Parse(&condExpr[arglen - 1], VAR_CMD,  
                                         doEval, &length, &doFree);  
                         if (val == var_Error) {  
                             t = Err;  
                         } else {  
                             /*  
                              * A variable is empty when it just contains  
                              * spaces... 4/15/92, christos  
                              */  
                             char *p;  
                             for (p = val; *p && isspace((unsigned char)*p); p++)  
                                 continue;  
                             t = (*p == '\0') ? True : False;  
                         }  
                         if (doFree) {  
                             free(val);  
                         }  
                         /*  
                          * Advance condExpr to beyond the closing ). Note that  
                          * we subtract one from arglen + length b/c length  
                          * is calculated from condExpr[arglen - 1].  
                          */  
                         condExpr += arglen + length - 1;  
                     } else {  
                         condExpr -= 5;  
                         goto use_default;  
                     }  
                     break;  
                 } else if (strncmp (condExpr, "target", 6) == 0) {  
                     /*  
                      * Use CondDoTarget to evaluate the argument and  
                      * CondGetArg to extract the argument from the  
                      * 'function call'.  
                      */  
                     evalProc = CondDoTarget;  
                     condExpr += 6;  
                     arglen = CondGetArg(&condExpr, &arg, "target", TRUE);  
                     if (arglen == 0) {  
                         condExpr -= 6;  
                         goto use_default;  
                     }  
                 } else if (strncmp (condExpr, "commands", 8) == 0) {  
                     /*  
                      * Use CondDoCommands to evaluate the argument and  
                      * CondGetArg to extract the argument from the  
                      * 'function call'.  
                      */  
                     evalProc = CondDoCommands;  
                     condExpr += 8;  
                     arglen = CondGetArg(&condExpr, &arg, "commands", TRUE);  
                     if (arglen == 0) {  
                         condExpr -= 8;  
                         goto use_default;  
                     }  
                 } else {  
                     /*  
                      * The symbol is itself the argument to the default  
                      * function. We advance condExpr to the end of the symbol  
                      * by hand (the next whitespace, closing paren or  
                      * binary operator) and set to invert the evaluation  
                      * function if condInvert is TRUE.  
                      */  
                 use_default:  
                     invert = condInvert;  
                     evalProc = condDefProc;  
                     arglen = CondGetArg(&condExpr, &arg, "", FALSE);  
                 }  
   
                 /*  
                  * Evaluate the argument using the set function. If invert  
                  * is TRUE, we invert the sense of the function.  
                  */  
                 t = (!doEval || (* evalProc) (arglen, arg) ?  
                      (invert ? False : True) :  
                      (invert ? True : False));  
                 free(arg);  
                 break;  
             }  
         }          }
     } else {      } else {
         t = condPushBack;          t = condPushBack;
Line 972  error:
Line 1039  error:
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 static Token  static Token
 CondT(doEval)  CondT(Boolean doEval)
     Boolean doEval;  
 {  {
     Token   t;      Token   t;
   
Line 1021  CondT(doEval)
Line 1087  CondT(doEval)
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 static Token  static Token
 CondF(doEval)  CondF(Boolean doEval)
     Boolean doEval;  
 {  {
     Token   l, o;      Token   l, o;
   
Line 1041  CondF(doEval)
Line 1106  CondF(doEval)
             if (l == True) {              if (l == True) {
                 l = CondF(doEval);                  l = CondF(doEval);
             } else {              } else {
                 (void) CondF(FALSE);                  (void)CondF(FALSE);
             }              }
         } else {          } else {
             /*              /*
              * F -> T               * F -> T
              */               */
             CondPushBack (o);              CondPushBack(o);
         }          }
     }      }
     return (l);      return (l);
Line 1068  CondF(doEval)
Line 1133  CondF(doEval)
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 static Token  static Token
 CondE(doEval)  CondE(Boolean doEval)
     Boolean doEval;  
 {  {
     Token   l, o;      Token   l, o;
   
Line 1089  CondE(doEval)
Line 1153  CondE(doEval)
             if (l == False) {              if (l == False) {
                 l = CondE(doEval);                  l = CondE(doEval);
             } else {              } else {
                 (void) CondE(FALSE);                  (void)CondE(FALSE);
             }              }
         } else {          } else {
             /*              /*
              * E -> F               * E -> F
              */               */
             CondPushBack (o);              CondPushBack(o);
         }          }
     }      }
     return (l);      return (l);
Line 1120  CondE(doEval)
Line 1184  CondE(doEval)
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 int  int
 Cond_EvalExpression(dosetup, line, value, eprint)  Cond_EvalExpression(int dosetup, char *line, Boolean *value, int eprint)
     int dosetup;  
     char *line;  
     Boolean *value;  
     int eprint;  
 {  {
     if (dosetup) {      if (dosetup) {
         condDefProc = CondDoDefined;          condDefProc = CondDoDefined;
Line 1154  Cond_EvalExpression(dosetup, line, value
Line 1214  Cond_EvalExpression(dosetup, line, value
     case Err:      case Err:
 err:  err:
         if (eprint)          if (eprint)
             Parse_Error (PARSE_FATAL, "Malformed conditional (%s)",              Parse_Error(PARSE_FATAL, "Malformed conditional (%s)",
                          line);                           line);
         return (COND_INVALID);          return (COND_INVALID);
     default:      default:
Line 1170  err:
Line 1230  err:
  * Cond_Eval --   * Cond_Eval --
  *      Evaluate the conditional in the passed line. The line   *      Evaluate the conditional in the passed line. The line
  *      looks like this:   *      looks like this:
  *          #<cond-type> <expr>   *          .<cond-type> <expr>
  *      where <cond-type> is any of if, ifmake, ifnmake, ifdef,   *      where <cond-type> is any of if, ifmake, ifnmake, ifdef,
  *      ifndef, elif, elifmake, elifnmake, elifdef, elifndef   *      ifndef, elif, elifmake, elifnmake, elifdef, elifndef
  *      and <expr> consists of &&, ||, !, make(target), defined(variable)   *      and <expr> consists of &&, ||, !, make(target), defined(variable)
  *      and parenthetical groupings thereof.   *      and parenthetical groupings thereof.
  *   *
    * Input:
    *      line            Line to parse
    *
  * Results:   * Results:
  *      COND_PARSE      if should parse lines after the conditional   *      COND_PARSE      if should parse lines after the conditional
  *      COND_SKIP       if should skip lines after the conditional   *      COND_SKIP       if should skip lines after the conditional
Line 1184  err:
Line 1247  err:
  * Side Effects:   * Side Effects:
  *      None.   *      None.
  *   *
    * Note that the states IF_ACTIVE and ELSE_ACTIVE are only different in order
    * to detect splurious .else lines (as are SKIP_TO_ELSE and SKIP_TO_ENDIF)
    * otherwise .else could be treated as '.elif 1'.
    *
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 int  int
 Cond_Eval (line)  Cond_Eval(char *line)
     char            *line;    /* Line to parse */  
 {  {
     struct If       *ifp;      #define         MAXIF       64      /* maximum depth of .if'ing */
     Boolean         isElse;      enum if_states {
     Boolean         value = FALSE;          IF_ACTIVE,              /* .if or .elif part active */
           ELSE_ACTIVE,            /* .else part active */
           SEARCH_FOR_ELIF,        /* searching for .elif/else to execute */
           SKIP_TO_ELSE,           /* has been true, but not seen '.else' */
           SKIP_TO_ENDIF           /* nothing else to execute */
       };
       static enum if_states cond_state[MAXIF + 1] = { IF_ACTIVE };
   
       const struct If *ifp;
       Boolean         isElif;
       Boolean         value;
     int             level;      /* Level at which to report errors. */      int             level;      /* Level at which to report errors. */
       enum if_states  state;
   
     level = PARSE_FATAL;      level = PARSE_FATAL;
   
     for (line++; *line == ' ' || *line == '\t'; line++) {      /* skip leading character (the '.') and any whitespace */
       for (line++; *line == ' ' || *line == '\t'; line++)
         continue;          continue;
     }  
   
     /*      /* Find what type of if we're dealing with.  */
      * Find what type of if we're dealing with. The result is left      if (line[0] == 'e') {
      * in ifp and isElse is set TRUE if it's an elif line.          if (line[1] != 'l') {
      */              if (!istoken(line + 1, "ndif", 4))
     if (line[0] == 'e' && line[1] == 'l') {                  return COND_INVALID;
               /* End of conditional section */
               if (cond_depth == cond_min_depth) {
                   Parse_Error(level, "if-less endif");
                   return COND_PARSE;
               }
               /* Return state for previous conditional */
               cond_depth--;
               if (cond_depth > MAXIF)
                   return COND_SKIP;
               return cond_state[cond_depth] <= ELSE_ACTIVE ? COND_PARSE : COND_SKIP;
           }
   
           /* Quite likely this is 'else' or 'elif' */
         line += 2;          line += 2;
         isElse = TRUE;          if (istoken(line, "se", 2)) {
     } else if (strncmp (line, "endif", 5) == 0) {              /* It is else... */
         /*              if (cond_depth == cond_min_depth) {
          * End of a conditional section. If skipIfLevel is non-zero, that                  Parse_Error(level, "if-less else");
          * conditional was skipped, so lines following it should also be                  return COND_PARSE;
          * skipped. Hence, we return COND_SKIP. Otherwise, the conditional              }
          * was read so succeeding lines should be parsed (think about it...)  
          * so we return COND_PARSE, unless this endif isn't paired with              if (cond_depth > MAXIF)
          * a decent if.                  return COND_SKIP;
          */              state = cond_state[cond_depth];
         if (skipIfLevel != 0) {              switch (state) {
             skipIfLevel -= 1;              case SEARCH_FOR_ELIF:
             return (COND_SKIP);                  state = ELSE_ACTIVE;
         } else {                  break;
             if (condTop == MAXIF) {              case ELSE_ACTIVE:
                 Parse_Error (level, "if-less endif");              case SKIP_TO_ENDIF:
                 return (COND_INVALID);                  Parse_Error(PARSE_WARNING, "extra else");
             } else {                  /* FALLTHROUGH */
                 skipLine = FALSE;              default:
                 condTop += 1;              case IF_ACTIVE:
                 return (COND_PARSE);              case SKIP_TO_ELSE:
                   state = SKIP_TO_ENDIF;
                   break;
             }              }
               cond_state[cond_depth] = state;
               return state <= ELSE_ACTIVE ? COND_PARSE : COND_SKIP;
         }          }
     } else {          /* Assume for now it is an elif */
         isElse = FALSE;          isElif = TRUE;
     }      } else
           isElif = FALSE;
   
       if (line[0] != 'i' || line[1] != 'f')
           /* Not an ifxxx or elifxxx line */
           return COND_INVALID;
   
     /*      /*
      * Figure out what sort of conditional it is -- what its default       * Figure out what sort of conditional it is -- what its default
      * function is, etc. -- by looking in the table of valid "ifs"       * function is, etc. -- by looking in the table of valid "ifs"
      */       */
     for (ifp = ifs; ifp->form != (char *)0; ifp++) {      line += 2;
         if (strncmp (ifp->form, line, ifp->formlen) == 0) {      for (ifp = ifs; ; ifp++) {
           if (ifp->form == NULL)
               return COND_INVALID;
           if (istoken(ifp->form, line, ifp->formlen)) {
               line += ifp->formlen;
             break;              break;
         }          }
     }      }
   
     if (ifp->form == (char *) 0) {      /* Now we know what sort of 'if' it is... */
         /*  
          * Nothing fit. If the first word on the line is actually      if (isElif) {
          * "else", it's a valid conditional whose value is the inverse          if (cond_depth == cond_min_depth) {
          * of the previous if we parsed.              Parse_Error(level, "if-less elif");
          */              return COND_PARSE;
         if (isElse && (line[0] == 's') && (line[1] == 'e')) {          }
             if (condTop == MAXIF) {          if (cond_depth > MAXIF)
                 Parse_Error (level, "if-less else");              /* Error reported when we saw the .if ... */
                 return (COND_INVALID);              return COND_SKIP;
             } else if (skipIfLevel == 0) {          state = cond_state[cond_depth];
                 value = !condStack[condTop];          if (state == SKIP_TO_ENDIF || state == ELSE_ACTIVE) {
             } else {              Parse_Error(PARSE_WARNING, "extra elif");
                 return (COND_SKIP);              cond_state[cond_depth] = SKIP_TO_ENDIF;
             }              return COND_SKIP;
         } else {          }
             /*          if (state != SEARCH_FOR_ELIF) {
              * Not a valid conditional type. No error...              /* Either just finished the 'true' block, or already SKIP_TO_ELSE */
              */              cond_state[cond_depth] = SKIP_TO_ELSE;
             return (COND_INVALID);              return COND_SKIP;
         }          }
     } else {      } else {
         if (isElse) {          /* Normal .if */
             if (condTop == MAXIF) {          if (cond_depth >= MAXIF) {
                 Parse_Error (level, "if-less elif");              cond_depth++;
                 return (COND_INVALID);              Parse_Error(PARSE_FATAL, "Too many nested if's. %d max.", MAXIF);
             } else if (skipIfLevel != 0) {              return COND_SKIP;
                 /*          }
                  * If skipping this conditional, just ignore the whole thing.          state = cond_state[cond_depth];
                  * If we don't, the user might be employing a variable that's          cond_depth++;
                  * undefined, for which there's an enclosing ifdef that          if (state > ELSE_ACTIVE) {
                  * we're skipping...              /* If we aren't parsing the data, treat as always false */
                  */              cond_state[cond_depth] = SKIP_TO_ELSE;
                 return(COND_SKIP);              return COND_SKIP;
             }  
         } else if (skipLine) {  
             /*  
              * Don't even try to evaluate a conditional that's not an else if  
              * we're skipping things...  
              */  
             skipIfLevel += 1;  
             return(COND_SKIP);  
         }          }
   
         /*  
          * Initialize file-global variables for parsing  
          */  
         condDefProc = ifp->defProc;  
         condInvert = ifp->doNot;  
   
         line += ifp->formlen;  
         if (Cond_EvalExpression(0, line, &value, 1) == COND_INVALID)  
                 return COND_INVALID;  
     }  
     if (!isElse) {  
         condTop -= 1;  
     } else if ((skipIfLevel != 0) || condStack[condTop]) {  
         /*  
          * If this is an else-type conditional, it should only take effect  
          * if its corresponding if was evaluated and FALSE. If its if was  
          * TRUE or skipped, we return COND_SKIP (and start skipping in case  
          * we weren't already), leaving the stack unmolested so later elif's  
          * don't screw up...  
          */  
         skipLine = TRUE;  
         return (COND_SKIP);  
     }      }
   
     if (condTop < 0) {      /* Initialize file-global variables for parsing the expression */
         /*      condDefProc = ifp->defProc;
          * This is the one case where we can definitely proclaim a fatal      condInvert = ifp->doNot;
          * error. If we don't, we're hosed.  
          */      /* And evaluate the conditional expresssion */
         Parse_Error (PARSE_FATAL, "Too many nested if's. %d max.", MAXIF);      if (Cond_EvalExpression(0, line, &value, 1) == COND_INVALID) {
         return (COND_INVALID);          /* Syntax error in conditional, error message already output. */
     } else {          /* Skip everything to matching .endif */
         condStack[condTop] = value;          cond_state[cond_depth] = SKIP_TO_ELSE;
         skipLine = !value;          return COND_SKIP;
         return (value ? COND_PARSE : COND_SKIP);      }
   
       if (!value) {
           cond_state[cond_depth] = SEARCH_FOR_ELIF;
           return COND_SKIP;
     }      }
       cond_state[cond_depth] = IF_ACTIVE;
       return COND_PARSE;
 }  }
   
   
Line 1342  Cond_Eval (line)
Line 1420  Cond_Eval (line)
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 void  void
 Cond_End()  Cond_restore_depth(unsigned int saved_depth)
 {  {
     if (condTop != MAXIF) {      int open_conds = cond_depth - cond_min_depth;
         Parse_Error(PARSE_FATAL, "%d open conditional%s", MAXIF-condTop,  
                     MAXIF-condTop == 1 ? "" : "s");      if (open_conds != 0 || saved_depth > cond_depth) {
           Parse_Error(PARSE_FATAL, "%d open conditional%s", open_conds,
                       open_conds == 1 ? "" : "s");
           cond_depth = cond_min_depth;
     }      }
     condTop = MAXIF;  
       cond_min_depth = saved_depth;
   }
   
   unsigned int
   Cond_save_depth(void)
   {
       int depth = cond_min_depth;
   
       cond_min_depth = cond_depth;
       return depth;
 }  }

Legend:
Removed from v.1.12  
changed lines
  Added in v.1.46

CVSweb <webmaster@jp.NetBSD.org>