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