Fix Savannah bug #1454: skip over semicolons (and comments) inside variable

references in target definition lines.
This commit is contained in:
Paul Smith 2005-06-25 21:30:13 +00:00
parent 1dd9ed1c05
commit 6cdaff0948
6 changed files with 108 additions and 53 deletions

View file

@ -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.

2
make.h
View file

@ -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 *));

16
misc.c
View file

@ -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). */

95
read.c
View file

@ -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);

View file

@ -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.

View file

@ -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;