xref: /freebsd/contrib/bmake/unit-tests/cond-func-empty.mk (revision 6a7405f5a6b639682cacf01e35d561411ff556aa)
1*6a7405f5SSimon J. Gerraty# $NetBSD: cond-func-empty.mk,v 1.28 2025/01/11 20:54:45 rillig Exp $
22c3632d1SSimon J. Gerraty#
3d5e0a182SSimon J. Gerraty# Tests for the empty() function in .if conditions, which tests an
4956e45f6SSimon J. Gerraty# expression for emptiness.
5956e45f6SSimon J. Gerraty#
6d5e0a182SSimon J. Gerraty# Note that the argument in the parentheses is a variable name, not an
798875883SSimon J. Gerraty# expression.  That name may be followed by ':...' modifiers.
8956e45f6SSimon J. Gerraty#
92c3632d1SSimon J. Gerraty
10956e45f6SSimon J. Gerraty.undef UNDEF
11956e45f6SSimon J. GerratyEMPTY=	# empty
12956e45f6SSimon J. GerratySPACE=	${:U }
1398875883SSimon J. GerratyZERO=	0
14956e45f6SSimon J. GerratyWORD=	word
15956e45f6SSimon J. Gerraty
1698875883SSimon J. Gerraty# An undefined variable counts as empty.
17956e45f6SSimon J. Gerraty.if !empty(UNDEF)
18956e45f6SSimon J. Gerraty.  error
19956e45f6SSimon J. Gerraty.endif
20956e45f6SSimon J. Gerraty
21956e45f6SSimon J. Gerraty# An undefined variable has the empty string as the value, and the :M
22956e45f6SSimon J. Gerraty# variable modifier does not change that.
23956e45f6SSimon J. Gerraty#
24956e45f6SSimon J. Gerraty.if !empty(UNDEF:M*)
25956e45f6SSimon J. Gerraty.  error
26956e45f6SSimon J. Gerraty.endif
27956e45f6SSimon J. Gerraty
288c973ee2SSimon J. Gerraty# The :S modifier replaces the empty value with an actual word.  After
29148ee845SSimon J. Gerraty# applying the :S modifier to the expression, its value is 'empty', so it is
308c973ee2SSimon J. Gerraty# no longer empty, but it is still based on an undefined variable.  There are
318c973ee2SSimon J. Gerraty# a few modifiers that turn an undefined expression into a defined expression,
328c973ee2SSimon J. Gerraty# among them :U and :D, but not :S.  Therefore, at the end of evaluating the
338c973ee2SSimon J. Gerraty# expression, the expression is still undefined, so its final value becomes an
348c973ee2SSimon J. Gerraty# empty string.
35956e45f6SSimon J. Gerraty#
36956e45f6SSimon J. Gerraty# XXX: This is hard to explain to someone who doesn't know these
37956e45f6SSimon J. Gerraty# implementation details.
38956e45f6SSimon J. Gerraty#
39956e45f6SSimon J. Gerraty.if !empty(UNDEF:S,^$,value,W)
40956e45f6SSimon J. Gerraty.  error
41956e45f6SSimon J. Gerraty.endif
42956e45f6SSimon J. Gerraty
4312904384SSimon J. Gerraty# The :U modifier changes the state of a previously undefined expression from
4412904384SSimon J. Gerraty# DEF_UNDEF to DEF_DEFINED.  This marks the expression as "being interesting
4512904384SSimon J. Gerraty# enough to be further processed".
46956e45f6SSimon J. Gerraty#
47956e45f6SSimon J. Gerraty.if empty(UNDEF:S,^$,value,W:Ufallback)
48956e45f6SSimon J. Gerraty.  error
49956e45f6SSimon J. Gerraty.endif
50956e45f6SSimon J. Gerraty
518c973ee2SSimon J. Gerraty# When an expression is based on an undefined variable, its modifiers interact
528c973ee2SSimon J. Gerraty# in sometimes surprising ways.  Applying the :S modifier to the undefined
538c973ee2SSimon J. Gerraty# expression makes its value non-empty, but doesn't change that the expression
548c973ee2SSimon J. Gerraty# is based on an undefined variable.  The :U modifier that follows only looks
558c973ee2SSimon J. Gerraty# at the definedness state to decide whether the variable is defined or not.
568c973ee2SSimon J. Gerraty# This kind of makes sense since the :U modifier tests the _variable_, not the
57e2eeea75SSimon J. Gerraty# _expression_.
58956e45f6SSimon J. Gerraty#
598c973ee2SSimon J. Gerraty# Since the variable was undefined to begin with, the fallback value from the
608c973ee2SSimon J. Gerraty# :U modifier is used in this expression, instead of keeping the 'value' from
618c973ee2SSimon J. Gerraty# the :S modifier.
62956e45f6SSimon J. Gerraty#
63956e45f6SSimon J. Gerraty.if ${UNDEF:S,^$,value,W:Ufallback} != "fallback"
64956e45f6SSimon J. Gerraty.  error
65956e45f6SSimon J. Gerraty.endif
66956e45f6SSimon J. Gerraty
67956e45f6SSimon J. Gerraty# The variable EMPTY is completely empty (0 characters).
68956e45f6SSimon J. Gerraty.if !empty(EMPTY)
69956e45f6SSimon J. Gerraty.  error
70956e45f6SSimon J. Gerraty.endif
71956e45f6SSimon J. Gerraty
72956e45f6SSimon J. Gerraty# The variable SPACE has a single space, which counts as being empty.
73956e45f6SSimon J. Gerraty.if !empty(SPACE)
74956e45f6SSimon J. Gerraty.  error
75956e45f6SSimon J. Gerraty.endif
76956e45f6SSimon J. Gerraty
77956e45f6SSimon J. Gerraty# The variable .newline has a single newline, which counts as being empty.
78956e45f6SSimon J. Gerraty.if !empty(.newline)
79956e45f6SSimon J. Gerraty.  error
80956e45f6SSimon J. Gerraty.endif
81956e45f6SSimon J. Gerraty
8298875883SSimon J. Gerraty# The variable ZERO has the numeric value 0, but is not empty.  This is a
8398875883SSimon J. Gerraty# subtle difference between using either 'empty(ZERO)' or the expression
8498875883SSimon J. Gerraty# '${ZERO}' in a condition.
8598875883SSimon J. Gerraty.if empty(ZERO)
8698875883SSimon J. Gerraty.  error
8798875883SSimon J. Gerraty.elif ${ZERO}
8898875883SSimon J. Gerraty.  error
8998875883SSimon J. Gerraty.elif ${ZERO} == ""
9098875883SSimon J. Gerraty.  error
9198875883SSimon J. Gerraty.endif
9298875883SSimon J. Gerraty
9312904384SSimon J. Gerraty# The following example constructs an expression with the variable name ""
9412904384SSimon J. Gerraty# and the value " ".  This expression counts as empty since the value contains
9512904384SSimon J. Gerraty# only whitespace.
96956e45f6SSimon J. Gerraty#
97956e45f6SSimon J. Gerraty# Contrary to the other functions in conditionals, the trailing space is not
98956e45f6SSimon J. Gerraty# stripped off, as can be seen in the -dv debug log.  If the space had been
9912904384SSimon J. Gerraty# stripped, it wouldn't make a difference in this case, but in other cases.
100956e45f6SSimon J. Gerraty#
101956e45f6SSimon J. Gerraty.if !empty(:U )
102956e45f6SSimon J. Gerraty.  error
103956e45f6SSimon J. Gerraty.endif
104956e45f6SSimon J. Gerraty
105956e45f6SSimon J. Gerraty# Now the variable named " " gets a non-empty value, which demonstrates that
106956e45f6SSimon J. Gerraty# neither leading nor trailing spaces are trimmed in the argument of the
1078d5c8e21SSimon J. Gerraty# function.  If the spaces were trimmed, the variable name would be "", and
1088d5c8e21SSimon J. Gerraty# that variable is indeed undefined.  Since CondParser_FuncCallEmpty allows
1098d5c8e21SSimon J. Gerraty# subexpressions to be based on undefined variables, the value of the
1108d5c8e21SSimon J. Gerraty# undefined variable "" would be returned as an empty string.
111956e45f6SSimon J. Gerraty${:U }=	space
112956e45f6SSimon J. Gerraty.if empty( )
113956e45f6SSimon J. Gerraty.  error
114956e45f6SSimon J. Gerraty.endif
115956e45f6SSimon J. Gerraty
11698875883SSimon J. Gerraty# The value of the following expression is " word", which is not empty.  To be
11798875883SSimon J. Gerraty# empty, _all_ characters in the expression value have to be whitespace, not
11898875883SSimon J. Gerraty# only the first.
119956e45f6SSimon J. Gerraty.if empty(:U word)
120956e45f6SSimon J. Gerraty.  error
121956e45f6SSimon J. Gerraty.endif
122956e45f6SSimon J. Gerraty
123d5e0a182SSimon J. Gerraty# The :L modifier creates an expression that has the same value as
124956e45f6SSimon J. Gerraty# its name, which both are "VAR" in this case.  The value is therefore not
125956e45f6SSimon J. Gerraty# empty.
126956e45f6SSimon J. Gerraty.if empty(VAR:L)
127956e45f6SSimon J. Gerraty.  error
128956e45f6SSimon J. Gerraty.endif
129956e45f6SSimon J. Gerraty
130956e45f6SSimon J. Gerraty# The variable WORD has the value "word", which does not count as empty.
131956e45f6SSimon J. Gerraty.if empty(WORD)
132956e45f6SSimon J. Gerraty.  error
133956e45f6SSimon J. Gerraty.endif
134956e45f6SSimon J. Gerraty
135956e45f6SSimon J. Gerraty# The expression ${} for a variable with the empty name always evaluates
136956e45f6SSimon J. Gerraty# to an empty string (see Var_Parse, varUndefined).
137956e45f6SSimon J. Gerraty.if !empty()
138956e45f6SSimon J. Gerraty.  error
139956e45f6SSimon J. Gerraty.endif
140956e45f6SSimon J. Gerraty
141d5e0a182SSimon J. Gerraty# Ensure that expressions that appear as part of the function call
1428c973ee2SSimon J. Gerraty# argument are properly parsed.  Typical use cases for this are .for loops,
1438c973ee2SSimon J. Gerraty# which are expanded to exactly these ${:U} expressions.
144956e45f6SSimon J. Gerraty#
14598875883SSimon J. Gerraty# The argument expands to "WORD", and that variable is defined at the
14698875883SSimon J. Gerraty# beginning of this file.  The surrounding 'W' and 'D' ensure that
14798875883SSimon J. Gerraty# CondParser_FuncCallEmpty keeps track of the parsing position, both before
14898875883SSimon J. Gerraty# and after the call to Var_Parse.
149956e45f6SSimon J. Gerraty.if empty(W${:UOR}D)
150956e45f6SSimon J. Gerraty.  error
151956e45f6SSimon J. Gerraty.endif
152956e45f6SSimon J. Gerraty
15398875883SSimon J. Gerraty# There may be spaces outside the parentheses.
154956e45f6SSimon J. Gerraty# Spaces inside the parentheses are interpreted as part of the variable name.
155956e45f6SSimon J. Gerraty.if ! empty ( WORD )
156956e45f6SSimon J. Gerraty.  error
157956e45f6SSimon J. Gerraty.endif
158956e45f6SSimon J. Gerraty
159956e45f6SSimon J. Gerraty${:U WORD }=	variable name with spaces
160956e45f6SSimon J. Gerraty
161956e45f6SSimon J. Gerraty# Now there is a variable named " WORD ", and it is not empty.
162956e45f6SSimon J. Gerraty.if empty ( WORD )
163956e45f6SSimon J. Gerraty.  error
164956e45f6SSimon J. Gerraty.endif
1652c3632d1SSimon J. Gerraty
166*6a7405f5SSimon J. Gerraty# expect+1: Unclosed variable "WORD"
167e2eeea75SSimon J. Gerraty.if empty(WORD
168e2eeea75SSimon J. Gerraty.  error
169e2eeea75SSimon J. Gerraty.else
170e2eeea75SSimon J. Gerraty.  error
171e2eeea75SSimon J. Gerraty.endif
172e2eeea75SSimon J. Gerraty
17312904384SSimon J. Gerraty# Since cond.c 1.76 from 2020-06-28 and before var.c 1.226 from 2020-07-02,
17412904384SSimon J. Gerraty# the following example generated a wrong error message "Variable VARNAME is
17512904384SSimon J. Gerraty# recursive".
17606b9b3e0SSimon J. Gerraty#
17712904384SSimon J. Gerraty# Since at least 1993, the manual page claimed that irrelevant parts of
17812904384SSimon J. Gerraty# conditions were not evaluated, but that was wrong for a long time.  The
17912904384SSimon J. Gerraty# expressions in irrelevant parts of the condition were actually evaluated,
1808c973ee2SSimon J. Gerraty# they just allowed undefined variables to be used in the conditions.  These
1818c973ee2SSimon J. Gerraty# unnecessary evaluations were fixed in several commits, starting with var.c
1828c973ee2SSimon J. Gerraty# 1.226 from 2020-07-02.
18312904384SSimon J. Gerraty#
18412904384SSimon J. Gerraty# In this example, the variable "VARNAME2" is not defined, so evaluation of
18512904384SSimon J. Gerraty# the condition should have stopped at this point, and the rest of the
18612904384SSimon J. Gerraty# condition should have been processed in parse-only mode.  The right-hand
18712904384SSimon J. Gerraty# side containing the '!empty' was evaluated though, as it had always been.
18806b9b3e0SSimon J. Gerraty#
18906b9b3e0SSimon J. Gerraty# When evaluating the !empty condition, the variable name was parsed as
190d5e0a182SSimon J. Gerraty# "VARNAME${:U2}", but without expanding any nested expression, in
19112904384SSimon J. Gerraty# this case the ${:U2}.  The expression '${:U2}' was replaced with an empty
19212904384SSimon J. Gerraty# string, the resulting variable name was thus "VARNAME".  This conceptually
19312904384SSimon J. Gerraty# wrong variable name should have been discarded quickly after parsing it, to
19412904384SSimon J. Gerraty# prevent it from doing any harm.
19506b9b3e0SSimon J. Gerraty#
1968d5c8e21SSimon J. Gerraty# The expression was evaluated, and this was wrong.  The evaluation was done
1978d5c8e21SSimon J. Gerraty# without VARE_EVAL (called VARF_WANTRES back then) though.  This had the
1988d5c8e21SSimon J. Gerraty# effect that the ${:U1} from the value of VARNAME evaluated to an empty
1998d5c8e21SSimon J. Gerraty# string.  This in turn created the seemingly recursive definition
2008d5c8e21SSimon J. Gerraty# VARNAME=${VARNAME}, and that definition was evaluated even though it was
2018d5c8e21SSimon J. Gerraty# never meant to be evaluated.
20206b9b3e0SSimon J. Gerraty#
2038d5c8e21SSimon J. Gerraty# This was fixed by evaluating nested expressions in the variable name only
2048d5c8e21SSimon J. Gerraty# when the whole expression was evaluated as well.
20506b9b3e0SSimon J. GerratyVARNAME=	${VARNAME${:U1}}
20606b9b3e0SSimon J. Gerraty.if defined(VARNAME${:U2}) && !empty(VARNAME${:U2})
20706b9b3e0SSimon J. Gerraty.endif
20806b9b3e0SSimon J. Gerraty
209*6a7405f5SSimon J. Gerraty# Expressions in the argument of a function call don't have to be defined.
210*6a7405f5SSimon J. Gerraty.if !empty(${UNDEF})
211*6a7405f5SSimon J. Gerraty.  error
212*6a7405f5SSimon J. Gerraty.endif
2139f45a3c8SSimon J. Gerraty
2149f45a3c8SSimon J. Gerraty# If the word 'empty' is not followed by '(', it is not a function call but an
2159f45a3c8SSimon J. Gerraty# ordinary bare word.  This bare word is interpreted as 'defined(empty)', and
2169f45a3c8SSimon J. Gerraty# since there is no variable named 'empty', the condition evaluates to false.
2179f45a3c8SSimon J. Gerraty.if empty
2189f45a3c8SSimon J. Gerraty.  error
2199f45a3c8SSimon J. Gerraty.endif
2209f45a3c8SSimon J. Gerraty
2219f45a3c8SSimon J. Gerratyempty=		# defined but empty
2229f45a3c8SSimon J. Gerraty.if empty
2239f45a3c8SSimon J. Gerraty.else
2249f45a3c8SSimon J. Gerraty.  error
2259f45a3c8SSimon J. Gerraty.endif
226