var-op-sunsh.mk revision 1.4 1 1.4 rillig # $NetBSD: var-op-sunsh.mk,v 1.4 2020/10/04 08:14:35 rillig Exp $
2 1.1 rillig #
3 1.1 rillig # Tests for the :sh= variable assignment operator, which runs its right-hand
4 1.1 rillig # side through the shell. It is a seldom-used alternative to the !=
5 1.2 rillig # assignment operator, adopted from Sun make.
6 1.1 rillig
7 1.1 rillig .MAKEFLAGS: -dL # Enable sane error messages
8 1.1 rillig
9 1.1 rillig # This is the idiomatic form of the Sun shell assignment operator.
10 1.1 rillig # The assignment operator is directly preceded by the ':sh'.
11 1.1 rillig VAR:sh= echo colon-sh
12 1.1 rillig .if ${VAR} != "colon-sh"
13 1.1 rillig . error
14 1.1 rillig .endif
15 1.1 rillig
16 1.2 rillig # It is also possible to have whitespace around the :sh assignment
17 1.2 rillig # operator modifier.
18 1.2 rillig VAR :sh = echo colon-sh-spaced
19 1.2 rillig .if ${VAR} != "colon-sh-spaced"
20 1.2 rillig . error
21 1.2 rillig .endif
22 1.2 rillig
23 1.2 rillig # Until 2020-10-04, the ':sh' could even be followed by other characters.
24 1.2 rillig # This was neither documented by NetBSD make nor by Solaris make and was
25 1.2 rillig # an implementation error.
26 1.2 rillig #
27 1.2 rillig # Since 2020-10-04, this is a normal variable assignment using the '='
28 1.2 rillig # assignment operator.
29 1.1 rillig VAR:shell= echo colon-shell
30 1.2 rillig .if ${${:UVAR\:shell}} != "echo colon-shell"
31 1.1 rillig . error
32 1.1 rillig .endif
33 1.1 rillig
34 1.2 rillig # Several colons can syntactically appear in a variable name.
35 1.2 rillig # Until 2020-10-04, the last of them was interpreted as the ':sh'
36 1.2 rillig # assignment operator.
37 1.2 rillig #
38 1.2 rillig # Since 2020-10-04, the colons are part of the variable name.
39 1.1 rillig VAR:shoe:shore= echo two-colons
40 1.2 rillig .if ${${:UVAR\:shoe\:shore}} != "echo two-colons"
41 1.1 rillig . error
42 1.1 rillig .endif
43 1.1 rillig
44 1.2 rillig # Until 2020-10-04, the following expression was wrongly marked as
45 1.2 rillig # a parse error. This was because the parser for variable assignments
46 1.2 rillig # just looked for the previous ":sh", without taking any contextual
47 1.2 rillig # information into account.
48 1.1 rillig #
49 1.1 rillig # There are two different syntactical elements that look exactly the same:
50 1.1 rillig # The variable modifier ':sh' and the assignment operator modifier ':sh'.
51 1.2 rillig # Intuitively this variable name contains the variable modifier, but until
52 1.2 rillig # 2020-10-04, the parser regarded it as an assignment operator modifier, in
53 1.2 rillig # Parse_DoVar.
54 1.2 rillig VAR.${:Uecho 123:sh}= ok-123
55 1.2 rillig .if ${VAR.123} != "ok-123"
56 1.1 rillig . error
57 1.1 rillig .endif
58 1.1 rillig
59 1.2 rillig # Same pattern here. Until 2020-10-04, the ':sh' inside the nested expression
60 1.2 rillig # was taken for the :sh assignment operator modifier, even though it was
61 1.2 rillig # escaped by a backslash.
62 1.2 rillig VAR.${:U echo\:shell}= ok-shell
63 1.2 rillig .if ${VAR.${:U echo\:shell}} != "ok-shell"
64 1.1 rillig . error
65 1.1 rillig .endif
66 1.1 rillig
67 1.2 rillig # Until 2020-10-04, the word 'shift' was also affected since it starts with
68 1.2 rillig # ':sh'.
69 1.2 rillig VAR.key:shift= Shift
70 1.2 rillig .if ${${:UVAR.key\:shift}} != "Shift"
71 1.1 rillig . error
72 1.1 rillig .endif
73 1.1 rillig
74 1.3 rillig # Just for fun: The code in Parse_IsVar allows for multiple appearances of
75 1.3 rillig # the ':sh' assignment operator modifier. Let's see what happens ...
76 1.3 rillig #
77 1.3 rillig # Well, the end result is correct but the way until there is rather
78 1.3 rillig # adventurous. This only works because the parser replaces each an every
79 1.3 rillig # whitespace character that is not nested with '\0' (see Parse_DoVar).
80 1.3 rillig # The variable name therefore ends before the first ':sh', and the last
81 1.3 rillig # ':sh' turns the assignment operator into the shell command evaluation.
82 1.3 rillig # Parse_DoVar completely trusts Parse_IsVar to properly verify the syntax.
83 1.3 rillig #
84 1.3 rillig # The ':sh' is the only word that may occur between the variable name and
85 1.3 rillig # the assignment operator. All other words would lead to a parse error
86 1.3 rillig # since the left-hand side of an assignment must be exactly one word.
87 1.3 rillig VAR :sh :sh :sh :sh= echo multiple
88 1.3 rillig .if ${VAR} != "multiple"
89 1.3 rillig . error
90 1.3 rillig .endif
91 1.3 rillig
92 1.4 rillig # The word ':sh' is not the only thing that can occur after a variable name.
93 1.4 rillig # Since the parser just counts braces and parentheses instead of properly
94 1.4 rillig # expanding nested expressions, the token ' :sh' can be used to add arbitrary
95 1.4 rillig # text between the variable name and the assignment operator, it just has to
96 1.4 rillig # be enclosed in braces or parentheses.
97 1.4 rillig VAR :sh(Put a comment here)= comment in parentheses
98 1.4 rillig .if ${VAR} != "comment in parentheses"
99 1.4 rillig . error
100 1.4 rillig .endif
101 1.4 rillig
102 1.4 rillig # The unintended comment can include multiple levels of nested braces and
103 1.4 rillig # parentheses, they don't even need to be balanced since they are only
104 1.4 rillig # counted by Parse_IsVar and ignored by Parse_DoVar.
105 1.4 rillig VAR :sh{Put}((((a}{comment}}}}{here}= comment in braces
106 1.4 rillig .if ${VAR} != "comment in braces"
107 1.4 rillig . error
108 1.4 rillig .endif
109 1.4 rillig
110 1.1 rillig all:
111 1.1 rillig @:;
112