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