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