summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Smith <psmith@gnu.org>2005-06-25 21:30:13 +0000
committerPaul Smith <psmith@gnu.org>2005-06-25 21:30:13 +0000
commit6cdaff0948bbec3220d5cb071f79d5f2e1c9b083 (patch)
tree407efa2f97b6dfb472fb96396d6fa73892f38a97
parent1dd9ed1c0537cb2583e1de8367994560ad1470aa (diff)
downloadgunmake-6cdaff0948bbec3220d5cb071f79d5f2e1c9b083.tar.gz
Fix Savannah bug #1454: skip over semicolons (and comments) inside variable
references in target definition lines.
-rw-r--r--ChangeLog13
-rw-r--r--make.h2
-rw-r--r--misc.c16
-rw-r--r--read.c95
-rw-r--r--tests/ChangeLog3
-rw-r--r--tests/scripts/misc/general332
6 files changed, 108 insertions, 53 deletions
diff --git a/ChangeLog b/ChangeLog
index 8e53a64..c764580 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,18 @@
2005-06-25 Paul D. Smith <psmith@gnu.org>
+ Fix Savannah bug #1454.
+
+ * read.c (find_char_unquote): Accept a new argument IGNOREVARS.
+ If it's set, then don't stop on STOPCHARs or BLANKs if they're
+ inside a variable reference. Make this function static as it's
+ only used here.
+ (eval): Call find_char_unquote() with IGNOREVARS set when we're
+ parsing an unexpanded line looking for semicolons.
+ * misc.c (remove_comments): Move this to read.c and make it static
+ as it's only used there. Call find_char_unquote() with new arg.
+ * make.h: Remove prototypes for find_char_unquote() and
+ remove_comments() since they're static now.
+
Implement the MAKE_RESTARTS variable, and disable -B if it's >0.
Fixes Savannah bug #7566.
diff --git a/make.h b/make.h
index 699a6e4..20ee569 100644
--- a/make.h
+++ b/make.h
@@ -421,11 +421,9 @@ extern char *find_next_token PARAMS ((char **, unsigned int *));
extern char *next_token PARAMS ((const char *));
extern char *end_of_token PARAMS ((const char *));
extern void collapse_continuations PARAMS ((char *));
-extern void remove_comments PARAMS((char *));
extern char *lindex PARAMS ((const char *, const char *, int));
extern int alpha_compare PARAMS ((const void *, const void *));
extern void print_spaces PARAMS ((unsigned int));
-extern char *find_char_unquote PARAMS ((char *, int, int, int));
extern char *find_percent PARAMS ((char *));
extern FILE *open_tmpfile PARAMS ((char **, const char *));
diff --git a/misc.c b/misc.c
index 995fd20..ac50270 100644
--- a/misc.c
+++ b/misc.c
@@ -149,22 +149,6 @@ collapse_continuations (char *line)
*out = '\0';
}
-
-
-/* Remove comments from LINE.
- This is done by copying the text at LINE onto itself. */
-
-void
-remove_comments (char *line)
-{
- char *comment;
-
- comment = find_char_unquote (line, '#', 0, 0);
-
- if (comment != 0)
- /* Cut off the line at the #. */
- *comment = '\0';
-}
/* Print N spaces (used in debug for target-depth). */
diff --git a/read.c b/read.c
index 40ff986..2e97995 100644
--- a/read.c
+++ b/read.c
@@ -143,6 +143,9 @@ static void record_target_var PARAMS ((struct nameseq *filenames, char *defn,
const struct floc *flocp));
static enum make_word_type get_next_mword PARAMS ((char *buffer, char *delim,
char **startp, unsigned int *length));
+static void remove_comments PARAMS ((char *line));
+static char *find_char_unquote PARAMS ((char *string, int stop1,
+ int stop2, int blank, int ignorevars));
/* Read in all the makefiles and return the chain of their names. */
@@ -882,7 +885,7 @@ eval (struct ebuffer *ebuf, int set_default)
/* Search the line for an unquoted ; that is not after an
unquoted #. */
- cmdleft = find_char_unquote (line, ';', '#', 0);
+ cmdleft = find_char_unquote (line, ';', '#', 0, 1);
if (cmdleft != 0 && *cmdleft == '#')
{
/* We found a comment before a semicolon. */
@@ -929,7 +932,7 @@ eval (struct ebuffer *ebuf, int set_default)
if (cmdleft == 0)
{
/* Look for a semicolon in the expanded line. */
- cmdleft = find_char_unquote (p2, ';', 0, 0);
+ cmdleft = find_char_unquote (p2, ';', 0, 0, 0);
if (cmdleft != 0)
{
@@ -956,7 +959,7 @@ eval (struct ebuffer *ebuf, int set_default)
}
}
- colonp = find_char_unquote(p2, ':', 0, 0);
+ colonp = find_char_unquote(p2, ':', 0, 0, 0);
#ifdef HAVE_DOS_PATHS
/* The drive spec brain-damage strikes again... */
/* Note that the only separators of targets in this context
@@ -965,7 +968,7 @@ eval (struct ebuffer *ebuf, int set_default)
while (colonp && (colonp[1] == '/' || colonp[1] == '\\') &&
colonp > p2 && isalpha ((unsigned char)colonp[-1]) &&
(colonp == p2 + 1 || strchr (" \t(", colonp[-2]) != 0))
- colonp = find_char_unquote(colonp + 1, ':', 0, 0);
+ colonp = find_char_unquote(colonp + 1, ':', 0, 0, 0);
#endif
if (colonp != 0)
break;
@@ -1079,7 +1082,7 @@ eval (struct ebuffer *ebuf, int set_default)
/* This is a normal target, _not_ a target-specific variable.
Unquote any = in the dependency list. */
- find_char_unquote (lb_next, '=', 0, 0);
+ find_char_unquote (lb_next, '=', 0, 0, 0);
/* We have some targets, so don't ignore the following commands. */
no_targets = 0;
@@ -1094,7 +1097,7 @@ eval (struct ebuffer *ebuf, int set_default)
/* Look for a semicolon in the expanded line. */
if (cmdleft == 0)
{
- cmdleft = find_char_unquote (p2, ';', 0, 0);
+ cmdleft = find_char_unquote (p2, ';', 0, 0, 0);
if (cmdleft != 0)
*(cmdleft++) = '\0';
}
@@ -1310,8 +1313,23 @@ eval (struct ebuffer *ebuf, int set_default)
return 1;
}
-
+
+/* Remove comments from LINE.
+ This is done by copying the text at LINE onto itself. */
+
+static void
+remove_comments (char *line)
+{
+ char *comment;
+
+ comment = find_char_unquote (line, '#', 0, 0, 0);
+
+ if (comment != 0)
+ /* Cut off the line at the #. */
+ *comment = '\0';
+}
+
/* Execute a `define' directive.
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. */
@@ -2158,34 +2176,75 @@ record_files (struct nameseq *filenames, char *pattern, char *pattern_percent,
Backslashes quote STOPCHAR, blanks if BLANK is nonzero, and backslash.
Quoting backslashes are removed from STRING by compacting it into
itself. Returns a pointer to the first unquoted STOPCHAR if there is
- one, or nil if there are none. */
+ one, or nil if there are none. STOPCHARs inside variable references are
+ ignored if IGNOREVARS is true.
-char *
-find_char_unquote (char *string, int stop1, int stop2, int blank)
+ STOPCHAR _cannot_ be '$' if IGNOREVARS is true. */
+
+static char *
+find_char_unquote (char *string, int stop1, int stop2, int blank,
+ int ignorevars)
{
unsigned int string_len = 0;
register char *p = string;
+ int pcount = 0;
+ char openparen;
+ char closeparen;
+
+ if (ignorevars)
+ ignorevars = '$';
while (1)
{
if (stop2 && blank)
- while (*p != '\0' && *p != stop1 && *p != stop2
+ while (*p != '\0' && *p != ignorevars && *p != stop1 && *p != stop2
&& ! isblank ((unsigned char) *p))
++p;
else if (stop2)
- while (*p != '\0' && *p != stop1 && *p != stop2)
+ while (*p != '\0' && *p != ignorevars && *p != stop1 && *p != stop2)
++p;
else if (blank)
- while (*p != '\0' && *p != stop1
+ while (*p != '\0' && *p != ignorevars && *p != stop1
&& ! isblank ((unsigned char) *p))
++p;
else
- while (*p != '\0' && *p != stop1)
+ while (*p != '\0' && *p != ignorevars && *p != stop1)
++p;
if (*p == '\0')
break;
+ /* If we stopped due to a variable reference, skip over its contents. */
+ if (*p == ignorevars)
+ {
+ char openparen = p[1];
+
+ p += 2;
+
+ /* Skip the contents of a non-quoted, multi-char variable ref. */
+ if (openparen == '(' || openparen == '{')
+ {
+ unsigned int pcount = 1;
+ char closeparen = (openparen == '(' ? ')' : '}');
+
+ while (*p)
+ {
+ if (*p == openparen)
+ ++pcount;
+ else if (*p == closeparen)
+ if (--pcount == 0)
+ {
+ ++p;
+ break;
+ }
+ ++p;
+ }
+ }
+
+ /* Skipped the variable reference: look for STOPCHARS again. */
+ continue;
+ }
+
if (p > string && p[-1] == '\\')
{
/* Search for more backslashes. */
@@ -2221,7 +2280,7 @@ find_char_unquote (char *string, int stop1, int stop2, int blank)
char *
find_percent (char *pattern)
{
- return find_char_unquote (pattern, '%', 0, 0);
+ return find_char_unquote (pattern, '%', 0, 0, 0);
}
/* Parse a string into a sequence of filenames represented as a
@@ -2263,7 +2322,7 @@ parse_file_seq (char **stringp, int stopchar, unsigned int size, int strip)
/* Yes, find end of next name. */
q = p;
- p = find_char_unquote (q, stopchar, VMS_COMMA, 1);
+ p = find_char_unquote (q, stopchar, VMS_COMMA, 1, 0);
#ifdef VMS
/* convert comma separated list to space separated */
if (p && *p == ',')
@@ -2274,7 +2333,7 @@ parse_file_seq (char **stringp, int stopchar, unsigned int size, int strip)
&& !(isspace ((unsigned char)p[1]) || !p[1]
|| isspace ((unsigned char)p[-1])))
{
- p = find_char_unquote (p+1, stopchar, VMS_COMMA, 1);
+ p = find_char_unquote (p+1, stopchar, VMS_COMMA, 1, 0);
}
#endif
#ifdef HAVE_DOS_PATHS
@@ -2285,7 +2344,7 @@ parse_file_seq (char **stringp, int stopchar, unsigned int size, int strip)
if (stopchar == ':')
while (p != 0 && !isspace ((unsigned char)*p) &&
(p[1] == '\\' || p[1] == '/') && isalpha ((unsigned char)p[-1]))
- p = find_char_unquote (p + 1, stopchar, VMS_COMMA, 1);
+ p = find_char_unquote (p + 1, stopchar, VMS_COMMA, 1, 0);
#endif
if (p == 0)
p = q + strlen (q);
diff --git a/tests/ChangeLog b/tests/ChangeLog
index be5169b..fa6420d 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,5 +1,8 @@
2005-06-25 Paul D. Smith <psmith@gnu.org>
+ * scripts/misc/general3: Test semicolons in variable references.
+ Tests fix for Savannah bug #1454.
+
* scripts/variables/MAKE_RESTARTS: New file: test the
MAKE_RESTARTS variable.
* scripts/options/dash-B: Test re-exec doesn't loop infinitely.
diff --git a/tests/scripts/misc/general3 b/tests/scripts/misc/general3
index 2421ed4..40b7ed9 100644
--- a/tests/scripts/misc/general3
+++ b/tests/scripts/misc/general3
@@ -5,13 +5,7 @@ This tests random features of the parser that need to be supported, and
which have either broken at some point in the past or seem likely to
break.";
-$makefile2 = &get_tmpfile;
-
-open(MAKEFILE,"> $makefile");
-
-# The contents of the Makefile ...
-
-print MAKEFILE <<EOF;
+run_make_test("
# We want to allow both empty commands _and_ commands that resolve to empty.
EMPTY =
@@ -31,20 +25,15 @@ TAB = \t \# A TAB and some spaces
\$(STR)
-\$(STR) \$(TAB)
-
-EOF
-
-close(MAKEFILE);
-
-&run_make_with_options($makefile,"",&get_logfile);
-$answer = "$make_name: Nothing to be done for `all'.\n";
-&compare_output($answer,&get_logfile(1));
-
+\$(STR) \$(TAB)",
+ '', "#MAKE#: Nothing to be done for `all'.");
# TEST 2
# Make sure files without trailing newlines are handled properly.
+# Have to use the old style invocation to test this.
+
+$makefile2 = &get_tmpfile;
open(MAKEFILE, "> $makefile2");
print MAKEFILE "all:;\@echo FOO = \$(FOO)\nFOO = foo";
@@ -54,5 +43,14 @@ close(MAKEFILE);
$answer = "FOO = foo\n";
&compare_output($answer,&get_logfile(1));
+# TEST 3
+
+# Check semicolons in variable references
+
+run_make_test('
+$(if true,$(info true; true))
+all: ; @:
+',
+ '', 'true; true');
1;