diff options
author | Paul Smith <psmith@gnu.org> | 2005-06-25 21:30:13 +0000 |
---|---|---|
committer | Paul Smith <psmith@gnu.org> | 2005-06-25 21:30:13 +0000 |
commit | 6cdaff0948bbec3220d5cb071f79d5f2e1c9b083 (patch) | |
tree | 407efa2f97b6dfb472fb96396d6fa73892f38a97 | |
parent | 1dd9ed1c0537cb2583e1de8367994560ad1470aa (diff) | |
download | gunmake-6cdaff0948bbec3220d5cb071f79d5f2e1c9b083.tar.gz |
Fix Savannah bug #1454: skip over semicolons (and comments) inside variable
references in target definition lines.
-rw-r--r-- | ChangeLog | 13 | ||||
-rw-r--r-- | make.h | 2 | ||||
-rw-r--r-- | misc.c | 16 | ||||
-rw-r--r-- | read.c | 95 | ||||
-rw-r--r-- | tests/ChangeLog | 3 | ||||
-rw-r--r-- | tests/scripts/misc/general3 | 32 |
6 files changed, 108 insertions, 53 deletions
@@ -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. @@ -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 *)); @@ -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). */ @@ -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; |