2012-03-04 Paul Smith * read.c (unescape_char): New function to remove escapes from a char. (record_files): Call it on the dependency string to unescape ":". Fixes Savannah bug #12126 and bug #16545. * tests/scripts/features/se_explicit: Test $(x:%=%) format in secondary expansion prerequisite lists. See Savannah bug #16545. * tests/scripts/features/escape: Test escaped ":" in prerequisite lists. See Savannah bug #12126. --- a/read.c +++ b/read.c @@ -156,6 +156,7 @@ static enum make_word_type get_next_mword (char *buffer, char *delim, static void remove_comments (char *line); static char *find_char_unquote (char *string, int stop1, int stop2, int blank, int ignorevars); +static char *unescape_char (char *string, int c); /* Compare a word, both length and contents. @@ -1872,24 +1873,28 @@ record_files (struct nameseq *filenames, const char *pattern, expansion: if so, snap_deps() will do it. */ if (depstr == 0) deps = 0; - else if (second_expansion && strchr (depstr, '$')) - { - deps = alloc_dep (); - deps->name = depstr; - deps->need_2nd_expansion = 1; - deps->staticpattern = pattern != 0; - } else { - deps = split_prereqs (depstr); - free (depstr); - - /* We'll enter static pattern prereqs later when we have the stem. We - don't want to enter pattern rules at all so that we don't think that - they ought to exist (make manual "Implicit Rule Search Algorithm", - item 5c). */ - if (! pattern && ! implicit_percent) - deps = enter_prereqs (deps, NULL); + depstr = unescape_char (depstr, ':'); + if (second_expansion && strchr (depstr, '$')) + { + deps = alloc_dep (); + deps->name = depstr; + deps->need_2nd_expansion = 1; + deps->staticpattern = pattern != 0; + } + else + { + deps = split_prereqs (depstr); + free (depstr); + + /* We'll enter static pattern prereqs later when we have the stem. + We don't want to enter pattern rules at all so that we don't + think that they ought to exist (make manual "Implicit Rule Search + Algorithm", item 5c). */ + if (! pattern && ! implicit_percent) + deps = enter_prereqs (deps, NULL); + } } /* For implicit rules, _all_ the targets must have a pattern. That means we @@ -2211,6 +2216,46 @@ find_char_unquote (char *string, int stop1, int stop2, int blank, return 0; } +/* Unescape a character in a string. The string is compressed onto itself. */ + +static char * +unescape_char (char *string, int c) +{ + char *p = string; + char *s = string; + + while (*s != '\0') + { + if (*s == '\\') + { + char *e = s; + int l; + + /* We found a backslash. See if it's escaping our character. */ + while (*e == '\\') + ++e; + l = e - s; + + if (*e != c || l%2 == 0) + /* It's not; just take it all without unescaping. */ + memcpy (p, s, l); + else if (l > 1) + { + /* It is, and there's >1 backslash. Take half of them. */ + l /= 2; + memcpy (p, s, l); + p += l; + } + s = e; + } + + *(p++) = *(s++); + } + + *p = '\0'; + return string; +} + /* Search PATTERN for an unquoted % and handle quoting. */ char * --- a/tests/scripts/features/escape +++ b/tests/scripts/features/escape @@ -54,5 +54,13 @@ run_make_test(undef, 'sharp', 'foo#bar.ext = (foo#bar.ext)'); +# Test escaped colons in prerequisites +# Quoting of backslashes in q!! is kind of messy. +run_make_test(q! +foo: foo\\:bar foo\\\\\\:bar foo\\\\\\\\\\:bar +foo foo\\:bar foo\\\\\\:bar foo\\\\\\\\\\:bar: ; @echo '$@' +!, + '', "foo:bar\nfoo\\:bar\nfoo\\\\:bar\nfoo\n"); + # This tells the test driver that the perl test script executed properly. 1; --- a/tests/scripts/features/se_explicit +++ b/tests/scripts/features/se_explicit @@ -152,5 +152,13 @@ a%l: q1x $$+ q2x ; @echo '$+' '', "q1x bar bar q2x bar bar\n"); -# This tells the test driver that the perl test script executed properly. +# Allow patsubst shorthand in second expansion context. +# Requires the colon to be quoted. Savannah bug #16545 +run_make_test(q! +.PHONY: foo.bar +.SECONDEXPANSION: +foo: $$(@\\:%=%.bar); @echo '$^' +!, + '', "foo.bar\n"); + 1;