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