1 1.18 rillig # $NetBSD: varname.mk,v 1.18 2025/06/28 22:39:29 rillig Exp $ 2 1.1 rillig # 3 1.17 rillig # Tests for variable names. 4 1.1 rillig 5 1.5 rillig .MAKEFLAGS: -dv 6 1.5 rillig 7 1.17 rillig # In a variable assignment, braces are allowed in the variable name, but they 8 1.17 rillig # must be balanced. Parentheses and braces may be mixed. 9 1.5 rillig VAR{{{}}}= 3 braces 10 1.5 rillig .if "${VAR{{{}}}}" != "3 braces" 11 1.5 rillig . error 12 1.5 rillig .endif 13 1.5 rillig 14 1.14 rillig # In expressions, the parser works differently. It doesn't treat 15 1.5 rillig # braces and parentheses equally, therefore the first closing brace already 16 1.5 rillig # marks the end of the variable name. 17 1.5 rillig VARNAME= VAR((( 18 1.5 rillig ${VARNAME}= 3 open parentheses 19 1.5 rillig .if "${VAR(((}}}}" != "3 open parentheses}}}" 20 1.5 rillig . error 21 1.5 rillig .endif 22 1.5 rillig 23 1.5 rillig # In the above test, the variable name is constructed indirectly. Neither 24 1.5 rillig # of the following expressions produces the intended effect. 25 1.7 rillig # 26 1.7 rillig # This is not a variable assignment since the parentheses and braces are not 27 1.7 rillig # balanced. At the end of the line, there are still 3 levels open, which 28 1.7 rillig # means the variable name is not finished. 29 1.18 rillig # expect+2: Missing ")" in archive specification 30 1.16 rillig # expect+1: Error in archive specification: "VAR" 31 1.6 rillig ${:UVAR(((}= try1 32 1.8 rillig # On the left-hand side of a variable assignments, the backslash is not parsed 33 1.8 rillig # as an escape character, therefore the parentheses still count to the nesting 34 1.8 rillig # level, which at the end of the line is still 3. Therefore this is not a 35 1.8 rillig # variable assignment as well. 36 1.18 rillig # expect+1: Invalid line "${:UVAR\(\(\(}= try2", expanded to "VAR\(\(\(= try2" 37 1.6 rillig ${:UVAR\(\(\(}= try2 38 1.8 rillig # To assign to a variable with an arbitrary name, the variable name has to 39 1.8 rillig # come from an external source, not the text that is parsed in the assignment 40 1.8 rillig # itself. This is exactly the reason why further above, the indirect 41 1.8 rillig # ${VARNAME} works, while all other attempts fail. 42 1.8 rillig ${VARNAME}= try3 43 1.5 rillig 44 1.5 rillig .MAKEFLAGS: -d0 45 1.1 rillig 46 1.9 rillig # All variable names of a scope are stored in the same hash table, using a 47 1.10 rillig # simple hash function. Ensure that HashTable_Find handles collisions 48 1.9 rillig # correctly and that the correct variable is looked up. The strings "0x" and 49 1.9 rillig # "1Y" have the same hash code, as 31 * '0' + 'x' == 31 * '1' + 'Y'. 50 1.9 rillig V.0x= 0x 51 1.9 rillig V.1Y= 1Y 52 1.9 rillig .if ${V.0x} != "0x" || ${V.1Y} != "1Y" 53 1.9 rillig . error 54 1.9 rillig .endif 55 1.9 rillig 56 1.9 rillig # The string "ASDZguv", when used as a prefix of a variable name, keeps the 57 1.9 rillig # hash code unchanged, its own hash code is 0. 58 1.9 rillig ASDZguvV.0x= 0x 59 1.9 rillig ASDZguvV.1Y= 1Y 60 1.9 rillig .if ${ASDZguvV.0x} != "0x" 61 1.9 rillig . error 62 1.9 rillig .elif ${ASDZguvV.1Y} != "1Y" 63 1.9 rillig . error 64 1.9 rillig .endif 65 1.9 rillig 66 1.9 rillig # Ensure that variables with the same hash code whose name is a prefix of the 67 1.9 rillig # other can be accessed. In this case, the shorter variable name is defined 68 1.9 rillig # first to make it appear later in the bucket of the hash table. 69 1.9 rillig ASDZguv= once 70 1.9 rillig ASDZguvASDZguv= twice 71 1.9 rillig .if ${ASDZguv} != "once" 72 1.9 rillig . error 73 1.9 rillig .elif ${ASDZguvASDZguv} != "twice" 74 1.9 rillig . error 75 1.9 rillig .endif 76 1.9 rillig 77 1.9 rillig # Ensure that variables with the same hash code whose name is a prefix of the 78 1.9 rillig # other can be accessed. In this case, the longer variable name is defined 79 1.9 rillig # first to make it appear later in the bucket of the hash table. 80 1.9 rillig ASDZguvASDZguv.param= twice 81 1.9 rillig ASDZguv.param= once 82 1.9 rillig .if ${ASDZguv.param} != "once" 83 1.9 rillig . error 84 1.9 rillig .elif ${ASDZguvASDZguv.param} != "twice" 85 1.9 rillig . error 86 1.9 rillig .endif 87 1.9 rillig 88 1.17 rillig 89 1.17 rillig # Warn about expressions in the style of GNU make, as these would silently 90 1.17 rillig # expand to an empty string instead. 91 1.17 rillig # 92 1.17 rillig # https://pubs.opengroup.org/onlinepubs/9799919799/utilities/make.html says: 93 1.17 rillig # a macro name shall not contain an <equals-sign>, <blank>, or control 94 1.17 rillig # character. 95 1.17 rillig # 96 1.17 rillig GNU_MAKE_IF= $(if ${HAVE_STRLEN},yes,no) 97 1.17 rillig # expect+1: warning: Invalid character " " in variable name "if ,yes,no" 98 1.17 rillig .if ${GNU_MAKE_IF} != "" 99 1.17 rillig . error 100 1.17 rillig .endif 101 1.17 rillig # 102 1.17 rillig # This requirement needs to be ignored for expressions with a ":L" or ":?:" 103 1.17 rillig # modifier, as these modifiers rely on arbitrary characters in the expression 104 1.17 rillig # name. 105 1.17 rillig .if ${"left" == "right":?equal:unequal} != "unequal" 106 1.17 rillig . error 107 1.17 rillig .endif 108 1.17 rillig # 109 1.17 rillig # In fact, this requirement is ignored for any expression that has a modifier. 110 1.17 rillig # In this indirect case, though, the expression with the space in the name is 111 1.17 rillig # a nested expression, so the ":U" modifier doesn't affect the warning. 112 1.17 rillig # expect+1: warning: Invalid character " " in variable name "if ,yes,no" 113 1.17 rillig .if ${GNU_MAKE_IF:Ufallback} != "" 114 1.17 rillig . error 115 1.17 rillig .endif 116 1.17 rillig # 117 1.17 rillig # A modifier in a nested expression does not affect the warning. 118 1.17 rillig GNU_MAKE_IF_EXPR= $(if ${HAVE_STRLEN},${HEADERS:.h=.c},) 119 1.17 rillig # expect+1: warning: Invalid character " " in variable name "if ,," 120 1.17 rillig .if ${GNU_MAKE_IF_EXPR} != "" 121 1.17 rillig . error 122 1.17 rillig .endif 123 1.17 rillig # 124 1.17 rillig # When the GNU make expression contains a colon, chances are good that the 125 1.17 rillig # colon is interpreted as an unknown modifier. 126 1.17 rillig GNU_MAKE_IF_MODIFIER= $(if ${HAVE_STRLEN},answer:yes,answer:no) 127 1.17 rillig # expect+1: Unknown modifier ":yes,answer" 128 1.17 rillig .if ${GNU_MAKE_IF_MODIFIER} != "no)" 129 1.17 rillig . error 130 1.17 rillig .endif 131 1.17 rillig # 132 1.17 rillig # If the variable name contains a non-printable character, the warning 133 1.17 rillig # contains the numeric character value instead, to prevent control sequences 134 1.17 rillig # in the output. 135 1.17 rillig CONTROL_CHARACTER= ${:U a b:ts\t} 136 1.17 rillig # expect+2: warning: Invalid character "\x09" in variable name "a b" 137 1.17 rillig # expect+1: Variable "a b" is undefined 138 1.17 rillig .if ${${CONTROL_CHARACTER}} != "" 139 1.17 rillig .endif 140 1.17 rillig # 141 1.17 rillig # For now, only whitespace generates a warning, non-ASCII characters don't. 142 1.17 rillig UMLAUT= 143 1.17 rillig # expect+1: Variable "" is undefined 144 1.17 rillig .if ${${UMLAUT}} != "" 145 1.17 rillig .endif 146