summaryrefslogtreecommitdiff
path: root/read.c
diff options
context:
space:
mode:
Diffstat (limited to 'read.c')
-rw-r--r--read.c374
1 files changed, 184 insertions, 190 deletions
diff --git a/read.c b/read.c
index eb4b212..ec6d6af 100644
--- a/read.c
+++ b/read.c
@@ -56,6 +56,17 @@ struct ebuffer
struct floc floc; /* Info on the file in fp (if any). */
};
+/* Track the modifiers we can have on variable assignments */
+
+struct vmodifiers
+ {
+ unsigned int assign_v:1;
+ unsigned int define_v:1;
+ unsigned int export_v:1;
+ unsigned int override_v:1;
+ unsigned int private_v:1;
+ };
+
/* Types of "words" that can be read in a makefile. */
enum make_word_type
{
@@ -125,8 +136,9 @@ static int eval_makefile (const char *filename, int flags);
static int eval (struct ebuffer *buffer, int flags);
static long readline (struct ebuffer *ebuf);
-static void do_define (char *name, unsigned int namelen,
- enum variable_origin origin, struct ebuffer *ebuf);
+static struct variable *do_define (char *name, unsigned int namelen,
+ enum variable_origin origin,
+ struct ebuffer *ebuf);
static int conditional_line (char *line, int len, const struct floc *flocp);
static void record_files (struct nameseq *filenames, const char *pattern,
const char *pattern_percent, struct dep *deps,
@@ -134,13 +146,21 @@ static void record_files (struct nameseq *filenames, const char *pattern,
unsigned int commands_idx, int two_colon,
const struct floc *flocp);
static void record_target_var (struct nameseq *filenames, char *defn,
- enum variable_origin origin, int enabled,
+ enum variable_origin origin,
+ struct vmodifiers *vmod,
const struct floc *flocp);
static enum make_word_type get_next_mword (char *buffer, char *delim,
char **startp, unsigned int *length);
static void remove_comments (char *line);
static char *find_char_unquote (char *string, int stop1, int stop2,
int blank, int ignorevars);
+
+
+/* Compare a word, both length and contents.
+ P must point to the word to be tested, and WLEN must be the length.
+*/
+#define word1eq(s) (wlen == sizeof(s)-1 && strneq (s, p, sizeof(s)-1))
+
/* Read in all the makefiles and return the chain of their names. */
@@ -434,8 +454,75 @@ eval_buffer (char *buffer)
alloca (0);
return r;
}
+
+/* Check LINE to see if it's a variable assignment.
+
+ It might use one of the modifiers "export", "override", "private", or it
+ might be one of the conditional tokens like "ifdef", "include", etc.
+
+ If it's not a variable assignment, VMOD.V_ASSIGN is 0. Returns LINE.
+
+ Returns a pointer to the first non-modifier character, and sets VMOD
+ based on the modifiers found if any, plus V_ASSIGN is 1.
+ */
+char *
+parse_var_assignment (const char *line, struct vmodifiers *vmod)
+{
+ const char *p;
+ memset (vmod, '\0', sizeof (*vmod));
+
+ /* Find the start of the next token. If there isn't one we're done. */
+ line = next_token (line);
+ if (*line == '\0')
+ return (char *)line;
+
+ p = line;
+ while (1)
+ {
+ int wlen;
+ const char *p2;
+ enum variable_flavor flavor;
+
+ p2 = parse_variable_definition (p, &flavor);
+
+ /* If this is a variable assignment, we're done. */
+ if (p2)
+ break;
+
+ /* It's not a variable; see if it's a modifier. */
+ p2 = end_of_token (p);
+ wlen = p2 - p;
+
+ if (word1eq ("export"))
+ vmod->export_v = 1;
+ else if (word1eq ("override"))
+ vmod->override_v = 1;
+ else if (word1eq ("private"))
+ vmod->private_v = 1;
+ else if (word1eq ("define"))
+ {
+ /* We can't have modifiers after 'define' */
+ vmod->define_v = 1;
+ p = next_token (p2);
+ break;
+ }
+ else
+ /* Not a variable or modifier: this is not a variable assignment. */
+ return (char *)line;
+
+ /* It was a modifier. Try the next word. */
+ p = next_token (p2);
+ if (*p == '\0')
+ return (char *)line;
+ }
+
+ /* Found a variable assignment. */
+ vmod->assign_v = 1;
+ return (char *)p;
+}
+
/* Read file FILENAME as a makefile and add its contents to the data base.
SET_DEFAULT is true if we are allowed to set the default goal. */
@@ -502,7 +589,9 @@ eval (struct ebuffer *ebuf, int set_default)
unsigned int wlen;
char *p;
char *p2;
+ struct vmodifiers vmod;
+ /* At the top of this loop, we are starting a brand new line. */
/* Grab the next line to be evaluated */
ebuf->floc.lineno += nlines;
nlines = readline (ebuf);
@@ -527,7 +616,7 @@ eval (struct ebuffer *ebuf, int set_default)
continue;
/* If there is no preceding rule line, don't treat this line
- as a command, even though it begins with a tab character.
+ as a command, even though it begins with a recipe prefix.
SunOS 4 make appears to behave this way. */
if (filenames != 0)
@@ -566,7 +655,7 @@ eval (struct ebuffer *ebuf, int set_default)
}
}
- /* This line is not a shell command line. Don't worry about tabs.
+ /* This line is not a shell command line. Don't worry about whitespace.
Get more space if we need it; we don't need to preserve the current
contents of the buffer. */
@@ -575,6 +664,7 @@ eval (struct ebuffer *ebuf, int set_default)
collapsed_length = linelen+1;
if (collapsed)
free (collapsed);
+ /* Don't need xrealloc: we don't need to preserve the content. */
collapsed = xmalloc (collapsed_length);
}
strcpy (collapsed, line);
@@ -582,183 +672,113 @@ eval (struct ebuffer *ebuf, int set_default)
collapse_continuations (collapsed);
remove_comments (collapsed);
- /* Compare a word, both length and contents. */
-#define word1eq(s) (wlen == sizeof(s)-1 && strneq (s, p, sizeof(s)-1))
- p = collapsed;
- while (isspace ((unsigned char)*p))
- ++p;
+ /* See if this is a variable assignment. We need to do this early, to
+ allow variables with names like 'ifdef', 'export', 'private', etc. */
+ p = parse_var_assignment(collapsed, &vmod);
+ if (vmod.assign_v)
+ {
+ struct variable *v;
+ enum variable_origin origin = vmod.override_v ? o_override : o_file;
- if (*p == '\0')
- /* This line is completely empty--ignore it. */
- continue;
+ /* If we're ignoring then we're done now. */
+ if (ignoring)
+ {
+ if (vmod.define_v)
+ in_ignored_define = 1;
+ continue;
+ }
- /* Find the end of the first token. Note we don't need to worry about
- * ":" here since we compare tokens by length (so "export" will never
- * be equal to "export:").
- */
- for (p2 = p+1; *p2 != '\0' && !isspace ((unsigned char)*p2); ++p2)
- ;
- wlen = p2 - p;
+ /* If it's a multi-line define / endef, manage that. */
+ if (vmod.define_v)
+ {
+ if (*p == '\0')
+ fatal (fstart, _("empty variable name"));
- /* Find the start of the second token. If it looks like a target or
- variable definition it can't be a preprocessor token so skip
- them--this allows variables/targets named `ifdef', `export', etc. */
- while (isspace ((unsigned char)*p2))
- ++p2;
+ /* Let the variable name be the whole rest of the line,
+ with trailing blanks stripped (comments have already been
+ removed), so it could be a complex variable/function
+ reference that might contain blanks. */
+ p2 = p + strlen (p);
+ while (isblank ((unsigned char)p2[-1]))
+ --p2;
+ v = do_define (p, p2 - p, origin, ebuf);
+ }
+ else
+ {
+ v = try_variable_definition (fstart, p, origin, 0);
+ assert (v != NULL);
+ }
- if ((p2[0] == ':' || p2[0] == '+' || p2[0] == '=') && p2[1] == '\0')
- {
- /* It can't be a preprocessor token so skip it if we're ignoring */
- if (ignoring)
- continue;
+ if (vmod.export_v)
+ v->export = v_export;
+ if (vmod.private_v)
+ v->private_var = 1;
- goto skip_conditionals;
+ /* This line has been dealt with. */
+ goto rule_complete;
}
- /* We must first check for conditional and `define' directives before
- ignoring anything, since they control what we will do with
- following lines. */
-
- if (!in_ignored_define)
- {
- int i = conditional_line (p, wlen, fstart);
- if (i != -2)
- {
- if (i == -1)
- fatal (fstart, _("invalid syntax in conditional"));
-
- ignoring = i;
- continue;
- }
- }
+ /* If this line is completely empty, ignore it. */
+ if (*p == '\0')
+ continue;
- if (word1eq ("endef"))
- {
- if (!in_ignored_define)
- fatal (fstart, _("extraneous `endef'"));
- in_ignored_define = 0;
- continue;
- }
+ p2 = end_of_token (p);
+ wlen = p2 - p;
+ p2 = next_token (p2);
- if (word1eq ("define"))
+ /* If we're in an ignored define, skip this line (but maybe get out). */
+ if (in_ignored_define)
{
- if (ignoring)
- in_ignored_define = 1;
- else
- {
- if (*p2 == '\0')
- fatal (fstart, _("empty variable name"));
+ /* See if this is an endef line (plus optional comment). */
+ if (word1eq ("endef") && (*p2 == '\0' || *p2 == '#'))
+ in_ignored_define = 0;
- /* Let the variable name be the whole rest of the line,
- with trailing blanks stripped (comments have already been
- removed), so it could be a complex variable/function
- reference that might contain blanks. */
- p = strchr (p2, '\0');
- while (isblank ((unsigned char)p[-1]))
- --p;
- do_define (p2, p - p2, o_file, ebuf);
- }
continue;
}
- if (word1eq ("override"))
- {
- if (*p2 == '\0')
- error (fstart, _("empty `override' directive"));
-
- if (strneq (p2, "define", 6)
- && (isblank ((unsigned char)p2[6]) || p2[6] == '\0'))
- {
- if (ignoring)
- in_ignored_define = 1;
- else
- {
- p2 = next_token (p2 + 6);
- if (*p2 == '\0')
- fatal (fstart, _("empty variable name"));
-
- /* Let the variable name be the whole rest of the line,
- with trailing blanks stripped (comments have already been
- removed), so it could be a complex variable/function
- reference that might contain blanks. */
- p = strchr (p2, '\0');
- while (isblank ((unsigned char)p[-1]))
- --p;
- do_define (p2, p - p2, o_override, ebuf);
- }
- }
- else if (!ignoring
- && !try_variable_definition (fstart, p2, o_override, 0))
- error (fstart, _("invalid `override' directive"));
+ /* Check for conditional state changes. */
+ {
+ int i = conditional_line (p, wlen, fstart);
+ if (i != -2)
+ {
+ if (i == -1)
+ fatal (fstart, _("invalid syntax in conditional"));
- continue;
- }
+ ignoring = i;
+ continue;
+ }
+ }
+ /* Nothing to see here... move along. */
if (ignoring)
- /* Ignore the line. We continue here so conditionals
- can appear in the middle of a rule. */
continue;
- if (word1eq ("export"))
+ /* Manage the "export" keyword used outside of variable assignment
+ as well as "unexport". */
+ if (word1eq ("export") || word1eq ("unexport"))
{
- /* 'export' by itself causes everything to be exported. */
- if (*p2 == '\0')
- export_all_variables = 1;
- else
- {
- struct variable *v;
-
- v = try_variable_definition (fstart, p2, o_file, 0);
- if (v != 0)
- v->export = v_export;
- else
- {
- unsigned int l;
- const char *cp;
- char *ap;
-
- /* Expand the line so we can use indirect and constructed
- variable names in an export command. */
- cp = ap = allocated_variable_expand (p2);
-
- for (p = find_next_token (&cp, &l); p != 0;
- p = find_next_token (&cp, &l))
- {
- v = lookup_variable (p, l);
- if (v == 0)
- v = define_variable_loc (p, l, "", o_file, 0, fstart);
- v->export = v_export;
- }
-
- free (ap);
- }
- }
- goto rule_complete;
- }
+ int exporting = *p == 'u' ? 0 : 1;
- if (word1eq ("unexport"))
- {
+ /* (un)export by itself causes everything to be (un)exported. */
if (*p2 == '\0')
- export_all_variables = 0;
+ export_all_variables = exporting;
else
{
unsigned int l;
- struct variable *v;
const char *cp;
char *ap;
/* Expand the line so we can use indirect and constructed
- variable names in an unexport command. */
+ variable names in an (un)export command. */
cp = ap = allocated_variable_expand (p2);
for (p = find_next_token (&cp, &l); p != 0;
p = find_next_token (&cp, &l))
{
- v = lookup_variable (p, l);
+ struct variable *v = lookup_variable (p, l);
if (v == 0)
v = define_variable_loc (p, l, "", o_file, 0, fstart);
-
- v->export = v_noexport;
+ v->export = exporting ? v_export : v_noexport;
}
free (ap);
@@ -766,7 +786,7 @@ eval (struct ebuffer *ebuf, int set_default)
goto rule_complete;
}
- skip_conditionals:
+ /* Handle the special syntax for vpath. */
if (word1eq ("vpath"))
{
const char *cp;
@@ -791,6 +811,7 @@ eval (struct ebuffer *ebuf, int set_default)
goto rule_complete;
}
+ /* Handle include and variants. */
if (word1eq ("include") || word1eq ("-include") || word1eq ("sinclude"))
{
/* We have found an `include' line specifying a nested
@@ -849,10 +870,6 @@ eval (struct ebuffer *ebuf, int set_default)
goto rule_complete;
}
- if (try_variable_definition (fstart, p, o_file, 0))
- /* This line has been dealt with. */
- goto rule_complete;
-
/* This line starts with a tab but was not caught above because there
was no preceding target, and the line might have been usable as a
variable definition. But now we know it is definitely lossage. */
@@ -871,8 +888,6 @@ eval (struct ebuffer *ebuf, int set_default)
{
enum make_word_type wtype;
- enum variable_origin v_origin;
- int exported;
char *cmdleft, *semip, *lb_next;
unsigned int plen = 0;
char *colonp;
@@ -1038,31 +1053,8 @@ eval (struct ebuffer *ebuf, int set_default)
p2 = variable_buffer + l;
}
- /* See if it's an "override" or "export" keyword; if so see if what
- comes after it looks like a variable definition. */
-
- wtype = get_next_mword (p2, NULL, &p, &wlen);
-
- v_origin = o_file;
- exported = 0;
- if (wtype == w_static)
- {
- if (word1eq ("override"))
- {
- v_origin = o_override;
- wtype = get_next_mword (p+wlen, NULL, &p, &wlen);
- }
- else if (word1eq ("export"))
- {
- exported = 1;
- wtype = get_next_mword (p+wlen, NULL, &p, &wlen);
- }
- }
-
- if (wtype != w_eol)
- wtype = get_next_mword (p+wlen, NULL, NULL, NULL);
-
- if (wtype == w_varassign)
+ p2 = parse_var_assignment (p2, &vmod);
+ if (vmod.assign_v)
{
/* If there was a semicolon found, add it back, plus anything
after it. */
@@ -1074,7 +1066,9 @@ eval (struct ebuffer *ebuf, int set_default)
semip, strlen (semip)+1);
p = variable_buffer + l;
}
- record_target_var (filenames, p, v_origin, exported, fstart);
+ record_target_var (filenames, p2,
+ vmod.override_v ? o_override : o_file,
+ &vmod, fstart);
filenames = 0;
continue;
}
@@ -1319,7 +1313,7 @@ remove_comments (char *line)
The first line has already been read, and NAME is the name of
the variable to be defined. The following lines remain to be read. */
-static void
+static struct variable *
do_define (char *name, unsigned int namelen,
enum variable_origin origin, struct ebuffer *ebuf)
{
@@ -1382,6 +1376,8 @@ do_define (char *name, unsigned int namelen,
if (--nlevels == 0)
{
+ struct variable *v;
+
/* Define the variable. */
if (idx == 0)
definition[0] = '\0';
@@ -1389,10 +1385,10 @@ do_define (char *name, unsigned int namelen,
definition[idx - 1] = '\0';
/* Always define these variables in the global set. */
- define_variable_global (var, strlen (var), definition,
- origin, 1, &defstart);
+ v = define_variable_global (var, strlen (var), definition,
+ origin, 1, &defstart);
free (definition);
- return;
+ return (v);
}
}
}
@@ -1413,9 +1409,6 @@ do_define (char *name, unsigned int namelen,
/* No `endef'!! */
fatal (&defstart, _("missing `endef', unterminated `define'"));
-
- /* NOTREACHED */
- return;
}
/* Interpret conditional commands "ifdef", "ifndef", "ifeq",
@@ -1763,7 +1756,7 @@ uniquize_deps (struct dep *chain)
static void
record_target_var (struct nameseq *filenames, char *defn,
- enum variable_origin origin, int exported,
+ enum variable_origin origin, struct vmodifiers *vmod,
const struct floc *flocp)
{
struct nameseq *nextf;
@@ -1795,7 +1788,7 @@ record_target_var (struct nameseq *filenames, char *defn,
p->variable.fileinfo = *flocp;
/* I don't think this can fail since we already determined it was a
variable definition. */
- v = parse_variable_definition (&p->variable, defn);
+ v = assign_variable_definition (&p->variable, defn);
assert (v != 0);
if (v->flavor == f_simple)
@@ -1825,14 +1818,15 @@ record_target_var (struct nameseq *filenames, char *defn,
current_variable_set_list = f->variables;
v = try_variable_definition (flocp, defn, origin, 1);
if (!v)
- error (flocp, _("Malformed target-specific variable definition"));
+ fatal (flocp, _("Malformed target-specific variable definition"));
current_variable_set_list = global;
}
/* Set up the variable to be *-specific. */
v->origin = origin;
v->per_target = 1;
- v->export = exported ? v_export : v_default;
+ v->private_var = vmod->private_v;
+ v->export = vmod->export_v ? v_export : v_default;
/* If it's not an override, check to see if there was a command-line
setting. If so, reset the value. */