1 1.30 rillig # $NetBSD: varmod.mk,v 1.30 2025/06/29 11:27:21 rillig Exp $ 2 1.1 rillig # 3 1.2 rillig # Tests for variable modifiers, such as :Q, :S,from,to or :Ufallback. 4 1.7 rillig # 5 1.7 rillig # See also: 6 1.7 rillig # varparse-errors.mk 7 1.1 rillig 8 1.14 rillig # As of 2024-06-05, the possible behaviors during parsing are: 9 1.6 rillig # 10 1.6 rillig # * `strict`: the parsing style used by most modifiers: 11 1.6 rillig # * either uses `ParseModifierPart` or parses the modifier literal 12 1.6 rillig # * other modifiers may follow, separated by a ':' 13 1.6 rillig # 14 1.6 rillig # * `greedy`: calls `ParseModifierPart` with `ch->endc`; this means 15 1.6 rillig # that no further modifiers are parsed in that expression. 16 1.6 rillig # 17 1.6 rillig # * `no-colon`: after parsing this modifier, the following modifier 18 1.6 rillig # does not need to be separated by a colon. 19 1.6 rillig # Omitting this colon is bad style. 20 1.6 rillig # 21 1.6 rillig # * `individual`: parsing this modifier does not follow the common 22 1.6 rillig # pattern of calling `ParseModifierPart`. 23 1.6 rillig # 24 1.23 rillig # The SysV column says whether a modifier falls back trying the `:from=to` 25 1.23 rillig # System V modifier. Remarks: 26 1.6 rillig # 27 1.23 rillig # In the assignment modifiers `::=` and its variants, the `=` is part of 28 1.23 rillig # the modifier name, so they never fall back to the `:from=to` modifier. 29 1.23 rillig # 30 1.23 rillig # All no-colon modifiers get a "no", as the modifier name would be 31 1.23 rillig # trimmed off before the `:from=to` modifier could see them, for 32 1.23 rillig # example, ${VAR:LAR=ALUE} and ${VAR:L:AR=ALUE} behave the same. 33 1.23 rillig # 34 1.23 rillig # | **Modifier** | **Behavior** | **Remarks** | **SysV** | 35 1.6 rillig # |--------------|--------------|--------------------|----------| 36 1.23 rillig # | ! | no-colon | | no | 37 1.23 rillig # | := | greedy | | no | 38 1.23 rillig # | :?= | greedy | | no | 39 1.23 rillig # | :+= | greedy | | no | 40 1.23 rillig # | :!= | greedy | | no | 41 1.23 rillig # | ?: | greedy | | no | 42 1.23 rillig # | @ | no-colon | | no | 43 1.23 rillig # | C | no-colon | | no | 44 1.23 rillig # | D | individual | custom parser | no | 45 1.23 rillig # | E | strict | | yes | 46 1.23 rillig # | H | strict | | yes | 47 1.23 rillig # | L | no-colon | | no | 48 1.23 rillig # | M | individual | custom parser | no | 49 1.23 rillig # | N | individual | custom parser | no | 50 1.24 rillig # | O | strict | only literal value | yes | 51 1.23 rillig # | P | no-colon | | no | 52 1.23 rillig # | Q | strict | | yes | 53 1.23 rillig # | R | strict | | yes | 54 1.23 rillig # | S | no-colon | | no | 55 1.23 rillig # | T | strict | | yes | 56 1.23 rillig # | U | individual | custom parser | no | 57 1.23 rillig # | [ | strict | | no | 58 1.23 rillig # | _ | individual | strcspn | no | 59 1.23 rillig # | gmtime | strict | | no | 60 1.23 rillig # | hash | strict | | yes | 61 1.23 rillig # | localtime | strict | | no | 62 1.23 rillig # | q | strict | | yes | 63 1.23 rillig # | range | strict | | no | 64 1.23 rillig # | sh | strict | | yes | 65 1.25 rillig # | t | strict | | yes | 66 1.23 rillig # | u | strict | | yes | 67 1.23 rillig # | from=to | greedy | SysV, fallback | --- | 68 1.6 rillig 69 1.10 sjg # These tests assume 70 1.10 sjg .MAKE.SAVE_DOLLARS = yes 71 1.10 sjg 72 1.3 rillig DOLLAR1= $$ 73 1.3 rillig DOLLAR2= ${:U\$} 74 1.1 rillig 75 1.9 rillig # To get a single '$' sign in the value of an expression, it has to 76 1.3 rillig # be written as '$$' in a literal variable value. 77 1.3 rillig # 78 1.3 rillig # See Var_Parse, where it calls Var_Subst. 79 1.3 rillig .if ${DOLLAR1} != "\$" 80 1.3 rillig . error 81 1.3 rillig .endif 82 1.3 rillig 83 1.3 rillig # Another way to get a single '$' sign is to use the :U modifier. In the 84 1.3 rillig # argument of that modifier, a '$' is escaped using the backslash instead. 85 1.3 rillig # 86 1.3 rillig # See Var_Parse, where it calls Var_Subst. 87 1.3 rillig .if ${DOLLAR2} != "\$" 88 1.3 rillig . error 89 1.3 rillig .endif 90 1.3 rillig 91 1.3 rillig # It is also possible to use the :U modifier directly in the expression. 92 1.3 rillig # 93 1.3 rillig # See Var_Parse, where it calls Var_Subst. 94 1.3 rillig .if ${:U\$} != "\$" 95 1.3 rillig . error 96 1.3 rillig .endif 97 1.3 rillig 98 1.3 rillig # XXX: As of 2020-09-13, it is not possible to use '$$' in a variable name 99 1.3 rillig # to mean a single '$'. This contradicts the manual page, which says that 100 1.3 rillig # '$' can be escaped as '$$'. 101 1.3 rillig .if ${$$:L} != "" 102 1.3 rillig . error 103 1.3 rillig .endif 104 1.3 rillig 105 1.3 rillig # In lint mode, make prints helpful error messages. 106 1.3 rillig # For compatibility, make does not print these error messages in normal mode. 107 1.3 rillig # Should it? 108 1.3 rillig .MAKEFLAGS: -dL 109 1.8 rillig # expect+2: To escape a dollar, use \$, not $$, at "$$:L} != """ 110 1.27 rillig # expect+1: Invalid variable name ":", at "$:L} != """ 111 1.3 rillig .if ${$$:L} != "" 112 1.3 rillig . error 113 1.3 rillig .endif 114 1.3 rillig 115 1.3 rillig # A '$' followed by nothing is an error as well. 116 1.20 rillig # expect+1: Dollar followed by nothing 117 1.3 rillig .if ${:Uword:@word@${word}$@} != "word" 118 1.3 rillig . error 119 1.3 rillig .endif 120 1.3 rillig 121 1.30 rillig # The modifier :P does not fall back to the SysV modifier. 122 1.4 rillig # Therefore the modifier :P=RE generates a parse error. 123 1.4 rillig VAR= STOP 124 1.27 rillig # expect+1: Missing delimiter ":" after modifier "P" 125 1.4 rillig .if ${VAR:P=RE} != "STORE" 126 1.30 rillig . error 127 1.30 rillig .else 128 1.4 rillig . error 129 1.4 rillig .endif 130 1.4 rillig 131 1.12 rillig # Test the word selection modifier ':[n]' with a very large number that is 132 1.12 rillig # larger than ULONG_MAX for any supported platform. 133 1.26 rillig # expect+1: Invalid modifier ":[99333000222000111000]" 134 1.12 rillig .if ${word:L:[99333000222000111000]} 135 1.12 rillig .endif 136 1.26 rillig # expect+1: Invalid modifier ":[2147483648]" 137 1.12 rillig .if ${word:L:[2147483648]} 138 1.12 rillig .endif 139 1.12 rillig 140 1.12 rillig # Test the range generation modifier ':range=n' with a very large number that 141 1.12 rillig # is larger than SIZE_MAX for any supported platform. 142 1.27 rillig # expect+1: Invalid number "99333000222000111000}" for modifier ":range" 143 1.12 rillig .if ${word:L:range=99333000222000111000} 144 1.12 rillig .endif 145 1.13 rillig 146 1.13 rillig # In an indirect modifier, the delimiter is '\0', which at the same time marks 147 1.13 rillig # the end of the string. The sequence '\\' '\0' is not an escaped delimiter, 148 1.13 rillig # as it would be wrong to skip past the end of the string. 149 1.22 rillig # expect+1: Invalid time value "\" 150 1.13 rillig .if ${:${:Ugmtime=\\}} 151 1.13 rillig . error 152 1.13 rillig .endif 153 1.15 rillig 154 1.15 rillig # Test a '$' at the end of a modifier part, for all modifiers in the order 155 1.15 rillig # listed in ApplyModifier. 156 1.15 rillig # 157 1.15 rillig # The only modifier parts where an unescaped '$' makes sense at the end are 158 1.15 rillig # the 'from' parts of the ':S' and ':C' modifiers. In all other modifier 159 1.15 rillig # parts, an unescaped '$' is an undocumented and discouraged edge case, as it 160 1.15 rillig # means the same as an escaped '$'. 161 1.15 rillig .if ${:U:!printf '%s\n' $!} != "\$" 162 1.15 rillig . error 163 1.15 rillig .endif 164 1.20 rillig # expect+1: Dollar followed by nothing 165 1.15 rillig .if ${VAR::=value$} != "" || ${VAR} != "value" 166 1.15 rillig . error 167 1.15 rillig .endif 168 1.15 rillig ${:U }= <space> 169 1.20 rillig # expect+2: Dollar followed by nothing 170 1.20 rillig # expect+1: Dollar followed by nothing 171 1.15 rillig .if ${VAR::+=appended$} != "" || ${VAR} != "value<space>appended" 172 1.15 rillig . error 173 1.15 rillig .endif 174 1.15 rillig .if ${1:?then$:else$} != "then\$" 175 1.15 rillig . error 176 1.15 rillig .endif 177 1.15 rillig .if ${0:?then$:else$} != "else\$" 178 1.15 rillig . error 179 1.15 rillig .endif 180 1.20 rillig # expect+1: Dollar followed by nothing 181 1.15 rillig .if ${word:L:@w@$w$@} != "word" 182 1.15 rillig . error 183 1.15 rillig .endif 184 1.26 rillig # expect+1: Invalid modifier ":[$]" 185 1.15 rillig .if ${word:[$]} 186 1.15 rillig . error 187 1.15 rillig .else 188 1.15 rillig . error 189 1.15 rillig .endif 190 1.15 rillig VAR_DOLLAR= VAR$$ 191 1.15 rillig .if ${word:L:_=VAR$} != "word" || ${${VAR_DOLLAR}} != "word" 192 1.15 rillig . error 193 1.15 rillig .endif 194 1.15 rillig .if ${word:L:C,d$,m,} != "worm" 195 1.15 rillig . error 196 1.15 rillig .endif 197 1.15 rillig .if ${word:L:C,d,$,} != "wor\$" 198 1.15 rillig . error 199 1.15 rillig .endif 200 1.20 rillig # expect+2: Dollar followed by nothing 201 1.27 rillig # expect+1: Invalid variable name "}", at "$} != "set"" 202 1.15 rillig .if ${VAR:Dset$} != "set" 203 1.15 rillig . error 204 1.15 rillig .endif 205 1.27 rillig # expect+1: Invalid variable name "}", at "$} != "fallback"" 206 1.15 rillig .if ${:Ufallback$} != "fallback" 207 1.15 rillig . error 208 1.15 rillig .endif 209 1.22 rillig # expect+1: Invalid time value "1000$" 210 1.15 rillig .if ${%y:L:gmtime=1000$} 211 1.15 rillig . error 212 1.15 rillig .else 213 1.15 rillig . error 214 1.15 rillig .endif 215 1.22 rillig # expect+1: Invalid time value "1000$" 216 1.15 rillig .if ${%y:L:localtime=1000$} 217 1.15 rillig . error 218 1.15 rillig .else 219 1.15 rillig . error 220 1.15 rillig .endif 221 1.20 rillig # expect+1: Dollar followed by nothing 222 1.15 rillig .if ${word:L:Mw*$} != "word" 223 1.15 rillig . error 224 1.15 rillig .endif 225 1.20 rillig # expect+1: Dollar followed by nothing 226 1.15 rillig .if ${word:L:NX*$} != "word" 227 1.15 rillig . error 228 1.15 rillig .endif 229 1.27 rillig # expect+1: Invalid argument "fallback$" for modifier ":mtime" 230 1.15 rillig .if ${.:L:mtime=fallback$} 231 1.15 rillig . error 232 1.15 rillig .else 233 1.15 rillig . error 234 1.15 rillig .endif 235 1.15 rillig .if ${word:L:S,d$,m,} != "worm" 236 1.15 rillig . error 237 1.15 rillig .endif 238 1.15 rillig .if ${word:L:S,d,m$,} != "worm\$" 239 1.15 rillig . error 240 1.15 rillig .endif 241 1.23 rillig 242 1.23 rillig .undef VAR 243 1.27 rillig # expect+1: Missing delimiter ":" after modifier "L" 244 1.23 rillig .if ${VAR:LAR=ALUE} != "VALUE" 245 1.23 rillig . error 246 1.23 rillig .endif 247 1.23 rillig .if ${VAR:L:AR=ALUE} != "VALUE" 248 1.23 rillig . error 249 1.23 rillig .endif 250 1.28 rillig 251 1.28 rillig 252 1.29 rillig # When an expression has the usual form ${...} with braces, 253 1.29 rillig # in the part of a modifier, ":}\$" can be escaped using a backslash. 254 1.29 rillig # All other characters are passed through unmodified. 255 1.29 rillig # expect+1: Invalid time value " : } \ $ ) \) ( " 256 1.29 rillig .if ${%Y:L:localtime= \: \} \\ \$ ) \) ( :M*} != ": } \\ \$ ) \\) (" 257 1.29 rillig . error 258 1.29 rillig .endif 259 1.29 rillig # When an expression has the unusual form $(...) with parentheses, 260 1.29 rillig # in the part of a modifier, ":)\$" can be escaped using a backslash. 261 1.29 rillig # All other characters are passed through unmodified. 262 1.29 rillig # expect+1: Invalid time value " : \) \ $ " 263 1.29 rillig .if ${%Y:L:localtime= \: \) \\ \$ } \} { :M*} != ": ) \\ \$ } \\} {" 264 1.29 rillig . error 265 1.29 rillig .endif 266 1.29 rillig # Same when the modifier is the last modifier in an expression. 267 1.29 rillig # expect+1: Invalid time value " : } \ $ ) \) ( " 268 1.29 rillig .if ${%Y:L:localtime= \: \} \\ \$ ) \) ( } != " : } \\ \$ ) \\) ( " 269 1.29 rillig . error 270 1.29 rillig .endif 271 1.29 rillig # Same when the modifier is the last modifier in an expression. 272 1.29 rillig # expect+1: Invalid time value " : \) \ $ " 273 1.29 rillig .if ${%Y:L:localtime= \: \) \\ \$ } \} { } != " : ) \\ \$ } \\} { " 274 1.28 rillig . error 275 1.28 rillig .endif 276