summaryrefslogtreecommitdiff
path: root/usr.bin/make/parse.c
diff options
context:
space:
mode:
authorrillig <rillig@NetBSD.org>2023-06-19 12:53:57 +0000
committerrillig <rillig@NetBSD.org>2023-06-19 12:53:57 +0000
commitee7acaf59f3c249dd69ad13ec152fa11358b217b (patch)
tree897d1df7407864a5deed5ae2fe1f99e6a8b9ebe9 /usr.bin/make/parse.c
parent2230fdab1e3c61d322c3dd92a3e721300532b4f4 (diff)
make: if a makefile is protected by a guard, only include it once
"looks reasonable" sjg@
Diffstat (limited to 'usr.bin/make/parse.c')
-rw-r--r--usr.bin/make/parse.c76
1 files changed, 73 insertions, 3 deletions
diff --git a/usr.bin/make/parse.c b/usr.bin/make/parse.c
index 3daa3c536ba..fbe6fbfc78d 100644
--- a/usr.bin/make/parse.c
+++ b/usr.bin/make/parse.c
@@ -1,4 +1,4 @@
-/* $NetBSD: parse.c,v 1.699 2023/06/01 06:25:34 rillig Exp $ */
+/* $NetBSD: parse.c,v 1.700 2023/06/19 12:53:57 rillig Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -105,7 +105,15 @@
#include "pathnames.h"
/* "@(#)parse.c 8.3 (Berkeley) 3/19/94" */
-MAKE_RCSID("$NetBSD: parse.c,v 1.699 2023/06/01 06:25:34 rillig Exp $");
+MAKE_RCSID("$NetBSD: parse.c,v 1.700 2023/06/19 12:53:57 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.
@@ -128,6 +136,9 @@ typedef struct IncludedFile {
char *buf_ptr; /* next char to be read */
char *buf_end; /* buf_end[-1] == '\n' */
+ GuardState guard;
+ char *guardVarname;
+
struct ForLoop *forLoop;
} IncludedFile;
@@ -299,6 +310,8 @@ static const struct {
enum PosixState posix_state = PS_NOT_YET;
+static HashTable guards;
+
static IncludedFile *
GetInclude(size_t i)
{
@@ -1212,6 +1225,7 @@ IncludeFile(const char *file, bool isSystem, bool depinc, bool silent)
{
Buffer buf;
char *fullname; /* full pathname of file */
+ char *guardVarname;
int fd;
fullname = file[0] == '/' ? bmake_strdup(file) : NULL;
@@ -1231,6 +1245,14 @@ IncludeFile(const char *file, bool isSystem, bool depinc, bool silent)
return;
}
+ guardVarname = HashTable_FindValue(&guards, fullname);
+ if (guardVarname != NULL
+ && GNode_ValueDirect(SCOPE_GLOBAL, guardVarname) != NULL) {
+ DEBUG2(PARSE, "Skipping '%s' because '%s' is already set\n",
+ fullname, guardVarname);
+ return;
+ }
+
if ((fd = open(fullname, O_RDONLY)) == -1) {
if (!silent)
Parse_Error(PARSE_FATAL, "Cannot open %s", fullname);
@@ -2174,6 +2196,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->guard = forLoop == NULL ? GS_START : GS_NO;
+ curFile->guardVarname = NULL;
curFile->forLoop = forLoop;
if (forLoop != NULL && !For_NextIteration(forLoop, &curFile->buf))
@@ -2316,8 +2340,15 @@ ParseEOF(void)
Cond_EndFile();
+ if (curFile->guard == GS_DONE) {
+ HashTable_Set(&guards,
+ curFile->name.str, curFile->guardVarname);
+ curFile->guardVarname = NULL;
+ }
+
FStr_Done(&curFile->name);
Buf_Done(&curFile->buf);
+ free(curFile->guardVarname);
if (curFile->forLoop != NULL)
ForLoop_Free(curFile->forLoop);
Vector_Pop(&includes);
@@ -2616,8 +2647,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;
@@ -2626,10 +2659,24 @@ ReadHighLevelLine(void)
if (line == NULL)
return NULL;
+ if (curFile->guard != GS_NO
+ && ((curFile->guard == GS_START && line[0] != '.')
+ || curFile->guard == GS_DONE))
+ curFile->guard = GS_NO;
if (line[0] != '.')
return line;
- switch (Cond_EvalLine(line)) {
+ condResult = Cond_EvalLine(line);
+ if (curFile->guard == GS_START) {
+ char *varname;
+ if (condResult == CR_TRUE
+ && (varname = Cond_ExtractGuard(line)) != NULL) {
+ curFile->guard = GS_COND;
+ curFile->guardVarname = varname;
+ } else
+ curFile->guard = GS_NO;
+ }
+ switch (condResult) {
case CR_FALSE: /* May also mean a syntax error. */
if (!SkipIrrelevantBranches())
return NULL;
@@ -2784,6 +2831,22 @@ 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->guard = GS_NO;
+}
+
+void
+Parse_GuardEndif(void)
+{
+ IncludedFile *curFile = CurFile();
+ if (cond_depth == curFile->condMinDepth && curFile->guard == GS_COND)
+ curFile->guard = GS_DONE;
+}
+
static char *
FindSemicolon(char *p)
{
@@ -2974,6 +3037,7 @@ Parse_Init(void)
sysIncPath = SearchPath_New();
defSysIncPath = SearchPath_New();
Vector_Init(&includes, sizeof(IncludedFile));
+ HashTable_Init(&guards);
}
/* Clean up the parsing module. */
@@ -2981,6 +3045,8 @@ void
Parse_End(void)
{
#ifdef CLEANUP
+ HashIter hi;
+
Lst_DoneCall(&targCmds, free);
assert(targets == NULL);
SearchPath_Free(defSysIncPath);
@@ -2988,6 +3054,10 @@ Parse_End(void)
SearchPath_Free(parseIncPath);
assert(includes.len == 0);
Vector_Done(&includes);
+ HashIter_Init(&hi, &guards);
+ while (HashIter_Next(&hi) != NULL)
+ free(hi.entry->value);
+ HashTable_Done(&guards);
#endif
}