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