[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.19 and 1.38

version 1.19, 2004/01/06 01:18:52 version 1.38, 2008/02/06 18:26:37
Line 69 
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 114  __RCSID("$NetBSD$");
Line 114  __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 151  static Token CondT(Boolean);
Line 152  static Token CondT(Boolean);
 static Token CondF(Boolean);  static Token CondF(Boolean);
 static Token CondE(Boolean);  static Token CondE(Boolean);
   
 static struct If {  static const struct If {
     const 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)(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 }
 };  };
   
Line 171  static char    *condExpr;      /* The ex
Line 172  static char    *condExpr;      /* The ex
 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 243  CondGetArg(char **linePtr, char **argPtr
Line 245  CondGetArg(char **linePtr, char **argPtr
          * 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 257  CondGetArg(char **linePtr, char **argPtr
Line 259  CondGetArg(char **linePtr, char **argPtr
      */       */
     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 267  CondGetArg(char **linePtr, char **argPtr
Line 269  CondGetArg(char **linePtr, char **argPtr
              */               */
             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 290  CondGetArg(char **linePtr, char **argPtr
Line 290  CondGetArg(char **linePtr, char **argPtr
         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 325  CondDoDefined(int argLen, char *arg)
Line 325  CondDoDefined(int argLen, char *arg)
     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 353  CondDoDefined(int argLen, char *arg)
Line 353  CondDoDefined(int argLen, char *arg)
 static int  static int
 CondStrMatch(ClientData string, ClientData pattern)  CondStrMatch(ClientData string, ClientData pattern)
 {  {
     return(!Str_Match((char *) string,(char *) pattern));      return(!Str_Match((char *)string,(char *)pattern));
 }  }
   
 /*-  /*-
Line 376  CondDoMake(int argLen, char *arg)
Line 376  CondDoMake(int argLen, char *arg)
     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 407  CondDoExists(int argLen, char *arg)
Line 407  CondDoExists(int argLen, char *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 527  CondCvtArg(char *str, double *value)
Line 531  CondCvtArg(char *str, double *value)
   
 /*-  /*-
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
    * 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:
    *      Moves condExpr to end of this token.
    *
    *
    *-----------------------------------------------------------------------
    */
   /* coverity:[+alloc : arg-*2] */
   static char *
   CondGetString(Boolean doEval, Boolean *quoted, void **freeIt)
   {
       Buffer buf;
       char *cp;
       char *str;
       int len;
       int qt;
       char *start;
   
       buf = Buf_Init(0);
       str = NULL;
       *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
                   Buf_AddByte(buf, (Byte)*condExpr);
               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;
           }
       }
    got_str:
       Buf_AddByte(buf, (Byte)'\0');
       str = (char *)Buf_GetAll(buf, NULL);
       *freeIt = str;
    cleanup:
       Buf_Destroy(buf, FALSE);
       return str;
   }
   
   /*-
    *-----------------------------------------------------------------------
  * CondToken --   * CondToken --
  *      Return the next token from the input.   *      Return the next token from the input.
  *   *
Line 579  CondToken(Boolean doEval)
Line 700  CondToken(Boolean doEval)
             case '\0':              case '\0':
                 t = EndOfFile;                  t = EndOfFile;
                 break;                  break;
               case '"':
             case '$': {              case '$': {
                 char    *lhs;                  char    *lhs;
                 char    *rhs;                  char    *rhs;
                 char    *op;                  char    *op;
                 int     varSpecLen;                  void    *lhsFree;
                 Boolean doFree;                  void    *rhsFree;
                   Boolean lhsQuoted;
                   Boolean rhsQuoted;
   
                   rhs = NULL;
                   lhsFree = rhsFree = FALSE;
                   lhsQuoted = rhsQuoted = FALSE;
   
                 /*                  /*
                  * Parse the variable spec and skip over it, saving its                   * Parse the variable spec and skip over it, saving its
                  * value in lhs.                   * value in lhs.
                  */                   */
                 t = Err;                  t = Err;
                 lhs = Var_Parse(condExpr, VAR_CMD, doEval,&varSpecLen,&doFree);                  lhs = CondGetString(doEval, &lhsQuoted, &lhsFree);
                 if (lhs == var_Error) {                  if (!lhs) {
                     /*                      if (lhsFree)
                      * Even if !doEval, we still report syntax errors, which                          free(lhsFree);
                      * is what getting var_Error back with !doEval means.                      return Err;
                      */  
                     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');  
                     lhs = (char *)Buf_GetAll(buf, &varSpecLen);  
                     Buf_Destroy(buf, FALSE);  
   
                     doFree = TRUE;  
                 }                  }
   
                 /*                  /*
                  * Skip whitespace to get to the operator                   * Skip whitespace to get to the operator
                  */                   */
Line 650  CondToken(Boolean doEval)
Line 750  CondToken(Boolean doEval)
                         break;                          break;
                     default:                      default:
                         op = UNCONST("!=");                          op = UNCONST("!=");
                         rhs = UNCONST("0");                          if (lhsQuoted)
                               rhs = UNCONST("");
                           else
                               rhs = UNCONST("0");
   
                         goto do_compare;                          goto do_compare;
                 }                  }
Line 662  CondToken(Boolean doEval)
Line 765  CondToken(Boolean doEval)
                                 "Missing right-hand-side of operator");                                  "Missing right-hand-side of operator");
                     goto error;                      goto error;
                 }                  }
                 rhs = condExpr;                  rhs = CondGetString(doEval, &rhsQuoted, &rhsFree);
                   if (!rhs) {
                       if (lhsFree)
                           free(lhsFree);
                       if (rhsFree)
                           free(rhsFree);
                       return Err;
                   }
 do_compare:  do_compare:
                 if (*rhs == '"') {                  if (rhsQuoted || lhsQuoted) {
                     /*  
                      * Doing a string comparison. Only allow == and != for  
                      * operators.  
                      */  
                     char    *string;  
                     char    *cp, *cp2;  
                     int     qt;  
                     Buffer  buf;  
   
 do_string_compare:  do_string_compare:
                     if (((*op != '!') && (*op != '=')) || (op[1] != '=')) {                      if (((*op != '!') && (*op != '=')) || (op[1] != '=')) {
                         Parse_Error(PARSE_WARNING,                          Parse_Error(PARSE_WARNING,
Line 681  do_string_compare:
Line 782  do_string_compare:
                         goto error;                          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)) {                      if (DEBUG(COND)) {
                         printf("lhs = \"%s\", rhs = \"%s\", op = %.2s\n",                          fprintf(debug_file, "lhs = \"%s\", rhs = \"%s\", op = %.2s\n",
                                lhs, string, op);                                 lhs, rhs, op);
                     }                      }
                     /*                      /*
                      * Null-terminate rhs and perform the comparison.                       * Null-terminate rhs and perform the comparison.
                      * t is set to the result.                       * t is set to the result.
                      */                       */
                     if (*op == '=') {                      if (*op == '=') {
                         t = strcmp(lhs, string) ? False : True;                          t = strcmp(lhs, rhs) ? False : True;
                     } else {                      } else {
                         t = strcmp(lhs, string) ? True : False;                          t = strcmp(lhs, rhs) ? True : False;
                     }  
                     free(string);  
                     if (rhs == condExpr) {  
                         if (!qt && *cp == ')')  
                             condExpr = cp;  
                         else  
                             condExpr = cp + 1;  
                     }                      }
                 } else {                  } else {
                     /*                      /*
Line 745  do_string_compare:
Line 801  do_string_compare:
                      * lhs and the rhs to a double and compare the two.                       * lhs and the rhs to a double and compare the two.
                      */                       */
                     double      left, right;                      double      left, right;
                     char        *string;                      char        *cp;
   
                     if (CondCvtArg(lhs, &left))                      if (CondCvtArg(lhs, &left))
                         goto do_string_compare;                          goto do_string_compare;
                     if (*rhs == '$') {                      if ((cp = CondCvtArg(rhs, &right)) &&
                         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 {  
                         char *cp;  
   
                         if ((cp = CondCvtArg(rhs, &right)) &&  
                             cp == rhs)                              cp == rhs)
                             goto do_string_compare;                          goto do_string_compare;
                         if (rhs == condExpr) {  
                             /*  
                              * Skip over the right-hand side  
                              */  
                             if (cp)  
                                 condExpr = cp;  
                             else  
                                 condExpr = strchr(rhs, '\0');  
                         }  
                     }  
   
                     if (DEBUG(COND)) {                      if (DEBUG(COND)) {
                         printf("left = %f, right = %f, op = %.2s\n", left,                          fprintf(debug_file, "left = %f, right = %f, op = %.2s\n", left,
                                right, op);                                 right, op);
                     }                      }
                     switch(op[0]) {                      switch(op[0]) {
Line 822  do_string_compare:
Line 847  do_string_compare:
                     }                      }
                 }                  }
 error:  error:
                 if (doFree)                  if (lhsFree)
                     free(lhs);                      free(lhsFree);
                   if (rhsFree)
                       free(rhsFree);
                 break;                  break;
             }              }
             default: {              default: {
                 Boolean (*evalProc)(int, char *);                  Boolean (*evalProc)(int, char *);
                 Boolean invert = FALSE;                  Boolean invert = FALSE;
                 char    *arg;                  char    *arg = NULL;
                 int     arglen;                  int     arglen = 0;
   
                 if (strncmp (condExpr, "defined", 7) == 0) {                  if (istoken(condExpr, "defined", 7)) {
                     /*                      /*
                      * Use CondDoDefined to evaluate the argument and                       * Use CondDoDefined to evaluate the argument and
                      * CondGetArg to extract the argument from the 'function                       * CondGetArg to extract the argument from the 'function
Line 840  error:
Line 867  error:
                      */                       */
                     evalProc = CondDoDefined;                      evalProc = CondDoDefined;
                     condExpr += 7;                      condExpr += 7;
                     arglen = CondGetArg (&condExpr, &arg, "defined", TRUE);                      arglen = CondGetArg(&condExpr, &arg, "defined", TRUE);
                     if (arglen == 0) {                      if (arglen == 0) {
                         condExpr -= 7;                          condExpr -= 7;
                         goto use_default;                          goto use_default;
                     }                      }
                 } else if (strncmp (condExpr, "make", 4) == 0) {                  } else if (istoken(condExpr, "make", 4)) {
                     /*                      /*
                      * Use CondDoMake to evaluate the argument and                       * Use CondDoMake to evaluate the argument and
                      * CondGetArg to extract the argument from the 'function                       * CondGetArg to extract the argument from the 'function
Line 853  error:
Line 880  error:
                      */                       */
                     evalProc = CondDoMake;                      evalProc = CondDoMake;
                     condExpr += 4;                      condExpr += 4;
                     arglen = CondGetArg (&condExpr, &arg, "make", TRUE);                      arglen = CondGetArg(&condExpr, &arg, "make", TRUE);
                     if (arglen == 0) {                      if (arglen == 0) {
                         condExpr -= 4;                          condExpr -= 4;
                         goto use_default;                          goto use_default;
                     }                      }
                 } else if (strncmp (condExpr, "exists", 6) == 0) {                  } else if (istoken(condExpr, "exists", 6)) {
                     /*                      /*
                      * Use CondDoExists to evaluate the argument and                       * Use CondDoExists to evaluate the argument and
                      * CondGetArg to extract the argument from the                       * CondGetArg to extract the argument from the
Line 871  error:
Line 898  error:
                         condExpr -= 6;                          condExpr -= 6;
                         goto use_default;                          goto use_default;
                     }                      }
                 } else if (strncmp(condExpr, "empty", 5) == 0) {                  } else if (istoken(condExpr, "empty", 5)) {
                     /*                      /*
                      * Use Var_Parse to parse the spec in parens and return                       * Use Var_Parse to parse the spec in parens and return
                      * True if the resulting string is empty.                       * True if the resulting string is empty.
                      */                       */
                     int     length;                      int     length;
                     Boolean doFree;                      void    *freeIt;
                     char    *val;                      char    *val;
   
                     condExpr += 5;                      condExpr += 5;
   
                     for (arglen = 0;                      for (arglen = 0; condExpr[arglen] != '\0'; arglen += 1) {
                          condExpr[arglen] != '(' && condExpr[arglen] != '\0';                          if (condExpr[arglen] == '(')
                          arglen += 1)                              break;
                         continue;                          if (!isspace((unsigned char)condExpr[arglen]))
                               Parse_Error(PARSE_WARNING,
                                   "Extra characters after \"empty\"");
                       }
   
                     if (condExpr[arglen] != '\0') {                      if (condExpr[arglen] != '\0') {
                         val = Var_Parse(&condExpr[arglen - 1], VAR_CMD,                          val = Var_Parse(&condExpr[arglen - 1], VAR_CMD,
                                         FALSE, &length, &doFree);                                          FALSE, &length, &freeIt);
                         if (val == var_Error) {                          if (val == var_Error) {
                             t = Err;                              t = Err;
                         } else {                          } else {
Line 902  error:
Line 932  error:
                                 continue;                                  continue;
                             t = (*p == '\0') ? True : False;                              t = (*p == '\0') ? True : False;
                         }                          }
                         if (doFree) {                          if (freeIt) {
                             free(val);                              free(freeIt);
                         }                          }
                         /*                          /*
                          * Advance condExpr to beyond the closing ). Note that                           * Advance condExpr to beyond the closing ). Note that
Line 916  error:
Line 946  error:
                         goto use_default;                          goto use_default;
                     }                      }
                     break;                      break;
                 } else if (strncmp (condExpr, "target", 6) == 0) {                  } else if (istoken(condExpr, "target", 6)) {
                     /*                      /*
                      * Use CondDoTarget to evaluate the argument and                       * Use CondDoTarget to evaluate the argument and
                      * CondGetArg to extract the argument from the                       * CondGetArg to extract the argument from the
Line 929  error:
Line 959  error:
                         condExpr -= 6;                          condExpr -= 6;
                         goto use_default;                          goto use_default;
                     }                      }
                 } else if (strncmp (condExpr, "commands", 8) == 0) {                  } else if (istoken(condExpr, "commands", 8)) {
                     /*                      /*
                      * Use CondDoCommands to evaluate the argument and                       * Use CondDoCommands to evaluate the argument and
                      * CondGetArg to extract the argument from the                       * CondGetArg to extract the argument from the
Line 963  error:
Line 993  error:
                 t = (!doEval || (* evalProc) (arglen, arg) ?                  t = (!doEval || (* evalProc) (arglen, arg) ?
                      (invert ? False : True) :                       (invert ? False : True) :
                      (invert ? True : False));                       (invert ? True : False));
                 free(arg);                  if (arg)
                       free(arg);
                 break;                  break;
             }              }
         }          }
Line 1059  CondF(Boolean doEval)
Line 1090  CondF(Boolean 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 1106  CondE(Boolean doEval)
Line 1137  CondE(Boolean 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 1167  Cond_EvalExpression(int dosetup, char *l
Line 1198  Cond_EvalExpression(int dosetup, char *l
     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 1183  err:
Line 1214  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)
Line 1200  err:
Line 1231  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(char *line)  Cond_Eval(char *line)
 {  {
     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--;
               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_INVALID;
          * 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              state = cond_state[cond_depth];
          * a decent if.              switch (state) {
          */              case SEARCH_FOR_ELIF:
         if (skipIfLevel != 0) {                  state = ELSE_ACTIVE;
             skipIfLevel -= 1;                  break;
             return (COND_SKIP);              case ELSE_ACTIVE:
         } else {              case SKIP_TO_ENDIF:
             if (condTop == MAXIF) {                  Parse_Error(PARSE_WARNING, "extra else");
                 Parse_Error (level, "if-less endif");                  /* FALLTHROUGH */
                 return (COND_INVALID);              default:
             } else {              case IF_ACTIVE:
                 skipLine = FALSE;              case SKIP_TO_ELSE:
                 condTop += 1;                  state = SKIP_TO_ENDIF;
                 return (COND_PARSE);                  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... */
         /*      state = cond_state[cond_depth];
          * Nothing fit. If the first word on the line is actually  
          * "else", it's a valid conditional whose value is the inverse      if (isElif) {
          * of the previous if we parsed.          if (cond_depth == cond_min_depth) {
          */              Parse_Error(level, "if-less elif");
         if (isElse && (line[0] == 's') && (line[1] == 'e')) {              return COND_INVALID;
             if (condTop == MAXIF) {          }
                 Parse_Error (level, "if-less else");          if (state == SKIP_TO_ENDIF || state == ELSE_ACTIVE)
                 return (COND_INVALID);              Parse_Error(PARSE_WARNING, "extra elif");
             } else if (skipIfLevel == 0) {          if (state != SEARCH_FOR_ELIF) {
                 value = !condStack[condTop];              /* Either just finished the 'true' block, or already SKIP_TO_ELSE */
             } else {              cond_state[cond_depth] = SKIP_TO_ELSE;
                 return (COND_SKIP);              return COND_SKIP;
             }  
         } else {  
             /*  
              * Not a valid conditional type. No error...  
              */  
             return (COND_INVALID);  
         }          }
     } else {      } else {
         if (isElse) {          if (cond_depth >= MAXIF) {
             if (condTop == MAXIF) {              Parse_Error(PARSE_FATAL, "Too many nested if's. %d max.", MAXIF);
                 Parse_Error (level, "if-less elif");              return COND_INVALID;
                 return (COND_INVALID);          }
             } else if (skipIfLevel != 0) {          cond_depth++;
                 /*          if (state > ELSE_ACTIVE) {
                  * If skipping this conditional, just ignore the whole thing.              /* If we aren't parsing the data, treat as always false */
                  * If we don't, the user might be employing a variable that's              cond_state[cond_depth] = SKIP_TO_ELSE;
                  * undefined, for which there's an enclosing ifdef that              return COND_SKIP;
                  * we're skipping...  
                  */  
                 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);          /* Although we get make to reprocess the line, set a state */
     } else {          cond_state[cond_depth] = SEARCH_FOR_ELIF;
         condStack[condTop] = value;          return COND_INVALID;
         skipLine = !value;      }
         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 1357  Cond_Eval(char *line)
Line 1390  Cond_Eval(char *line)
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 void  void
 Cond_End(void)  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.19  
changed lines
  Added in v.1.38

CVSweb <webmaster@jp.NetBSD.org>