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