aboutsummaryrefslogtreecommitdiff
path: root/parse.c
diff options
context:
space:
mode:
Diffstat (limited to 'parse.c')
-rw-r--r--parse.c106
1 files changed, 98 insertions, 8 deletions
diff --git a/parse.c b/parse.c
index f0644ea67a14..c23e523fce58 100644
--- a/parse.c
+++ b/parse.c
@@ -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
}