1# $NetBSD: varmod-subst.mk,v 1.14 2023/12/18 11:13:51 rillig Exp $ 2# 3# Tests for the :S,from,to, variable modifier. 4 5all: mod-subst 6all: mod-subst-delimiter 7all: mod-subst-chain 8all: mod-subst-dollar 9 10WORDS= sequences of letters 11 12# The empty pattern never matches anything, except if it is anchored at the 13# beginning or the end of the word. 14.if ${WORDS:S,,,} != ${WORDS} 15. error 16.endif 17 18# The :S modifier flag '1' is applied exactly once. 19.if ${WORDS:S,e,*,1} != "s*quences of letters" 20. error 21.endif 22 23# The :S modifier flag '1' is applied to the first occurrence, no matter if 24# the occurrence is in the first word or not. 25.if ${WORDS:S,f,*,1} != "sequences o* letters" 26. error 27.endif 28 29# The :S modifier replaces every first match per word. 30.if ${WORDS:S,e,*,} != "s*quences of l*tters" 31. error 32.endif 33 34# The :S modifier flag 'g' replaces every occurrence. 35.if ${WORDS:S,e,*,g} != "s*qu*nc*s of l*tt*rs" 36. error 37.endif 38 39# The '^' in the search pattern anchors the pattern at the beginning of each 40# word, thereby matching a prefix. 41.if ${WORDS:S,^sequ,occurr,} != "occurrences of letters" 42. error 43.endif 44 45# The :S modifier with a '^' anchor replaces the whole word if that word is 46# exactly the pattern. 47.if ${WORDS:S,^of,with,} != "sequences with letters" 48. error 49.endif 50 51# The :S modifier does not match if the pattern is longer than the word. 52.if ${WORDS:S,^office,does not match,} != ${WORDS} 53. warning 54.endif 55 56# The '$' in the search pattern anchors the pattern at the end of each word, 57# thereby matching a suffix. 58.if ${WORDS:S,f$,r,} != "sequences or letters" 59. error 60.endif 61 62# The :S modifier with a '$' anchor replaces at most one occurrence per word. 63.if ${WORDS:S,s$,,} != "sequence of letter" 64. error 65.endif 66 67# The :S modifier with a '$' anchor replaces the whole word if that word is 68# exactly the pattern. 69.if ${WORDS:S,of$,,} != "sequences letters" 70. error 71.endif 72 73# The :S modifier with a '$' anchor and a pattern that is longer than a word 74# cannot match that word. 75.if ${WORDS:S,eof$,,} != ${WORDS} 76. warning 77.endif 78 79# The :S modifier with the '^' and '$' anchors matches an exact word. 80.if ${WORDS:S,^of$,,} != "sequences letters" 81. error 82.endif 83 84# The :S modifier with the '^' and '$' anchors does not match a word that 85# starts with the pattern but is longer than the pattern. 86.if ${WORDS:S,^o$,,} != ${WORDS} 87. error 88.endif 89 90# The :S modifier with the '^' and '$' anchors does not match a word that ends 91# with the pattern but is longer than the pattern. 92.if ${WORDS:S,^f$,,} != ${WORDS} 93. error 94.endif 95 96# The :S modifier with the '^' and '$' anchors does not match a word if the 97# pattern ends with the word but is longer than the word. 98.if ${WORDS:S,^eof$,,} != ${WORDS} 99. error 100.endif 101 102# The :S modifier with the '^' and '$' anchors does not match a word if the 103# pattern starts with the word but is longer than the word. 104.if ${WORDS:S,^office$,,} != ${WORDS} 105. error 106.endif 107 108# Except for the '^' and '$' anchors, the pattern does not contain any special 109# characters, so the '*' from the pattern would only match a literal '*' in a 110# word. 111.if ${WORDS:S,*,replacement,} != ${WORDS} 112. error 113.endif 114 115# Except for the '^' and '$' anchors, the pattern does not contain any special 116# characters, so the '.' from the pattern would only match a literal '.' in a 117# word. 118.if ${WORDS:S,.,replacement,} != ${WORDS} 119. error 120.endif 121 122# The '&' in the replacement is a placeholder for the text matched by the 123# pattern. 124.if ${:Uvalue:S,^val,&,} != "value" 125. error 126.endif 127.if ${:Uvalue:S,ue$,&,} != "value" 128. error 129.endif 130.if ${:Uvalue:S,^val,&-&-&,} != "val-val-value" 131. error 132.endif 133.if ${:Uvalue:S,ue$,&-&-&,} != "value-ue-ue" 134. error 135.endif 136 137 138# When a word is replaced with nothing, the remaining words are separated by a 139# single space, not two. 140.if ${1 2 3:L:S,2,,} != "1 3" 141. error 142.endif 143 144 145# In an empty expression, the ':S' modifier matches a single time, but only if 146# the search string is empty and anchored at either the beginning or the end 147# of the word. 148.if ${:U:S,,out-of-nothing,} != "" 149. error 150.endif 151.if ${:U:S,^,out-of-nothing,} != "out-of-nothing" 152. error 153.endif 154.if ${:U:S,$,out-of-nothing,} != "out-of-nothing" 155. error 156.endif 157.if ${:U:S,^$,out-of-nothing,} != "out-of-nothing" 158. error 159.endif 160.if ${:U:S,,out-of-nothing,g} != "" 161. error 162.endif 163.if ${:U:S,^,out-of-nothing,g} != "out-of-nothing" 164. error 165.endif 166.if ${:U:S,$,out-of-nothing,g} != "out-of-nothing" 167. error 168.endif 169.if ${:U:S,^$,out-of-nothing,g} != "out-of-nothing" 170. error 171.endif 172.if ${:U:S,,out-of-nothing,W} != "" 173. error 174.endif 175.if ${:U:S,^,out-of-nothing,W} != "out-of-nothing" 176. error 177.endif 178.if ${:U:S,$,out-of-nothing,W} != "out-of-nothing" 179. error 180.endif 181.if ${:U:S,^$,out-of-nothing,W} != "out-of-nothing" 182. error 183.endif 184 185 186mod-subst: 187 @echo $@: 188 @echo :${:Ua b b c:S,a b,,:Q}: 189 @echo :${:Ua b b c:S,a b,,1:Q}: 190 @echo :${:Ua b b c:S,a b,,W:Q}: 191 @echo :${:Ua b b c:S,b,,g:Q}: 192 @echo :${:U1 2 3 1 2 3:S,1 2,___,Wg:S,_,x,:Q}: 193 @echo ${:U12345:S,,sep,g:Q} 194 195# The :S and :C modifiers accept an arbitrary character as the delimiter, 196# including characters that are otherwise used as escape characters or 197# interpreted in a special way. This can be used to confuse humans. 198mod-subst-delimiter: 199 @echo $@: 200 @echo ${:U1 2 3:S 2 two :Q} horizontal tabulator 201 @echo ${:U1 2 3:S 2 two :Q} space 202 @echo ${:U1 2 3:S!2!two!:Q} exclamation mark 203 @echo ${:U1 2 3:S"2"two":Q} quotation mark 204 # In shell command lines, the hash does not need to be escaped. 205 # It needs to be escaped in variable assignment lines though. 206 @echo ${:U1 2 3:S#2#two#:Q} number sign 207 @echo ${:U1 2 3:S$2$two$:Q} dollar sign 208 @echo ${:U1 2 3:S%2%two%:Q} percent sign 209 @echo ${:U1 2 3:S&2&two&:Q} ampersand 210 @echo ${:U1 2 3:S'2'two':Q} apostrophe 211 @echo ${:U1 2 3:S(2(two(:Q} left parenthesis 212 @echo ${:U1 2 3:S)2)two):Q} right parenthesis 213 @echo ${:U1 2 3:S*2*two*:Q} asterisk 214 @echo ${:U1 2 3:S+2+two+:Q} plus sign 215 @echo ${:U1 2 3:S,2,two,:Q} comma 216 @echo ${:U1 2 3:S-2-two-:Q} hyphen-minus 217 @echo ${:U1 2 3:S.2.two.:Q} full stop 218 @echo ${:U1 2 3:S/2/two/:Q} solidus 219 @echo ${:U1 2 3:S121two1:Q} digit 220 @echo ${:U1 2 3:S:2:two::Q} colon 221 @echo ${:U1 2 3:S;2;two;:Q} semicolon 222 @echo ${:U1 2 3:S<2<two<:Q} less-than sign 223 @echo ${:U1 2 3:S=2=two=:Q} equals sign 224 @echo ${:U1 2 3:S>2>two>:Q} greater-than sign 225 @echo ${:U1 2 3:S?2?two?:Q} question mark 226 @echo ${:U1 2 3:S@2@two@:Q} commercial at 227 @echo ${:U1 2 3:SA2AtwoA:Q} capital letter 228 @echo ${:U1 2 3:S[2[two[:Q} left square bracket 229 @echo ${:U1 2 3:S\2\two\:Q} reverse solidus 230 @echo ${:U1 2 3:S]2]two]:Q} right square bracket 231 @echo ${:U1 2 3:S^2^two^:Q} circumflex accent 232 @echo ${:U1 2 3:S_2_two_:Q} low line 233 @echo ${:U1 2 3:S`2`two`:Q} grave accent 234 @echo ${:U1 2 3:Sa2atwoa:Q} small letter 235 @echo ${:U1 2 3:S{2{two{:Q} left curly bracket 236 @echo ${:U1 2 3:S|2|two|:Q} vertical line 237 @echo ${:U1 2 3:S}2}two}:Q} right curly bracket 238 @echo ${:U1 2 3:S~2~two~:Q} tilde 239 240# The :S and :C modifiers can be chained without a separating ':'. 241# This is not documented in the manual page. 242# It works because ApplyModifier_Subst scans for the known modifiers g1W 243# and then just returns to ApplyModifiers. There, the colon is optionally 244# skipped (see the *st.next == ':' at the end of the loop). 245# 246# Most other modifiers cannot be chained since their parsers skip until 247# the next ':' or '}' or ')'. 248mod-subst-chain: 249 @echo $@: 250 @echo ${:Ua b c:S,a,A,S,b,B,}. 251 # There is no 'i' modifier for the :S or :C modifiers. 252 # The error message is "make: Unknown modifier 'i'", which is 253 # kind of correct, although it is mixing the terms for variable 254 # modifiers with the matching modifiers. 255 @echo ${:Uvalue:S,a,x,i}. 256 257# No matter how many dollar signs there are, they all get merged 258# into a single dollar by the :S modifier. 259# 260# As of 2020-08-09, this is because ParseModifierPart sees a '$' and 261# calls Var_Parse to expand the variable. In all other places, the "$$" 262# is handled outside of Var_Parse. Var_Parse therefore considers "$$" 263# one of the "really stupid names", skips the first dollar, and parsing 264# continues with the next character. This repeats for the other dollar 265# signs, except the one before the delimiter. That one is handled by 266# the code that optionally interprets the '$' as the end-anchor in the 267# first part of the :S modifier. That code doesn't call Var_Parse but 268# simply copies the dollar to the result. 269mod-subst-dollar: 270 @echo $@:${:U1:S,^,$,:Q}: 271 @echo $@:${:U2:S,^,$$,:Q}: 272 @echo $@:${:U3:S,^,$$$,:Q}: 273 @echo $@:${:U4:S,^,$$$$,:Q}: 274 @echo $@:${:U5:S,^,$$$$$,:Q}: 275 @echo $@:${:U6:S,^,$$$$$$,:Q}: 276 @echo $@:${:U7:S,^,$$$$$$$,:Q}: 277 @echo $@:${:U8:S,^,$$$$$$$$,:Q}: 278 @echo $@:${:U40:S,^,$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$,:Q}: 279# This generates no dollar at all: 280 @echo $@:${:UU8:S,^,${:U$$$$$$$$},:Q}: 281# Here is an alternative way to generate dollar signs. 282# It's unexpectedly complicated though. 283 @echo $@:${:U:range=5:ts\x24:C,[0-9],,g:Q}: 284# In modifiers, dollars are escaped using the backslash, not using another 285# dollar sign. Therefore, creating a dollar sign is pretty simple: 286 @echo $@:${:Ugood3:S,^,\$\$\$,:Q} 287