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