gnezdo noticed that :S/old_string/new_string/ modifiers such as
:S/^sth/&/ and :S/sth$/&/ with an anchor in the old_string and an &
in the new_string don't work as documented (and expected) since they
replace & with old_string including the anchors.

This is because get_spatternarg() deals with skipping the anchors in
pattern->lhs only after having replaced any '&' in new_string with
pattern->lhs.  This happens in VarGetPattern if the last argument is
non-NULL when pattern->rhs is determined, i.e., before
common_get_patternarg() is done.

I think the fix should be as simple as the diff below.  I added a small
extension of a regress test for this.  Unpatched make fails, patched
make passes.

Simple test case that illustrates the problem:

$ cat > makefile
A= foo bar barr
B= ${A:S/^b/s&/}
C= ${A:S/r$/&/}
D= ${A:S/^bar$/&&ian/}

all:
        @echo "B= $B"
        @echo "C= $C"
        @echo "D= $D"
EOF
$ make
B= foo s^bar s^barr
C= foo bar$ barr$
D= foo ^bar$bar barr

I'm not entirely clear on why I get that result for D, but with the
patch below, I get the expected " foo barbarian barr"

Index: usr.bin/make/varmodifiers.c
===================================================================
RCS file: /var/cvs/src/usr.bin/make/varmodifiers.c,v
retrieving revision 1.47
diff -u -p -r1.47 varmodifiers.c
--- usr.bin/make/varmodifiers.c 10 Jul 2017 07:10:29 -0000      1.47
+++ usr.bin/make/varmodifiers.c 20 Aug 2020 16:03:54 -0000
@@ -1215,21 +1215,7 @@ get_patternarg(const char **p, SymTable 
 static void *
 get_spatternarg(const char **p, SymTable *ctxt, bool err, int endc)
 {
-       VarPattern *pattern;
-
-       pattern = common_get_patternarg(p, ctxt, err, endc, true);
-       if (pattern != NULL && pattern->leftLen > 0) {
-               if (pattern->lhs[pattern->leftLen-1] == '$') {
-                           pattern->leftLen--;
-                           pattern->flags |= VAR_MATCH_END;
-               }
-               if (pattern->lhs[0] == '^') {
-                           pattern->lhs++;
-                           pattern->leftLen--;
-                           pattern->flags |= VAR_MATCH_START;
-               }
-       }
-       return pattern;
+       return common_get_patternarg(p, ctxt, err, endc, true);
 }
 
 static void
@@ -1304,6 +1290,17 @@ common_get_patternarg(const char **p, Sy
            &pattern->leftLen, NULL);
        pattern->lbuffer = pattern->lhs;
        if (pattern->lhs != NULL) {
+               if (dosubst && pattern->leftLen > 0) {
+                       if (pattern->lhs[pattern->leftLen-1] == '$') {
+                                   pattern->leftLen--;
+                                   pattern->flags |= VAR_MATCH_END;
+                       }
+                       if (pattern->lhs[0] == '^') {
+                                   pattern->lhs++;
+                                   pattern->leftLen--;
+                                   pattern->flags |= VAR_MATCH_START;
+                       }
+               }
                pattern->rhs = VarGetPattern(ctxt, err, &s, delim, delim,
                    &pattern->rightLen, dosubst ? pattern: NULL);
                if (pattern->rhs != NULL) {
Index: regress/usr.bin/make/mk21
===================================================================
RCS file: /var/cvs/src/regress/usr.bin/make/mk21,v
retrieving revision 1.2
diff -u -p -r1.2 mk21
--- regress/usr.bin/make/mk21   7 Jul 2017 16:31:37 -0000       1.2
+++ regress/usr.bin/make/mk21   20 Aug 2020 16:20:31 -0000
@@ -12,7 +12,13 @@ X?=        ${TRUC:C@([^:/])/.+$@\1/@}
 Y?=        ${TRUC:S/^${X}//:S/^://}
 Z?=        ${TRUC:S/^${TRUC:C@([^:/])/.+$@\1/@}//:S/^://}
 
+A?=    machin truc
+B?=    ${A:S/^/mot: &/}
+C?=    ${A:S/$/&: mot/}
+
 all:
+       @echo "B= $B"
+       @echo "C= $C"
        @echo "S= $S"
        @echo "T= $T"
        @echo "X= $X"
Index: regress/usr.bin/make/t21.out
===================================================================
RCS file: /var/cvs/src/regress/usr.bin/make/t21.out,v
retrieving revision 1.2
diff -u -p -r1.2 t21.out
--- regress/usr.bin/make/t21.out        7 Jul 2017 16:31:37 -0000       1.2
+++ regress/usr.bin/make/t21.out        20 Aug 2020 16:20:31 -0000
@@ -1,3 +1,5 @@
+B= mot: machin mot: truc
+C= machin: mot truc: mot
 S= sourceforge/%SUBDIR%/
 T= sourceforge/%SUBDIR%/
 X= http://heanet.dl.sourceforge.net/

Reply via email to