1# $NetBSD: varmod.mk,v 1.15 2024/06/06 20:41:50 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"": 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": 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+1: Malformed conditional (${word:L:[99333000222000111000]}) 125.if ${word:L:[99333000222000111000]} 126.endif 127# expect+1: Malformed conditional (${word:L:[2147483648]}) 128.if ${word:L:[2147483648]} 129.endif 130 131# Test the range generation modifier ':range=n' with a very large number that 132# is larger than SIZE_MAX for any supported platform. 133# expect+2: Malformed conditional (${word:L:range=99333000222000111000}) 134# expect+1: while evaluating variable "word": Invalid number "99333000222000111000}" for ':range' modifier 135.if ${word:L:range=99333000222000111000} 136.endif 137 138# In an indirect modifier, the delimiter is '\0', which at the same time marks 139# the end of the string. The sequence '\\' '\0' is not an escaped delimiter, 140# as it would be wrong to skip past the end of the string. 141# expect+2: while evaluating "${:${:Ugmtime=\\}}": Invalid time value "\" 142# expect+1: Malformed conditional (${:${:Ugmtime=\\}}) 143.if ${:${:Ugmtime=\\}} 144. error 145.endif 146 147# Test a '$' at the end of a modifier part, for all modifiers in the order 148# listed in ApplyModifier. 149# 150# The only modifier parts where an unescaped '$' makes sense at the end are 151# the 'from' parts of the ':S' and ':C' modifiers. In all other modifier 152# parts, an unescaped '$' is an undocumented and discouraged edge case, as it 153# means the same as an escaped '$'. 154.if ${:U:!printf '%s\n' $!} != "\$" 155. error 156.endif 157# expect+1: while evaluating variable "VAR": Dollar followed by nothing 158.if ${VAR::=value$} != "" || ${VAR} != "value" 159. error 160.endif 161${:U }= <space> 162# expect+2: while evaluating variable "VAR": Dollar followed by nothing 163# expect+1: while evaluating variable "VAR": Dollar followed by nothing 164.if ${VAR::+=appended$} != "" || ${VAR} != "value<space>appended" 165. error 166.endif 167.if ${1:?then$:else$} != "then\$" 168. error 169.endif 170.if ${0:?then$:else$} != "else\$" 171. error 172.endif 173# expect+1: while evaluating variable "word": Dollar followed by nothing 174.if ${word:L:@w@$w$@} != "word" 175. error 176.endif 177# expect: make: Bad modifier ":[$]" for variable "word" 178# expect+1: Malformed conditional (${word:[$]}) 179.if ${word:[$]} 180. error 181.else 182. error 183.endif 184VAR_DOLLAR= VAR$$ 185.if ${word:L:_=VAR$} != "word" || ${${VAR_DOLLAR}} != "word" 186. error 187.endif 188.if ${word:L:C,d$,m,} != "worm" 189. error 190.endif 191.if ${word:L:C,d,$,} != "wor\$" 192. error 193.endif 194# expect+2: while evaluating variable "VAR": Invalid variable name '}', at "$} != "set"" 195# expect+1: while evaluating variable "VAR": Dollar followed by nothing 196.if ${VAR:Dset$} != "set" 197. error 198.endif 199# expect+1: while evaluating "${:Ufallback$} != "fallback"": Invalid variable name '}', at "$} != "fallback"" 200.if ${:Ufallback$} != "fallback" 201. error 202.endif 203# expect+2: Malformed conditional (${%y:L:gmtime=1000$}) 204# expect+1: while evaluating variable "%y": Invalid time value "1000$" 205.if ${%y:L:gmtime=1000$} 206. error 207.else 208. error 209.endif 210# expect+2: Malformed conditional (${%y:L:localtime=1000$}) 211# expect+1: while evaluating variable "%y": Invalid time value "1000$" 212.if ${%y:L:localtime=1000$} 213. error 214.else 215. error 216.endif 217# expect+1: while evaluating variable "word": Dollar followed by nothing 218.if ${word:L:Mw*$} != "word" 219. error 220.endif 221# expect+1: while evaluating variable "word": Dollar followed by nothing 222.if ${word:L:NX*$} != "word" 223. error 224.endif 225# expect+2: while evaluating variable ".": Invalid argument 'fallback$' for modifier ':mtime' 226# expect+1: Malformed conditional (${.:L:mtime=fallback$}) 227.if ${.:L:mtime=fallback$} 228. error 229.else 230. error 231.endif 232.if ${word:L:S,d$,m,} != "worm" 233. error 234.endif 235.if ${word:L:S,d,m$,} != "worm\$" 236. error 237.endif 238