xref: /freebsd/contrib/bmake/unit-tests/cond-func-empty.mk (revision 8c973ee23d647bbdebd2c12cb51460d80101e11a)
1*8c973ee2SSimon J. Gerraty# $NetBSD: cond-func-empty.mk,v 1.18 2023/03/04 21:15:30 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
27*8c973ee2SSimon J. Gerraty# The :S modifier replaces the empty value with an actual word.  After
28*8c973ee2SSimon J. Gerraty# applying the :S modifier to the expression, it value is 'empty', so it is
29*8c973ee2SSimon J. Gerraty# no longer empty, but it is still based on an undefined variable.  There are
30*8c973ee2SSimon J. Gerraty# a few modifiers that turn an undefined expression into a defined expression,
31*8c973ee2SSimon J. Gerraty# among them :U and :D, but not :S.  Therefore, at the end of evaluating the
32*8c973ee2SSimon J. Gerraty# expression, the expression is still undefined, so its final value becomes an
33*8c973ee2SSimon J. Gerraty# empty string.
34956e45f6SSimon J. Gerraty#
35956e45f6SSimon J. Gerraty# XXX: This is hard to explain to someone who doesn't know these
36956e45f6SSimon J. Gerraty# implementation details.
37956e45f6SSimon J. Gerraty#
38956e45f6SSimon J. Gerraty.if !empty(UNDEF:S,^$,value,W)
39956e45f6SSimon J. Gerraty.  error
40956e45f6SSimon J. Gerraty.endif
41956e45f6SSimon J. Gerraty
4212904384SSimon J. Gerraty# The :U modifier changes the state of a previously undefined expression from
4312904384SSimon J. Gerraty# DEF_UNDEF to DEF_DEFINED.  This marks the expression as "being interesting
4412904384SSimon J. Gerraty# enough to be further processed".
45956e45f6SSimon J. Gerraty#
46956e45f6SSimon J. Gerraty.if empty(UNDEF:S,^$,value,W:Ufallback)
47956e45f6SSimon J. Gerraty.  error
48956e45f6SSimon J. Gerraty.endif
49956e45f6SSimon J. Gerraty
50*8c973ee2SSimon J. Gerraty# When an expression is based on an undefined variable, its modifiers interact
51*8c973ee2SSimon J. Gerraty# in sometimes surprising ways.  Applying the :S modifier to the undefined
52*8c973ee2SSimon J. Gerraty# expression makes its value non-empty, but doesn't change that the expression
53*8c973ee2SSimon J. Gerraty# is based on an undefined variable.  The :U modifier that follows only looks
54*8c973ee2SSimon J. Gerraty# at the definedness state to decide whether the variable is defined or not.
55*8c973ee2SSimon J. Gerraty# This kind of makes sense since the :U modifier tests the _variable_, not the
56e2eeea75SSimon J. Gerraty# _expression_.
57956e45f6SSimon J. Gerraty#
58*8c973ee2SSimon J. Gerraty# Since the variable was undefined to begin with, the fallback value from the
59*8c973ee2SSimon J. Gerraty# :U modifier is used in this expression, instead of keeping the 'value' from
60*8c973ee2SSimon J. Gerraty# the :S modifier.
61956e45f6SSimon J. Gerraty#
62956e45f6SSimon J. Gerraty.if ${UNDEF:S,^$,value,W:Ufallback} != "fallback"
63956e45f6SSimon J. Gerraty.  error
64956e45f6SSimon J. Gerraty.endif
65956e45f6SSimon J. Gerraty
66956e45f6SSimon J. Gerraty# The variable EMPTY is completely empty (0 characters).
67956e45f6SSimon J. Gerraty.if !empty(EMPTY)
68956e45f6SSimon J. Gerraty.  error
69956e45f6SSimon J. Gerraty.endif
70956e45f6SSimon J. Gerraty
71956e45f6SSimon J. Gerraty# The variable SPACE has a single space, which counts as being empty.
72956e45f6SSimon J. Gerraty.if !empty(SPACE)
73956e45f6SSimon J. Gerraty.  error
74956e45f6SSimon J. Gerraty.endif
75956e45f6SSimon J. Gerraty
76956e45f6SSimon J. Gerraty# The variable .newline has a single newline, which counts as being empty.
77956e45f6SSimon J. Gerraty.if !empty(.newline)
78956e45f6SSimon J. Gerraty.  error
79956e45f6SSimon J. Gerraty.endif
80956e45f6SSimon J. Gerraty
8112904384SSimon J. Gerraty# The following example constructs an expression with the variable name ""
8212904384SSimon J. Gerraty# and the value " ".  This expression counts as empty since the value contains
8312904384SSimon J. Gerraty# only whitespace.
84956e45f6SSimon J. Gerraty#
85956e45f6SSimon J. Gerraty# Contrary to the other functions in conditionals, the trailing space is not
86956e45f6SSimon J. Gerraty# stripped off, as can be seen in the -dv debug log.  If the space had been
8712904384SSimon J. Gerraty# stripped, it wouldn't make a difference in this case, but in other cases.
88956e45f6SSimon J. Gerraty#
89956e45f6SSimon J. Gerraty.if !empty(:U )
90956e45f6SSimon J. Gerraty.  error
91956e45f6SSimon J. Gerraty.endif
92956e45f6SSimon J. Gerraty
93956e45f6SSimon J. Gerraty# Now the variable named " " gets a non-empty value, which demonstrates that
94956e45f6SSimon J. Gerraty# neither leading nor trailing spaces are trimmed in the argument of the
95956e45f6SSimon J. Gerraty# function.  If the spaces were trimmed, the variable name would be "" and
9612904384SSimon J. Gerraty# that variable is indeed undefined.  Since CondParser_FuncCallEmpty calls
97*8c973ee2SSimon J. Gerraty# Var_Parse without VARE_UNDEFERR, the value of the undefined variable ""
98*8c973ee2SSimon J. Gerraty# would be returned as an empty string.
99956e45f6SSimon J. Gerraty${:U }=	space
100956e45f6SSimon J. Gerraty.if empty( )
101956e45f6SSimon J. Gerraty.  error
102956e45f6SSimon J. Gerraty.endif
103956e45f6SSimon J. Gerraty
104956e45f6SSimon J. Gerraty# The value of the following expression is " word", which is not empty.
105956e45f6SSimon J. Gerraty.if empty(:U word)
106956e45f6SSimon J. Gerraty.  error
107956e45f6SSimon J. Gerraty.endif
108956e45f6SSimon J. Gerraty
109956e45f6SSimon J. Gerraty# The :L modifier creates a variable expression that has the same value as
110956e45f6SSimon J. Gerraty# its name, which both are "VAR" in this case.  The value is therefore not
111956e45f6SSimon J. Gerraty# empty.
112956e45f6SSimon J. Gerraty.if empty(VAR:L)
113956e45f6SSimon J. Gerraty.  error
114956e45f6SSimon J. Gerraty.endif
115956e45f6SSimon J. Gerraty
116956e45f6SSimon J. Gerraty# The variable WORD has the value "word", which does not count as empty.
117956e45f6SSimon J. Gerraty.if empty(WORD)
118956e45f6SSimon J. Gerraty.  error
119956e45f6SSimon J. Gerraty.endif
120956e45f6SSimon J. Gerraty
121956e45f6SSimon J. Gerraty# The expression ${} for a variable with the empty name always evaluates
122956e45f6SSimon J. Gerraty# to an empty string (see Var_Parse, varUndefined).
123956e45f6SSimon J. Gerraty.if !empty()
124956e45f6SSimon J. Gerraty.  error
125956e45f6SSimon J. Gerraty.endif
126956e45f6SSimon J. Gerraty
127*8c973ee2SSimon J. Gerraty# Ensure that variable expressions that appear as part of the function call
128*8c973ee2SSimon J. Gerraty# argument are properly parsed.  Typical use cases for this are .for loops,
129*8c973ee2SSimon J. Gerraty# which are expanded to exactly these ${:U} expressions.
130956e45f6SSimon J. Gerraty#
131956e45f6SSimon J. Gerraty# If everything goes well, the argument expands to "WORD", and that variable
132956e45f6SSimon J. Gerraty# is defined at the beginning of this file.  The surrounding 'W' and 'D'
13312904384SSimon J. Gerraty# ensure that CondParser_FuncCallEmpty keeps track of the parsing position,
13412904384SSimon J. Gerraty# both before and after the call to Var_Parse.
135956e45f6SSimon J. Gerraty.if empty(W${:UOR}D)
136956e45f6SSimon J. Gerraty.  error
137956e45f6SSimon J. Gerraty.endif
138956e45f6SSimon J. Gerraty
139956e45f6SSimon J. Gerraty# There may be spaces at the outside of the parentheses.
140956e45f6SSimon J. Gerraty# Spaces inside the parentheses are interpreted as part of the variable name.
141956e45f6SSimon J. Gerraty.if ! empty ( WORD )
142956e45f6SSimon J. Gerraty.  error
143956e45f6SSimon J. Gerraty.endif
144956e45f6SSimon J. Gerraty
145956e45f6SSimon J. Gerraty${:U WORD }=	variable name with spaces
146956e45f6SSimon J. Gerraty
147956e45f6SSimon J. Gerraty# Now there is a variable named " WORD ", and it is not empty.
148956e45f6SSimon J. Gerraty.if empty ( WORD )
149956e45f6SSimon J. Gerraty.  error
150956e45f6SSimon J. Gerraty.endif
1512c3632d1SSimon J. Gerraty
152e2eeea75SSimon J. Gerraty# Parse error: missing closing parenthesis.
153e2eeea75SSimon J. Gerraty.if empty(WORD
154e2eeea75SSimon J. Gerraty.  error
155e2eeea75SSimon J. Gerraty.else
156e2eeea75SSimon J. Gerraty.  error
157e2eeea75SSimon J. Gerraty.endif
158e2eeea75SSimon J. Gerraty
15912904384SSimon J. Gerraty# Since cond.c 1.76 from 2020-06-28 and before var.c 1.226 from 2020-07-02,
16012904384SSimon J. Gerraty# the following example generated a wrong error message "Variable VARNAME is
16112904384SSimon J. Gerraty# recursive".
16206b9b3e0SSimon J. Gerraty#
16312904384SSimon J. Gerraty# Since at least 1993, the manual page claimed that irrelevant parts of
16412904384SSimon J. Gerraty# conditions were not evaluated, but that was wrong for a long time.  The
16512904384SSimon J. Gerraty# expressions in irrelevant parts of the condition were actually evaluated,
166*8c973ee2SSimon J. Gerraty# they just allowed undefined variables to be used in the conditions.  These
167*8c973ee2SSimon J. Gerraty# unnecessary evaluations were fixed in several commits, starting with var.c
168*8c973ee2SSimon J. Gerraty# 1.226 from 2020-07-02.
16912904384SSimon J. Gerraty#
17012904384SSimon J. Gerraty# In this example, the variable "VARNAME2" is not defined, so evaluation of
17112904384SSimon J. Gerraty# the condition should have stopped at this point, and the rest of the
17212904384SSimon J. Gerraty# condition should have been processed in parse-only mode.  The right-hand
17312904384SSimon J. Gerraty# side containing the '!empty' was evaluated though, as it had always been.
17406b9b3e0SSimon J. Gerraty#
17506b9b3e0SSimon J. Gerraty# When evaluating the !empty condition, the variable name was parsed as
17606b9b3e0SSimon J. Gerraty# "VARNAME${:U2}", but without expanding any nested variable expression, in
17712904384SSimon J. Gerraty# this case the ${:U2}.  The expression '${:U2}' was replaced with an empty
17812904384SSimon J. Gerraty# string, the resulting variable name was thus "VARNAME".  This conceptually
17912904384SSimon J. Gerraty# wrong variable name should have been discarded quickly after parsing it, to
18012904384SSimon J. Gerraty# prevent it from doing any harm.
18106b9b3e0SSimon J. Gerraty#
18206b9b3e0SSimon J. Gerraty# The variable expression was expanded though, and this was wrong.  The
183b0c40a00SSimon J. Gerraty# expansion was done without VARE_WANTRES (called VARF_WANTRES back
18406b9b3e0SSimon J. Gerraty# then) though.  This had the effect that the ${:U1} from the value of VARNAME
18506b9b3e0SSimon J. Gerraty# expanded to an empty string.  This in turn created the seemingly recursive
18606b9b3e0SSimon J. Gerraty# definition VARNAME=${VARNAME}, and that definition was never meant to be
18706b9b3e0SSimon J. Gerraty# expanded.
18806b9b3e0SSimon J. Gerraty#
18906b9b3e0SSimon J. Gerraty# This was fixed by expanding nested variable expressions in the variable name
19006b9b3e0SSimon J. Gerraty# only if the flag VARE_WANTRES is given.
19106b9b3e0SSimon J. GerratyVARNAME=	${VARNAME${:U1}}
19206b9b3e0SSimon J. Gerraty.if defined(VARNAME${:U2}) && !empty(VARNAME${:U2})
19306b9b3e0SSimon J. Gerraty.endif
19406b9b3e0SSimon J. Gerraty
1959f45a3c8SSimon J. Gerraty
1969f45a3c8SSimon J. Gerraty# If the word 'empty' is not followed by '(', it is not a function call but an
1979f45a3c8SSimon J. Gerraty# ordinary bare word.  This bare word is interpreted as 'defined(empty)', and
1989f45a3c8SSimon J. Gerraty# since there is no variable named 'empty', the condition evaluates to false.
1999f45a3c8SSimon J. Gerraty.if empty
2009f45a3c8SSimon J. Gerraty.  error
2019f45a3c8SSimon J. Gerraty.endif
2029f45a3c8SSimon J. Gerraty
2039f45a3c8SSimon J. Gerratyempty=		# defined but empty
2049f45a3c8SSimon J. Gerraty.if empty
2059f45a3c8SSimon J. Gerraty.else
2069f45a3c8SSimon J. Gerraty.  error
2079f45a3c8SSimon J. Gerraty.endif
208