xref: /freebsd/contrib/bmake/unit-tests/cond-short.mk (revision d5e0a182cf153f8993a633b93d9220c99a89e760)
1*d5e0a182SSimon J. Gerraty# $NetBSD: cond-short.mk,v 1.23 2023/11/19 22:32:44 rillig Exp $
23841c287SSimon J. Gerraty#
33841c287SSimon J. Gerraty# Demonstrates that in conditions, the right-hand side of an && or ||
43841c287SSimon J. Gerraty# is only evaluated if it can actually influence the result.
5e2eeea75SSimon J. Gerraty# This is called 'short-circuit evaluation' and is the usual evaluation
6e2eeea75SSimon J. Gerraty# mode in most programming languages.  A notable exception is Ada, which
7e2eeea75SSimon J. Gerraty# distinguishes between the operators 'And', 'And Then', 'Or', 'Or Else'.
83841c287SSimon J. Gerraty#
906b9b3e0SSimon J. Gerraty# Before 2020-06-28, the right-hand side of an && or || operator was always
1006b9b3e0SSimon J. Gerraty# evaluated, which was wrong.  In cond.c 1.69 and var.c 1.197 on 2015-10-11,
1106b9b3e0SSimon J. Gerraty# Var_Parse got a new parameter named 'wantit'.  Since then it would have been
12*d5e0a182SSimon J. Gerraty# possible to skip evaluation of irrelevant expressions and only
1306b9b3e0SSimon J. Gerraty# parse them.  They were still evaluated though, the only difference to
14*d5e0a182SSimon J. Gerraty# relevant expressions was that in the irrelevant
1512904384SSimon J. Gerraty# expressions, undefined variables were allowed.  This allowed for conditions
1612904384SSimon J. Gerraty# like 'defined(VAR) && ${VAR:S,from,to,} != ""', which no longer produced an
179f45a3c8SSimon J. Gerraty# error message 'Malformed conditional', but the irrelevant expression was
189f45a3c8SSimon J. Gerraty# still evaluated.
1912904384SSimon J. Gerraty#
2012904384SSimon J. Gerraty# Since the initial commit on 1993-03-21, the manual page has been saying that
2112904384SSimon J. Gerraty# make 'will only evaluate a conditional as far as is necessary to determine',
2212904384SSimon J. Gerraty# but that was wrong.  The code in cond.c 1.1 from 1993-03-21 looks good since
2312904384SSimon J. Gerraty# it calls Var_Parse(condExpr, VAR_CMD, doEval,&varSpecLen,&doFree), but the
249f45a3c8SSimon J. Gerraty# definition of Var_Parse did not call the third parameter 'doEval', as would
2512904384SSimon J. Gerraty# be expected, but instead 'err', accompanied by the comment 'TRUE if
2612904384SSimon J. Gerraty# undefined variables are an error'.  This subtle difference between 'do not
2712904384SSimon J. Gerraty# evaluate at all' and 'allow undefined variables' led to the unexpected
2812904384SSimon J. Gerraty# evaluation.
29b0c40a00SSimon J. Gerraty#
30b0c40a00SSimon J. Gerraty# See also:
31b0c40a00SSimon J. Gerraty#	var-eval-short.mk, for short-circuited variable modifiers
323841c287SSimon J. Gerraty
33b0c40a00SSimon J. Gerraty# The && operator:
343841c287SSimon J. Gerraty
353841c287SSimon J. Gerraty.if 0 && ${echo "unexpected and" 1>&2 :L:sh}
363841c287SSimon J. Gerraty.endif
373841c287SSimon J. Gerraty
383841c287SSimon J. Gerraty.if 1 && ${echo "expected and" 1>&2 :L:sh}
393841c287SSimon J. Gerraty.endif
403841c287SSimon J. Gerraty
413841c287SSimon J. Gerraty.if 0 && exists(nonexistent${echo "unexpected and exists" 1>&2 :L:sh})
423841c287SSimon J. Gerraty.endif
433841c287SSimon J. Gerraty
443841c287SSimon J. Gerraty.if 1 && exists(nonexistent${echo "expected and exists" 1>&2 :L:sh})
453841c287SSimon J. Gerraty.endif
463841c287SSimon J. Gerraty
473841c287SSimon J. Gerraty.if 0 && empty(${echo "unexpected and empty" 1>&2 :L:sh})
483841c287SSimon J. Gerraty.endif
493841c287SSimon J. Gerraty
503841c287SSimon J. Gerraty.if 1 && empty(${echo "expected and empty" 1>&2 :L:sh})
513841c287SSimon J. Gerraty.endif
523841c287SSimon J. Gerraty
533841c287SSimon J. Gerraty# "VAR U11" is not evaluated; it was evaluated before 2020-07-02.
543841c287SSimon J. Gerraty# The whole !empty condition is only parsed and then discarded.
553841c287SSimon J. GerratyVAR=	${VAR${:U11${echo "unexpected VAR U11" 1>&2 :L:sh}}}
563841c287SSimon J. GerratyVAR13=	${VAR${:U12${echo "unexpected VAR13" 1>&2 :L:sh}}}
573841c287SSimon J. Gerraty.if 0 && !empty(VAR${:U13${echo "unexpected U13 condition" 1>&2 :L:sh}})
583841c287SSimon J. Gerraty.endif
593841c287SSimon J. Gerraty
603841c287SSimon J. GerratyVAR=	${VAR${:U21${echo "unexpected VAR U21" 1>&2 :L:sh}}}
613841c287SSimon J. GerratyVAR23=	${VAR${:U22${echo   "expected VAR23" 1>&2 :L:sh}}}
623841c287SSimon J. Gerraty.if 1 && !empty(VAR${:U23${echo   "expected U23 condition" 1>&2 :L:sh}})
633841c287SSimon J. Gerraty.endif
643841c287SSimon J. GerratyVAR=	# empty again, for the following tests
653841c287SSimon J. Gerraty
663841c287SSimon J. Gerraty# The :M modifier is only parsed, not evaluated.
673841c287SSimon J. Gerraty# Before 2020-07-02, it was wrongly evaluated.
683841c287SSimon J. Gerraty.if 0 && !empty(VAR:M${:U${echo "unexpected M pattern" 1>&2 :L:sh}})
693841c287SSimon J. Gerraty.endif
703841c287SSimon J. Gerraty
713841c287SSimon J. Gerraty.if 1 && !empty(VAR:M${:U${echo   "expected M pattern" 1>&2 :L:sh}})
723841c287SSimon J. Gerraty.endif
733841c287SSimon J. Gerraty
743841c287SSimon J. Gerraty.if 0 && !empty(VAR:S,from,${:U${echo "unexpected S modifier" 1>&2 :L:sh}},)
753841c287SSimon J. Gerraty.endif
763841c287SSimon J. Gerraty
773841c287SSimon J. Gerraty.if 0 && !empty(VAR:C,from,${:U${echo "unexpected C modifier" 1>&2 :L:sh}},)
783841c287SSimon J. Gerraty.endif
793841c287SSimon J. Gerraty
803841c287SSimon J. Gerraty.if 0 && !empty("" == "" :? ${:U${echo "unexpected ? modifier" 1>&2 :L:sh}} :)
813841c287SSimon J. Gerraty.endif
823841c287SSimon J. Gerraty
833841c287SSimon J. Gerraty.if 0 && !empty(VAR:old=${:U${echo "unexpected = modifier" 1>&2 :L:sh}})
843841c287SSimon J. Gerraty.endif
853841c287SSimon J. Gerraty
863841c287SSimon J. Gerraty.if 0 && !empty(1 2 3:L:@var@${:U${echo "unexpected @ modifier" 1>&2 :L:sh}}@)
873841c287SSimon J. Gerraty.endif
883841c287SSimon J. Gerraty
893841c287SSimon J. Gerraty.if 0 && !empty(:U${:!echo "unexpected exclam modifier" 1>&2 !})
903841c287SSimon J. Gerraty.endif
913841c287SSimon J. Gerraty
922c3632d1SSimon J. Gerraty# Irrelevant assignment modifiers are skipped as well.
932c3632d1SSimon J. Gerraty.if 0 && ${1 2 3:L:@i@${FIRST::?=$i}@}
942c3632d1SSimon J. Gerraty.endif
952c3632d1SSimon J. Gerraty.if 0 && ${1 2 3:L:@i@${LAST::=$i}@}
962c3632d1SSimon J. Gerraty.endif
972c3632d1SSimon J. Gerraty.if 0 && ${1 2 3:L:@i@${APPENDED::+=$i}@}
982c3632d1SSimon J. Gerraty.endif
992c3632d1SSimon J. Gerraty.if 0 && ${echo.1 echo.2 echo.3:L:@i@${RAN::!=${i:C,.*,&; & 1>\&2,:S,., ,g}}@}
1002c3632d1SSimon J. Gerraty.endif
1012c3632d1SSimon J. Gerraty.if defined(FIRST) || defined(LAST) || defined(APPENDED) || defined(RAN)
1022c3632d1SSimon J. Gerraty.  warning first=${FIRST} last=${LAST} appended=${APPENDED} ran=${RAN}
1032c3632d1SSimon J. Gerraty.endif
1042c3632d1SSimon J. Gerraty
105b0c40a00SSimon J. Gerraty# The || operator:
1063841c287SSimon J. Gerraty
1073841c287SSimon J. Gerraty.if 1 || ${echo "unexpected or" 1>&2 :L:sh}
1083841c287SSimon J. Gerraty.endif
1093841c287SSimon J. Gerraty
1103841c287SSimon J. Gerraty.if 0 || ${echo "expected or" 1>&2 :L:sh}
1113841c287SSimon J. Gerraty.endif
1123841c287SSimon J. Gerraty
1133841c287SSimon J. Gerraty.if 1 || exists(nonexistent${echo "unexpected or exists" 1>&2 :L:sh})
1143841c287SSimon J. Gerraty.endif
1153841c287SSimon J. Gerraty
1163841c287SSimon J. Gerraty.if 0 || exists(nonexistent${echo "expected or exists" 1>&2 :L:sh})
1173841c287SSimon J. Gerraty.endif
1183841c287SSimon J. Gerraty
1193841c287SSimon J. Gerraty.if 1 || empty(${echo "unexpected or empty" 1>&2 :L:sh})
1203841c287SSimon J. Gerraty.endif
1213841c287SSimon J. Gerraty
1223841c287SSimon J. Gerraty.if 0 || empty(${echo "expected or empty" 1>&2 :L:sh})
1233841c287SSimon J. Gerraty.endif
1243841c287SSimon J. Gerraty
1259f45a3c8SSimon J. Gerraty# Unreachable nested conditions are skipped completely as well.  These skipped
1269f45a3c8SSimon J. Gerraty# lines may even contain syntax errors.  This allows to skip syntactically
1279f45a3c8SSimon J. Gerraty# incompatible new features in older versions of make.
1283841c287SSimon J. Gerraty
1293841c287SSimon J. Gerraty.if 0
1303841c287SSimon J. Gerraty.  if ${echo "unexpected nested and" 1>&2 :L:sh}
1313841c287SSimon J. Gerraty.  endif
1323841c287SSimon J. Gerraty.endif
1333841c287SSimon J. Gerraty
1343841c287SSimon J. Gerraty.if 1
1353841c287SSimon J. Gerraty.elif ${echo "unexpected nested or" 1>&2 :L:sh}
1363841c287SSimon J. Gerraty.endif
1373841c287SSimon J. Gerraty
1383841c287SSimon J. Gerraty
1398c973ee2SSimon J. GerratyNUMBER=		42
1408c973ee2SSimon J. GerratyINDIR_NUMBER=	${NUMBER}
1418c973ee2SSimon J. GerratyINDIR_UNDEF=	${UNDEF}
1423841c287SSimon J. Gerraty
1438c973ee2SSimon J. Gerraty.if defined(NUMBER) && ${NUMBER} > 0
1443841c287SSimon J. Gerraty.else
1458c973ee2SSimon J. Gerraty.  error
1463841c287SSimon J. Gerraty.endif
1472c3632d1SSimon J. Gerraty
1488c973ee2SSimon J. Gerraty# Starting with var.c 1.226 from from 2020-07-02, the following condition
1498c973ee2SSimon J. Gerraty# triggered a warning: "String comparison operator should be either == or !=".
1508c973ee2SSimon J. Gerraty#
1518c973ee2SSimon J. Gerraty# The left-hand side of the '&&' evaluated to false, which should have made
1528c973ee2SSimon J. Gerraty# the right-hand side irrelevant.
1538c973ee2SSimon J. Gerraty#
1548c973ee2SSimon J. Gerraty# On the right-hand side of the '&&', the expression ${INDIR_UNDEF} was
1558c973ee2SSimon J. Gerraty# defined and had the value '${UNDEF}', but the nested variable UNDEF was
1568c973ee2SSimon J. Gerraty# undefined.  The right hand side "${INDIR_UNDEF}" still needed to be parsed,
1578c973ee2SSimon J. Gerraty# and in parse-only mode, the "value" of the parsed expression was the
1588c973ee2SSimon J. Gerraty# uninterpreted variable value, in this case '${UNDEF}'.  And even though the
1598c973ee2SSimon J. Gerraty# right hand side of the '&&' should have been irrelevant, the two sides of
1608c973ee2SSimon J. Gerraty# the comparison were still parsed and evaluated.  Comparing these two values
1618c973ee2SSimon J. Gerraty# numerically was not possible since the string '${UNDEF}' is not a number,
1628c973ee2SSimon J. Gerraty# so the comparison fell back to string comparison, which then complained
1638c973ee2SSimon J. Gerraty# about the '>' operator.
16406b9b3e0SSimon J. Gerraty#
16506b9b3e0SSimon J. Gerraty# This was fixed in cond.c 1.79 from 2020-07-09 by not evaluating irrelevant
16606b9b3e0SSimon J. Gerraty# comparisons.  Instead, they are only parsed and then discarded.
16706b9b3e0SSimon J. Gerraty#
16806b9b3e0SSimon J. Gerraty# At that time, there was not enough debug logging to see the details in the
16906b9b3e0SSimon J. Gerraty# -dA log.  To actually see it, add debug logging at the beginning and end of
17006b9b3e0SSimon J. Gerraty# Var_Parse.
1718c973ee2SSimon J. Gerraty.if defined(UNDEF) && ${INDIR_UNDEF} < ${NUMBER}
1728c973ee2SSimon J. Gerraty.  error
1733841c287SSimon J. Gerraty.endif
1748c973ee2SSimon J. Gerraty# Adding a ':U' modifier to the irrelevant expression didn't help, as that
1758c973ee2SSimon J. Gerraty# expression was only parsed, not evaluated.  The resulting literal string
1768c973ee2SSimon J. Gerraty# '${INDIR_UNDEF:U2}' was not numeric either, for the same reason as above.
1778c973ee2SSimon J. Gerraty.if defined(UNDEF) && ${INDIR_UNDEF:U2} < ${NUMBER}
1788c973ee2SSimon J. Gerraty.  error
1793841c287SSimon J. Gerraty.endif
1802c3632d1SSimon J. Gerraty
181*d5e0a182SSimon J. Gerraty
182*d5e0a182SSimon J. Gerraty# Since cond.c 1.76 from 2020.06.28 and before var.c 1.225 from 2020.07.01,
183*d5e0a182SSimon J. Gerraty# the following snippet resulted in the error message 'Variable VAR is
184*d5e0a182SSimon J. Gerraty# recursive'.  The condition '0' evaluated to false, which made the right-hand
185*d5e0a182SSimon J. Gerraty# side of the '&&' irrelevant.  Back then, irrelevant condition parts were
186*d5e0a182SSimon J. Gerraty# still evaluated, but in "irrelevant mode", which allowed undefined variables
187*d5e0a182SSimon J. Gerraty# to occur in expressions.  In this mode, the variable name 'VAR' was
188*d5e0a182SSimon J. Gerraty# unnecessarily evaluated, resulting in the expression '${VAR${:U1}}'.  In
189*d5e0a182SSimon J. Gerraty# this expression, the variable name was 'VAR${:U1}', and of this variable
190*d5e0a182SSimon J. Gerraty# name, only the fixed part 'VAR' was evaluated, without the part '${:U1}'.
191*d5e0a182SSimon J. Gerraty# This partial evaluation led to the wrong error message about 'VAR' being
192*d5e0a182SSimon J. Gerraty# recursive.
193*d5e0a182SSimon J. GerratyVAR=	${VAR${:U1}}
194*d5e0a182SSimon J. Gerraty.if 0 && !empty(VAR)
195*d5e0a182SSimon J. Gerraty.endif
196*d5e0a182SSimon J. Gerraty
197*d5e0a182SSimon J. Gerraty
1988c973ee2SSimon J. Gerraty# Enclosing the expression in double quotes changes how that expression is
1998c973ee2SSimon J. Gerraty# evaluated.  In irrelevant expressions that are enclosed in double quotes,
2008c973ee2SSimon J. Gerraty# expressions based on undefined variables are allowed and evaluate to an
2018c973ee2SSimon J. Gerraty# empty string.
20206b9b3e0SSimon J. Gerraty#
2038c973ee2SSimon J. Gerraty# The manual page stated from at least 1993 on that irrelevant conditions were
2048c973ee2SSimon J. Gerraty# not evaluated, but that was wrong.  These conditions were evaluated, the
2058c973ee2SSimon J. Gerraty# only difference was that undefined variables in them didn't trigger an
2068c973ee2SSimon J. Gerraty# error.  Since numeric conditions are quite rare, this subtle difference
2078c973ee2SSimon J. Gerraty# didn't catch much attention, as most other conditions such as pattern
2088c973ee2SSimon J. Gerraty# matches or equality comparisons worked fine and never produced error
2098c973ee2SSimon J. Gerraty# messages.
2108c973ee2SSimon J. Gerraty.if defined(UNDEF) && "${INDIR_UNDEF}" < ${NUMBER}
2118c973ee2SSimon J. Gerraty.  error
2128c973ee2SSimon J. Gerraty.endif
2138c973ee2SSimon J. Gerraty
2148c973ee2SSimon J. Gerraty# Since the condition is relevant, the indirect undefined variable is
2158c973ee2SSimon J. Gerraty# evaluated as usual, resolving nested undefined expressions to an empty
2168c973ee2SSimon J. Gerraty# string.
21706b9b3e0SSimon J. Gerraty#
2188c973ee2SSimon J. Gerraty# Comparing an empty string numerically is not possible, however, make has an
2198c973ee2SSimon J. Gerraty# ugly hack in TryParseNumber that treats an empty string as a valid numerical
2208c973ee2SSimon J. Gerraty# value, thus hiding bugs in the makefile.
2218c973ee2SSimon J. Gerraty.if ${INDIR_UNDEF} < ${NUMBER}
2228c973ee2SSimon J. Gerraty#  only due to the ugly hack
2233841c287SSimon J. Gerraty.else
2248c973ee2SSimon J. Gerraty.  error
2253841c287SSimon J. Gerraty.endif
2262c3632d1SSimon J. Gerraty
2278c973ee2SSimon J. Gerraty# Due to the quotes around the left-hand side of the '<', the operand is
2288c973ee2SSimon J. Gerraty# marked as a string, thus preventing a numerical comparison.
2298c973ee2SSimon J. Gerraty#
2308c973ee2SSimon J. Gerraty# expect+1: Comparison with '<' requires both operands '' and '42' to be numeric
2318c973ee2SSimon J. Gerraty.if "${INDIR_UNDEF}" < ${NUMBER}
2328c973ee2SSimon J. Gerraty.  info yes
2333841c287SSimon J. Gerraty.else
2348c973ee2SSimon J. Gerraty.  info no
2353841c287SSimon J. Gerraty.endif
2362c3632d1SSimon J. Gerraty
2378c973ee2SSimon J. Gerraty# The right-hand side of '||' is irrelevant and thus not evaluated.
2388c973ee2SSimon J. Gerraty.if 1 || ${INDIR_NUMBER} < ${NUMBER}
2393841c287SSimon J. Gerraty.else
2408c973ee2SSimon J. Gerraty.  error
2413841c287SSimon J. Gerraty.endif
2428c973ee2SSimon J. Gerraty
2438c973ee2SSimon J. Gerraty# The right-hand side of '||' is relevant and thus evaluated normally.
2448c973ee2SSimon J. Gerraty.if 0 || ${INDIR_NUMBER} < ${NUMBER}
2458c973ee2SSimon J. Gerraty.  error
2468c973ee2SSimon J. Gerraty.endif
2478c973ee2SSimon J. Gerraty
2488c973ee2SSimon J. Gerraty# The right-hand side of '||' evaluates to an empty string, as the variable
2498c973ee2SSimon J. Gerraty# 'INDIR_UNDEF' is defined, therefore the modifier ':U2' has no effect.
2508c973ee2SSimon J. Gerraty# Comparing an empty string numerically is not possible, however, make has an
2518c973ee2SSimon J. Gerraty# ugly hack in TryParseNumber that treats an empty string as a valid numerical
2528c973ee2SSimon J. Gerraty# value, thus hiding bugs in the makefile.
2538c973ee2SSimon J. Gerraty.if 0 || ${INDIR_UNDEF:U2} < ${NUMBER}
2548c973ee2SSimon J. Gerraty#  only due to the ugly hack
2558c973ee2SSimon J. Gerraty.else
2568c973ee2SSimon J. Gerraty.  error
2578c973ee2SSimon J. Gerraty.endif
2588c973ee2SSimon J. Gerraty
2593841c287SSimon J. Gerraty
26006b9b3e0SSimon J. Gerraty# The right-hand side of the '&&' is irrelevant since the left-hand side
26106b9b3e0SSimon J. Gerraty# already evaluates to false.  Before cond.c 1.79 from 2020-07-09, it was
26206b9b3e0SSimon J. Gerraty# expanded nevertheless, although with a small modification:  undefined
26306b9b3e0SSimon J. Gerraty# variables may be used in these expressions without generating an error.
264e2eeea75SSimon J. Gerraty.if defined(UNDEF) && ${UNDEF} != "undefined"
265e2eeea75SSimon J. Gerraty.  error
266e2eeea75SSimon J. Gerraty.endif
267e2eeea75SSimon J. Gerraty
26812904384SSimon J. Gerraty
26912904384SSimon J. Gerraty# Ensure that irrelevant conditions do not influence the result of the whole
27012904384SSimon J. Gerraty# condition.  As of cond.c 1.302 from 2021-12-11, an irrelevant function call
2718c973ee2SSimon J. Gerraty# evaluated to true (see CondParser_FuncCall and CondParser_FuncCallEmpty), an
2728c973ee2SSimon J. Gerraty# irrelevant comparison evaluated to false (see CondParser_Comparison).
27312904384SSimon J. Gerraty#
27412904384SSimon J. Gerraty# An irrelevant true bubbles up to the outermost CondParser_And, where it is
27512904384SSimon J. Gerraty# ignored.  An irrelevant false bubbles up to the outermost CondParser_Or,
27612904384SSimon J. Gerraty# where it is ignored.
27712904384SSimon J. Gerraty#
27812904384SSimon J. Gerraty# If the condition parser should ever be restructured, the bubbling up of the
27912904384SSimon J. Gerraty# irrelevant evaluation results might show up accidentally.  Prevent this.
28012904384SSimon J. GerratyDEF=	defined
28112904384SSimon J. Gerraty.undef UNDEF
28212904384SSimon J. Gerraty
28312904384SSimon J. Gerraty.if 0 && defined(DEF)
28412904384SSimon J. Gerraty.  error
28512904384SSimon J. Gerraty.endif
28612904384SSimon J. Gerraty
28712904384SSimon J. Gerraty.if 1 && defined(DEF)
28812904384SSimon J. Gerraty.else
28912904384SSimon J. Gerraty.  error
29012904384SSimon J. Gerraty.endif
29112904384SSimon J. Gerraty
29212904384SSimon J. Gerraty.if 0 && defined(UNDEF)
29312904384SSimon J. Gerraty.  error
29412904384SSimon J. Gerraty.endif
29512904384SSimon J. Gerraty
29612904384SSimon J. Gerraty.if 1 && defined(UNDEF)
29712904384SSimon J. Gerraty.  error
29812904384SSimon J. Gerraty.endif
29912904384SSimon J. Gerraty
30012904384SSimon J. Gerraty.if 0 || defined(DEF)
30112904384SSimon J. Gerraty.else
30212904384SSimon J. Gerraty.  error
30312904384SSimon J. Gerraty.endif
30412904384SSimon J. Gerraty
30512904384SSimon J. Gerraty.if 1 || defined(DEF)
30612904384SSimon J. Gerraty.else
30712904384SSimon J. Gerraty.  error
30812904384SSimon J. Gerraty.endif
30912904384SSimon J. Gerraty
31012904384SSimon J. Gerraty.if 0 || defined(UNDEF)
31112904384SSimon J. Gerraty.  error
31212904384SSimon J. Gerraty.endif
31312904384SSimon J. Gerraty
31412904384SSimon J. Gerraty.if 1 || defined(UNDEF)
31512904384SSimon J. Gerraty.else
31612904384SSimon J. Gerraty.  error
31712904384SSimon J. Gerraty.endif
31812904384SSimon J. Gerraty
31912904384SSimon J. Gerraty
3203841c287SSimon J. Gerratyall:
321