1*d5e0a182SSimon J. Gerraty# $NetBSD: directive-for-if.mk,v 1.3 2023/11/19 21:47:52 rillig Exp $ 212904384SSimon J. Gerraty# 312904384SSimon J. Gerraty# Test for a .for directive that contains an .if directive. 412904384SSimon J. Gerraty# 512904384SSimon J. Gerraty# Before for.c 1.39 from 2008-12-21, when expanding the variables of a .for 612904384SSimon J. Gerraty# loop, their values were placed verbatim in the expanded body. Since then, 712904384SSimon J. Gerraty# each variable value expands to an expression of the form ${:Uvalue}. 812904384SSimon J. Gerraty# 912904384SSimon J. Gerraty# Before that change, the following adventurous code was possible: 1012904384SSimon J. Gerraty# 1112904384SSimon J. Gerraty# .for directive in if ifdef ifndef 1212904384SSimon J. Gerraty# . ${directive} "1" != "0" 1312904384SSimon J. Gerraty# . endif 1412904384SSimon J. Gerraty# .endfor 1512904384SSimon J. Gerraty# 1612904384SSimon J. Gerraty# A more practical usage of the .for loop that often led to surprises was the 1712904384SSimon J. Gerraty# following: 1812904384SSimon J. Gerraty# 1912904384SSimon J. Gerraty# .for var in VAR1 VAR2 VAR3 2012904384SSimon J. Gerraty# . if ${var} != "VAR2" 2112904384SSimon J. Gerraty# . endif 2212904384SSimon J. Gerraty# .endfor 2312904384SSimon J. Gerraty# 2412904384SSimon J. Gerraty# The .for loop body expanded to this string: 2512904384SSimon J. Gerraty# 2612904384SSimon J. Gerraty# . if VAR1 != "VAR2" 2712904384SSimon J. Gerraty# . endif 2812904384SSimon J. Gerraty# 2912904384SSimon J. Gerraty# Since bare words were not allowed at the left-hand side of a condition, 3012904384SSimon J. Gerraty# make complained about a "Malformed conditional", which was surprising since 3112904384SSimon J. Gerraty# the code before expanding the .for loop body looked quite well. 3212904384SSimon J. Gerraty# 3312904384SSimon J. Gerraty# In cond.c 1.48 from 2008-11-29, just a month before the expansion of .for 3412904384SSimon J. Gerraty# loops changed from plain textual value to using expressions of the form 3512904384SSimon J. Gerraty# ${:Uvalue}, this surprising behavior was documented in the code, and a 3612904384SSimon J. Gerraty# workaround was implemented that allowed bare words when they are followed 3712904384SSimon J. Gerraty# by either '!' or '=', as part of the operators '!=' or '=='. 3812904384SSimon J. Gerraty# 3912904384SSimon J. Gerraty# Since cond.c 1.68 from 2015-05-05, bare words are allowed on the left-hand 4012904384SSimon J. Gerraty# side of a condition, but that applies only to expression of the form 4112904384SSimon J. Gerraty# ${${cond} :? then : else}, it does not apply to conditions in ordinary .if 4212904384SSimon J. Gerraty# directives. 4312904384SSimon J. Gerraty 4412904384SSimon J. Gerraty# The following snippet worked in 2005, when the variables from the .for loop 4512904384SSimon J. Gerraty# expanded to their bare textual value. 4612904384SSimon J. Gerraty.for directive in if ifdef ifndef 4712904384SSimon J. Gerraty. ${directive} "1" != "0" 48148ee845SSimon J. Gerraty# expect+3: if-less endif 49148ee845SSimon J. Gerraty# expect+2: if-less endif 50148ee845SSimon J. Gerraty# expect+1: if-less endif 5112904384SSimon J. Gerraty. endif 5212904384SSimon J. Gerraty.endfor 5312904384SSimon J. Gerraty# In 2021, the above code does not generate an error message, even though the 5412904384SSimon J. Gerraty# code looks clearly malformed. This is due to the '!', which is interpreted 5512904384SSimon J. Gerraty# as a dependency operator, similar to ':' and '::'. The parser turns this 5612904384SSimon J. Gerraty# line into a dependency with the 3 targets '.', 'if', '"1"' and the 2 sources 5712904384SSimon J. Gerraty# '=' and '"0"'. Since that line is not interpreted as an '.if' directive, 5812904384SSimon J. Gerraty# the error message 'if-less endif' makes sense. 5912904384SSimon J. Gerraty 6012904384SSimon J. Gerraty# In 2005, make complained: 6112904384SSimon J. Gerraty# 6212904384SSimon J. Gerraty# .if line: Malformed conditional (VAR1 != "VAR2") 6312904384SSimon J. Gerraty# .endif line: if-less endif 6412904384SSimon J. Gerraty# .endif line: Need an operator 6512904384SSimon J. Gerraty# 6612904384SSimon J. Gerraty# 2008.11.30.22.37.55 does not complain about the left-hand side ${var}. 6712904384SSimon J. Gerraty.for var in VAR1 VAR2 VAR3 6812904384SSimon J. Gerraty. if ${var} != "VAR2" 6912904384SSimon J. Gerraty_!= echo "${var}" 1>&2; echo # In 2005, '.info' was not invented yet. 7012904384SSimon J. Gerraty. endif 7112904384SSimon J. Gerraty.endfor 7212904384SSimon J. Gerraty 7312904384SSimon J. Gerraty# Before for.c 1.39 from 2008-12-21, a common workaround was to surround the 74*d5e0a182SSimon J. Gerraty# expression from the .for loop with '"'. Such a string literal 7512904384SSimon J. Gerraty# has been allowed since cond.c 1.23 from 2004-04-13. Between that commit and 7612904384SSimon J. Gerraty# the one from 2008, the parser would still get confused if the value from the 7712904384SSimon J. Gerraty# .for loop contained '"', which was effectively a code injection. 7812904384SSimon J. Gerraty# 7912904384SSimon J. Gerraty# Surrounding ${var} with quotes disabled the check for typos though. For 8012904384SSimon J. Gerraty# ordinary variables, referring to an undefined variable on the left-hand side 8112904384SSimon J. Gerraty# of the comparison resulted in a "Malformed conditional". Since the .for 8212904384SSimon J. Gerraty# loop was usually close to the .if clause, this was not a problem in 8312904384SSimon J. Gerraty# practice. 8412904384SSimon J. Gerraty.for var in VAR1 VAR2 VAR3 8512904384SSimon J. Gerraty. if "${var}" != "VAR2" 8612904384SSimon J. Gerraty. endif 8712904384SSimon J. Gerraty.endfor 8812904384SSimon J. Gerraty 8912904384SSimon J. Gerratyall: 90