aboutsummaryrefslogtreecommitdiff
path: root/contrib/bmake/unit-tests/varmod-sysv.mk
blob: 712c1731717bb1e94d5e9e27dadf9c4cc02aceb5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
# $NetBSD: varmod-sysv.mk,v 1.14 2021/04/12 16:09:57 rillig Exp $
#
# Tests for the variable modifier ':from=to', which replaces the suffix
# "from" with "to".  It can also use '%' as a wildcard.
#
# This modifier is applied when the other modifiers don't match exactly.
#
# See ApplyModifier_SysV.

# A typical use case for the modifier ':from=to' is conversion of filename
# extensions.
.if ${src.c:L:.c=.o} != "src.o"
.  error
.endif

# The modifier applies to each word on its own.
.if ${one.c two.c three.c:L:.c=.o} != "one.o two.o three.o"
.  error
.endif

# Words that don't match the pattern are passed unmodified.
.if ${src.c src.h:L:.c=.o} != "src.o src.h"
.  error
.endif

# The modifier ':from=to' is therefore often combined with the modifier ':M'.
.if ${src.c src.h:L:M*.c:.c=.o} != "src.o"
.  error
.endif

# Another use case for the modifier ':from=to' is to append a suffix to each
# word.  In this case, the "from" string is empty, therefore it always
# matches.  The same effect can be achieved with the modifier ':S,$,teen,'.
.if ${four six seven nine:L:=teen} != "fourteen sixteen seventeen nineteen"
.  error
.endif

# The modifier ':from=to' can also be used to surround each word by strings.
# It might be tempting to use this for enclosing a string in quotes for the
# shell, but that's the job of the modifier ':Q'.
.if ${one two three:L:%=(%)} != "(one) (two) (three)"
.  error
.endif

# When the modifier ':from=to' is parsed, it lasts until the closing brace
# or parenthesis.  The ':Q' in the below expression may look like a modifier
# but it isn't.  It is part of the replacement string.
.if ${a b c d e:L:%a=x:Q} != "x:Q b c d e"
.  error
.endif

# In the modifier ':from=to', both parts can contain variable expressions.
.if ${one two:L:${:Uone}=${:U1}} != "1 two"
.  error
.endif

# In the modifier ':from=to', the "from" part is expanded exactly once.
.if ${:U\$ \$\$ \$\$\$\$:${:U\$\$\$\$}=4} != "\$ \$\$ 4"
.  error
.endif

# In the modifier ':from=to', the "to" part is expanded exactly twice.
# XXX: The right-hand side should be expanded only once.
# XXX: It's hard to get the escaping correct here, and to read that.
# XXX: It's not intuitive why the closing brace must be escaped but not
#      the opening brace.
.if ${:U1 2 4:4=${:Uonce\${\:Utwice\}}} != "1 2 oncetwice"
.  error
.endif

# The replacement string can contain spaces, thereby changing the number
# of words in the variable expression.
.if ${In:L:%=% ${:Uthe Sun}} != "In the Sun"
.  error
.endif

# If the variable value is empty, it is debatable whether it consists of a
# single empty word, or no word at all.  The modifier ':from=to' treats it as
# no word at all.
#
# See SysVMatch, which doesn't handle w_len == p_len specially.
.if ${:L:=suffix} != ""
.  error
.endif

# If the variable value is empty, it is debatable whether it consists of a
# single empty word (before 2020-05-06), or no word at all (since 2020-05-06).
#
# See SysVMatch, percent != NULL && w[0] == '\0'.
.if ${:L:%=suffix} != ""
.  error
.endif

# Before 2020-07-19, an ampersand could be used in the replacement part
# of a SysV substitution modifier, and it was replaced with the whole match,
# just like in the modifier ':S'.
#
# This was probably a copy-and-paste mistake since the code for the SysV
# modifier looked a lot like the code for the modifiers ':S' and ':C'.
# The ampersand is not mentioned in the manual page.
.if ${a.bcd.e:L:a.%=%} != "bcd.e"
.  error
.endif
# Before 2020-07-19, the result of the expression was "a.bcd.e".
.if ${a.bcd.e:L:a.%=&} != "&"
.  error
.endif

# Before 2020-07-20, when a SysV modifier was parsed, a single dollar
# before the '=' was parsed (but not interpreted) as an anchor.
# Parsing something without then evaluating it accordingly doesn't make
# sense, so this has been fixed.
.if ${value:L:e$=x} != "value"
.  error
.endif
# Before 2020-07-20, the modifier ':e$=x' was parsed as having a left-hand
# side 'e' and a right-hand side 'x'.  The dollar was parsed (but not
# interpreted) as 'anchor at the end'.  Therefore the modifier was equivalent
# to ':e=x', which doesn't match the string "value$".  Therefore the whole
# expression evaluated to "value$".
.if ${${:Uvalue\$}:L:e$=x} != "valux"
.  error
.endif
.if ${value:L:e=x} != "valux"
.  error
.endif

# Words that don't match are copied unmodified.
.if ${:Ufile.c file.h:%.c=%.cpp} != "file.cpp file.h"
.  error
.endif

# The % placeholder can be anywhere in the string, it doesn't have to be at
# the beginning of the pattern.
.if ${:Ufile.c other.c:file.%=renamed.%} != "renamed.c other.c"
.  error
.endif

# It's also possible to modify each word by replacing the prefix and adding
# a suffix.
.if ${one two:L:o%=a%w} != "anew two"
.  error
.endif

# Each word gets the suffix "X" appended.
.if ${one two:L:=X} != "oneX twoX"
.  error
.endif

# The suffix "o" is replaced with "X".
.if ${one two:L:o=X} != "one twX"
.  error
.endif

# The suffix "o" is replaced with nothing.
.if ${one two:L:o=} != "one tw"
.  error
.endif

# The suffix "o" is replaced with a literal percent.  The percent is only
# a wildcard when it appears on the left-hand side.
.if ${one two:L:o=%} != "one tw%"
.  error
.endif

# Each word with the suffix "o" is replaced with "X".  The percent is a
# wildcard even though the right-hand side does not contain another percent.
.if ${one two:L:%o=X} != "one X"
.  error
.endif

# Each word with the prefix "o" is replaced with "X".  The percent is a
# wildcard even though the right-hand side does not contain another percent.
.if ${one two:L:o%=X} != "X two"
.  error
.endif

# For each word with the prefix "o" and the suffix "e", the whole word is
# replaced with "X".
.if ${one two oe oxen:L:o%e=X} != "X two X oxen"
.  error
.endif

# Only the first '%' is the wildcard.
.if ${one two o%e other%e:L:o%%e=X} != "one two X X"
.  error
.endif

# In the replacement, only the first '%' is the placeholder, all others
# are literal percent characters.
.if ${one two:L:%=%%} != "one% two%"
.  error
.endif

# In the word "one", only a prefix of the pattern suffix "nes" matches,
# the whole word is too short.  Therefore it doesn't match.
.if ${one two:L:%nes=%xxx} != "one two"
.  error
.endif

# The modifier ':from=to' can be used to replace both the prefix and a suffix
# of a word with other strings.  This is not possible with a single :S
# modifier, and using a :C modifier for the same task looks more complicated
# in many cases.
.if ${prefix-middle-suffix:L:prefix-%-suffix=p-%-s} != "p-middle-s"
.  error
.endif

# This is not a SysV modifier since the nested variable expression expands
# to an empty string.  The '=' in it should be irrelevant during parsing.
# XXX: As of 2020-12-05, this expression generates an "Unfinished modifier"
# error, while the correct error message would be "Unknown modifier" since
# there is no modifier named "fromto".
.if ${word214:L:from${:D=}to}
.  error
.endif

# XXX: This specially constructed case demonstrates that the SysV modifier
# lasts longer than expected.  The whole expression initially has the value
# "fromto}...".  The next modifier is a SysV modifier.  ApplyModifier_SysV
# parses the modifier as "from${:D=}to", ending at the '}'.  Next, the two
# parts of the modifier are parsed using ParseModifierPart, which scans
# differently, properly handling nested variable expressions.  The two parts
# are now "fromto}..." and "replaced".
.if "${:Ufromto\}...:from${:D=}to}...=replaced}" != "replaced"
.  error
.endif

# As of 2020-10-06, the right-hand side of the SysV modifier is expanded
# twice.  The first expansion happens in ApplyModifier_SysV, where the
# modifier is split into its two parts.  The second expansion happens
# when each word is replaced in ModifyWord_SYSVSubst.
# XXX: This is unexpected.  Add more test case to demonstrate the effects
# of removing one of the expansions.
VALUE=		value
INDIRECT=	1:${VALUE} 2:$${VALUE} 4:$$$${VALUE}
.if ${x:L:x=${INDIRECT}} != "1:value 2:value 4:\${VALUE}"
.  error
.endif

# Test all relevant combinations of prefix, '%' and suffix in both the pattern
# and the replacement.
!=1>&2	printf '%-24s %-24s %-24s\n' 'word' 'modifier' 'result'
.for from in '' ffix % pre% %ffix pre%ffix
.  for to in '' NS % %NS NPre% NPre%NS
.    for word in '' suffix prefix pre-middle-suffix
.      for mod in ${from:N''}=${to:N''}
!=1>&2	printf '%-24s %-24s "%s"\n' ''${word:Q} ''${mod:Q} ''${word:N'':${mod}:Q}
.      endfor
.    endfor
.  endfor
.endfor

all: