varmod-to-separator.mk revision 1.13 1 # $NetBSD: varmod-to-separator.mk,v 1.13 2023/11/19 21:47:52 rillig Exp $
2 #
3 # Tests for the :ts variable modifier, which joins the words of the variable
4 # using an arbitrary character as word separator.
5
6 WORDS= one two three four five six
7
8 # The words are separated by a single space, just as usual.
9 .if ${WORDS:ts } != "one two three four five six"
10 . warning Space as separator does not work.
11 .endif
12
13 # The separator can be an arbitrary character, for example a comma.
14 .if ${WORDS:ts,} != "one,two,three,four,five,six"
15 . warning Comma as separator does not work.
16 .endif
17
18 # After the :ts modifier, other modifiers can follow.
19 .if ${WORDS:ts/:tu} != "ONE/TWO/THREE/FOUR/FIVE/SIX"
20 . warning Chaining modifiers does not work.
21 .endif
22
23 # To use the ':' as the separator, just write it normally.
24 # The first colon is the separator, the second ends the modifier.
25 .if ${WORDS:ts::tu} != "ONE:TWO:THREE:FOUR:FIVE:SIX"
26 . warning Colon as separator does not work.
27 .endif
28
29 # When there is just a colon but no other character, the words are
30 # "separated" by an empty string, that is, they are all squashed
31 # together.
32 .if ${WORDS:ts:tu} != "ONETWOTHREEFOURFIVESIX"
33 . warning Colon as separator does not work.
34 .endif
35
36 # Applying the :tu modifier first and then the :ts modifier does not change
37 # anything since neither of these modifiers is related to how the string is
38 # split into words. Beware of separating the words using a single or double
39 # quote though, or other special characters like dollar or backslash.
40 #
41 # This example also demonstrates that the closing brace is not interpreted
42 # as a separator, but as the closing delimiter of the whole
43 # expression.
44 .if ${WORDS:tu:ts} != "ONETWOTHREEFOURFIVESIX"
45 . warning Colon as separator does not work.
46 .endif
47
48 # The '}' plays the same role as the ':' in the preceding examples.
49 # Since there is a single character before it, that character is taken as
50 # the separator.
51 .if ${WORDS:tu:ts/} != "ONE/TWO/THREE/FOUR/FIVE/SIX"
52 . warning Colon as separator does not work.
53 .endif
54
55 # Now it gets interesting and ambiguous: The separator could either be empty
56 # since it is followed by a colon. Or it could be the colon since that
57 # colon is followed by the closing brace. It's the latter case.
58 .if ${WORDS:ts:} != "one:two:three:four:five:six"
59 . warning Colon followed by closing brace does not work.
60 .endif
61
62 # As in the ${WORDS:tu:ts} example above, the separator is empty.
63 .if ${WORDS:ts} != "onetwothreefourfivesix"
64 . warning Empty separator before closing brace does not work.
65 .endif
66
67 # The :ts modifier can be followed by other modifiers.
68 .if ${WORDS:ts:S/two/2/} != "one2threefourfivesix"
69 . warning Separator followed by :S modifier does not work.
70 .endif
71
72 # The :ts modifier can follow other modifiers.
73 .if ${WORDS:S/two/2/:ts} != "one2threefourfivesix"
74 . warning :S modifier followed by :ts modifier does not work.
75 .endif
76
77 # The :ts modifier with an actual separator can be followed by other
78 # modifiers.
79 .if ${WORDS:ts/:S/two/2/} != "one/2/three/four/five/six"
80 . warning The :ts modifier followed by an :S modifier does not work.
81 .endif
82
83 # After the modifier ':ts/', the expression value is a single word since all
84 # spaces have been replaced with '/'. This single word does not start with
85 # 'two', which makes the modifier ':S' a no-op.
86 .if ${WORDS:ts/:S/^two/2/} != "one/two/three/four/five/six"
87 . error
88 .endif
89
90 # After the :ts modifier, the whole string is interpreted as a single
91 # word since all spaces have been replaced with x. Because of this single
92 # word, only the first 'b' is replaced with 'B'.
93 .if ${aa bb aa bb aa bb:L:tsx:S,b,B,} != "aaxBbxaaxbbxaaxbb"
94 . error
95 .endif
96
97 # The :ts modifier also applies to word separators that are added
98 # afterwards. First, the modifier ':tsx' joins the 3 words, then the modifier
99 # ':S' replaces the 2 'b's with spaces. These spaces are part of the word,
100 # so when the words are joined at the end of the modifier ':S', there is only
101 # a single word, and the custom separator from the modifier ':tsx' has no
102 # effect.
103 .if ${a ababa c:L:tsx:S,b, ,g} != "axa a axc"
104 . error
105 .endif
106
107 # Adding the modifier ':M*' at the end of the above chain splits the
108 # expression value and then joins it again. At this point of splitting, the
109 # newly added spaces are treated as word separators, resulting in 3 words.
110 # When these 3 words are joined, the separator from the modifier ':tsx' is
111 # used.
112 .if ${a ababa c:L:tsx:S,b, ,g:M*} != "axaxaxaxc"
113 . error
114 .endif
115
116 # Not all modifiers use the separator from the previous modifier ':ts' though.
117 # The modifier ':@' always uses a space as word separator instead. This has
118 # probably been an oversight during implementation. For consistency, the
119 # result should rather be "axaxaxaxc", as in the previous example.
120 .if ${a ababa c:L:tsx:S,b, ,g:@v@$v@} != "axa a axc"
121 . error
122 .endif
123
124 # Adding a final :M* modifier applies the :ts separator again, though.
125 .if ${a ababa c:L:tsx:S,b, ,g:@v@${v}@:M*} != "axaxaxaxc"
126 . error
127 .endif
128
129 # The separator can be \n, which is a newline.
130 .if ${WORDS:[1..3]:ts\n} != "one${.newline}two${.newline}three"
131 . warning The separator \n does not produce a newline.
132 .endif
133
134 # The separator can be \t, which is a tab.
135 .if ${WORDS:[1..3]:ts\t} != "one two three"
136 . warning The separator \t does not produce a tab.
137 .endif
138
139 # The separator can be given as octal number.
140 .if ${WORDS:[1..3]:ts\012:tu} != "ONE${.newline}TWO${.newline}THREE"
141 . warning The separator \012 is not interpreted in octal ASCII.
142 .endif
143
144 # The octal number can have as many digits as it wants.
145 .if ${WORDS:[1..2]:ts\000000000000000000000000012:tu} != "ONE${.newline}TWO"
146 . warning The separator \012 cannot have many leading zeroes.
147 .endif
148
149 # The value of the separator character must not be outside the value space
150 # for an unsigned character though.
151 #
152 # Since 2020-11-01, these out-of-bounds values are rejected.
153 # expect+2: Invalid character number at "400:tu}"
154 # expect+1: Malformed conditional (${WORDS:[1..3]:ts\400:tu})
155 .if ${WORDS:[1..3]:ts\400:tu}
156 . warning The separator \400 is accepted even though it is out of bounds.
157 .else
158 . warning The separator \400 is accepted even though it is out of bounds.
159 .endif
160
161 # The separator can be given as hexadecimal number.
162 .if ${WORDS:[1..3]:ts\xa:tu} != "ONE${.newline}TWO${.newline}THREE"
163 . warning The separator \xa is not interpreted in hexadecimal ASCII.
164 .endif
165
166 # The hexadecimal number must be in the range of an unsigned char.
167 #
168 # Since 2020-11-01, these out-of-bounds values are rejected.
169 # expect+2: Invalid character number at "100:tu}"
170 # expect+1: Malformed conditional (${WORDS:[1..3]:ts\x100:tu})
171 .if ${WORDS:[1..3]:ts\x100:tu}
172 . warning The separator \x100 is accepted even though it is out of bounds.
173 .else
174 . warning The separator \x100 is accepted even though it is out of bounds.
175 .endif
176
177 # Negative numbers are not allowed for the separator character.
178 # expect+1: Malformed conditional (${WORDS:[1..3]:ts\-300:tu})
179 .if ${WORDS:[1..3]:ts\-300:tu}
180 . warning The separator \-300 is accepted even though it is negative.
181 .else
182 . warning The separator \-300 is accepted even though it is negative.
183 .endif
184
185 # The character number is interpreted as octal number by default.
186 # The digit '8' is not an octal digit though.
187 # expect+1: Malformed conditional (${1 2 3:L:ts\8:tu})
188 .if ${1 2 3:L:ts\8:tu}
189 . warning The separator \8 is accepted even though it is not octal.
190 .else
191 . warning The separator \8 is accepted even though it is not octal.
192 .endif
193
194 # Trailing characters after the octal character number are rejected.
195 # expect+1: Malformed conditional (${1 2 3:L:ts\100L})
196 .if ${1 2 3:L:ts\100L}
197 . warning The separator \100L is accepted even though it contains an 'L'.
198 .else
199 . warning The separator \100L is accepted even though it contains an 'L'.
200 .endif
201
202 # Trailing characters after the hexadecimal character number are rejected.
203 # expect+1: Malformed conditional (${1 2 3:L:ts\x40g})
204 .if ${1 2 3:L:ts\x40g}
205 . warning The separator \x40g is accepted even though it contains a 'g'.
206 .else
207 . warning The separator \x40g is accepted even though it contains a 'g'.
208 .endif
209
210
211 # In the :t modifier, the :t must be followed by any of A, l, s, u.
212 # expect: make: Bad modifier ":tx" for variable "WORDS"
213 # expect+1: Malformed conditional (${WORDS:tx})
214 .if ${WORDS:tx}
215 . error
216 .else
217 . error
218 .endif
219
220 # The word separator can only be a single character.
221 # expect: make: Bad modifier ":ts\X" for variable "WORDS"
222 # expect+1: Malformed conditional (${WORDS:ts\X})
223 .if ${WORDS:ts\X}
224 . error
225 .else
226 . error
227 .endif
228
229 # After the backslash, only n, t, an octal number, or x and a hexadecimal
230 # number are allowed.
231 # expect+1: Malformed conditional (${WORDS:t\X} != "anything")
232 .if ${WORDS:t\X} != "anything"
233 . info This line is not reached.
234 .endif
235
236
237 # Since 2003.07.23.18.06.46 and before 2016.03.07.20.20.35, the modifier ':ts'
238 # interpreted an "octal escape" as decimal if the first digit was not '0'.
239 .if ${:Ua b:ts\61} != "a1b" # decimal would have been "a=b"
240 . error
241 .endif
242
243 # Since the character escape is always interpreted as octal, let's see what
244 # happens for non-octal digits. From 2003.07.23.18.06.46 to
245 # 2016.02.27.16.20.06, the result was '1E2', since 2016.03.07.20.20.35 make no
246 # longer accepts this escape and complains.
247 # expect: make: Bad modifier ":ts\69" for variable ""
248 # expect+1: Malformed conditional (${:Ua b:ts\69})
249 .if ${:Ua b:ts\69}
250 . error
251 .else
252 . error
253 .endif
254
255 # Try whether bmake is Unicode-ready.
256 # expect+2: Invalid character number at "1F60E}"
257 # expect+1: Malformed conditional (${:Ua b:ts\x1F60E})
258 .if ${:Ua b:ts\x1F60E} # U+1F60E "smiling face with sunglasses"
259 . error
260 .else
261 . error
262 .endif
263