Sun Jul 26 12:18:12 2020 UTC ()
make(1): demonstrate bug in the :S modifier with the 1 modifier

The bug has been introduced in var.c r1.268 on 2020-07-19.


(rillig)
diff -r1.23 -r1.24 src/usr.bin/make/unit-tests/modmisc.mk

cvs diff -r1.23 -r1.24 src/usr.bin/make/unit-tests/modmisc.mk (switch to unified diff)

--- src/usr.bin/make/unit-tests/modmisc.mk 2020/07/26 11:39:55 1.23
+++ src/usr.bin/make/unit-tests/modmisc.mk 2020/07/26 12:18:11 1.24
@@ -1,194 +1,215 @@ @@ -1,194 +1,215 @@
1# $Id: modmisc.mk,v 1.23 2020/07/26 11:39:55 rillig Exp $ 1# $Id: modmisc.mk,v 1.24 2020/07/26 12:18:11 rillig Exp $
2# 2#
3# miscellaneous modifier tests 3# miscellaneous modifier tests
4 4
5# do not put any dirs in this list which exist on some 5# do not put any dirs in this list which exist on some
6# but not all target systems - an exists() check is below. 6# but not all target systems - an exists() check is below.
7path=:/bin:/tmp::/:.:/no/such/dir:. 7path=:/bin:/tmp::/:.:/no/such/dir:.
8# strip cwd from path. 8# strip cwd from path.
9MOD_NODOT=S/:/ /g:N.:ts: 9MOD_NODOT=S/:/ /g:N.:ts:
10# and decorate, note that $'s need to be doubled. Also note that  10# and decorate, note that $'s need to be doubled. Also note that
11# the modifier_variable can be used with other modifiers. 11# the modifier_variable can be used with other modifiers.
12MOD_NODOTX=S/:/ /g:N.:@d@'$$d'@ 12MOD_NODOTX=S/:/ /g:N.:@d@'$$d'@
13# another mod - pretend it is more interesting 13# another mod - pretend it is more interesting
14MOD_HOMES=S,/home/,/homes/, 14MOD_HOMES=S,/home/,/homes/,
15MOD_OPT=@d@$${exists($$d):?$$d:$${d:S,/usr,/opt,}}@ 15MOD_OPT=@d@$${exists($$d):?$$d:$${d:S,/usr,/opt,}}@
16MOD_SEP=S,:, ,g 16MOD_SEP=S,:, ,g
17 17
18all: modvar modvarloop modsysv mod-HTE emptyvar undefvar 18all: modvar modvarloop modsysv mod-HTE emptyvar undefvar
19all: mod-subst 19all: mod-subst
20all: mod-regex 20all: mod-regex
21all: mod-loop-varname mod-loop-resolve mod-loop-varname-dollar 21all: mod-loop-varname mod-loop-resolve mod-loop-varname-dollar
22all: mod-subst-dollar mod-loop-dollar 22all: mod-subst-dollar mod-loop-dollar
23all: mod-regex-limits 23all: mod-regex-limits
24all: mod-regex-errors 24all: mod-regex-errors
25all: mod-assign 25all: mod-assign
26all: mod-assign-nested 26all: mod-assign-nested
27all: mod-tu-space 27all: mod-tu-space
28all: mod-quote 28all: mod-quote
29all: mod-break-many-words 29all: mod-break-many-words
30 30
31# See also sysv.mk. 31# See also sysv.mk.
32modsysv: 32modsysv:
33 @echo "The answer is ${libfoo.a:L:libfoo.a=42}" 33 @echo "The answer is ${libfoo.a:L:libfoo.a=42}"
34 34
35# Demonstrates modifiers that are given indirectly from a variable. 35# Demonstrates modifiers that are given indirectly from a variable.
36modvar: 36modvar:
37 @echo "path='${path}'" 37 @echo "path='${path}'"
38 @echo "path='${path:${MOD_NODOT}}'" 38 @echo "path='${path:${MOD_NODOT}}'"
39 @echo "path='${path:S,home,homes,:${MOD_NODOT}}'" 39 @echo "path='${path:S,home,homes,:${MOD_NODOT}}'"
40 @echo "path=${path:${MOD_NODOTX}:ts:}" 40 @echo "path=${path:${MOD_NODOTX}:ts:}"
41 @echo "path=${path:${MOD_HOMES}:${MOD_NODOTX}:ts:}" 41 @echo "path=${path:${MOD_HOMES}:${MOD_NODOTX}:ts:}"
42 42
43.for d in ${path:${MOD_SEP}:N.} /usr/xbin 43.for d in ${path:${MOD_SEP}:N.} /usr/xbin
44path_$d?= ${d:${MOD_OPT}:${MOD_HOMES}}/ 44path_$d?= ${d:${MOD_OPT}:${MOD_HOMES}}/
45paths+= ${d:${MOD_OPT}:${MOD_HOMES}} 45paths+= ${d:${MOD_OPT}:${MOD_HOMES}}
46.endfor 46.endfor
47 47
48modvarloop: 48modvarloop:
49 @echo "path_/usr/xbin=${path_/usr/xbin}" 49 @echo "path_/usr/xbin=${path_/usr/xbin}"
50 @echo "paths=${paths}" 50 @echo "paths=${paths}"
51 @echo "PATHS=${paths:tu}" 51 @echo "PATHS=${paths:tu}"
52 52
53PATHNAMES= a/b/c def a.b.c a.b/c a a.a .gitignore a a.a 53PATHNAMES= a/b/c def a.b.c a.b/c a a.a .gitignore a a.a
54mod-HTE: 54mod-HTE:
55 @echo "dirname of '"${PATHNAMES:Q}"' is '"${PATHNAMES:H:Q}"'" 55 @echo "dirname of '"${PATHNAMES:Q}"' is '"${PATHNAMES:H:Q}"'"
56 @echo "basename of '"${PATHNAMES:Q}"' is '"${PATHNAMES:T:Q}"'" 56 @echo "basename of '"${PATHNAMES:Q}"' is '"${PATHNAMES:T:Q}"'"
57 @echo "suffix of '"${PATHNAMES:Q}"' is '"${PATHNAMES:E:Q}"'" 57 @echo "suffix of '"${PATHNAMES:Q}"' is '"${PATHNAMES:E:Q}"'"
58 @echo "root of '"${PATHNAMES:Q}"' is '"${PATHNAMES:R:Q}"'" 58 @echo "root of '"${PATHNAMES:Q}"' is '"${PATHNAMES:R:Q}"'"
59 59
60# When a modifier is applied to the "" variable, the result is discarded. 60# When a modifier is applied to the "" variable, the result is discarded.
61emptyvar: 61emptyvar:
62 @echo S:${:S,^$,empty,} 62 @echo S:${:S,^$,empty,}
63 @echo C:${:C,^$,empty,} 63 @echo C:${:C,^$,empty,}
64 @echo @:${:@var@${var}@} 64 @echo @:${:@var@${var}@}
65 65
66# The :U modifier turns even the "" variable into something that has a value. 66# The :U modifier turns even the "" variable into something that has a value.
67# The resulting variable is empty, but is still considered to contain a 67# The resulting variable is empty, but is still considered to contain a
68# single empty word. This word can be accessed by the :S and :C modifiers, 68# single empty word. This word can be accessed by the :S and :C modifiers,
69# but not by the :@ modifier since it explicitly skips empty words. 69# but not by the :@ modifier since it explicitly skips empty words.
70undefvar: 70undefvar:
71 @echo S:${:U:S,^$,empty,} 71 @echo S:${:U:S,^$,empty,}
72 @echo C:${:U:C,^$,empty,} 72 @echo C:${:U:C,^$,empty,}
73 @echo @:${:U:@var@empty@} 73 @echo @:${:U:@var@empty@}
74 74
 75WORDS= sequences of letters
 76# FIXME: The "*" in "letters" must not be substituted because of the 1.
 77.if ${WORDS:S,e,*,1} != "s*quences of l*tters"
 78.warning ${WORDS:S,e,*,1}
 79.endif
 80.if ${WORDS:S,e,*,} != "s*quences of l*tters"
 81.error oops
 82.endif
 83.if ${WORDS:S,e,*,g} != "s*qu*nc*s of l*tt*rs"
 84.error oops
 85.endif
 86.if ${WORDS:S,^sequ,occurr,} != "occurrences of letters"
 87.error oops
 88.endif
 89.if ${WORDS:S,^of,with,} != "sequences with letters"
 90.error oops
 91.endif
 92.if ${WORDS:S,^office,does not match,} != ${WORDS}
 93.error oops
 94.endif
 95
75mod-subst: 96mod-subst:
76 @echo $@: 97 @echo $@:
77 @echo :${:Ua b b c:S,a b,,:Q}: 98 @echo :${:Ua b b c:S,a b,,:Q}:
78 @echo :${:Ua b b c:S,a b,,1:Q}: 99 @echo :${:Ua b b c:S,a b,,1:Q}:
79 @echo :${:Ua b b c:S,a b,,W:Q}: 100 @echo :${:Ua b b c:S,a b,,W:Q}:
80 @echo :${:Ua b b c:S,b,,g:Q}: 101 @echo :${:Ua b b c:S,b,,g:Q}:
81 @echo :${:U1 2 3 1 2 3:S,1 2,___,Wg:S,_,x,:Q}: 102 @echo :${:U1 2 3 1 2 3:S,1 2,___,Wg:S,_,x,:Q}:
82 @echo ${:U12345:S,,sep,g:Q} 103 @echo ${:U12345:S,,sep,g:Q}
83 104
84mod-regex: 105mod-regex:
85 @echo $@: 106 @echo $@:
86 @echo :${:Ua b b c:C,a b,,:Q}: 107 @echo :${:Ua b b c:C,a b,,:Q}:
87 @echo :${:Ua b b c:C,a b,,1:Q}: 108 @echo :${:Ua b b c:C,a b,,1:Q}:
88 @echo :${:Ua b b c:C,a b,,W:Q}: 109 @echo :${:Ua b b c:C,a b,,W:Q}:
89 @echo :${:Uword1 word2:C,****,____,g:C,word,____,:Q}: 110 @echo :${:Uword1 word2:C,****,____,g:C,word,____,:Q}:
90 @echo :${:Ua b b c:C,b,,g:Q}: 111 @echo :${:Ua b b c:C,b,,g:Q}:
91 @echo :${:U1 2 3 1 2 3:C,1 2,___,Wg:C,_,x,:Q}: 112 @echo :${:U1 2 3 1 2 3:C,1 2,___,Wg:C,_,x,:Q}:
92 113
93# In the :@ modifier, the name of the loop variable can even be generated 114# In the :@ modifier, the name of the loop variable can even be generated
94# dynamically. There's no practical use-case for this, and hopefully nobody 115# dynamically. There's no practical use-case for this, and hopefully nobody
95# will ever depend on this, but technically it's possible. 116# will ever depend on this, but technically it's possible.
96mod-loop-varname: 117mod-loop-varname:
97 @echo :${:Uone two three:@${:Ubar:S,b,v,}@+${var}+@:Q}: 118 @echo :${:Uone two three:@${:Ubar:S,b,v,}@+${var}+@:Q}:
98 119
99# The :@ modifier resolves the variables a little more often than expected. 120# The :@ modifier resolves the variables a little more often than expected.
100# In particular, it resolves _all_ variables from the context, and not only 121# In particular, it resolves _all_ variables from the context, and not only
101# the loop variable (in this case v). 122# the loop variable (in this case v).
102# 123#
103# The d means direct reference, the i means indirect reference. 124# The d means direct reference, the i means indirect reference.
104RESOLVE= ${RES1} $${RES1} 125RESOLVE= ${RES1} $${RES1}
105RES1= 1d${RES2} 1i$${RES2} 126RES1= 1d${RES2} 1i$${RES2}
106RES2= 2d${RES3} 2i$${RES3} 127RES2= 2d${RES3} 2i$${RES3}
107RES3= 3 128RES3= 3
108 129
109mod-loop-resolve: 130mod-loop-resolve:
110 @echo $@:${RESOLVE:@v@w${v}w@:Q}: 131 @echo $@:${RESOLVE:@v@w${v}w@:Q}:
111 132
112# Until 2020-07-20, the variable name of the :@ modifier could end with one 133# Until 2020-07-20, the variable name of the :@ modifier could end with one
113# or two dollar signs, which were silently ignored. 134# or two dollar signs, which were silently ignored.
114# There's no point in allowing a dollar sign in that position. 135# There's no point in allowing a dollar sign in that position.
115mod-loop-varname-dollar: 136mod-loop-varname-dollar:
116 @echo $@:${1 2 3:L:@v$@($v)@:Q}. 137 @echo $@:${1 2 3:L:@v$@($v)@:Q}.
117 @echo $@:${1 2 3:L:@v$$@($v)@:Q}. 138 @echo $@:${1 2 3:L:@v$$@($v)@:Q}.
118 @echo $@:${1 2 3:L:@v$$$@($v)@:Q}. 139 @echo $@:${1 2 3:L:@v$$$@($v)@:Q}.
119 140
120# No matter how many dollar characters there are, they all get merged 141# No matter how many dollar characters there are, they all get merged
121# into a single dollar by the :S modifier. 142# into a single dollar by the :S modifier.
122mod-subst-dollar: 143mod-subst-dollar:
123 @echo $@:${:U1:S,^,$,:Q}: 144 @echo $@:${:U1:S,^,$,:Q}:
124 @echo $@:${:U2:S,^,$$,:Q}: 145 @echo $@:${:U2:S,^,$$,:Q}:
125 @echo $@:${:U3:S,^,$$$,:Q}: 146 @echo $@:${:U3:S,^,$$$,:Q}:
126 @echo $@:${:U4:S,^,$$$$,:Q}: 147 @echo $@:${:U4:S,^,$$$$,:Q}:
127 @echo $@:${:U5:S,^,$$$$$,:Q}: 148 @echo $@:${:U5:S,^,$$$$$,:Q}:
128 @echo $@:${:U6:S,^,$$$$$$,:Q}: 149 @echo $@:${:U6:S,^,$$$$$$,:Q}:
129 @echo $@:${:U7:S,^,$$$$$$$,:Q}: 150 @echo $@:${:U7:S,^,$$$$$$$,:Q}:
130 @echo $@:${:U8:S,^,$$$$$$$$,:Q}: 151 @echo $@:${:U8:S,^,$$$$$$$$,:Q}:
131# This generates no dollar at all: 152# This generates no dollar at all:
132 @echo $@:${:UU8:S,^,${:U$$$$$$$$},:Q}: 153 @echo $@:${:UU8:S,^,${:U$$$$$$$$},:Q}:
133# Here is an alternative way to generate dollar characters. 154# Here is an alternative way to generate dollar characters.
134# It's unexpectedly complicated though. 155# It's unexpectedly complicated though.
135 @echo $@:${:U:range=5:ts\x24:C,[0-9],,g:Q}: 156 @echo $@:${:U:range=5:ts\x24:C,[0-9],,g:Q}:
136 157
137# Demonstrate that it is possible to generate dollar characters using the 158# Demonstrate that it is possible to generate dollar characters using the
138# :@ modifier. 159# :@ modifier.
139# 160#
140# These are edge cases that could have resulted in a parse error as well 161# These are edge cases that could have resulted in a parse error as well
141# since the $@ at the end could have been interpreted as a variable, which 162# since the $@ at the end could have been interpreted as a variable, which
142# would mean a missing closing @ delimiter. 163# would mean a missing closing @ delimiter.
143mod-loop-dollar: 164mod-loop-dollar:
144 @echo $@:${:U1:@word@${word}$@:Q}: 165 @echo $@:${:U1:@word@${word}$@:Q}:
145 @echo $@:${:U2:@word@$${word}$$@:Q}: 166 @echo $@:${:U2:@word@$${word}$$@:Q}:
146 @echo $@:${:U3:@word@$$${word}$$$@:Q}: 167 @echo $@:${:U3:@word@$$${word}$$$@:Q}:
147 @echo $@:${:U4:@word@$$$${word}$$$$@:Q}: 168 @echo $@:${:U4:@word@$$$${word}$$$$@:Q}:
148 @echo $@:${:U5:@word@$$$$${word}$$$$$@:Q}: 169 @echo $@:${:U5:@word@$$$$${word}$$$$$@:Q}:
149 @echo $@:${:U6:@word@$$$$$${word}$$$$$$@:Q}: 170 @echo $@:${:U6:@word@$$$$$${word}$$$$$$@:Q}:
150 171
151mod-regex-limits: 172mod-regex-limits:
152 @echo $@:00-ok:${:U1 23 456:C,..,\0\0,:Q} 173 @echo $@:00-ok:${:U1 23 456:C,..,\0\0,:Q}
153 @echo $@:11-missing:${:U1 23 456:C,..,\1\1,:Q} 174 @echo $@:11-missing:${:U1 23 456:C,..,\1\1,:Q}
154 @echo $@:11-ok:${:U1 23 456:C,(.).,\1\1,:Q} 175 @echo $@:11-ok:${:U1 23 456:C,(.).,\1\1,:Q}
155 @echo $@:22-missing:${:U1 23 456:C,..,\2\2,:Q} 176 @echo $@:22-missing:${:U1 23 456:C,..,\2\2,:Q}
156 @echo $@:22-missing:${:U1 23 456:C,(.).,\2\2,:Q} 177 @echo $@:22-missing:${:U1 23 456:C,(.).,\2\2,:Q}
157 @echo $@:22-ok:${:U1 23 456:C,(.)(.),\2\2,:Q} 178 @echo $@:22-ok:${:U1 23 456:C,(.)(.),\2\2,:Q}
158 # The :C modifier only handles single-digit capturing groups, 179 # The :C modifier only handles single-digit capturing groups,
159 # which is more than enough for daily use. 180 # which is more than enough for daily use.
160 @echo $@:capture:${:UabcdefghijABCDEFGHIJrest:C,(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.),\9\8\7\6\5\4\3\2\1\0\10\11\12,} 181 @echo $@:capture:${:UabcdefghijABCDEFGHIJrest:C,(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.),\9\8\7\6\5\4\3\2\1\0\10\11\12,}
161 182
162mod-regex-errors: 183mod-regex-errors:
163 @echo $@: ${UNDEF:Uvalue:C,[,,} 184 @echo $@: ${UNDEF:Uvalue:C,[,,}
164 185
165# Just a bit of basic code coverage for the obscure ::= assignment modifiers. 186# Just a bit of basic code coverage for the obscure ::= assignment modifiers.
166mod-assign: 187mod-assign:
167 @echo $@: ${1 2 3:L:@i@${FIRST::?=$i}@} first=${FIRST}. 188 @echo $@: ${1 2 3:L:@i@${FIRST::?=$i}@} first=${FIRST}.
168 @echo $@: ${1 2 3:L:@i@${LAST::=$i}@} last=${LAST}. 189 @echo $@: ${1 2 3:L:@i@${LAST::=$i}@} last=${LAST}.
169 @echo $@: ${1 2 3:L:@i@${APPENDED::+=$i}@} appended=${APPENDED}. 190 @echo $@: ${1 2 3:L:@i@${APPENDED::+=$i}@} appended=${APPENDED}.
170 @echo $@: ${echo.1 echo.2 echo.3:L:@i@${RAN::!=${i:C,.*,&; & 1>\&2,:S,., ,g}}@} ran:${RAN}. 191 @echo $@: ${echo.1 echo.2 echo.3:L:@i@${RAN::!=${i:C,.*,&; & 1>\&2,:S,., ,g}}@} ran:${RAN}.
171 # The assignments happen in the global scope and thus are 192 # The assignments happen in the global scope and thus are
172 # preserved even after the shell command has been run. 193 # preserved even after the shell command has been run.
173 @echo $@: global: ${FIRST:Q}, ${LAST:Q}, ${APPENDED:Q}, ${RAN:Q}. 194 @echo $@: global: ${FIRST:Q}, ${LAST:Q}, ${APPENDED:Q}, ${RAN:Q}.
174 195
175mod-assign-nested: 196mod-assign-nested:
176 @echo $@: ${1:?${THEN1::=then1${IT1::=t1}}:${ELSE1::=else1${IE1::=e1}}}${THEN1}${ELSE1}${IT1}${IE1} 197 @echo $@: ${1:?${THEN1::=then1${IT1::=t1}}:${ELSE1::=else1${IE1::=e1}}}${THEN1}${ELSE1}${IT1}${IE1}
177 @echo $@: ${0:?${THEN2::=then2${IT2::=t2}}:${ELSE2::=else2${IE2::=e2}}}${THEN2}${ELSE2}${IT2}${IE2} 198 @echo $@: ${0:?${THEN2::=then2${IT2::=t2}}:${ELSE2::=else2${IE2::=e2}}}${THEN2}${ELSE2}${IT2}${IE2}
178 @echo $@: ${SINK3:Q} 199 @echo $@: ${SINK3:Q}
179 @echo $@: ${SINK4:Q} 200 @echo $@: ${SINK4:Q}
180SINK3:= ${1:?${THEN3::=then3${IT3::=t3}}:${ELSE3::=else3${IE3::=e3}}}${THEN3}${ELSE3}${IT3}${IE3} 201SINK3:= ${1:?${THEN3::=then3${IT3::=t3}}:${ELSE3::=else3${IE3::=e3}}}${THEN3}${ELSE3}${IT3}${IE3}
181SINK4:= ${0:?${THEN4::=then4${IT4::=t4}}:${ELSE4::=else4${IE4::=e4}}}${THEN4}${ELSE4}${IT4}${IE4} 202SINK4:= ${0:?${THEN4::=then4${IT4::=t4}}:${ELSE4::=else4${IE4::=e4}}}${THEN4}${ELSE4}${IT4}${IE4}
182 203
183mod-tu-space: 204mod-tu-space:
184 # The :tu and :tl modifiers operate on the variable value 205 # The :tu and :tl modifiers operate on the variable value
185 # as a single string, not as a list of words. Therefore, 206 # as a single string, not as a list of words. Therefore,
186 # the adjacent spaces are preserved. 207 # the adjacent spaces are preserved.
187 @echo $@: ${a b:L:tu:Q} 208 @echo $@: ${a b:L:tu:Q}
188 209
189mod-quote: 210mod-quote:
190 @echo $@: new${.newline:Q}${.newline:Q}line 211 @echo $@: new${.newline:Q}${.newline:Q}line
191 212
192# Cover the bmake_realloc in brk_string. 213# Cover the bmake_realloc in brk_string.
193mod-break-many-words: 214mod-break-many-words:
194 @echo $@: ${UNDEF:U:range=500:[#]} 215 @echo $@: ${UNDEF:U:range=500:[#]}