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