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