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

Diff for /src/usr.bin/make/parse.c between version 1.60 and 1.61

version 1.60, 2001/05/15 12:52:15 version 1.61, 2001/05/23 12:34:47
Line 66 
Line 66 
  * SUCH DAMAGE.   * SUCH DAMAGE.
  */   */
   
 /*-  
  * parse.c --  
  *      Functions to parse a makefile.  
  *  
  *      One function, Parse_Init, must be called before any functions  
  *      in this module are used. After that, the function Parse_File is the  
  *      main entry point and controls most of the other functions in this  
  *      module.  
  *  
  *      Most important structures are kept in Lsts. Directories for  
  *      the #include "..." function are kept in the 'parseIncPath' Lst, while  
  *      those for the #include <...> are kept in the 'sysIncPath' Lst. The  
  *      targets currently being defined are kept in the 'targets' Lst.  
  *  
  *      The variables 'fname' and 'lineno' are used to track the name  
  *      of the current file and the line number in that file so that error  
  *      messages can be more meaningful.  
  *  
  * Interface:  
  *      Parse_Init                  Initialization function which must be  
  *                                  called before anything else in this module  
  *                                  is used.  
  *  
  *      Parse_End                   Cleanup the module  
  *  
  *      Parse_File                  Function used to parse a makefile. It must  
  *                                  be given the name of the file, which should  
  *                                  already have been opened, and a function  
  *                                  to call to read a character from the file.  
  *  
  *      Parse_IsVar                 Returns TRUE if the given line is a  
  *                                  variable assignment. Used by MainParseArgs  
  *                                  to determine if an argument is a target  
  *                                  or a variable assignment. Used internally  
  *                                  for pretty much the same thing...  
  *  
  *      Parse_Error                 Function called when an error occurs in  
  *                                  parsing. Used by the variable and  
  *                                  conditional modules.  
  *      Parse_MainName              Returns a Lst of the main target to create.  
  */  
   
 #ifdef __STDC__  
 #include <stdarg.h>  
 #else  
 #include <varargs.h>  
 #endif  
 #include <assert.h>  #include <assert.h>
 #include <stddef.h>  
 #include <stdio.h>  
 #include <ctype.h>  #include <ctype.h>
 #include <errno.h>  #include <stdio.h>
 #include "make.h"  #include <string.h>
 #include "ohash.h"  #include "config.h"
   #include "defines.h"
 #include "dir.h"  #include "dir.h"
 #include "job.h"  #include "job.h"
 #include "buf.h"  #include "buf.h"
 #include "pathnames.h"  #include "for.h"
 #include "lowparse.h"  #include "lowparse.h"
   #include "arch.h"
   #include "cond.h"
   #include "suff.h"
   #include "parse.h"
   #include "var.h"
   #include "targ.h"
   #include "error.h"
   #include "str.h"
   #include "main.h"
   #include "gnode.h"
   #include "memory.h"
   #include "extern.h"
   #include "lst.h"
   #include "parsevar.h"
   
 #ifndef lint  static LIST     theParseIncPath;/* list of directories for "..." includes */
 #if 0  static LIST     theSysIncPath;  /* list of directories for <...> includes */
 static char sccsid[] = "@(#)parse.c     8.3 (Berkeley) 3/19/94";  Lst sysIncPath = &theSysIncPath;
 #else  Lst parseIncPath = &theParseIncPath;
 UNUSED  
 static char rcsid[] = "$OpenBSD$";  
 #endif  
 #endif /* not lint */  
   
 LIST            parseIncPath;   /* list of directories for "..." includes */  
 LIST            sysIncPath;     /* list of directories for <...> includes */  
   
 static LIST         targets;    /* targets we're working on */  static LIST         targets;    /* targets we're working on */
 #ifdef CLEANUP  #ifdef CLEANUP
 static LIST         targCmds;   /* command lines for targets */  static LIST         targCmds;   /* command lines for targets */
 static LIST         fileNames;  
 #endif  #endif
   
 static GNode        *mainNode;  /* The main target to create. This is the  static GNode        *mainNode;  /* The main target to create. This is the
Line 254 
Line 212 
 static void ParseDoInclude(char *);  static void ParseDoInclude(char *);
 static void ParseTraditionalInclude(char *);  static void ParseTraditionalInclude(char *);
 static void ParseConditionalInclude(char *);  static void ParseConditionalInclude(char *);
 static void ParseLookupIncludeFile(char *, char *, Boolean, Boolean);  static void ParseLookupIncludeFile(char *, char *, bool, bool);
 #define ParseGetLoopLine(linebuf)       ParseGetLine(linebuf, "for loop")  #define ParseReadLoopLine(linebuf) Parse_ReadUnparsedLine(linebuf, "for loop")
 static void ParseFinishDependency(void);  static void ParseFinishDependency(void);
 static Boolean ParseIsCond(Buffer, Buffer, char *);  static bool ParseIsCond(Buffer, Buffer, char *);
 static char *strip_comments(Buffer, const char *);  static char *strip_comments(Buffer, const char *);
   
 static void ParseDoCommands(const char *);  static void ParseDoCommands(const char *);
 static const char *find_op1(const char *);  
 static const char *find_op2(const char *);  
   
 /*-  /*-
  *----------------------------------------------------------------------   *----------------------------------------------------------------------
Line 317 
Line 273 
     GNode               *pgn;   /* The parent node */      GNode               *pgn;   /* The parent node */
     GNode               *cgn;   /* The child node */      GNode               *cgn;   /* The child node */
 {  {
     if (Lst_AddNew(&pgn->children, cgn) == SUCCESS) {      if (Lst_AddNew(&pgn->children, cgn)) {
         if (specType == Not)          if (specType == Not)
             Lst_AtEnd(&cgn->parents, pgn);              Lst_AtEnd(&cgn->parents, pgn);
         pgn->unmade++;          pgn->unmade++;
Line 366 
Line 322 
         GNode           *cohort;          GNode           *cohort;
         LstNode         ln;          LstNode         ln;
   
         cohort = Targ_NewGN(gn->name, NULL);          cohort = Targ_NewGN(gn->name);
         /* Duplicate links to parents so graph traversal is simple. Perhaps          /* Duplicate links to parents so graph traversal is simple. Perhaps
          * some type bits should be duplicated?           * some type bits should be duplicated?
          *           *
Line 470 
Line 426 
         /*          /*
          * If we have noted the existence of a .MAIN, it means we need           * If we have noted the existence of a .MAIN, it means we need
          * to add the sources of said target to the list of things           * to add the sources of said target to the list of things
          * to create. The string 'src' is likely to be free, so we           * to create. The string 'src' is likely to be freed, so we
          * must make a new copy of it. Note that this will only be           * must make a new copy of it. Note that this will only be
          * invoked if the user didn't specify a target on the command           * invoked if the user didn't specify a target on the command
          * line. This is to allow #ifmake's to succeed, or something...           * line. This is to allow #ifmake's to succeed, or something...
          */           */
         Lst_AtEnd(&create, estrdup(src));          Lst_AtEnd(create, estrdup(src));
         /*          /*
          * Add the name to the .TARGETS variable as well, so the user cna           * Add the name to the .TARGETS variable as well, so the user can
          * employ that, if desired.           * employ that, if desired.
          */           */
         Var_Append(".TARGETS", src, VAR_GLOBAL);          Var_Append(".TARGETS", src, VAR_GLOBAL);
Line 488 
Line 444 
          * Create proper predecessor/successor links between the previous           * Create proper predecessor/successor links between the previous
          * source and the current one.           * source and the current one.
          */           */
         gn = Targ_FindNode(src, NULL, TARG_CREATE);          gn = Targ_FindNode(src, TARG_CREATE);
         if (predecessor != NULL) {          if (predecessor != NULL) {
             Lst_AtEnd(&predecessor->successors, gn);              Lst_AtEnd(&predecessor->successors, gn);
             Lst_AtEnd(&gn->preds, predecessor);              Lst_AtEnd(&gn->preds, predecessor);
Line 511 
Line 467 
          * the 'cohorts' list of the node) or all the cohorts are linked           * the 'cohorts' list of the node) or all the cohorts are linked
          * to all the targets.           * to all the targets.
          */           */
         gn = Targ_FindNode(src, NULL, TARG_CREATE);          gn = Targ_FindNode(src, TARG_CREATE);
         if (tOp) {          if (tOp) {
             gn->type |= tOp;              gn->type |= tOp;
         } else {          } else {
Line 589 
Line 545 
     void *path;      void *path;
     void *name;      void *name;
 {  {
     Dir_AddDir((Lst)path, (char *)name, NULL);      Dir_AddDir((Lst)path, (char *)name);
 }  }
   
 /*-  /*-
Line 712 
Line 668 
              * things like "archive(file1.o file2.o file3.o)" are permissible.               * things like "archive(file1.o file2.o file3.o)" are permissible.
              * Arch_ParseArchive will set 'line' to be the first non-blank               * Arch_ParseArchive will set 'line' to be the first non-blank
              * after the archive-spec. It creates/finds nodes for the members               * after the archive-spec. It creates/finds nodes for the members
              * and places them on the given list, returning SUCCESS if all               * and places them on the given list, returning true if all
              * went well and FAILURE if there was an error in the               * went well and false if there was an error in the
              * specification. On error, line should remain untouched.  */               * specification. On error, line should remain untouched.  */
             if (Arch_ParseArchive(&line, &targets, NULL) != SUCCESS) {              if (!Arch_ParseArchive(&line, &targets, NULL)) {
                 Parse_Error(PARSE_FATAL,                  Parse_Error(PARSE_FATAL,
                              "Error in archive specification: \"%s\"", line);                               "Error in archive specification: \"%s\"", line);
                 return;                  return;
Line 777 
Line 733 
                  */                   */
                 switch (specType) {                  switch (specType) {
                     case ExPath:                      case ExPath:
                         Lst_AtEnd(&paths, &dirSearchPath);                          Lst_AtEnd(&paths, dirSearchPath);
                         break;                          break;
                     case Main:                      case Main:
                         if (!Lst_IsEmpty(&create)) {                          if (!Lst_IsEmpty(create)) {
                             specType = Not;                              specType = Not;
                         }                          }
                         break;                          break;
                     case Begin:                      case Begin:
                     case End:                      case End:
                     case Interrupt:                      case Interrupt:
                         gn = Targ_FindNode(line, NULL, TARG_CREATE);                          gn = Targ_FindNode(line, TARG_CREATE);
                         gn->type |= OP_NOTMAIN;                          gn->type |= OP_NOTMAIN;
                         Lst_AtEnd(&targets, gn);                          Lst_AtEnd(&targets, gn);
                         break;                          break;
                     case Default:                      case Default:
                         gn = Targ_NewGN(".DEFAULT", NULL);                          gn = Targ_NewGN(".DEFAULT");
                         gn->type |= OP_NOTMAIN|OP_TRANSFORM;                          gn->type |= OP_NOTMAIN|OP_TRANSFORM;
                         Lst_AtEnd(&targets, gn);                          Lst_AtEnd(&targets, gn);
                         DEFAULT = gn;                          DEFAULT = gn;
Line 863 
Line 819 
   
             while ((targName = (char *)Lst_DeQueue(&curTargs)) != NULL) {              while ((targName = (char *)Lst_DeQueue(&curTargs)) != NULL) {
                 if (!Suff_IsTransform(targName)) {                  if (!Suff_IsTransform(targName)) {
                     gn = Targ_FindNode(targName, NULL, TARG_CREATE);                      gn = Targ_FindNode(targName, TARG_CREATE);
                 } else {                  } else {
                     gn = Suff_AddTransform(targName);                      gn = Suff_AddTransform(targName);
                 }                  }
Line 881 
Line 837 
          * allow on this line...           * allow on this line...
          */           */
         if (specType != Not && specType != ExPath) {          if (specType != Not && specType != ExPath) {
             Boolean warn = FALSE;              bool warn = false;
   
             while (*cp != '!' && *cp != ':' && *cp) {              while (*cp != '!' && *cp != ':' && *cp) {
                 if (*cp != ' ' && *cp != '\t') {                  if (*cp != ' ' && *cp != '\t') {
                     warn = TRUE;                      warn = true;
                 }                  }
                 cp++;                  cp++;
             }              }
Line 965 
Line 921 
                 Suff_ClearSuffixes();                  Suff_ClearSuffixes();
                 break;                  break;
             case Precious:              case Precious:
                 allPrecious = TRUE;                  allPrecious = true;
                 break;                  break;
             case Ignore:              case Ignore:
                 ignoreErrors = TRUE;                  ignoreErrors = true;
                 break;                  break;
             case Silent:              case Silent:
                 beSilent = TRUE;                  beSilent = true;
                 break;                  break;
             case ExPath:              case ExPath:
                 Lst_Every(&paths, ParseClearPath);                  Lst_Every(&paths, ParseClearPath);
Line 988 
Line 944 
         Main_ParseArgLine(line);          Main_ParseArgLine(line);
         *line = '\0';          *line = '\0';
     } else if (specType == ExShell) {      } else if (specType == ExShell) {
         if (Job_ParseShell(line) != SUCCESS) {          if (!Job_ParseShell(line)) {
             Parse_Error(PARSE_FATAL, "improper shell specification");              Parse_Error(PARSE_FATAL, "improper shell specification");
             return;              return;
         }          }
Line 1090 
Line 1046 
                                     * expansion */                                      * expansion */
   
                 Lst_Init(&sources);                  Lst_Init(&sources);
                 if (Arch_ParseArchive(&line, &sources, NULL) != SUCCESS) {                  if (!Arch_ParseArchive(&line, &sources, NULL)) {
                     Parse_Error(PARSE_FATAL,                      Parse_Error(PARSE_FATAL,
                                  "Error in source archive spec \"%s\"", line);                                   "Error in source archive spec \"%s\"", line);
                     return;                      return;
Line 1127 
Line 1083 
 }  }
   
 /*-  /*-
  *---------------------------------------------------------------------  
  * Parse_IsVar  --  
  *      Return TRUE if the passed line is a variable assignment. A variable  
  *      assignment consists of a single word followed by optional whitespace  
  *      followed by either a += or an = operator.  
  *      This function is used both by the Parse_File function and main when  
  *      parsing the command-line arguments.  
  *  
  * Results:  
  *      TRUE if it is. FALSE if it ain't  
  *---------------------------------------------------------------------  
  */  
 Boolean  
 Parse_IsVar(line)  
     char  *line;        /* the line to check */  
 {  
     Boolean wasSpace = FALSE;   /* set TRUE if found a space */  
     Boolean haveName = FALSE;   /* Set TRUE if have a variable name */  
     int level = 0;  
 #define ISEQOPERATOR(c) \  
         ((c) == '+' || (c) == ':' || (c) == '?' || (c) == '!')  
   
     for (; *line != '=' || level != 0; line++)  
         switch (*line) {  
         case '\0':  
             /* end-of-line -- can't be a variable assignment.  */  
             return FALSE;  
   
         case ' ':  
         case '\t':  
             /*  
              * there can be as much white space as desired so long as there is  
              * only one word before the operator  
              */  
             wasSpace = TRUE;  
             break;  
   
         case '(':  
         case '{':  
             level++;  
             break;  
   
         case '}':  
         case ')':  
             level--;  
             break;  
   
         default:  
             if (wasSpace && haveName) {  
                     if (ISEQOPERATOR(*line)) {  
                         /* We must have a finished word.  */  
                         if (level != 0)  
                             return FALSE;  
   
                         /* When an = operator [+?!:] is found, the next  
                          * character must be an = or it ain't a valid  
                          * assignment.  */  
                         if (line[1] == '=')  
                             return haveName;  
                         /* This is a shell command.  */  
                         if (FEATURES(FEATURE_SUNSHCMD) &&  
                             strncmp(line, ":sh", 3) == 0)  
                             return haveName;  
                     }  
                     /* This is the start of another word, so not assignment.  */  
                     return FALSE;  
             }  
             else {  
                 haveName = TRUE;  
                 wasSpace = FALSE;  
             }  
             break;  
         }  
   
     return haveName;  
 }  
   
 static const char *  
 find_op1(p)  
     const char *p;  
 {  
     for(;; p++) {  
         if (*p == '=' || isspace(*p) || *p == '$')  
             break;  
         if (p[1] == '=' && (*p == '?' || *p == ':' || *p == '!' || *p == '+'))  
             break;  
         if (p[0] == ':' && p[1] == 's' && p[2] == 'h')  
             break;  
     }  
     return p;  
 }  
   
 static const char *  
 find_op2(p)  
     const char *p;  
 {  
     for(;; p++) {  
         if (*p == '=' || isspace(*p) || *p == '$')  
             break;  
         if (p[1] == '=' && (*p == '?' || *p == ':' || *p == '!' || *p == '+'))  
             break;  
     }  
     return p;  
 }  
   
 /*-  
  *---------------------------------------------------------------------  
  * Parse_DoVar  --  
  *      Take the variable assignment in the passed line and do it in the  
  *      global context.  
  *  
  *      Note: There is a lexical ambiguity with assignment modifier characters  
  *      in variable names. This routine interprets the character before the =  
  *      as a modifier. Therefore, an assignment like  
  *          C++=/usr/bin/CC  
  *      is interpreted as "C+ +=" instead of "C++ =".  
  *  
  * Side Effects:  
  *      the variable structure of the given variable name is altered in the  
  *      global context.  
  *---------------------------------------------------------------------  
  */  
 void  
 Parse_DoVar(line, ctxt)  
     const char      *line;      /* a line guaranteed to be a variable  
                                  * assignment. This reduces error checks */  
     GSymT           *ctxt;    /* Context in which to do the assignment */  
 {  
     const char      *end;  
     const char      *arg;  
     enum {  
         VAR_SUBST, VAR_APPEND, VAR_SHELL, VAR_NORMAL  
     }               type;       /* Type of assignment */  
     struct Name     name;  
   
     end = Var_Name_Get(line, &name, (SymTable *)ctxt, TRUE,  
         FEATURES(FEATURE_SUNSHCMD) ? find_op1 : find_op2);  
   
     while (isspace(*end))  
         end++;  
   
     /* Check operator type.  */  
     switch (*end) {  
         case '+':  
             type = VAR_APPEND;  
             break;  
   
         case '?':  
             /* If the variable already has a value, we don't do anything.  */  
             if (Var_Value_interval(name.s, name.e) != NULL) {  
                 Var_Name_Free(&name);  
                 return;  
             }  
             type = VAR_NORMAL;  
             break;  
   
         case ':':  
             if (FEATURES(FEATURE_SUNSHCMD) && strncmp(end, ":sh", 3) == 0)  
                 type = VAR_SHELL;  
             else  
                 type = VAR_SUBST;  
             break;  
   
         case '!':  
             type = VAR_SHELL;  
             break;  
   
         default:  
             type = VAR_NORMAL;  
             break;  
     }  
   
     /* Find operator itself and go over it.  */  
     arg = end;  
     while (*arg != '=')  
         arg++;  
     arg++;  
     while (isspace(*arg))  
         arg++;  
   
     if (type == VAR_APPEND)  
         Var_Append_interval(name.s, name.e, arg, ctxt);  
     else if (type == VAR_SUBST) {  
         char *sub;  
         /*  
          * Allow variables in the old value to be undefined, but leave their  
          * invocation alone -- this is done by forcing oldVars to be false.  
          * XXX: This can cause recursive variables, but that's not hard to do,  
          * and this allows someone to do something like  
          *  
          *  CFLAGS = $(.INCLUDES)  
          *  CFLAGS := -I.. $(CFLAGS)  
          *  
          * And not get an error.  
          */  
         Boolean   oldOldVars = oldVars;  
   
         oldVars = FALSE;  
         /* ensure the variable is set to something to avoid `variable  
          * is recursive' errors.  */  
         if (Var_Value_interval(name.s, name.e) == NULL)  
             Var_Set_interval(name.s, name.e, "", ctxt);  
   
         sub = Var_Subst(arg, (SymTable *)ctxt, FALSE);  
         oldVars = oldOldVars;  
   
         Var_Set_interval(name.s, name.e, sub, ctxt);  
         free(sub);  
     } else if (type == VAR_SHELL) {  
         char *res, *err;  
   
         if (strchr(arg, '$') != NULL) {  
             char *sub;  
             /* There's a dollar sign in the command, so perform variable  
              * expansion on the whole thing. */  
             sub = Var_Subst(arg, NULL, TRUE);  
             res = Cmd_Exec(sub, &err);  
             free(sub);  
         } else  
             res = Cmd_Exec(arg, &err);  
   
         Var_Set_interval(name.s, name.e, res, ctxt);  
         free(res);  
   
         if (err)  
             Parse_Error(PARSE_WARNING, err, arg);  
   
     } else  
         /* Normal assignment -- just do it.  */  
         Var_Set_interval(name.s, name.e, arg, ctxt);  
     Var_Name_Free(&name);  
 }  
   
   
 /*-  
  * ParseAddCmd  --   * ParseAddCmd  --
  *      Lst_ForEach function to add a command line to all targets   *      Lst_ForEach function to add a command line to all targets
  *   *
Line 1417 
Line 1138 
 Parse_AddIncludeDir(dir)  Parse_AddIncludeDir(dir)
     const char  *dir;   /* The name of the directory to add */      const char  *dir;   /* The name of the directory to add */
 {  {
     Dir_AddDir(&parseIncPath, dir, NULL);      Dir_AddDir(parseIncPath, dir);
 }  }
   
 /*-  /*-
Line 1441 
Line 1162 
 {  {
     char          endc;         /* the character which ends the file spec */      char          endc;         /* the character which ends the file spec */
     char          *cp;          /* current position in file spec */      char          *cp;          /* current position in file spec */
     Boolean       isSystem;     /* TRUE if makefile is a system makefile */      bool          isSystem;     /* true if makefile is a system makefile */
   
     /* Skip to delimiter character so we know where to look.  */      /* Skip to delimiter character so we know where to look.  */
     while (*file == ' ' || *file == '\t')      while (*file == ' ' || *file == '\t')
Line 1457 
Line 1178 
      * characters which bracket its name. Angle-brackets imply it's       * characters which bracket its name. Angle-brackets imply it's
      * a system Makefile while double-quotes imply it's a user makefile */       * a system Makefile while double-quotes imply it's a user makefile */
     if (*file == '<') {      if (*file == '<') {
         isSystem = TRUE;          isSystem = true;
         endc = '>';          endc = '>';
     } else {      } else {
         isSystem = FALSE;          isSystem = false;
         endc = '"';          endc = '"';
     }      }
   
Line 1473 
Line 1194 
             return;              return;
         }          }
     }      }
     ParseLookupIncludeFile(file, cp, isSystem, TRUE);      ParseLookupIncludeFile(file, cp, isSystem, true);
 }  }
   
 /*-  /*-
Line 1509 
Line 1230 
     for (cp = file; *cp != '\0' && !isspace(*cp);)      for (cp = file; *cp != '\0' && !isspace(*cp);)
         cp++;          cp++;
   
     ParseLookupIncludeFile(file, cp, TRUE, TRUE);      ParseLookupIncludeFile(file, cp, true, true);
 }  }
   
 /*-  /*-
Line 1539 
Line 1260 
     for (cp = file; *cp != '\0' && !isspace(*cp);)      for (cp = file; *cp != '\0' && !isspace(*cp);)
         cp++;          cp++;
   
     ParseLookupIncludeFile(file, cp, TRUE, FALSE);      ParseLookupIncludeFile(file, cp, true, false);
 }  }
   
 /* Common part to lookup and read an include file.  */  /* Common part to lookup and read an include file.  */
Line 1547 
Line 1268 
 ParseLookupIncludeFile(spec, endSpec, isSystem, errIfNotFound)  ParseLookupIncludeFile(spec, endSpec, isSystem, errIfNotFound)
     char *spec;      char *spec;
     char *endSpec;      char *endSpec;
     Boolean isSystem;      bool isSystem;
     Boolean errIfNotFound;      bool errIfNotFound;
 {  {
     char *file;      char *file;
     char *fullname;      char *fullname;
Line 1558 
Line 1279 
      * find the thing.  */       * find the thing.  */
     endc = *endSpec;      endc = *endSpec;
     *endSpec = '\0';      *endSpec = '\0';
     file = Var_Subst(spec, NULL, FALSE);      file = Var_Subst(spec, NULL, false);
     *endSpec = endc;      *endSpec = endc;
   
     /* Now that we know the file name and its search path, we attempt to      /* Now that we know the file name and its search path, we attempt to
Line 1572 
Line 1293 
          * location. We don't want to cd there, of course, so we           * location. We don't want to cd there, of course, so we
          * just tack on the old file's leading path components           * just tack on the old file's leading path components
          * and call Dir_FindFile to see if we can locate the beast.  */           * and call Dir_FindFile to see if we can locate the beast.  */
         char      *slash;          char            *slash;
           const char      *fname;
   
         slash = strrchr(Parse_Getfilename(), '/');          fname = Parse_Getfilename();
   
           slash = strrchr(fname, '/');
         if (slash != NULL) {          if (slash != NULL) {
             char *base, *newName;              char *newName;
   
             base = interval_dup(Parse_Getfilename(), slash);              newName = Str_concati(fname, slash, file, strchr(file, '\0'), '/');
             newName = str_concat(base, file, '/');              fullname = Dir_FindFile(newName, parseIncPath);
             free(base);  
             fullname = Dir_FindFile(newName, &parseIncPath);  
             if (fullname == NULL)              if (fullname == NULL)
                 fullname = Dir_FindFile(newName, &dirSearchPath);                  fullname = Dir_FindFile(newName, dirSearchPath);
             free(newName);              free(newName);
         }          }
     }      }
Line 1592 
Line 1314 
      * search path, if not found in a -I directory.       * search path, if not found in a -I directory.
      * XXX: Suffix specific?  */       * XXX: Suffix specific?  */
     if (fullname == NULL)      if (fullname == NULL)
         fullname = Dir_FindFile(file, &parseIncPath);          fullname = Dir_FindFile(file, parseIncPath);
     if (fullname == NULL)      if (fullname == NULL)
         fullname = Dir_FindFile(file, &dirSearchPath);          fullname = Dir_FindFile(file, dirSearchPath);
   
     /* Still haven't found the makefile. Look for it on the system      /* Still haven't found the makefile. Look for it on the system
      * path as a last resort.  */       * path as a last resort.  */
     if (fullname == NULL)      if (fullname == NULL)
         fullname = Dir_FindFile(file, &sysIncPath);          fullname = Dir_FindFile(file, sysIncPath);
   
     if (fullname == NULL && errIfNotFound)      if (fullname == NULL && errIfNotFound)
             Parse_Error(PARSE_FATAL, "Could not find %s", file);              Parse_Error(PARSE_FATAL, "Could not find %s", file);
Line 1646 
Line 1368 
         for (p = line; *p != '\0'; p++) {          for (p = line; *p != '\0'; p++) {
             if (*p == '\\') {              if (*p == '\\') {
                 if (p[1] == '#') {                  if (p[1] == '#') {
                     Buf_AddInterval(copy, line, p);                      Buf_Addi(copy, line, p);
                     Buf_AddChar(copy, '#');                      Buf_AddChar(copy, '#');
                     line = p+2;                      line = p+2;
                 }                  }
Line 1655 
Line 1377 
             } else if (*p == '#')              } else if (*p == '#')
                 break;                  break;
         }          }
         Buf_AddInterval(copy, line, p);          Buf_Addi(copy, line, p);
         Buf_KillTrailingSpaces(copy);          Buf_KillTrailingSpaces(copy);
         return Buf_Retrieve(copy);          return Buf_Retrieve(copy);
     }      }
 }  }
   
 static Boolean  static bool
 ParseIsCond(linebuf, copy, line)  ParseIsCond(linebuf, copy, line)
     Buffer      linebuf;      Buffer      linebuf;
     Buffer      copy;      Buffer      copy;
Line 1679 
Line 1401 
     case COND_SKIP:      case COND_SKIP:
         /* Skip to next conditional that evaluates to COND_PARSE.  */          /* Skip to next conditional that evaluates to COND_PARSE.  */
         do {          do {
             line = ParseSkipGetLine(linebuf);              line = Parse_ReadNextConditionalLine(linebuf);
             if (line != NULL) {              if (line != NULL) {
                 while (*line != '\0' && isspace(*line))                  while (*line != '\0' && isspace(*line))
                     line++;                      line++;
Line 1688 
Line 1410 
         } while (line != NULL && Cond_Eval(stripped) != COND_PARSE);          } while (line != NULL && Cond_Eval(stripped) != COND_PARSE);
         /* FALLTHROUGH */          /* FALLTHROUGH */
     case COND_PARSE:      case COND_PARSE:
         return TRUE;          return true;
     default:      default:
         break;          break;
     }      }
Line 1698 
Line 1420 
   
     loop = For_Eval(line);      loop = For_Eval(line);
     if (loop != NULL) {      if (loop != NULL) {
         Boolean ok;          bool ok;
         do {          do {
             /* Find the matching endfor.  */              /* Find the matching endfor.  */
             line = ParseGetLoopLine(linebuf);              line = ParseReadLoopLine(linebuf);
             if (line == NULL) {              if (line == NULL) {
                 Parse_Error(PARSE_FATAL,                  Parse_Error(PARSE_FATAL,
                          "Unexpected end of file in for loop.\n");                           "Unexpected end of file in for loop.\n");
                 return FALSE;                  return false;
             }              }
             ok = For_Accumulate(loop, line);              ok = For_Accumulate(loop, line);
         } while (ok);          } while (ok);
         For_Run(loop);          For_Run(loop);
         return TRUE;          return true;
     }      }
     }      }
   
     if (strncmp(line, "include", 7) == 0) {      if (strncmp(line, "include", 7) == 0) {
         ParseDoInclude(line + 7);          ParseDoInclude(line + 7);
         return TRUE;          return true;
     } else if (strncmp(line, "undef", 5) == 0) {      } else if (strncmp(line, "undef", 5) == 0) {
         char *cp;          char *cp;
   
Line 1727 
Line 1449 
             cp++;              cp++;
         *cp = '\0';          *cp = '\0';
         Var_Delete(line);          Var_Delete(line);
         return TRUE;          return true;
     }      }
     return FALSE;      return false;
 }  }
   
 /*-  /*-
Line 1763 
Line 1485 
 #endif  #endif
 }  }
   
 /*-  
  *---------------------------------------------------------------------  
  * Parse_File --  
  *      Parse a file into its component parts, incorporating it into the  
  *      current dependency graph. This is the main function and controls  
  *      almost every other function in this module  
  *  
  * Side Effects:  
  *      Loads. Nodes are added to the list of all targets, nodes and links  
  *      are added to the dependency graph. etc. etc. etc.  
  *---------------------------------------------------------------------  
  */  
 void  void
 Parse_File(name, stream)  Parse_File(name, stream)
     char          *name;        /* the name of the file being read */      const char    *name;        /* the name of the file being read */
     FILE          *stream;      /* Stream open to makefile to parse */      FILE          *stream;      /* Stream open to makefile to parse */
 {  {
     char          *cp,          /* pointer into the line */      char          *cp,          /* pointer into the line */
                   *line;        /* the line we're working on */                    *line;        /* the line we're working on */
     Boolean       inDependency; /* true if currently in a dependency      bool          inDependency; /* true if currently in a dependency
                                  * line or its commands */                                   * line or its commands */
   
     BUFFER        buf;      BUFFER        buf;
Line 1790 
Line 1500 
   
     Buf_Init(&buf, MAKE_BSIZE);      Buf_Init(&buf, MAKE_BSIZE);
     Buf_Init(&copy, MAKE_BSIZE);      Buf_Init(&copy, MAKE_BSIZE);
     inDependency = FALSE;      inDependency = false;
     Parse_FromFile(name, stream);      Parse_FromFile(name, stream);
   
     do {      do {
         while ((line = ParseReadLine(&buf)) != NULL) {          while ((line = Parse_ReadNormalLine(&buf)) != NULL) {
             if (*line == '\t') {              if (*line == '\t') {
                 if (inDependency)                  if (inDependency)
                     ParseDoCommands(line+1);                      ParseDoCommands(line+1);
Line 1824 
Line 1534 
   
                     if (inDependency)                      if (inDependency)
                         ParseFinishDependency();                          ParseFinishDependency();
                     if (Parse_IsVar(stripped)) {                      if (Parse_DoVar(stripped, VAR_GLOBAL))
                         inDependency = FALSE;                          inDependency = false;
                         Parse_DoVar(stripped, VAR_GLOBAL);                      else {
                     } else {  
                         size_t pos;                          size_t pos;
                         char *end;                          char *end;
   
                         /* Need a new list for the target nodes.  */                          /* Need a new list for the target nodes.  */
                         Lst_Init(&targets);                          Lst_Init(&targets);
                         inDependency = TRUE;                          inDependency = true;
   
                         dep = NULL;                          dep = NULL;
                         /* First we need to find eventual dependencies */                          /* First we need to find eventual dependencies */
Line 1854 
Line 1563 
                          * have all variables expanded before being parsed.                           * have all variables expanded before being parsed.
                          * Tell the variable module to complain if some                           * Tell the variable module to complain if some
                          * variable is undefined... */                           * variable is undefined... */
                         cp = Var_Subst(stripped, NULL, TRUE);                          cp = Var_Subst(stripped, NULL, true);
                         ParseDoDependency(cp);                          ParseDoDependency(cp);
                         free(cp);                          free(cp);
   
Line 1877 
Line 1586 
     /* Make sure conditionals are clean.  */      /* Make sure conditionals are clean.  */
     Cond_End();      Cond_End();
   
     Finish_Errors();      Parse_ReportErrors();
     Buf_Destroy(&buf);      Buf_Destroy(&buf);
     Buf_Destroy(&copy);      Buf_Destroy(&copy);
 }  }
   
 /*-  
  *---------------------------------------------------------------------  
  * Parse_Init --  
  *      initialize the parsing module  
  *  
  * Side Effects:  
  *      the parseIncPath list is initialized...  
  *---------------------------------------------------------------------  
  */  
 void  void
 Parse_Init()  Parse_Init()
 {  {
     mainNode = NULL;      mainNode = NULL;
     Lst_Init(&parseIncPath);      Lst_Init(parseIncPath);
     Lst_Init(&sysIncPath);      Lst_Init(sysIncPath);
     Lst_Init(&targets);      Lst_Init(&targets);
 #ifdef CLEANUP  
     LowParse_Init();      LowParse_Init();
   #ifdef CLEANUP
     Lst_Init(&targCmds);      Lst_Init(&targCmds);
     Lst_Init(&fileNames);  
 #endif  #endif
 }  }
   
   #ifdef CLEANUP
 void  void
 Parse_End()  Parse_End()
 {  {
 #ifdef CLEANUP  
     Lst_Destroy(&targCmds, (SimpleProc)free);      Lst_Destroy(&targCmds, (SimpleProc)free);
     Lst_Destroy(&fileNames, (SimpleProc)free);  
     Lst_Destroy(&targets, NOFREE);      Lst_Destroy(&targets, NOFREE);
     Lst_Destroy(&sysIncPath, Dir_Destroy);      Lst_Destroy(sysIncPath, Dir_Destroy);
     Lst_Destroy(&parseIncPath, Dir_Destroy);      Lst_Destroy(parseIncPath, Dir_Destroy);
     LowParse_End();      LowParse_End();
 #endif  
 }  }
   #endif
   
   
 /*-  
  *-----------------------------------------------------------------------  
  * Parse_MainName --  
  *      Return a Lst of the main target to create for main()'s sake. If  
  *      no such target exists, we Punt with an obnoxious error message.  
  *  
  * Side effect:  
  *      Add the node to create to the list.  
  *-----------------------------------------------------------------------  
  */  
 void  void
 Parse_MainName(listmain)  Parse_MainName(listmain)
     Lst           listmain;     /* result list */      Lst           listmain;     /* result list */

Legend:
Removed from v.1.60  
changed lines
  Added in v.1.61