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