summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc Espie <espie@cvs.openbsd.org>2007-07-30 10:03:12 +0000
committerMarc Espie <espie@cvs.openbsd.org>2007-07-30 10:03:12 +0000
commite7db4966f96a9de5cfd46d8c61c75ce28a7ea3dc (patch)
tree94c8f51b02b5fbbad6ea00ae500cb964428d603b
parentefa0d3130461b35a2d6a7e220e7eb4221d97d4e4 (diff)
introduce a Var_Substi to substitute on intervals.
Since we don't really know how to change Var_Subst and dependent functions, we cheat, and copy the string to a buffer instead. Clean-up the parser a bit: reorganize the include files lookup function: introduce a resolve_include_filename function that figures out the full name of the file, introduce a handle_include_file that does all the include file handling, and rename the functions into handle_xxx_include, so that we can remove most comments. Rename ParseIsCond into handle_bsd_command, cut most of its code into constituent functions. Semantic changes: - follow the rules that, if an optional construct does not parse correctly, then it's not a real extension, and give the normal parser a chance to figure it out. If the syntax checks out, semantic errors ARE real errors. - allow variables to not be defined in include file names, no reason not to. okay miod@
-rw-r--r--usr.bin/make/parse.c588
-rw-r--r--usr.bin/make/var.c19
-rw-r--r--usr.bin/make/var.h3
3 files changed, 295 insertions, 315 deletions
diff --git a/usr.bin/make/parse.c b/usr.bin/make/parse.c
index 100a9d9e38c..34ce909912e 100644
--- a/usr.bin/make/parse.c
+++ b/usr.bin/make/parse.c
@@ -1,5 +1,5 @@
/* $OpenPackages$ */
-/* $OpenBSD: parse.c,v 1.78 2007/07/30 09:51:53 espie Exp $ */
+/* $OpenBSD: parse.c,v 1.79 2007/07/30 10:03:11 espie Exp $ */
/* $NetBSD: parse.c,v 1.29 1997/03/10 21:20:04 christos Exp $ */
/*
@@ -215,16 +215,19 @@ static void add_target_nodes(const char *);
static void ParseDoDependency(char *);
static void ParseAddCmd(void *, void *);
static void ParseHasCommands(void *);
-static void ParseDoInclude(char *);
-static void ParseDoPoison(char *);
-static void ParseTraditionalInclude(char *);
-static void ParseConditionalInclude(char *);
-static void ParseLookupIncludeFile(char *, char *, bool, bool);
+static bool handle_poison(const char *);
+static bool handle_for_loop(Buffer, const char *);
+static bool handle_undef(const char *);
#define ParseReadLoopLine(linebuf) Parse_ReadUnparsedLine(linebuf, "for loop")
static void ParseFinishDependency(void);
-static bool ParseIsCond(Buffer, Buffer, char *);
+static bool handle_bsd_command(Buffer, Buffer, const char *);
static char *strip_comments(Buffer, const char *);
-static char *find_include(const char *, bool);
+static char *resolve_include_filename(const char *, bool);
+static void handle_include_file(const char *, const char *, bool, bool);
+static bool lookup_bsd_include(const char *);
+static void lookup_sysv_style_include(const char *, const char *, bool);
+static void lookup_sysv_include(const char *, const char *);
+static void lookup_conditional_include(const char *, const char *);
static void ParseDoCommands(const char *);
@@ -1119,242 +1122,185 @@ ParseHasCommands(void *gnp) /* Node to examine */
}
}
-/*-
- *-----------------------------------------------------------------------
- * Parse_AddIncludeDir --
- * Add a directory to the path searched for included makefiles
- * bracketed by double-quotes. Used by functions in main.c
- *-----------------------------------------------------------------------
- */
+
+
+/***
+ *** Support for various include constructs
+ ***/
+
+
void
-Parse_AddIncludeDir(const char *dir) /* The name of the directory to add */
+Parse_AddIncludeDir(const char *dir)
{
- Dir_AddDir(parseIncPath, dir);
+ Dir_AddDir(parseIncPath, dir);
}
-/*-
- *---------------------------------------------------------------------
- * ParseDoInclude --
- * Push to another file.
- *
- * The input is the line minus the #include. A file spec is a string
- * enclosed in <> or "". The former is looked for only in sysIncPath.
- * The latter in . and the directories specified by -I command line
- * options
- *
- * Side Effects:
- * old parse context is pushed on the stack, new file becomes
- * current context.
- *---------------------------------------------------------------------
- */
-static void
-ParseDoInclude(char *file)/* file specification */
+static char *
+resolve_include_filename(const char *file, bool isSystem)
{
- char endc; /* the character which ends the file spec */
- char *cp; /* current position in file spec */
- bool isSystem; /* true if makefile is a system makefile */
-
- /* Skip to delimiter character so we know where to look. */
- while (*file == ' ' || *file == '\t')
- file++;
+ char *fullname;
+
+ /* Look up system files on the system path first */
+ if (isSystem) {
+ fullname = Dir_FindFileNoDot(file, sysIncPath);
+ if (fullname)
+ return fullname;
+ }
- if (*file != '"' && *file != '<') {
- Parse_Error(PARSE_FATAL,
- ".include filename must be delimited by '\"' or '<'");
- return;
- }
+ /* Handle non-system non-absolute files... */
+ if (!isSystem && file[0] != '/') {
+ /* ... by looking first under the same directory as the
+ * current file */
+ char *slash;
+ const char *fname;
+
+ fname = Parse_Getfilename();
+
+ slash = strrchr(fname, '/');
+ if (slash != NULL) {
+ char *newName;
+
+ newName = Str_concati(fname, slash, file,
+ strchr(file, '\0'), '/');
+ fullname = Dir_FindFile(newName, parseIncPath);
+ if (fullname == NULL)
+ fullname = Dir_FindFile(newName, dirSearchPath);
+ free(newName);
+ if (fullname)
+ return fullname;
+ }
+ }
- /* Set the search path on which to find the include file based on the
- * characters which bracket its name. Angle-brackets imply it's
- * a system Makefile while double-quotes imply it's a user makefile */
- if (*file == '<') {
- isSystem = true;
- endc = '>';
- } else {
- isSystem = false;
- endc = '"';
- }
+ /* Now look first on the -I search path, then on the .PATH
+ * search path, if not found in a -I directory.
+ * XXX: Suffix specific? */
+ fullname = Dir_FindFile(file, parseIncPath);
+ if (fullname)
+ return fullname;
+ fullname = Dir_FindFile(file, dirSearchPath);
+ if (fullname)
+ return fullname;
- /* Skip to matching delimiter. */
- for (cp = ++file; *cp != endc; cp++) {
- if (*cp == '\0') {
- Parse_Error(PARSE_FATAL,
- "Unclosed %cinclude filename. '%c' expected",
- '.', endc);
- return;
- }
- }
- ParseLookupIncludeFile(file, cp, isSystem, true);
+ /* Still haven't found the makefile. Look for it on the system
+ * path as a last resort (if we haven't already). */
+ if (isSystem)
+ return NULL;
+ else
+ return Dir_FindFile(file, sysIncPath);
}
-/*-
- *---------------------------------------------------------------------
- * ParseTraditionalInclude --
- * Push to another file.
- *
- * The input is the line minus the "include". The file name is
- * the string following the "include".
- *
- * Side Effects:
- * old parse context is pushed on the stack, new file becomes
- * current context.
- *
- * XXX May wish to support multiple files and wildcards ?
- *---------------------------------------------------------------------
- */
static void
-ParseTraditionalInclude(char *file) /* file specification */
+handle_include_file(const char *name, const char *ename, bool isSystem,
+ bool errIfNotFound)
{
- char *cp; /* current position in file spec */
-
- /* Skip over whitespace. */
- while (isspace(*file))
- file++;
- if (*file == '\0') {
- Parse_Error(PARSE_FATAL,
- "Filename missing from \"include\"");
- return;
- }
- /* Skip to end of line or next whitespace. */
- for (cp = file; *cp != '\0' && !isspace(*cp);)
- cp++;
+ char *file;
+ char *fullname;
- ParseLookupIncludeFile(file, cp, true, true);
-}
+ /* Substitute for any variables in the file name before trying to
+ * find the thing. */
+ file = Var_Substi(name, ename, NULL, false);
+
+ fullname = resolve_include_filename(file, isSystem);
+ if (fullname == NULL && errIfNotFound)
+ Parse_Error(PARSE_FATAL, "Could not find %s", file);
+ free(file);
-/*-
- *---------------------------------------------------------------------
- * ParseConditionalInclude --
- * May push to another file.
- *
- * No error if the file does not exist.
- * See ParseTraditionalInclude otherwise.
- *---------------------------------------------------------------------
- */
-static void
-ParseConditionalInclude(char *file)/* file specification */
-{
- char *cp; /* current position in file spec */
-
- /* Skip over whitespace. */
- while (isspace(*file))
- file++;
- if (*file == '\0') {
- Parse_Error(PARSE_FATAL,
- "Filename missing from \"include\"");
- return;
- }
- /* Skip to end of line or next whitespace. */
- for (cp = file; *cp != '\0' && !isspace(*cp);)
- cp++;
- ParseLookupIncludeFile(file, cp, true, false);
+ if (fullname != NULL) {
+ FILE *f;
+
+ f = fopen(fullname, "r");
+ if (f == NULL && errIfNotFound)
+ Parse_Error(PARSE_FATAL, "Cannot open %s", fullname);
+ else
+ Parse_FromFile(fullname, f);
+ }
}
-/* helper function for ParseLookupIncludeFile */
-static char *
-find_include(const char *file, bool isSystem)
+/* .include <file> (system) or .include "file" (normal) */
+static bool
+lookup_bsd_include(const char *file)
{
- char *fullname;
-
- /* Look up system files on the system path first */
- if (isSystem) {
- fullname = Dir_FindFileNoDot(file, sysIncPath);
- if (fullname)
- return fullname;
- }
-
- /* Handle non-system non-absolute files... */
- if (!isSystem && file[0] != '/') {
- /* ... by first searching relative to the including file's
- * location. We don't want to cd there, of course, so we
- * just tack on the old file's leading path components
- * and call Dir_FindFile to see if we can locate the beast. */
- char *slash;
- const char *fname;
-
- fname = Parse_Getfilename();
-
- slash = strrchr(fname, '/');
- if (slash != NULL) {
- char *newName;
-
- newName = Str_concati(fname, slash, file, strchr(file, '\0'), '/');
- fullname = Dir_FindFile(newName, parseIncPath);
- if (fullname == NULL)
- fullname = Dir_FindFile(newName, dirSearchPath);
- free(newName);
- if (fullname)
- return fullname;
+ char endc;
+ const char *efile;
+ bool isSystem;
+
+ /* find starting delimiter */
+ while (isspace(*file))
+ file++;
+
+ /* determine type of file */
+ if (*file == '<') {
+ isSystem = true;
+ endc = '>';
+ } else if (*file == '"') {
+ isSystem = false;
+ endc = '"';
+ } else {
+ Parse_Error(PARSE_WARNING,
+ ".include filename must be delimited by '\"' or '<'");
+ return false;
}
- }
- /* Now look first on the -I search path, then on the .PATH
- * search path, if not found in a -I directory.
- * XXX: Suffix specific? */
- fullname = Dir_FindFile(file, parseIncPath);
- if (fullname)
- return fullname;
- fullname = Dir_FindFile(file, dirSearchPath);
- if (fullname)
- return fullname;
-
- /* Still haven't found the makefile. Look for it on the system
- * path as a last resort. */
- if (isSystem)
- return NULL;
- else
- return Dir_FindFile(file, sysIncPath);
+ /* delimit file name between file and efile */
+ for (efile = ++file; *efile != endc; efile++) {
+ if (*efile == '\0') {
+ Parse_Error(PARSE_WARNING,
+ "Unclosed .include filename. '%c' expected", endc);
+ return false;
+ }
+ }
+ handle_include_file(file, efile, isSystem, true);
+ return true;
}
-/* Common part to lookup and read an include file. */
+
static void
-ParseLookupIncludeFile(char *spec, char *endSpec, bool isSystem,
- bool errIfNotFound)
+lookup_sysv_style_include(const char *file, const char *directive,
+ bool errIfMissing)
{
- char *file;
- char *fullname;
- char endc;
-
- /* Substitute for any variables in the file name before trying to
- * find the thing. */
- endc = *endSpec;
- *endSpec = '\0';
- file = Var_Subst(spec, NULL, false);
- *endSpec = endc;
-
- fullname = find_include(file, isSystem);
- if (fullname == NULL && errIfNotFound)
- Parse_Error(PARSE_FATAL, "Could not find %s", file);
-
+ const char *efile;
+
+ /* find beginning of name */
+ while (isspace(*file))
+ file++;
+ if (*file == '\0') {
+ Parse_Error(PARSE_FATAL, "Filename missing from \"%s\"",
+ directive);
+ return;
+ }
+ /* sys5 delimits file up to next blank character or end of line */
+ for (efile = file; *efile != '\0' && !isspace(*efile);)
+ efile++;
- free(file);
+ handle_include_file(file, efile, true, errIfMissing);
+}
- if (fullname != NULL) {
- FILE *f;
- f = fopen(fullname, "r");
- if (f == NULL && errIfNotFound) {
- Parse_Error(PARSE_FATAL, "Cannot open %s", fullname);
- } else {
- /* Once we find the absolute path to the file, we push the current
- * stream to the includes stack, and start reading from the new
- * file. We set up the file name to be its absolute name so that
- * error messages are informative. */
- Parse_FromFile(fullname, f);
- }
- }
+/* system V construct: include file */
+static void
+lookup_sysv_include(const char *file, const char *directive)
+{
+ lookup_sysv_style_include(file, directive, true);
}
+/* sinclude file and -include file */
static void
-ParseDoPoison(char *line)
+lookup_conditional_include(const char *file, const char *directive)
{
- char *p = line;
+ lookup_sysv_style_include(file, directive, false);
+}
+
+
+static bool
+handle_poison(const char *line)
+{
+ const char *p = line;
int type = POISON_NORMAL;
bool not = false;
bool paren_to_match = false;
- char *name, *ename;
+ const char *name, *ename;
while (isspace(*p))
p++;
@@ -1404,114 +1350,123 @@ ParseDoPoison(char *line)
type = POISON_INVALID;
break;
}
- if ((*p != '\0' && *p != '#') || type == POISON_INVALID)
- Parse_Error(PARSE_FATAL, "Invalid syntax for .poison: %s",
+ if ((*p != '\0' && *p != '#') || type == POISON_INVALID) {
+ Parse_Error(PARSE_WARNING, "Invalid syntax for .poison: %s",
line);
- Var_MarkPoisoned(name, ename, type);
+ return false;
+ } else {
+ Var_MarkPoisoned(name, ename, type);
+ return true;
+ }
}
-/* Strip comments from the line. May return either a copy of the line, or
- * the line itself. */
+/* Strip comments from the line. Build a copy in buffer if necessary, */
static char *
strip_comments(Buffer copy, const char *line)
{
- const char *comment;
- const char *p;
-
- comment = strchr(line, '#');
- assert(comment != line);
- if (comment == NULL)
- return (char *)line;
- else {
- Buf_Reset(copy);
-
- for (p = line; *p != '\0'; p++) {
- if (*p == '\\') {
- if (p[1] == '#') {
- Buf_Addi(copy, line, p);
- Buf_AddChar(copy, '#');
- line = p+2;
+ const char *comment;
+ const char *p;
+
+ comment = strchr(line, '#');
+ assert(comment != line);
+ if (comment == NULL)
+ return (char *)line;
+ else {
+ Buf_Reset(copy);
+
+ for (p = line; *p != '\0'; p++) {
+ if (*p == '\\') {
+ if (p[1] == '#') {
+ Buf_Addi(copy, line, p);
+ Buf_AddChar(copy, '#');
+ line = p+2;
+ }
+ if (p[1] != '\0')
+ p++;
+ } else if (*p == '#')
+ break;
}
- if (p[1] != '\0')
- p++;
- } else if (*p == '#')
- break;
+ Buf_Addi(copy, line, p);
+ Buf_KillTrailingSpaces(copy);
+ return Buf_Retrieve(copy);
}
- Buf_Addi(copy, line, p);
- Buf_KillTrailingSpaces(copy);
- return Buf_Retrieve(copy);
- }
}
static bool
-ParseIsCond(Buffer linebuf, Buffer copy, char *line)
+handle_for_loop(Buffer linebuf, const char *line)
{
-
- char *stripped;
-
- while (isspace(*line))
- line++;
-
- /* The line might be a conditional. Ask the conditional module
- * about it and act accordingly. */
- switch (Cond_Eval(line)) {
- case COND_SKIP:
- /* Skip to next conditional that evaluates to COND_PARSE. */
- do {
- line = Parse_ReadNextConditionalLine(linebuf);
- if (line != NULL) {
- while (isspace(*line))
- line++;
- stripped = strip_comments(copy, line);
- }
- } while (line != NULL && Cond_Eval(stripped) != COND_PARSE);
- /* FALLTHROUGH */
- case COND_PARSE:
- return true;
- case COND_ISFOR: {
For *loop;
loop = For_Eval(line+3);
if (loop != NULL) {
- bool ok;
- do {
- /* Find the matching endfor. */
- line = ParseReadLoopLine(linebuf);
- if (line == NULL) {
- Parse_Error(PARSE_FATAL,
- "Unexpected end of file in for loop.\n");
- return false;
- }
- ok = For_Accumulate(loop, line);
- } while (ok);
- For_Run(loop);
- return true;
- }
- break;
- }
- case COND_ISINCLUDE:
- ParseDoInclude(line + 7);
- return true;
- case COND_ISPOISON:
- ParseDoPoison(line + 6);
- return true;
- case COND_ISUNDEF: {
- char *cp;
+ bool ok;
+ do {
+ /* Find the matching endfor. */
+ line = ParseReadLoopLine(linebuf);
+ if (line == NULL) {
+ Parse_Error(PARSE_FATAL,
+ "Unexpected end of file in for loop.\n");
+ return false;
+ }
+ ok = For_Accumulate(loop, line);
+ } while (ok);
+ For_Run(loop);
+ return true;
+ } else
+ return false;
+}
+
+static bool
+handle_undef(const char *line)
+{
+ const char *eline;
- line+=5;
while (isspace(*line))
- line++;
- for (cp = line; !isspace(*cp) && *cp != '\0';)
- cp++;
- Var_Deletei(line, cp);
+ line++;
+ for (eline = line; !isspace(*eline) && *eline != '\0';)
+ eline++;
+ Var_Deletei(line, eline);
return true;
- }
- default:
- break;
- }
+}
+
+static bool
+handle_bsd_command(Buffer linebuf, Buffer copy, const char *line)
+{
+ char *stripped;
- return false;
+ while (isspace(*line))
+ line++;
+
+ /* The line might be a conditional. Ask the conditional module
+ * about it and act accordingly. */
+ switch (Cond_Eval(line)) {
+ case COND_SKIP:
+ /* Skip to next conditional that evaluates to COND_PARSE. */
+ do {
+ line = Parse_ReadNextConditionalLine(linebuf);
+ if (line != NULL) {
+ while (isspace(*line))
+ line++;
+ stripped = strip_comments(copy, line);
+ }
+ } while (line != NULL && Cond_Eval(stripped) != COND_PARSE);
+ /* FALLTHROUGH */
+ case COND_PARSE:
+ return true;
+ case COND_ISFOR:
+ return handle_for_loop(linebuf, line);
+ case COND_ISINCLUDE:
+ return lookup_bsd_include(line + 7);
+ case COND_ISPOISON:
+ return handle_poison(line+6);
+ case COND_ISUNDEF:
+ return handle_undef(line + 5);
+ default:
+ break;
+ }
+
+ return false;
}
/*-
@@ -1575,20 +1530,25 @@ Parse_File(
} else {
char *stripped;
stripped = strip_comments(&copy, line);
- if (*stripped == '.' && ParseIsCond(&buf, &copy, stripped+1))
- ;
+ if (*stripped == '.' && handle_bsd_command(&buf, &copy,
+ stripped+1))
+ ;
else if (FEATURES(FEATURE_SYSVINCLUDE) &&
strncmp(stripped, "include", 7) == 0 &&
isspace(stripped[7]) &&
strchr(stripped, ':') == NULL) {
/* It's an S3/S5-style "include". */
- ParseTraditionalInclude(stripped + 7);
+ lookup_sysv_include(stripped + 7, "include");
} else if (FEATURES(FEATURE_CONDINCLUDE) &&
- (*stripped == '-' || *stripped == 's') &&
- strncmp(stripped+1, "include", 7) == 0 &&
+ strncmp(stripped, "sinclude", 8) == 0 &&
isspace(stripped[8]) &&
strchr(stripped, ':') == NULL) {
- ParseConditionalInclude(stripped+8);
+ lookup_conditional_include(stripped+8, "sinclude");
+ } else if (FEATURES(FEATURE_CONDINCLUDE) &&
+ strncmp(stripped, "-include", 8) == 0 &&
+ isspace(stripped[8]) &&
+ strchr(stripped, ':') == NULL) {
+ lookup_conditional_include(stripped+8, "-include");
} else {
char *dep;
@@ -1654,15 +1614,15 @@ Parse_File(
void
Parse_Init(void)
{
- mainNode = NULL;
- Static_Lst_Init(parseIncPath);
- Static_Lst_Init(sysIncPath);
- Array_Init(&gsources, SOURCES_SIZE);
- Array_Init(&gtargets, TARGETS_SIZE);
-
- LowParse_Init();
+ mainNode = NULL;
+ Static_Lst_Init(parseIncPath);
+ Static_Lst_Init(sysIncPath);
+ Array_Init(&gsources, SOURCES_SIZE);
+ Array_Init(&gtargets, TARGETS_SIZE);
+
+ LowParse_Init();
#ifdef CLEANUP
- Static_Lst_Init(&targCmds);
+ Static_Lst_Init(&targCmds);
#endif
}
@@ -1670,10 +1630,10 @@ Parse_Init(void)
void
Parse_End(void)
{
- Lst_Destroy(&targCmds, (SimpleProc)free);
- Lst_Destroy(sysIncPath, Dir_Destroy);
- Lst_Destroy(parseIncPath, Dir_Destroy);
- LowParse_End();
+ Lst_Destroy(&targCmds, (SimpleProc)free);
+ Lst_Destroy(sysIncPath, Dir_Destroy);
+ Lst_Destroy(parseIncPath, Dir_Destroy);
+ LowParse_End();
}
#endif
diff --git a/usr.bin/make/var.c b/usr.bin/make/var.c
index 04a684e9845..715161df681 100644
--- a/usr.bin/make/var.c
+++ b/usr.bin/make/var.c
@@ -1,5 +1,5 @@
/* $OpenPackages$ */
-/* $OpenBSD: var.c,v 1.73 2007/07/30 09:51:53 espie Exp $ */
+/* $OpenBSD: var.c,v 1.74 2007/07/30 10:03:11 espie Exp $ */
/* $NetBSD: var.c,v 1.18 1997/03/18 19:24:46 christos Exp $ */
/*
@@ -1104,6 +1104,22 @@ Var_Subst(const char *str, /* the string in which to substitute */
return Buf_Retrieve(&buf);
}
+static BUFFER subst_buffer;
+
+/* we would like to subst on intervals, but it's complicated, so we cheat
+ * by storing the interval in a static buffer.
+ */
+char *
+Var_Substi(const char *str, const char *estr, SymTable *ctxt, bool undefErr)
+{
+ /* delimited string: no need to copy */
+ if (estr == NULL || *estr == '\0')
+ return Var_Subst(str, ctxt, undefErr);
+
+ Buf_Reset(&subst_buffer);
+ Buf_Addi(&subst_buffer, str, estr);
+ return Var_Subst(Buf_Retrieve(&subst_buffer), ctxt, undefErr);
+}
/***
*** Supplementary support for .for loops.
@@ -1262,6 +1278,7 @@ Var_Init(void)
Var_setCheckEnvFirst(false);
VarModifiers_Init();
+ Buf_Init(&subst_buffer, MAKE_BSIZE);
}
diff --git a/usr.bin/make/var.h b/usr.bin/make/var.h
index 0617f79b9b7..3fa22378f9e 100644
--- a/usr.bin/make/var.h
+++ b/usr.bin/make/var.h
@@ -121,6 +121,9 @@ extern bool Var_ParseBuffer(Buffer, const char *, SymTable *,
* Emit a PARSE_FATAL error if undef_is_bad and an undef variable is
* encountered. The result is always a copy that should be free. */
extern char *Var_Subst(const char *, SymTable *, bool);
+/* subst = Var_Substi(str, estr, ctxt, undef_if_bad);
+ */
+extern char *Var_Substi(const char *, const char *, SymTable *, bool);
/* For loop handling.