varmod.mk revision 1.23 1 1.23 rillig # $NetBSD: varmod.mk,v 1.23 2025/03/29 20:19:58 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.23 rillig # | O | strict | only literal value | no |
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.23 rillig # | t | strict | | no |
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.8 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.4 rillig # The variable 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.9 rillig # XXX: The .error should not be reached since the expression is
124 1.5 rillig # malformed, and this error should be propagated up to Cond_EvalLine.
125 1.4 rillig VAR= STOP
126 1.20 rillig # expect+1: Missing delimiter ':' after modifier "P"
127 1.4 rillig .if ${VAR:P=RE} != "STORE"
128 1.8 rillig # expect+1: Missing argument for ".error"
129 1.4 rillig . error
130 1.4 rillig .endif
131 1.4 rillig
132 1.12 rillig # Test the word selection modifier ':[n]' with a very large number that is
133 1.12 rillig # larger than ULONG_MAX for any supported platform.
134 1.22 rillig # expect+1: Bad modifier ":[99333000222000111000]"
135 1.12 rillig .if ${word:L:[99333000222000111000]}
136 1.12 rillig .endif
137 1.22 rillig # expect+1: Bad modifier ":[2147483648]"
138 1.12 rillig .if ${word:L:[2147483648]}
139 1.12 rillig .endif
140 1.12 rillig
141 1.12 rillig # Test the range generation modifier ':range=n' with a very large number that
142 1.12 rillig # is larger than SIZE_MAX for any supported platform.
143 1.22 rillig # expect+1: Invalid number "99333000222000111000}" for ':range' modifier
144 1.12 rillig .if ${word:L:range=99333000222000111000}
145 1.12 rillig .endif
146 1.13 rillig
147 1.13 rillig # In an indirect modifier, the delimiter is '\0', which at the same time marks
148 1.13 rillig # the end of the string. The sequence '\\' '\0' is not an escaped delimiter,
149 1.13 rillig # as it would be wrong to skip past the end of the string.
150 1.22 rillig # expect+1: Invalid time value "\"
151 1.13 rillig .if ${:${:Ugmtime=\\}}
152 1.13 rillig . error
153 1.13 rillig .endif
154 1.15 rillig
155 1.15 rillig # Test a '$' at the end of a modifier part, for all modifiers in the order
156 1.15 rillig # listed in ApplyModifier.
157 1.15 rillig #
158 1.15 rillig # The only modifier parts where an unescaped '$' makes sense at the end are
159 1.15 rillig # the 'from' parts of the ':S' and ':C' modifiers. In all other modifier
160 1.15 rillig # parts, an unescaped '$' is an undocumented and discouraged edge case, as it
161 1.15 rillig # means the same as an escaped '$'.
162 1.15 rillig .if ${:U:!printf '%s\n' $!} != "\$"
163 1.15 rillig . error
164 1.15 rillig .endif
165 1.20 rillig # expect+1: Dollar followed by nothing
166 1.15 rillig .if ${VAR::=value$} != "" || ${VAR} != "value"
167 1.15 rillig . error
168 1.15 rillig .endif
169 1.15 rillig ${:U }= <space>
170 1.20 rillig # expect+2: Dollar followed by nothing
171 1.20 rillig # expect+1: Dollar followed by nothing
172 1.15 rillig .if ${VAR::+=appended$} != "" || ${VAR} != "value<space>appended"
173 1.15 rillig . error
174 1.15 rillig .endif
175 1.15 rillig .if ${1:?then$:else$} != "then\$"
176 1.15 rillig . error
177 1.15 rillig .endif
178 1.15 rillig .if ${0:?then$:else$} != "else\$"
179 1.15 rillig . error
180 1.15 rillig .endif
181 1.20 rillig # expect+1: Dollar followed by nothing
182 1.15 rillig .if ${word:L:@w@$w$@} != "word"
183 1.15 rillig . error
184 1.15 rillig .endif
185 1.22 rillig # expect+1: Bad modifier ":[$]"
186 1.15 rillig .if ${word:[$]}
187 1.15 rillig . error
188 1.15 rillig .else
189 1.15 rillig . error
190 1.15 rillig .endif
191 1.15 rillig VAR_DOLLAR= VAR$$
192 1.15 rillig .if ${word:L:_=VAR$} != "word" || ${${VAR_DOLLAR}} != "word"
193 1.15 rillig . error
194 1.15 rillig .endif
195 1.15 rillig .if ${word:L:C,d$,m,} != "worm"
196 1.15 rillig . error
197 1.15 rillig .endif
198 1.15 rillig .if ${word:L:C,d,$,} != "wor\$"
199 1.15 rillig . error
200 1.15 rillig .endif
201 1.20 rillig # expect+2: Dollar followed by nothing
202 1.20 rillig # expect+1: Invalid variable name '}', at "$} != "set""
203 1.15 rillig .if ${VAR:Dset$} != "set"
204 1.15 rillig . error
205 1.15 rillig .endif
206 1.20 rillig # expect+1: Invalid variable name '}', at "$} != "fallback""
207 1.15 rillig .if ${:Ufallback$} != "fallback"
208 1.15 rillig . error
209 1.15 rillig .endif
210 1.22 rillig # expect+1: Invalid time value "1000$"
211 1.15 rillig .if ${%y:L:gmtime=1000$}
212 1.15 rillig . error
213 1.15 rillig .else
214 1.15 rillig . error
215 1.15 rillig .endif
216 1.22 rillig # expect+1: Invalid time value "1000$"
217 1.15 rillig .if ${%y:L:localtime=1000$}
218 1.15 rillig . error
219 1.15 rillig .else
220 1.15 rillig . error
221 1.15 rillig .endif
222 1.20 rillig # expect+1: Dollar followed by nothing
223 1.15 rillig .if ${word:L:Mw*$} != "word"
224 1.15 rillig . error
225 1.15 rillig .endif
226 1.20 rillig # expect+1: Dollar followed by nothing
227 1.15 rillig .if ${word:L:NX*$} != "word"
228 1.15 rillig . error
229 1.15 rillig .endif
230 1.22 rillig # expect+1: Invalid argument 'fallback$' for modifier ':mtime'
231 1.15 rillig .if ${.:L:mtime=fallback$}
232 1.15 rillig . error
233 1.15 rillig .else
234 1.15 rillig . error
235 1.15 rillig .endif
236 1.15 rillig .if ${word:L:S,d$,m,} != "worm"
237 1.15 rillig . error
238 1.15 rillig .endif
239 1.15 rillig .if ${word:L:S,d,m$,} != "worm\$"
240 1.15 rillig . error
241 1.15 rillig .endif
242 1.23 rillig
243 1.23 rillig .undef VAR
244 1.23 rillig # expect+1: Missing delimiter ':' after modifier "L"
245 1.23 rillig .if ${VAR:LAR=ALUE} != "VALUE"
246 1.23 rillig . error
247 1.23 rillig .endif
248 1.23 rillig .if ${VAR:L:AR=ALUE} != "VALUE"
249 1.23 rillig . error
250 1.23 rillig .endif
251