diff options
Diffstat (limited to 'parse.c')
| -rw-r--r-- | parse.c | 106 |
1 files changed, 98 insertions, 8 deletions
@@ -1,4 +1,4 @@ -/* $NetBSD: parse.c,v 1.698 2023/05/10 16:10:02 rillig Exp $ */ +/* $NetBSD: parse.c,v 1.704 2023/06/23 06:08:56 rillig Exp $ */ /* * Copyright (c) 1988, 1989, 1990, 1993 @@ -121,7 +121,15 @@ #include "pathnames.h" /* "@(#)parse.c 8.3 (Berkeley) 3/19/94" */ -MAKE_RCSID("$NetBSD: parse.c,v 1.698 2023/05/10 16:10:02 rillig Exp $"); +MAKE_RCSID("$NetBSD: parse.c,v 1.704 2023/06/23 06:08:56 rillig Exp $"); + +/* Detects a multiple-inclusion guard in a makefile. */ +typedef enum { + GS_START, /* at the beginning of the file */ + GS_COND, /* after the guard condition */ + GS_DONE, /* after the closing .endif */ + GS_NO /* the file is not guarded */ +} GuardState; /* * A file being read. @@ -141,9 +149,12 @@ typedef struct IncludedFile { Buffer buf; /* the file's content or the body of the .for * loop; either empty or ends with '\n' */ - char *buf_ptr; /* next char to be read */ + char *buf_ptr; /* next char to be read from buf */ char *buf_end; /* buf_end[-1] == '\n' */ + GuardState guardState; + Guard *guard; + struct ForLoop *forLoop; } IncludedFile; @@ -315,6 +326,8 @@ static const struct { enum PosixState posix_state = PS_NOT_YET; +static HashTable /* full file name -> Guard */ guards; + static IncludedFile * GetInclude(size_t i) { @@ -429,8 +442,8 @@ IsEscaped(const char *line, const char *p) } /* - * Add the filename and lineno to the GNode so that we remember where it - * was first defined. + * Add the filename and lineno to the GNode so that we remember where its + * last command was added or where it was mentioned in a .depend file. */ static void RememberLocation(GNode *gn) @@ -1213,6 +1226,24 @@ FindInQuotPath(const char *file) return fullname; } +static bool +SkipGuarded(const char *fullname) +{ + Guard *guard = HashTable_FindValue(&guards, fullname); + if (guard != NULL && guard->kind == GK_VARIABLE + && GNode_ValueDirect(SCOPE_GLOBAL, guard->name) != NULL) + goto skip; + if (guard != NULL && guard->kind == GK_TARGET + && Targ_FindNode(guard->name) != NULL) + goto skip; + return false; + +skip: + DEBUG2(PARSE, "Skipping '%s' because '%s' is defined\n", + fullname, guard->name); + return true; +} + /* * Handle one of the .[-ds]include directives by remembering the current file * and pushing the included file on the stack. After the included file has @@ -1247,6 +1278,9 @@ IncludeFile(const char *file, bool isSystem, bool depinc, bool silent) return; } + if (SkipGuarded(fullname)) + return; + if ((fd = open(fullname, O_RDONLY)) == -1) { if (!silent) Parse_Error(PARSE_FATAL, "Cannot open %s", fullname); @@ -2190,6 +2224,8 @@ Parse_PushInput(const char *name, unsigned lineno, unsigned readLines, curFile->forBodyReadLines = readLines; curFile->buf = buf; curFile->depending = doing_depend; /* restore this on EOF */ + curFile->guardState = forLoop == NULL ? GS_START : GS_NO; + curFile->guard = NULL; curFile->forLoop = forLoop; if (forLoop != NULL && !For_NextIteration(forLoop, &curFile->buf)) @@ -2332,6 +2368,13 @@ ParseEOF(void) Cond_EndFile(); + if (curFile->guardState == GS_DONE) + HashTable_Set(&guards, curFile->name.str, curFile->guard); + else if (curFile->guard != NULL) { + free(curFile->guard->name); + free(curFile->guard); + } + FStr_Done(&curFile->name); Buf_Done(&curFile->buf); if (curFile->forLoop != NULL) @@ -2632,8 +2675,10 @@ static char * ReadHighLevelLine(void) { char *line; + CondResult condResult; for (;;) { + IncludedFile *curFile = CurFile(); line = ReadLowLevelLine(LK_NONEMPTY); if (posix_state == PS_MAYBE_NEXT_LINE) posix_state = PS_NOW_OR_NEVER; @@ -2642,10 +2687,24 @@ ReadHighLevelLine(void) if (line == NULL) return NULL; + if (curFile->guardState != GS_NO + && ((curFile->guardState == GS_START && line[0] != '.') + || curFile->guardState == GS_DONE)) + curFile->guardState = GS_NO; if (line[0] != '.') return line; - switch (Cond_EvalLine(line)) { + condResult = Cond_EvalLine(line); + if (curFile->guardState == GS_START) { + Guard *guard; + if (condResult != CR_ERROR + && (guard = Cond_ExtractGuard(line)) != NULL) { + curFile->guardState = GS_COND; + curFile->guard = guard; + } else + curFile->guardState = GS_NO; + } + switch (condResult) { case CR_FALSE: /* May also mean a syntax error. */ if (!SkipIrrelevantBranches()) return NULL; @@ -2716,10 +2775,14 @@ ParseLine_ShellCommand(const char *p) } static void -HandleBreak(void) +HandleBreak(const char *arg) { IncludedFile *curFile = CurFile(); + if (arg[0] != '\0') + Parse_Error(PARSE_FATAL, + "The .break directive does not take arguments"); + if (curFile->forLoop != NULL) { /* pretend we reached EOF */ For_Break(curFile->forLoop); @@ -2758,7 +2821,7 @@ ParseDirective(char *line) arg = cp; if (Substring_Equals(dir, "break")) - HandleBreak(); + HandleBreak(arg); else if (Substring_Equals(dir, "undef")) Var_Undef(arg); else if (Substring_Equals(dir, "export")) @@ -2796,6 +2859,23 @@ Parse_VarAssign(const char *line, bool finishDependencyGroup, GNode *scope) return true; } +void +Parse_GuardElse(void) +{ + IncludedFile *curFile = CurFile(); + if (cond_depth == curFile->condMinDepth + 1) + curFile->guardState = GS_NO; +} + +void +Parse_GuardEndif(void) +{ + IncludedFile *curFile = CurFile(); + if (cond_depth == curFile->condMinDepth + && curFile->guardState == GS_COND) + curFile->guardState = GS_DONE; +} + static char * FindSemicolon(char *p) { @@ -2986,6 +3066,7 @@ Parse_Init(void) sysIncPath = SearchPath_New(); defSysIncPath = SearchPath_New(); Vector_Init(&includes, sizeof(IncludedFile)); + HashTable_Init(&guards); } /* Clean up the parsing module. */ @@ -2993,6 +3074,8 @@ void Parse_End(void) { #ifdef CLEANUP + HashIter hi; + Lst_DoneCall(&targCmds, free); assert(targets == NULL); SearchPath_Free(defSysIncPath); @@ -3000,6 +3083,13 @@ Parse_End(void) SearchPath_Free(parseIncPath); assert(includes.len == 0); Vector_Done(&includes); + HashIter_Init(&hi, &guards); + while (HashIter_Next(&hi) != NULL) { + Guard *guard = hi.entry->value; + free(guard->name); + free(guard); + } + HashTable_Done(&guards); #endif } |
