1 # $NetBSD: varmod-to-separator.mk,v 1.23 2025/03/30 00:35: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 . error 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 . error 16 .endif 17 18 # After the :ts modifier, other modifiers can follow. 19 .if ${WORDS:ts/:tu} != "ONE/TWO/THREE/FOUR/FIVE/SIX" 20 . error 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 . error 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 . error 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 . error 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 . error 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 . error 60 .endif 61 62 # As in the ${WORDS:tu:ts} example above, the separator is empty. 63 .if ${WORDS:ts} != "onetwothreefourfivesix" 64 . error 65 .endif 66 67 # The :ts modifier can be followed by other modifiers. 68 .if ${WORDS:ts:S/two/2/} != "one2threefourfivesix" 69 . error 70 .endif 71 72 # The :ts modifier can follow other modifiers. 73 .if ${WORDS:S/two/2/:ts} != "one2threefourfivesix" 74 . error 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 . error 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 . error 132 .endif 133 134 # The separator can be \t, which is a tab. 135 .if ${WORDS:[1..3]:ts\t} != "one two three" 136 . error 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 . error 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 . error 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+1: Invalid character number at "400:tu}" 154 .if ${WORDS:[1..3]:ts\400:tu} 155 . error 156 .else 157 . error 158 .endif 159 160 # The separator can be given as hexadecimal number. 161 .if ${WORDS:[1..3]:ts\xa:tu} != "ONE${.newline}TWO${.newline}THREE" 162 . error 163 .endif 164 165 # The hexadecimal number must be in the range of an unsigned char. 166 # 167 # Since 2020-11-01, these out-of-bounds values are rejected. 168 # expect+1: Invalid character number at "100:tu}" 169 .if ${WORDS:[1..3]:ts\x100:tu} 170 . error 171 .else 172 . error 173 .endif 174 175 # The number after ':ts\x' must be hexadecimal. 176 # expect+1: Invalid character number at ",}" 177 .if ${word:L:ts\x,} 178 .endif 179 180 # The hexadecimal number must be in the range of 'unsigned long' on all 181 # supported platforms. 182 # expect+1: Invalid character number at "112233445566778899}" 183 .if ${word:L:ts\x112233445566778899} 184 .endif 185 186 # Negative numbers are not allowed for the separator character. 187 # expect+1: Unknown modifier ":ts\-300" 188 .if ${WORDS:[1..3]:ts\-300:tu} 189 . error 190 .else 191 . error 192 .endif 193 194 # The character number is interpreted as octal number by default. 195 # The digit '8' is not an octal digit though. 196 # expect+1: Unknown modifier ":ts\8" 197 .if ${1 2 3:L:ts\8:tu} 198 . error 199 .else 200 . error 201 .endif 202 203 # Trailing characters after the octal character number are rejected. 204 # expect+1: Unknown modifier ":ts\100L" 205 .if ${1 2 3:L:ts\100L} 206 . error 207 .else 208 . error 209 .endif 210 211 # Trailing characters after the hexadecimal character number are rejected. 212 # expect+1: Unknown modifier ":ts\x40g" 213 .if ${1 2 3:L:ts\x40g} 214 . error 215 .else 216 . error 217 .endif 218 219 220 # In the :t modifier, the :t must be followed by any of A, l, s, u. 221 # expect+1: Unknown modifier ":tx" 222 .if ${WORDS:tx} 223 . error 224 .else 225 . error 226 .endif 227 228 # The word separator can only be a single character. 229 # expect+1: Unknown modifier ":ts\X" 230 .if ${WORDS:ts\X} 231 . error 232 .else 233 . error 234 .endif 235 236 # After the backslash, only n, t, an octal number, or x and a hexadecimal 237 # number are allowed. 238 # expect+1: Unknown modifier ":ts\X" 239 .if ${WORDS:ts\X} != "anything" 240 . error 241 .endif 242 243 244 # Since 2003.07.23.18.06.46 and before 2016.03.07.20.20.35, the modifier ':ts' 245 # interpreted an "octal escape" as decimal if the first digit was not '0'. 246 .if ${:Ua b:ts\61} != "a1b" # decimal would have been "a=b" 247 . error 248 .endif 249 250 # Since the character escape is always interpreted as octal, let's see what 251 # happens for non-octal digits. From 2003.07.23.18.06.46 to 252 # 2016.02.27.16.20.06, the result was '1E2', since 2016.03.07.20.20.35 make no 253 # longer accepts this escape and complains. 254 # expect+1: Unknown modifier ":ts\69" 255 .if ${:Ua b:ts\69} 256 . error 257 .else 258 . error 259 .endif 260 261 # Try whether bmake is Unicode-ready. 262 # expect+1: Invalid character number at "1F60E}" 263 .if ${:Ua b:ts\x1F60E} # U+1F60E "smiling face with sunglasses" 264 . error 265 .else 266 . error 267 .endif 268