10SN/A# $NetBSD: varmod-defined.mk,v 1.16 2023/11/19 21:47:52 rillig Exp $
2157SN/A#
30SN/A# Tests for the :D variable modifier, which returns the given string
40SN/A# if the variable is defined.  It is closely related to the :U modifier.
50SN/A
60SN/A# Force the test results to be independent of the default value of this
7157SN/A# setting, which is 'yes' for NetBSD's usr.bin/make but 'no' for the bmake
80SN/A# distribution and pkgsrc/devel/bmake.
9157SN/A.MAKE.SAVE_DOLLARS=	yes
100SN/A
110SN/ADEF=	defined
120SN/A.undef UNDEF
130SN/A
140SN/A# Since DEF is defined, the value of the expression is "value", not
150SN/A# "defined".
160SN/A#
170SN/A.if ${DEF:Dvalue} != "value"
180SN/A.  error
190SN/A.endif
200SN/A
21157SN/A# Since UNDEF is not defined, the "value" is ignored.  Instead of leaving the
22157SN/A# expression undefined, it is set to "", exactly to allow the expression to
23157SN/A# be used in .if conditions.  In this place, other undefined expressions
240SN/A# would generate an error message.
250SN/A# XXX: Ideally the error message would be "undefined variable", but as of
260SN/A# 2020-08-25 it is "Malformed conditional".
270SN/A#
280SN/A.if ${UNDEF:Dvalue} != ""
290SN/A.  error
300SN/A.endif
310SN/A
320SN/A# The modifier text may contain plain text as well as expressions.
330SN/A#
340SN/A.if ${DEF:D<${DEF}>} != "<defined>"
350SN/A.  error
360SN/A.endif
370SN/A
380SN/A# Special characters that would be interpreted differently can be escaped.
390SN/A# These are '}' (the closing character of the expression), ':', '$' and '\'.
400SN/A# Any other backslash sequences are preserved.
410SN/A#
420SN/A# The escaping rules for string literals in conditions are completely
430SN/A# different though. There, any character may be escaped using a backslash.
440SN/A#
450SN/A.if ${DEF:D \} \: \$ \\ \) \n } != " } : \$ \\ \\) \\n "
460SN/A.  error
470SN/A.endif
480SN/A
490SN/A# Like in several other places in expressions, when
500SN/A# ApplyModifier_Defined calls Var_Parse, double dollars lead to a parse
510SN/A# error that is silently ignored.  This makes all dollar signs disappear,
520SN/A# except for the last, which is a well-formed expression.
530SN/A#
540SN/A.if ${DEF:D$$$$$${DEF}} != "defined"
550SN/A.  error
560SN/A.endif
570SN/A
580SN/A# Any other text is written without any further escaping.  In contrast
590SN/A# to the :M modifier, parentheses and braces do not need to be nested.
600SN/A# Instead, the :D modifier is implemented sanely by parsing nested
610SN/A# expressions as such, without trying any shortcuts. See ParseModifier_Match
620SN/A# for an inferior variant.
630SN/A#
640SN/A.if ${DEF:D!&((((} != "!&(((("
650SN/A.  error
660SN/A.endif
670SN/A
680SN/A# The :D modifier is often used in combination with the :U modifier.
690SN/A# It does not matter in which order the :D and :U modifiers appear.
700SN/A.if ${UNDEF:Dyes:Uno} != no
710SN/A.  error
720SN/A.endif
730SN/A.if ${UNDEF:Uno:Dyes} != no
740SN/A.  error
750SN/A.endif
760SN/A.if ${DEF:Dyes:Uno} != yes
770SN/A.  error
780SN/A.endif
790SN/A.if ${DEF:Uno:Dyes} != yes
800SN/A.  error
810SN/A.endif
820SN/A
830SN/A# Since the variable with the empty name is never defined, the :D modifier
840SN/A# can be used to add comments in the middle of an expression.  That
850SN/A# expression always evaluates to an empty string.
860SN/A.if ${:D This is a comment. } != ""
870SN/A.  error
880SN/A.endif
890SN/A
900SN/A# TODO: Add more tests for parsing the plain text part, to cover each branch
910SN/A# of ApplyModifier_Defined.
920SN/A
930SN/A# The :D and :U modifiers behave differently from the :@var@ modifier in
940SN/A# that they preserve dollars in a ':=' assignment.  This is because
950SN/A# ApplyModifier_Defined passes the emode unmodified to Var_Parse, unlike
960SN/A# ApplyModifier_Loop, which uses ParseModifierPart, which in turn removes
970SN/A# the keepDollar flag from emode.
980SN/A#
990SN/A# XXX: This inconsistency is documented nowhere.
1000SN/A.MAKEFLAGS: -dv
1010SN/A8_DOLLARS=	$$$$$$$$
1020SN/AVAR:=		${8_DOLLARS}
1030SN/AVAR:=		${VAR:D${8_DOLLARS}}
1040SN/AVAR:=		${VAR:@var@${8_DOLLARS}@}
1050SN/A.MAKEFLAGS: -d0
1060SN/A
1070SN/A
1080SN/A# Before var.c 1.1030 from 2022-08-24, the following expression caused an
1090SN/A# out-of-bounds read when parsing the indirect ':U' modifier.
1100SN/AM_U_backslash:=	${:UU\\}
1110SN/A.if ${:${M_U_backslash}} != "\\"
1120SN/A.  error
1130SN/A.endif
1140SN/A
1150SN/A
1160SN/Aall: .PHONY
1170SN/A