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

Diff for /src/usr.bin/make/cond.c between version 1.24 and 1.25

version 1.24, 2001/05/03 13:41:02 version 1.25, 2001/05/23 12:34:41
Line 40 
Line 40 
  * SUCH DAMAGE.   * SUCH DAMAGE.
  */   */
   
 /*-  #include <ctype.h>
  * cond.c --  #include <stddef.h>
  *      Functions to handle conditionals in a makefile.  #include <stdio.h>
  *  #include <string.h>
  * Interface:  #include "config.h"
  *      Cond_Eval       Evaluate the conditional in the passed line.  #include "defines.h"
  *  #include "dir.h"
  */  #include "buf.h"
   #include "cond.h"
   #include "error.h"
   #include "var.h"
   #include "varname.h"
   #include "targ.h"
   #include "lowparse.h"
   #include "str.h"
   #include "main.h"
   #include "gnode.h"
   #include "lst.h"
   
 #include    <ctype.h>  
 #include    <math.h>  
 #include    <stddef.h>  
 #include    "make.h"  
 #include    "ohash.h"  
 #include    "dir.h"  
 #include    "buf.h"  
   
 #ifndef lint  
 #if 0  
 static char sccsid[] = "@(#)cond.c      8.2 (Berkeley) 1/2/94";  
 #else  
 UNUSED  
 static char rcsid[] = "$OpenBSD$";  
 #endif  
 #endif /* not lint */  
   
   
 /* The parsing of conditional expressions is based on this grammar:  /* The parsing of conditional expressions is based on this grammar:
  *      E -> F || E   *      E -> F || E
  *      E -> F   *      E -> F
Line 92 
Line 85 
  * will return And for '&' and '&&', Or for '|' and '||', Not for '!',   * will return And for '&' and '&&', Or for '|' and '||', Not for '!',
  * LParen for '(', RParen for ')' and will evaluate the other terminal   * LParen for '(', RParen for ')' and will evaluate the other terminal
  * symbols, using either the default function or the function given in the   * symbols, using either the default function or the function given in the
  * terminal, and return the result as either True or False.   * terminal, and return the result as either true or False.
  *   *
  * All Non-Terminal functions (CondE, CondF and CondT) return Err on error.  */   * All Non-Terminal functions (CondE, CondF and CondT) return Err on error.  */
 typedef enum {  typedef enum {
Line 103 
Line 96 
  * 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 Boolean CondGetArg(const char **, struct Name *,  static bool CondGetArg(const char **, struct Name *,
     const char *, Boolean);      const char *, bool);
 static Boolean CondDoDefined(struct Name *);  static bool CondDoDefined(struct Name *);
 static Boolean CondDoMake(struct Name *);  static bool CondDoMake(struct Name *);
 static Boolean CondDoExists(struct Name *);  static bool CondDoExists(struct Name *);
 static Boolean CondDoTarget(struct Name *);  static bool CondDoTarget(struct Name *);
 static Boolean CondCvtArg(const char *, double *);  static bool CondCvtArg(const char *, double *);
 static Token CondToken(Boolean);  static Token CondToken(bool);
 static Token CondT(Boolean);  static Token CondT(bool);
 static Token CondF(Boolean);  static Token CondF(bool);
 static Token CondE(Boolean);  static Token CondE(bool);
 static Token CondHandleVarSpec(Boolean);  static Token CondHandleVarSpec(bool);
 static Token CondHandleDefault(Boolean);  static Token CondHandleDefault(bool);
 static const char *find_cond(const char *);  static const char *find_cond(const char *);
   
   
 static struct If {  static struct If {
     char        *form;          /* Form of if */      char        *form;          /* Form of if */
     int         formlen;        /* Length of form */      int         formlen;        /* Length of form */
     Boolean     doNot;          /* TRUE if default function should be negated */      bool        doNot;          /* true if default function should be negated */
     Boolean     (*defProc)(struct Name *);      bool        (*defProc)(struct Name *);
                                 /* Default function to apply */                                  /* Default function to apply */
 } ifs[] = {  } ifs[] = {
     { "ifdef",    5,      FALSE,  CondDoDefined },      { "ifdef",    5,      false,  CondDoDefined },
     { "ifndef",   6,      TRUE,   CondDoDefined },      { "ifndef",   6,      true,   CondDoDefined },
     { "ifmake",   6,      FALSE,  CondDoMake },      { "ifmake",   6,      false,  CondDoMake },
     { "ifnmake",  7,      TRUE,   CondDoMake },      { "ifnmake",  7,      true,   CondDoMake },
     { "if",       2,      FALSE,  CondDoDefined },      { "if",       2,      false,  CondDoDefined },
     { NULL,       0,      FALSE,  NULL }      { NULL,       0,      false,  NULL }
 };  };
   
 static Boolean    condInvert;           /* Invert the default function */  static bool       condInvert;           /* Invert the default function */
 static Boolean    (*condDefProc)        /* Default function to apply */  static bool       (*condDefProc)        /* Default function to apply */
                    (struct Name *);                     (struct Name *);
 static const char *condExpr;            /* The expression to parse */  static const 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
Line 144 
Line 137 
 #define MAXIF           30        /* greatest depth of #if'ing */  #define MAXIF           30        /* greatest depth of #if'ing */
   
 static struct {  static struct {
         Boolean         value;          bool    value;
         unsigned long   lineno;          unsigned long   lineno;
         const char      *filename;          const char      *filename;
 } condStack[MAXIF];                     /* Stack of conditionals */  } condStack[MAXIF];                     /* Stack of conditionals */
 static int        condTop = MAXIF;      /* Top-most conditional */  static int        condTop = MAXIF;      /* Top-most conditional */
 static int        skipIfLevel=0;        /* Depth of skipped conditionals */  static int        skipIfLevel=0;        /* Depth of skipped conditionals */
 static Boolean    skipLine = FALSE;     /* Whether the parse module is skipping  static bool       skipLine = false;     /* Whether the parse module is skipping
                                          * lines */                                           * lines */
   
 static const char *  static const char *
Line 170 
Line 163 
  *      Find the argument of a built-in function.   *      Find the argument of a built-in function.
  *   *
  * Results:   * Results:
  *      TRUE if evaluation went okay   *      true if evaluation went okay
  *   *
  * Side Effects:   * Side Effects:
  *      The line pointer is set to point to the closing parenthesis of the   *      The line pointer is set to point to the closing parenthesis of the
  *      function call. The argument is filled.   *      function call. The argument is filled.
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 static Boolean  static bool
 CondGetArg(linePtr, arg, func, parens)  CondGetArg(linePtr, arg, func, parens)
     const char          **linePtr;      const char          **linePtr;
     struct Name         *arg;      struct Name         *arg;
     const char          *func;      const char          *func;
     Boolean             parens; /* TRUE if arg should be bounded by parens */      bool                parens; /* true if arg should be bounded by parens */
 {  {
     const char          *cp;      const char          *cp;
   
Line 201 
Line 194 
          * the word 'make' or 'defined' at the beginning of a symbol...  */           * the word 'make' or 'defined' at the beginning of a symbol...  */
         arg->s = cp;          arg->s = cp;
         arg->e = cp;          arg->e = cp;
         arg->tofree = FALSE;          arg->tofree = false;
         return FALSE;          return false;
     }      }
   
     while (*cp == ' ' || *cp == '\t')      while (*cp == ' ' || *cp == '\t')
         cp++;          cp++;
   
   
     cp = Var_Name_Get(cp, arg, NULL, TRUE, find_cond);      cp = VarName_Get(cp, arg, NULL, true, find_cond);
   
     while (*cp == ' ' || *cp == '\t')      while (*cp == ' ' || *cp == '\t')
         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 FALSE;          return false;
     } else if (parens)      } else if (parens)
         /* Advance pointer past close parenthesis.  */          /* Advance pointer past close parenthesis.  */
         cp++;          cp++;
   
     *linePtr = cp;      *linePtr = cp;
     return TRUE;      return true;
 }  }
   
 /*-  /*-
Line 231 
Line 224 
  *      Handle the 'defined' function for conditionals.   *      Handle the 'defined' function for conditionals.
  *   *
  * Results:   * Results:
  *      TRUE if the given variable is defined.   *      true if the given variable is defined.
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 static Boolean  static bool
 CondDoDefined(arg)  CondDoDefined(arg)
     struct Name *arg;      struct Name *arg;
 {  {
     if (Var_Value_interval(arg->s, arg->e) != NULL)      if (Var_Valuei(arg->s, arg->e) != NULL)
         return TRUE;          return true;
     else      else
         return FALSE;          return false;
 }  }
   
 /*-  /*-
Line 250 
Line 243 
  *      Handle the 'make' function for conditionals.   *      Handle the 'make' function for conditionals.
  *   *
  * Results:   * Results:
  *      TRUE if the given target is being made.   *      true if the given target is being made.
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 static Boolean  static bool
 CondDoMake(arg)  CondDoMake(arg)
     struct Name *arg;      struct Name *arg;
 {  {
     LstNode ln;      LstNode ln;
   
     for (ln = Lst_First(&create); ln != NULL; ln = Lst_Adv(ln)) {      for (ln = Lst_First(create); ln != NULL; ln = Lst_Adv(ln)) {
         if (Str_Matchi((char *)Lst_Datum(ln), arg->s, arg->e))          char *s = (char *)Lst_Datum(ln);
             return TRUE;          if (Str_Matchi(s, strchr(s, '\0'), arg->s, arg->e))
               return true;
     }      }
   
     return FALSE;      return false;
 }  }
   
 /*-  /*-
Line 273 
Line 267 
  *      See if the given file exists.   *      See if the given file exists.
  *   *
  * Results:   * Results:
  *      TRUE if the file exists and FALSE if it does not.   *      true if the file exists and false if it does not.
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 static Boolean  static bool
 CondDoExists(arg)  CondDoExists(arg)
     struct Name *arg;      struct Name *arg;
 {  {
     Boolean result;      bool result;
     char    *path;      char    *path;
   
     path = Dir_FindFilei(arg->s, arg->e, &dirSearchPath);      path = Dir_FindFilei(arg->s, arg->e, dirSearchPath);
     if (path != NULL) {      if (path != NULL) {
         result = TRUE;          result = true;
         free(path);          free(path);
     } else {      } else {
         result = FALSE;          result = false;
     }      }
     return result;      return result;
 }  }
Line 299 
Line 293 
  *      See if the given node exists and is an actual target.   *      See if the given node exists and is an actual target.
  *   *
  * Results:   * Results:
  *      TRUE if the node exists as a target and FALSE if it does not.   *      true if the node exists as a target and false if it does not.
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 static Boolean  static bool
 CondDoTarget(arg)  CondDoTarget(arg)
     struct Name *arg;      struct Name *arg;
 {  {
     GNode   *gn;      GNode   *gn;
   
     gn = Targ_FindNode(arg->s, arg->e, TARG_NOCREATE);      gn = Targ_FindNodei(arg->s, arg->e, TARG_NOCREATE);
     if (gn != NULL && !OP_NOP(gn->type))      if (gn != NULL && !OP_NOP(gn->type))
         return TRUE;          return true;
     else      else
         return FALSE;          return false;
 }  }
   
   
Line 332 
Line 326 
  *      Can change 'value' even if string is not a valid number.   *      Can change 'value' even if string is not a valid number.
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  */   */
 static Boolean  static bool
 CondCvtArg(str, value)  CondCvtArg(str, value)
     const char          *str;      const char          *str;
     double              *value;      double              *value;
Line 347 
Line 341 
             else if (isxdigit(*str))              else if (isxdigit(*str))
                 x = 10 + *str - isupper(*str) ? 'A' : 'a';                  x = 10 + *str - isupper(*str) ? 'A' : 'a';
             else              else
                 return FALSE;                  return false;
             i = (i << 4) + x;              i = (i << 4) + x;
         }          }
         *value = (double) i;          *value = (double) i;
         return TRUE;          return true;
     }      }
     else {      else {
         char *eptr;          char *eptr;
Line 363 
Line 357 
   
 static Token  static Token
 CondHandleVarSpec(doEval)  CondHandleVarSpec(doEval)
     Boolean doEval;      bool doEval;
 {  {
     Token       t;      Token       t;
     char        *lhs;      char        *lhs;
     const char  *rhs;      const char  *rhs;
     const char  *op;      const char  *op;
     size_t      varSpecLen;      size_t      varSpecLen;
     Boolean     doFree;      bool        doFree;
   
     /* 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.  */
Line 398 
Line 392 
   
         lhs = Buf_Retrieve(&buf);          lhs = Buf_Retrieve(&buf);
   
         doFree = TRUE;          doFree = true;
     }      }
   
     /* Skip whitespace to get to the operator.  */      /* Skip whitespace to get to the operator.  */
Line 459 
Line 453 
             if (*cp == '$') {              if (*cp == '$') {
                 size_t  len;                  size_t  len;
   
                 if (Var_ParseBuffer(&buf, cp, NULL, doEval, &len)                  if (Var_ParseBuffer(&buf, cp, NULL, doEval, &len)) {
                     == SUCCESS) {  
                     cp += len;                      cp += len;
                     continue;                      continue;
                 }                  }
Line 501 
Line 494 
             goto do_string_compare;              goto do_string_compare;
         if (*rhs == '$') {          if (*rhs == '$') {
             size_t      len;              size_t      len;
             Boolean     freeIt;              bool        freeIt;
   
             string = Var_Parse(rhs, NULL, doEval,&len,&freeIt);              string = Var_Parse(rhs, NULL, doEval,&len,&freeIt);
             if (string == var_Error)              if (string == var_Error)
Line 573 
Line 566 
 static struct operator {  static struct operator {
     const char *s;      const char *s;
     size_t len;      size_t len;
     Boolean (*proc)(struct Name *);      bool (*proc)(struct Name *);
 } ops[] = {  } ops[] = {
     {S("defined"), CondDoDefined},      {S("defined"), CondDoDefined},
     {S("make"), CondDoMake},      {S("make"), CondDoMake},
Line 583 
Line 576 
 };  };
 static Token  static Token
 CondHandleDefault(doEval)  CondHandleDefault(doEval)
     Boolean     doEval;      bool        doEval;
 {  {
     Boolean     t;      bool        t;
     Boolean     (*evalProc)(struct Name *);      bool        (*evalProc)(struct Name *);
     Boolean     invert = FALSE;      bool        invert = false;
     struct Name arg;      struct Name arg;
     size_t arglen;      size_t arglen;
   
Line 596 
Line 589 
         /* 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.  */
         size_t   length;          size_t   length;
         Boolean doFree;          bool doFree;
         char    *val;          char    *val;
   
         condExpr += 5;          condExpr += 5;
Line 632 
Line 625 
         for (op = ops; op != NULL; op++)          for (op = ops; op != NULL; op++)
             if (strncmp(condExpr, op->s, op->len) == 0) {              if (strncmp(condExpr, op->s, op->len) == 0) {
                 condExpr += op->len;                  condExpr += op->len;
                 if (CondGetArg(&condExpr, &arg, op->s, TRUE))                  if (CondGetArg(&condExpr, &arg, op->s, true))
                     evalProc = op->proc;                      evalProc = op->proc;
                 else                  else
                     condExpr -= op->len;                      condExpr -= op->len;
Line 644 
Line 637 
          * function. We advance condExpr to the end of the symbol           * function. We advance condExpr to the end of the symbol
          * by hand (the next whitespace, closing paren or           * by hand (the next whitespace, closing paren or
          * binary operator) and set to invert the evaluation           * binary operator) and set to invert the evaluation
          * function if condInvert is TRUE.  */           * function if condInvert is true.  */
         invert = condInvert;          invert = condInvert;
         evalProc = condDefProc;          evalProc = condDefProc;
         /* XXX should we ignore problems now ? */          /* XXX should we ignore problems now ? */
         CondGetArg(&condExpr, &arg, "", FALSE);          CondGetArg(&condExpr, &arg, "", false);
     }      }
   
     /* Evaluate the argument using the set function. If invert      /* Evaluate the argument using the set function. If invert
      * is TRUE, we invert the sense of the function.  */       * is true, we invert the sense of the function.  */
     t = (!doEval || (*evalProc)(&arg) ?      t = (!doEval || (*evalProc)(&arg) ?
          (invert ? False : True) :           (invert ? False : True) :
          (invert ? True : False));           (invert ? True : False));
     Var_Name_Free(&arg);      VarName_Free(&arg);
     return t;      return t;
 }  }
   
Line 674 
Line 667 
  */   */
 static Token  static Token
 CondToken(doEval)  CondToken(doEval)
     Boolean doEval;      bool doEval;
 {  {
   
     if (condPushBack != None) {      if (condPushBack != None) {
Line 735 
Line 728 
  */   */
 static Token  static Token
 CondT(doEval)  CondT(doEval)
     Boolean doEval;      bool doEval;
 {  {
     Token   t;      Token   t;
   
Line 776 
Line 769 
  */   */
 static Token  static Token
 CondF(doEval)  CondF(doEval)
     Boolean doEval;      bool doEval;
 {  {
     Token   l, o;      Token   l, o;
   
Line 793 
Line 786 
             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;
Line 816 
Line 809 
  */   */
 static Token  static Token
 CondE(doEval)  CondE(doEval)
     Boolean doEval;      bool doEval;
 {  {
     Token   l, o;      Token   l, o;
   
Line 834 
Line 827 
             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;
Line 842 
Line 835 
     return l;      return l;
 }  }
   
 /*-  /* A conditional line looks like this:
  *-----------------------------------------------------------------------  
  * Cond_Eval --  
  *      Evaluate the conditional in the passed fragment. The fragment  
  *      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.
  *  
  * Results:  
  *      COND_PARSE      if should parse lines after the conditional  
  *      COND_SKIP       if should skip lines after the conditional  
  *      COND_INVALID    if not a valid conditional.  
  *-----------------------------------------------------------------------  
  */   */
 int  int
 Cond_Eval(line)  Cond_Eval(line)
     char            *line;    /* Line to parse */      const char      *line;    /* Line to parse */
 {  {
     struct If       *ifp;      struct If       *ifp;
     Boolean         isElse;      bool            isElse;
     Boolean         value = FALSE;      bool            value = false;
     int             level;      /* Level at which to report errors. */      int             level;      /* Level at which to report errors. */
   
     level = PARSE_FATAL;      level = PARSE_FATAL;
Line 874 
Line 857 
      * otherwise, this is not our turf.  */       * otherwise, this is not our turf.  */
   
     /* Find what type of if we're dealing with. The result is left      /* Find what type of if we're dealing with. The result is left
      * in ifp and isElse is set TRUE if it's an elif line.  */       * in ifp and isElse is set true if it's an elif line.  */
     if (line[0] == 'e' && line[1] == 'l') {      if (line[0] == 'e' && line[1] == 'l') {
         line += 2;          line += 2;
         isElse = TRUE;          isElse = true;
     } else if (strncmp(line, "endif", 5) == 0) {      } else if (strncmp(line, "endif", 5) == 0) {
         /* End of a conditional section. If skipIfLevel is non-zero, that          /* End of a conditional section. If skipIfLevel is non-zero, that
          * conditional was skipped, so lines following it should also be           * conditional was skipped, so lines following it should also be
Line 893 
Line 876 
                 Parse_Error(level, "if-less endif");                  Parse_Error(level, "if-less endif");
                 return COND_INVALID;                  return COND_INVALID;
             } else {              } else {
                 skipLine = FALSE;                  skipLine = false;
                 condTop += 1;                  condTop += 1;
                 return COND_PARSE;                  return COND_PARSE;
             }              }
         }          }
     } else      } else
         isElse = FALSE;          isElse = false;
   
     /* 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" */
Line 954 
Line 937 
         condExpr = line;          condExpr = line;
         condPushBack = None;          condPushBack = None;
   
         switch (CondE(TRUE)) {          switch (CondE(true)) {
             case True:              case True:
                 if (CondToken(TRUE) == EndOfFile) {                  if (CondToken(true) == EndOfFile) {
                     value = TRUE;                      value = true;
                     break;                      break;
                 }                  }
                 goto err;                  goto err;
                 /* FALLTHROUGH */                  /* FALLTHROUGH */
             case False:              case False:
                 if (CondToken(TRUE) == EndOfFile) {                  if (CondToken(true) == EndOfFile) {
                     value = FALSE;                      value = false;
                     break;                      break;
                 }                  }
                 /* FALLTHROUGH */                  /* FALLTHROUGH */
Line 980 
Line 963 
         condTop -= 1;          condTop -= 1;
     else if (skipIfLevel != 0 || condStack[condTop].value) {      else if (skipIfLevel != 0 || condStack[condTop].value) {
         /* If this is an else-type conditional, it should only take effect          /* If this is an else-type conditional, it should only take effect
          * if its corresponding if was evaluated and FALSE. If its if was           * if its corresponding if was evaluated and false. If its if was
          * TRUE or skipped, we return COND_SKIP (and start skipping in case           * true or skipped, we return COND_SKIP (and start skipping in case
          * we weren't already), leaving the stack unmolested so later elif's           * we weren't already), leaving the stack unmolested so later elif's
          * don't screw up...  */           * don't screw up...  */
         skipLine = TRUE;          skipLine = true;
         return COND_SKIP;          return COND_SKIP;
     }      }
   
Line 1002 
Line 985 
     }      }
 }  }
   
 /*-  
  *-----------------------------------------------------------------------  
  * Cond_End --  
  *      Make sure everything's clean at the end of a makefile.  
  *  
  * Side Effects:  
  *      Parse_Error will be called if open conditionals are around.  
  *-----------------------------------------------------------------------  
  */  
 void  void
 Cond_End()  Cond_End()
 {  {

Legend:
Removed from v.1.24  
changed lines
  Added in v.1.25