xref: /freebsd/contrib/bmake/unit-tests/cond-func-empty.mk (revision 9f45a3c8c82ffead7044ae836d9257113c630d3b)
1*9f45a3c8SSimon J. Gerraty# $NetBSD: cond-func-empty.mk,v 1.17 2021/12/28 22:13:56 rillig Exp $
22c3632d1SSimon J. Gerraty#
3956e45f6SSimon J. Gerraty# Tests for the empty() function in .if conditions, which tests a variable
4956e45f6SSimon J. Gerraty# expression for emptiness.
5956e45f6SSimon J. Gerraty#
612904384SSimon J. Gerraty# Note that the argument in the parentheses is a variable name, not a variable
712904384SSimon J. Gerraty# expression, optionally followed by variable modifiers.
8956e45f6SSimon J. Gerraty#
92c3632d1SSimon J. Gerraty
10956e45f6SSimon J. Gerraty.undef UNDEF
11956e45f6SSimon J. GerratyEMPTY=	# empty
12956e45f6SSimon J. GerratySPACE=	${:U }
13956e45f6SSimon J. GerratyWORD=	word
14956e45f6SSimon J. Gerraty
15956e45f6SSimon J. Gerraty# An undefined variable is empty.
16956e45f6SSimon J. Gerraty.if !empty(UNDEF)
17956e45f6SSimon J. Gerraty.  error
18956e45f6SSimon J. Gerraty.endif
19956e45f6SSimon J. Gerraty
20956e45f6SSimon J. Gerraty# An undefined variable has the empty string as the value, and the :M
21956e45f6SSimon J. Gerraty# variable modifier does not change that.
22956e45f6SSimon J. Gerraty#
23956e45f6SSimon J. Gerraty.if !empty(UNDEF:M*)
24956e45f6SSimon J. Gerraty.  error
25956e45f6SSimon J. Gerraty.endif
26956e45f6SSimon J. Gerraty
27e2eeea75SSimon J. Gerraty# The :S modifier replaces the empty value with an actual word.  The
2812904384SSimon J. Gerraty# expression is now no longer empty, but it is still based on an undefined
2912904384SSimon J. Gerraty# variable (DEF_UNDEF).  There are a few variable modifiers that turn an
3012904384SSimon J. Gerraty# undefined expression into a defined expression, among them :U and :D, but
3112904384SSimon J. Gerraty# not :S.
32956e45f6SSimon J. Gerraty#
33956e45f6SSimon J. Gerraty# XXX: This is hard to explain to someone who doesn't know these
34956e45f6SSimon J. Gerraty# implementation details.
35956e45f6SSimon J. Gerraty#
36956e45f6SSimon J. Gerraty.if !empty(UNDEF:S,^$,value,W)
37956e45f6SSimon J. Gerraty.  error
38956e45f6SSimon J. Gerraty.endif
39956e45f6SSimon J. Gerraty
4012904384SSimon J. Gerraty# The :U modifier changes the state of a previously undefined expression from
4112904384SSimon J. Gerraty# DEF_UNDEF to DEF_DEFINED.  This marks the expression as "being interesting
4212904384SSimon J. Gerraty# enough to be further processed".
43956e45f6SSimon J. Gerraty#
44956e45f6SSimon J. Gerraty.if empty(UNDEF:S,^$,value,W:Ufallback)
45956e45f6SSimon J. Gerraty.  error
46956e45f6SSimon J. Gerraty.endif
47956e45f6SSimon J. Gerraty
48956e45f6SSimon J. Gerraty# And now to the surprising part.  Applying the following :S modifier to the
4912904384SSimon J. Gerraty# undefined expression makes it non-empty, but the expression is still in
5012904384SSimon J. Gerraty# state DEF_UNDEF.  The :U modifier that follows only looks at the state
5112904384SSimon J. Gerraty# DEF_UNDEF to decide whether the variable is defined or not.  This kind of
5212904384SSimon J. Gerraty# makes sense since the :U modifier tests the _variable_, not the
53e2eeea75SSimon J. Gerraty# _expression_.
54956e45f6SSimon J. Gerraty#
55e2eeea75SSimon J. Gerraty# But since the variable was undefined to begin with, the fallback value from
56e2eeea75SSimon J. Gerraty# the :U modifier is used in this expression.
57956e45f6SSimon J. Gerraty#
58956e45f6SSimon J. Gerraty.if ${UNDEF:S,^$,value,W:Ufallback} != "fallback"
59956e45f6SSimon J. Gerraty.  error
60956e45f6SSimon J. Gerraty.endif
61956e45f6SSimon J. Gerraty
62956e45f6SSimon J. Gerraty# The variable EMPTY is completely empty (0 characters).
63956e45f6SSimon J. Gerraty.if !empty(EMPTY)
64956e45f6SSimon J. Gerraty.  error
65956e45f6SSimon J. Gerraty.endif
66956e45f6SSimon J. Gerraty
67956e45f6SSimon J. Gerraty# The variable SPACE has a single space, which counts as being empty.
68956e45f6SSimon J. Gerraty.if !empty(SPACE)
69956e45f6SSimon J. Gerraty.  error
70956e45f6SSimon J. Gerraty.endif
71956e45f6SSimon J. Gerraty
72956e45f6SSimon J. Gerraty# The variable .newline has a single newline, which counts as being empty.
73956e45f6SSimon J. Gerraty.if !empty(.newline)
74956e45f6SSimon J. Gerraty.  error
75956e45f6SSimon J. Gerraty.endif
76956e45f6SSimon J. Gerraty
7712904384SSimon J. Gerraty# The following example constructs an expression with the variable name ""
7812904384SSimon J. Gerraty# and the value " ".  This expression counts as empty since the value contains
7912904384SSimon J. Gerraty# only whitespace.
80956e45f6SSimon J. Gerraty#
81956e45f6SSimon J. Gerraty# Contrary to the other functions in conditionals, the trailing space is not
82956e45f6SSimon J. Gerraty# stripped off, as can be seen in the -dv debug log.  If the space had been
8312904384SSimon J. Gerraty# stripped, it wouldn't make a difference in this case, but in other cases.
84956e45f6SSimon J. Gerraty#
85956e45f6SSimon J. Gerraty.if !empty(:U )
86956e45f6SSimon J. Gerraty.  error
87956e45f6SSimon J. Gerraty.endif
88956e45f6SSimon J. Gerraty
89956e45f6SSimon J. Gerraty# Now the variable named " " gets a non-empty value, which demonstrates that
90956e45f6SSimon J. Gerraty# neither leading nor trailing spaces are trimmed in the argument of the
91956e45f6SSimon J. Gerraty# function.  If the spaces were trimmed, the variable name would be "" and
9212904384SSimon J. Gerraty# that variable is indeed undefined.  Since CondParser_FuncCallEmpty calls
9312904384SSimon J. Gerraty# Var_Parse without VARE_UNDEFERR, the value of the undefined variable is
94b0c40a00SSimon J. Gerraty# returned as an empty string.
95956e45f6SSimon J. Gerraty${:U }=	space
96956e45f6SSimon J. Gerraty.if empty( )
97956e45f6SSimon J. Gerraty.  error
98956e45f6SSimon J. Gerraty.endif
99956e45f6SSimon J. Gerraty
100956e45f6SSimon J. Gerraty# The value of the following expression is " word", which is not empty.
101956e45f6SSimon J. Gerraty.if empty(:U word)
102956e45f6SSimon J. Gerraty.  error
103956e45f6SSimon J. Gerraty.endif
104956e45f6SSimon J. Gerraty
105956e45f6SSimon J. Gerraty# The :L modifier creates a variable expression that has the same value as
106956e45f6SSimon J. Gerraty# its name, which both are "VAR" in this case.  The value is therefore not
107956e45f6SSimon J. Gerraty# empty.
108956e45f6SSimon J. Gerraty.if empty(VAR:L)
109956e45f6SSimon J. Gerraty.  error
110956e45f6SSimon J. Gerraty.endif
111956e45f6SSimon J. Gerraty
112956e45f6SSimon J. Gerraty# The variable WORD has the value "word", which does not count as empty.
113956e45f6SSimon J. Gerraty.if empty(WORD)
114956e45f6SSimon J. Gerraty.  error
115956e45f6SSimon J. Gerraty.endif
116956e45f6SSimon J. Gerraty
117956e45f6SSimon J. Gerraty# The expression ${} for a variable with the empty name always evaluates
118956e45f6SSimon J. Gerraty# to an empty string (see Var_Parse, varUndefined).
119956e45f6SSimon J. Gerraty.if !empty()
120956e45f6SSimon J. Gerraty.  error
121956e45f6SSimon J. Gerraty.endif
122956e45f6SSimon J. Gerraty
123956e45f6SSimon J. Gerraty# Ensure that variable expressions that appear as part of the argument are
124956e45f6SSimon J. Gerraty# properly parsed.  Typical use cases for this are .for loops, which are
125956e45f6SSimon J. Gerraty# expanded to exactly these ${:U} expressions.
126956e45f6SSimon J. Gerraty#
127956e45f6SSimon J. Gerraty# If everything goes well, the argument expands to "WORD", and that variable
128956e45f6SSimon J. Gerraty# is defined at the beginning of this file.  The surrounding 'W' and 'D'
12912904384SSimon J. Gerraty# ensure that CondParser_FuncCallEmpty keeps track of the parsing position,
13012904384SSimon J. Gerraty# both before and after the call to Var_Parse.
131956e45f6SSimon J. Gerraty.if empty(W${:UOR}D)
132956e45f6SSimon J. Gerraty.  error
133956e45f6SSimon J. Gerraty.endif
134956e45f6SSimon J. Gerraty
135956e45f6SSimon J. Gerraty# There may be spaces at the outside of the parentheses.
136956e45f6SSimon J. Gerraty# Spaces inside the parentheses are interpreted as part of the variable name.
137956e45f6SSimon J. Gerraty.if ! empty ( WORD )
138956e45f6SSimon J. Gerraty.  error
139956e45f6SSimon J. Gerraty.endif
140956e45f6SSimon J. Gerraty
141956e45f6SSimon J. Gerraty${:U WORD }=	variable name with spaces
142956e45f6SSimon J. Gerraty
143956e45f6SSimon J. Gerraty# Now there is a variable named " WORD ", and it is not empty.
144956e45f6SSimon J. Gerraty.if empty ( WORD )
145956e45f6SSimon J. Gerraty.  error
146956e45f6SSimon J. Gerraty.endif
1472c3632d1SSimon J. Gerraty
148e2eeea75SSimon J. Gerraty# Parse error: missing closing parenthesis.
149e2eeea75SSimon J. Gerraty.if empty(WORD
150e2eeea75SSimon J. Gerraty.  error
151e2eeea75SSimon J. Gerraty.else
152e2eeea75SSimon J. Gerraty.  error
153e2eeea75SSimon J. Gerraty.endif
154e2eeea75SSimon J. Gerraty
15512904384SSimon J. Gerraty# Since cond.c 1.76 from 2020-06-28 and before var.c 1.226 from 2020-07-02,
15612904384SSimon J. Gerraty# the following example generated a wrong error message "Variable VARNAME is
15712904384SSimon J. Gerraty# recursive".
15806b9b3e0SSimon J. Gerraty#
15912904384SSimon J. Gerraty# Since at least 1993, the manual page claimed that irrelevant parts of
16012904384SSimon J. Gerraty# conditions were not evaluated, but that was wrong for a long time.  The
16112904384SSimon J. Gerraty# expressions in irrelevant parts of the condition were actually evaluated,
16212904384SSimon J. Gerraty# they just allowed undefined variables to be used in the conditions, and the
16312904384SSimon J. Gerraty# result of evaluating them was not used further.  These unnecessary
16412904384SSimon J. Gerraty# evaluations were fixed in several commits, starting with var.c 1.226 from
16512904384SSimon J. Gerraty# 2020-07-02.
16612904384SSimon J. Gerraty#
16712904384SSimon J. Gerraty# In this example, the variable "VARNAME2" is not defined, so evaluation of
16812904384SSimon J. Gerraty# the condition should have stopped at this point, and the rest of the
16912904384SSimon J. Gerraty# condition should have been processed in parse-only mode.  The right-hand
17012904384SSimon J. Gerraty# side containing the '!empty' was evaluated though, as it had always been.
17106b9b3e0SSimon J. Gerraty#
17206b9b3e0SSimon J. Gerraty# When evaluating the !empty condition, the variable name was parsed as
17306b9b3e0SSimon J. Gerraty# "VARNAME${:U2}", but without expanding any nested variable expression, in
17412904384SSimon J. Gerraty# this case the ${:U2}.  The expression '${:U2}' was replaced with an empty
17512904384SSimon J. Gerraty# string, the resulting variable name was thus "VARNAME".  This conceptually
17612904384SSimon J. Gerraty# wrong variable name should have been discarded quickly after parsing it, to
17712904384SSimon J. Gerraty# prevent it from doing any harm.
17806b9b3e0SSimon J. Gerraty#
17906b9b3e0SSimon J. Gerraty# The variable expression was expanded though, and this was wrong.  The
180b0c40a00SSimon J. Gerraty# expansion was done without VARE_WANTRES (called VARF_WANTRES back
18106b9b3e0SSimon J. Gerraty# then) though.  This had the effect that the ${:U1} from the value of VARNAME
18206b9b3e0SSimon J. Gerraty# expanded to an empty string.  This in turn created the seemingly recursive
18306b9b3e0SSimon J. Gerraty# definition VARNAME=${VARNAME}, and that definition was never meant to be
18406b9b3e0SSimon J. Gerraty# expanded.
18506b9b3e0SSimon J. Gerraty#
18606b9b3e0SSimon J. Gerraty# This was fixed by expanding nested variable expressions in the variable name
18706b9b3e0SSimon J. Gerraty# only if the flag VARE_WANTRES is given.
18806b9b3e0SSimon J. GerratyVARNAME=	${VARNAME${:U1}}
18906b9b3e0SSimon J. Gerraty.if defined(VARNAME${:U2}) && !empty(VARNAME${:U2})
19006b9b3e0SSimon J. Gerraty.endif
19106b9b3e0SSimon J. Gerraty
192*9f45a3c8SSimon J. Gerraty
193*9f45a3c8SSimon J. Gerraty# If the word 'empty' is not followed by '(', it is not a function call but an
194*9f45a3c8SSimon J. Gerraty# ordinary bare word.  This bare word is interpreted as 'defined(empty)', and
195*9f45a3c8SSimon J. Gerraty# since there is no variable named 'empty', the condition evaluates to false.
196*9f45a3c8SSimon J. Gerraty.if empty
197*9f45a3c8SSimon J. Gerraty.  error
198*9f45a3c8SSimon J. Gerraty.endif
199*9f45a3c8SSimon J. Gerraty
200*9f45a3c8SSimon J. Gerratyempty=		# defined but empty
201*9f45a3c8SSimon J. Gerraty.if empty
202*9f45a3c8SSimon J. Gerraty.else
203*9f45a3c8SSimon J. Gerraty.  error
204*9f45a3c8SSimon J. Gerraty.endif
205