1# $NetBSD: varmod-defined.mk,v 1.11 2021/04/11 13:35:56 rillig Exp $
2#
3# Tests for the :D variable modifier, which returns the given string
4# if the variable is defined.  It is closely related to the :U modifier.
5
6.MAKE.SAVE_DOLLARS=	yes
7
8DEF=	defined
9.undef UNDEF
10
11# Since DEF is defined, the value of the expression is "value", not
12# "defined".
13#
14.if ${DEF:Dvalue} != "value"
15.  error
16.endif
17
18# Since UNDEF is not defined, the "value" is ignored.  Instead of leaving the
19# expression undefined, it is set to "", exactly to allow the expression to
20# be used in .if conditions.  In this place, other undefined expressions
21# would generate an error message.
22# XXX: Ideally the error message would be "undefined variable", but as of
23# 2020-08-25 it is "Malformed conditional".
24#
25.if ${UNDEF:Dvalue} != ""
26.  error
27.endif
28
29# The modifier text may contain plain text as well as expressions.
30#
31.if ${DEF:D<${DEF}>} != "<defined>"
32.  error
33.endif
34
35# Special characters that would be interpreted differently can be escaped.
36# These are '}' (the closing character of the expression), ':', '$' and '\'.
37# Any other backslash sequences are preserved.
38#
39# The escaping rules for string literals in conditions are completely
40# different though. There, any character may be escaped using a backslash.
41#
42.if ${DEF:D \} \: \$ \\ \) \n } != " } : \$ \\ \\) \\n "
43.  error
44.endif
45
46# Like in several other places in variable expressions, when
47# ApplyModifier_Defined calls Var_Parse, double dollars lead to a parse
48# error that is silently ignored.  This makes all dollar signs disappear,
49# except for the last, which is a well-formed variable expression.
50#
51.if ${DEF:D$$$$$${DEF}} != "defined"
52.  error
53.endif
54
55# Any other text is written without any further escaping.  In contrast
56# to the :M modifier, parentheses and braces do not need to be nested.
57# Instead, the :D modifier is implemented sanely by parsing nested
58# expressions as such, without trying any shortcuts. See ApplyModifier_Match
59# for an inferior variant.
60#
61.if ${DEF:D!&((((} != "!&(((("
62.  error
63.endif
64
65# The :D modifier is often used in combination with the :U modifier.
66# It does not matter in which order the :D and :U modifiers appear.
67.if ${UNDEF:Dyes:Uno} != no
68.  error
69.endif
70.if ${UNDEF:Uno:Dyes} != no
71.  error
72.endif
73.if ${DEF:Dyes:Uno} != yes
74.  error
75.endif
76.if ${DEF:Uno:Dyes} != yes
77.  error
78.endif
79
80# Since the variable with the empty name is never defined, the :D modifier
81# can be used to add comments in the middle of an expression.  That
82# expression always evaluates to an empty string.
83.if ${:D This is a comment. } != ""
84.  error
85.endif
86
87# TODO: Add more tests for parsing the plain text part, to cover each branch
88# of ApplyModifier_Defined.
89
90# The :D and :U modifiers behave differently from the :@var@ modifier in
91# that they preserve dollars in a ':=' assignment.  This is because
92# ApplyModifier_Defined passes the emode unmodified to Var_Parse, unlike
93# ApplyModifier_Loop, which uses ParseModifierPart, which in turn removes
94# the keepDollar flag from emode.
95#
96# XXX: This inconsistency is documented nowhere.
97.MAKEFLAGS: -dv
988_DOLLARS=	$$$$$$$$
99VAR:=		${8_DOLLARS}
100VAR:=		${VAR:D${8_DOLLARS}}
101VAR:=		${VAR:@var@${8_DOLLARS}@}
102.MAKEFLAGS: -d0
103
104all:
105	@:;
106