mirror of
https://salsa.debian.org/srivasta/make-dfsg.git
synced 2025-01-30 00:12:51 +00:00
Fix Savannah bug #1454: skip over semicolons (and comments) inside variable
references in target definition lines.
This commit is contained in:
parent
1dd9ed1c05
commit
6cdaff0948
6 changed files with 108 additions and 53 deletions
13
ChangeLog
13
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.
|
||||
|
||||
|
|
2
make.h
2
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 *));
|
||||
|
||||
|
|
16
misc.c
16
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). */
|
||||
|
||||
|
|
95
read.c
95
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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue