]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/bmake/cond.c
zfs: merge openzfs/zfs@3522f57b6 (master) to main
[FreeBSD/FreeBSD.git] / contrib / bmake / cond.c
1 /*      $NetBSD: cond.c,v 1.256 2021/02/05 05:15:12 rillig Exp $        */
2
3 /*
4  * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Adam de Boor.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34
35 /*
36  * Copyright (c) 1988, 1989 by Adam de Boor
37  * Copyright (c) 1989 by Berkeley Softworks
38  * All rights reserved.
39  *
40  * This code is derived from software contributed to Berkeley by
41  * Adam de Boor.
42  *
43  * Redistribution and use in source and binary forms, with or without
44  * modification, are permitted provided that the following conditions
45  * are met:
46  * 1. Redistributions of source code must retain the above copyright
47  *    notice, this list of conditions and the following disclaimer.
48  * 2. Redistributions in binary form must reproduce the above copyright
49  *    notice, this list of conditions and the following disclaimer in the
50  *    documentation and/or other materials provided with the distribution.
51  * 3. All advertising materials mentioning features or use of this software
52  *    must display the following acknowledgement:
53  *      This product includes software developed by the University of
54  *      California, Berkeley and its contributors.
55  * 4. Neither the name of the University nor the names of its contributors
56  *    may be used to endorse or promote products derived from this software
57  *    without specific prior written permission.
58  *
59  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
60  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
61  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
62  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
63  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
64  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
65  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
66  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
67  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
68  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
69  * SUCH DAMAGE.
70  */
71
72 /*
73  * Handling of conditionals in a makefile.
74  *
75  * Interface:
76  *      Cond_EvalLine   Evaluate the conditional directive, such as
77  *                      '.if <cond>', '.elifnmake <cond>', '.else', '.endif'.
78  *
79  *      Cond_EvalCondition
80  *                      Evaluate the conditional, which is either the argument
81  *                      of one of the .if directives or the condition in a
82  *                      ':?then:else' variable modifier.
83  *
84  *      Cond_save_depth
85  *      Cond_restore_depth
86  *                      Save and restore the nesting of the conditions, at
87  *                      the start and end of including another makefile, to
88  *                      ensure that in each makefile the conditional
89  *                      directives are well-balanced.
90  */
91
92 #include <errno.h>
93
94 #include "make.h"
95 #include "dir.h"
96
97 /*      "@(#)cond.c     8.2 (Berkeley) 1/2/94"  */
98 MAKE_RCSID("$NetBSD: cond.c,v 1.256 2021/02/05 05:15:12 rillig Exp $");
99
100 /*
101  * The parsing of conditional expressions is based on this grammar:
102  *      Or -> And '||' Or
103  *      Or -> And
104  *      And -> Term '&&' And
105  *      And -> Term
106  *      Term -> Function '(' Argument ')'
107  *      Term -> Leaf Operator Leaf
108  *      Term -> Leaf
109  *      Term -> '(' Or ')'
110  *      Term -> '!' Term
111  *      Leaf -> "string"
112  *      Leaf -> Number
113  *      Leaf -> VariableExpression
114  *      Leaf -> Symbol
115  *      Operator -> '==' | '!=' | '>' | '<' | '>=' | '<='
116  *
117  * 'Symbol' is an unquoted string literal to which the default function is
118  * applied.
119  *
120  * The tokens are scanned by CondToken, which returns:
121  *      TOK_AND         for '&&'
122  *      TOK_OR          for '||'
123  *      TOK_NOT         for '!'
124  *      TOK_LPAREN      for '('
125  *      TOK_RPAREN      for ')'
126  *
127  * Other terminal symbols are evaluated using either the default function or
128  * the function given in the terminal, they return either TOK_TRUE or
129  * TOK_FALSE.
130  */
131 typedef enum Token {
132         TOK_FALSE, TOK_TRUE, TOK_AND, TOK_OR, TOK_NOT,
133         TOK_LPAREN, TOK_RPAREN, TOK_EOF, TOK_NONE, TOK_ERROR
134 } Token;
135
136 typedef enum CondResult {
137         CR_FALSE, CR_TRUE, CR_ERROR
138 } CondResult;
139
140 typedef enum ComparisonOp {
141         LT, LE, GT, GE, EQ, NE
142 } ComparisonOp;
143
144 typedef struct CondParser {
145
146         /*
147          * The plain '.if ${VAR}' evaluates to true if the value of the
148          * expression has length > 0.  The other '.if' variants delegate
149          * to evalBare instead.
150          */
151         Boolean plain;
152
153         /* The function to apply on unquoted bare words. */
154         Boolean (*evalBare)(size_t, const char *);
155         Boolean negateEvalBare;
156
157         const char *p;          /* The remaining condition to parse */
158         Token curr;             /* Single push-back token used in parsing */
159
160         /*
161          * Whether an error message has already been printed for this
162          * condition. The first available error message is usually the most
163          * specific one, therefore it makes sense to suppress the standard
164          * "Malformed conditional" message.
165          */
166         Boolean printedError;
167 } CondParser;
168
169 static CondResult CondParser_Or(CondParser *par, Boolean);
170
171 static unsigned int cond_depth = 0;     /* current .if nesting level */
172 static unsigned int cond_min_depth = 0; /* depth at makefile open */
173
174 static const char *opname[] = { "<", "<=", ">", ">=", "==", "!=" };
175
176 /*
177  * Indicate when we should be strict about lhs of comparisons.
178  * In strict mode, the lhs must be a variable expression or a string literal
179  * in quotes. In non-strict mode it may also be an unquoted string literal.
180  *
181  * TRUE when CondEvalExpression is called from Cond_EvalLine (.if etc)
182  * FALSE when CondEvalExpression is called from ApplyModifier_IfElse
183  * since lhs is already expanded, and at that point we cannot tell if
184  * it was a variable reference or not.
185  */
186 static Boolean lhsStrict;
187
188 static Boolean
189 is_token(const char *str, const char *tok, size_t len)
190 {
191         return strncmp(str, tok, len) == 0 && !ch_isalpha(str[len]);
192 }
193
194 static Token
195 ToToken(Boolean cond)
196 {
197         return cond ? TOK_TRUE : TOK_FALSE;
198 }
199
200 /* Push back the most recent token read. We only need one level of this. */
201 static void
202 CondParser_PushBack(CondParser *par, Token t)
203 {
204         assert(par->curr == TOK_NONE);
205         assert(t != TOK_NONE);
206
207         par->curr = t;
208 }
209
210 static void
211 CondParser_SkipWhitespace(CondParser *par)
212 {
213         cpp_skip_whitespace(&par->p);
214 }
215
216 /*
217  * Parse the argument of a built-in function.
218  *
219  * Arguments:
220  *      *pp initially points at the '(',
221  *      upon successful return it points right after the ')'.
222  *
223  *      *out_arg receives the argument as string.
224  *
225  *      func says whether the argument belongs to an actual function, or
226  *      whether the parsed argument is passed to the default function.
227  *
228  * Return the length of the argument, or 0 on error.
229  */
230 static size_t
231 ParseFuncArg(CondParser *par, const char **pp, Boolean doEval, const char *func,
232              char **out_arg)
233 {
234         const char *p = *pp;
235         Buffer argBuf;
236         int paren_depth;
237         size_t argLen;
238
239         if (func != NULL)
240                 p++;            /* Skip opening '(' - verified by caller */
241
242         if (*p == '\0') {
243                 *out_arg = NULL; /* Missing closing parenthesis: */
244                 return 0;       /* .if defined( */
245         }
246
247         cpp_skip_hspace(&p);
248
249         Buf_InitSize(&argBuf, 16);
250
251         paren_depth = 0;
252         for (;;) {
253                 char ch = *p;
254                 if (ch == '\0' || ch == ' ' || ch == '\t')
255                         break;
256                 if ((ch == '&' || ch == '|') && paren_depth == 0)
257                         break;
258                 if (*p == '$') {
259                         /*
260                          * Parse the variable expression and install it as
261                          * part of the argument if it's valid. We tell
262                          * Var_Parse to complain on an undefined variable,
263                          * (XXX: but Var_Parse ignores that request)
264                          * so we don't need to do it. Nor do we return an
265                          * error, though perhaps we should.
266                          */
267                         VarEvalFlags eflags = doEval
268                             ? VARE_WANTRES | VARE_UNDEFERR
269                             : VARE_NONE;
270                         FStr nestedVal;
271                         (void)Var_Parse(&p, SCOPE_CMDLINE, eflags, &nestedVal);
272                         /* TODO: handle errors */
273                         Buf_AddStr(&argBuf, nestedVal.str);
274                         FStr_Done(&nestedVal);
275                         continue;
276                 }
277                 if (ch == '(')
278                         paren_depth++;
279                 else if (ch == ')' && --paren_depth < 0)
280                         break;
281                 Buf_AddByte(&argBuf, *p);
282                 p++;
283         }
284
285         argLen = argBuf.len;
286         *out_arg = Buf_DoneData(&argBuf);
287
288         cpp_skip_hspace(&p);
289
290         if (func != NULL && *p++ != ')') {
291                 Parse_Error(PARSE_FATAL,
292                     "Missing closing parenthesis for %s()", func);
293                 par->printedError = TRUE;
294                 return 0;
295         }
296
297         *pp = p;
298         return argLen;
299 }
300
301 /* Test whether the given variable is defined. */
302 /*ARGSUSED*/
303 static Boolean
304 FuncDefined(size_t argLen MAKE_ATTR_UNUSED, const char *arg)
305 {
306         FStr value = Var_Value(SCOPE_CMDLINE, arg);
307         Boolean result = value.str != NULL;
308         FStr_Done(&value);
309         return result;
310 }
311
312 /* See if the given target is being made. */
313 /*ARGSUSED*/
314 static Boolean
315 FuncMake(size_t argLen MAKE_ATTR_UNUSED, const char *arg)
316 {
317         StringListNode *ln;
318
319         for (ln = opts.create.first; ln != NULL; ln = ln->next)
320                 if (Str_Match(ln->datum, arg))
321                         return TRUE;
322         return FALSE;
323 }
324
325 /* See if the given file exists. */
326 /*ARGSUSED*/
327 static Boolean
328 FuncExists(size_t argLen MAKE_ATTR_UNUSED, const char *arg)
329 {
330         Boolean result;
331         char *path;
332
333         path = Dir_FindFile(arg, &dirSearchPath);
334         DEBUG2(COND, "exists(%s) result is \"%s\"\n",
335                arg, path != NULL ? path : "");
336         result = path != NULL;
337         free(path);
338         return result;
339 }
340
341 /* See if the given node exists and is an actual target. */
342 /*ARGSUSED*/
343 static Boolean
344 FuncTarget(size_t argLen MAKE_ATTR_UNUSED, const char *arg)
345 {
346         GNode *gn = Targ_FindNode(arg);
347         return gn != NULL && GNode_IsTarget(gn);
348 }
349
350 /*
351  * See if the given node exists and is an actual target with commands
352  * associated with it.
353  */
354 /*ARGSUSED*/
355 static Boolean
356 FuncCommands(size_t argLen MAKE_ATTR_UNUSED, const char *arg)
357 {
358         GNode *gn = Targ_FindNode(arg);
359         return gn != NULL && GNode_IsTarget(gn) && !Lst_IsEmpty(&gn->commands);
360 }
361
362 /*
363  * Convert the given number into a double.
364  * We try a base 10 or 16 integer conversion first, if that fails
365  * then we try a floating point conversion instead.
366  *
367  * Results:
368  *      Returns TRUE if the conversion succeeded.
369  *      Sets 'out_value' to the converted number.
370  */
371 static Boolean
372 TryParseNumber(const char *str, double *out_value)
373 {
374         char *end;
375         unsigned long ul_val;
376         double dbl_val;
377
378         errno = 0;
379         if (str[0] == '\0') {   /* XXX: why is an empty string a number? */
380                 *out_value = 0.0;
381                 return TRUE;
382         }
383
384         ul_val = strtoul(str, &end, str[1] == 'x' ? 16 : 10);
385         if (*end == '\0' && errno != ERANGE) {
386                 *out_value = str[0] == '-' ? -(double)-ul_val : (double)ul_val;
387                 return TRUE;
388         }
389
390         if (*end != '\0' && *end != '.' && *end != 'e' && *end != 'E')
391                 return FALSE;   /* skip the expensive strtod call */
392         dbl_val = strtod(str, &end);
393         if (*end != '\0')
394                 return FALSE;
395
396         *out_value = dbl_val;
397         return TRUE;
398 }
399
400 static Boolean
401 is_separator(char ch)
402 {
403         return ch == '\0' || ch_isspace(ch) || strchr("!=><)", ch) != NULL;
404 }
405
406 /*
407  * In a quoted or unquoted string literal or a number, parse a variable
408  * expression.
409  *
410  * Example: .if x${CENTER}y == "${PREFIX}${SUFFIX}" || 0x${HEX}
411  */
412 static Boolean
413 CondParser_StringExpr(CondParser *par, const char *start,
414                       Boolean const doEval, Boolean const quoted,
415                       Buffer *buf, FStr *const inout_str)
416 {
417         VarEvalFlags eflags;
418         const char *nested_p;
419         Boolean atStart;
420         VarParseResult parseResult;
421
422         /* if we are in quotes, an undefined variable is ok */
423         eflags = doEval && !quoted ? VARE_WANTRES | VARE_UNDEFERR
424             : doEval ? VARE_WANTRES
425             : VARE_NONE;
426
427         nested_p = par->p;
428         atStart = nested_p == start;
429         parseResult = Var_Parse(&nested_p, SCOPE_CMDLINE, eflags, inout_str);
430         /* TODO: handle errors */
431         if (inout_str->str == var_Error) {
432                 if (parseResult == VPR_ERR) {
433                         /*
434                          * FIXME: Even if an error occurs, there is no
435                          *  guarantee that it is reported.
436                          *
437                          * See cond-token-plain.mk $$$$$$$$.
438                          */
439                         par->printedError = TRUE;
440                 }
441                 /*
442                  * XXX: Can there be any situation in which a returned
443                  * var_Error requires freeIt?
444                  */
445                 FStr_Done(inout_str);
446                 /*
447                  * Even if !doEval, we still report syntax errors, which is
448                  * what getting var_Error back with !doEval means.
449                  */
450                 *inout_str = FStr_InitRefer(NULL);
451                 return FALSE;
452         }
453         par->p = nested_p;
454
455         /*
456          * If the '$' started the string literal (which means no quotes), and
457          * the variable expression is followed by a space, looks like a
458          * comparison operator or is the end of the expression, we are done.
459          */
460         if (atStart && is_separator(par->p[0]))
461                 return FALSE;
462
463         Buf_AddStr(buf, inout_str->str);
464         FStr_Done(inout_str);
465         *inout_str = FStr_InitRefer(NULL); /* not finished yet */
466         return TRUE;
467 }
468
469 /*
470  * Parse a string from a variable reference or an optionally quoted
471  * string.  This is called for the lhs and rhs of string comparisons.
472  *
473  * Results:
474  *      Returns the string, absent any quotes, or NULL on error.
475  *      Sets out_quoted if the string was quoted.
476  *      Sets out_freeIt.
477  */
478 static void
479 CondParser_String(CondParser *par, Boolean doEval, Boolean strictLHS,
480                   FStr *out_str, Boolean *out_quoted)
481 {
482         Buffer buf;
483         FStr str;
484         Boolean quoted;
485         const char *start;
486
487         Buf_Init(&buf);
488         str = FStr_InitRefer(NULL);
489         *out_quoted = quoted = par->p[0] == '"';
490         start = par->p;
491         if (quoted)
492                 par->p++;
493
494         while (par->p[0] != '\0' && str.str == NULL) {
495                 switch (par->p[0]) {
496                 case '\\':
497                         par->p++;
498                         if (par->p[0] != '\0') {
499                                 Buf_AddByte(&buf, par->p[0]);
500                                 par->p++;
501                         }
502                         continue;
503                 case '"':
504                         par->p++;
505                         if (quoted)
506                                 goto got_str;   /* skip the closing quote */
507                         Buf_AddByte(&buf, '"');
508                         continue;
509                 case ')':       /* see is_separator */
510                 case '!':
511                 case '=':
512                 case '>':
513                 case '<':
514                 case ' ':
515                 case '\t':
516                         if (!quoted)
517                                 goto got_str;
518                         Buf_AddByte(&buf, par->p[0]);
519                         par->p++;
520                         continue;
521                 case '$':
522                         if (!CondParser_StringExpr(par,
523                             start, doEval, quoted, &buf, &str))
524                                 goto cleanup;
525                         continue;
526                 default:
527                         if (strictLHS && !quoted && *start != '$' &&
528                             !ch_isdigit(*start)) {
529                                 /*
530                                  * The left-hand side must be quoted,
531                                  * a variable reference or a number.
532                                  */
533                                 str = FStr_InitRefer(NULL);
534                                 goto cleanup;
535                         }
536                         Buf_AddByte(&buf, par->p[0]);
537                         par->p++;
538                         continue;
539                 }
540         }
541 got_str:
542         str = FStr_InitOwn(buf.data);
543 cleanup:
544         Buf_DoneData(&buf);
545         *out_str = str;
546 }
547
548 static Boolean
549 If_Eval(const CondParser *par, const char *arg, size_t arglen)
550 {
551         Boolean res = par->evalBare(arglen, arg);
552         return par->negateEvalBare ? !res : res;
553 }
554
555 /*
556  * Evaluate a "comparison without operator", such as in ".if ${VAR}" or
557  * ".if 0".
558  */
559 static Boolean
560 EvalNotEmpty(CondParser *par, const char *value, Boolean quoted)
561 {
562         double num;
563
564         /* For .ifxxx "...", check for non-empty string. */
565         if (quoted)
566                 return value[0] != '\0';
567
568         /* For .ifxxx <number>, compare against zero */
569         if (TryParseNumber(value, &num))
570                 return num != 0.0;
571
572         /* For .if ${...}, check for non-empty string.  This is different from
573          * the evaluation function from that .if variant, which would test
574          * whether a variable of the given name were defined. */
575         /* XXX: Whitespace should count as empty, just as in ParseEmptyArg. */
576         if (par->plain)
577                 return value[0] != '\0';
578
579         return If_Eval(par, value, strlen(value));
580 }
581
582 /* Evaluate a numerical comparison, such as in ".if ${VAR} >= 9". */
583 static Boolean
584 EvalCompareNum(double lhs, ComparisonOp op, double rhs)
585 {
586         DEBUG3(COND, "lhs = %f, rhs = %f, op = %.2s\n", lhs, rhs, opname[op]);
587
588         switch (op) {
589         case LT:
590                 return lhs < rhs;
591         case LE:
592                 return lhs <= rhs;
593         case GT:
594                 return lhs > rhs;
595         case GE:
596                 return lhs >= rhs;
597         case NE:
598                 return lhs != rhs;
599         default:
600                 return lhs == rhs;
601         }
602 }
603
604 static Token
605 EvalCompareStr(CondParser *par, const char *lhs,
606                ComparisonOp op, const char *rhs)
607 {
608         if (op != EQ && op != NE) {
609                 Parse_Error(PARSE_FATAL,
610                     "String comparison operator must be either == or !=");
611                 par->printedError = TRUE;
612                 return TOK_ERROR;
613         }
614
615         DEBUG3(COND, "lhs = \"%s\", rhs = \"%s\", op = %.2s\n",
616             lhs, rhs, opname[op]);
617         return ToToken((op == EQ) == (strcmp(lhs, rhs) == 0));
618 }
619
620 /* Evaluate a comparison, such as "${VAR} == 12345". */
621 static Token
622 EvalCompare(CondParser *par, const char *lhs, Boolean lhsQuoted,
623             ComparisonOp op, const char *rhs, Boolean rhsQuoted)
624 {
625         double left, right;
626
627         if (!rhsQuoted && !lhsQuoted)
628                 if (TryParseNumber(lhs, &left) && TryParseNumber(rhs, &right))
629                         return ToToken(EvalCompareNum(left, op, right));
630
631         return EvalCompareStr(par, lhs, op, rhs);
632 }
633
634 static Boolean
635 CondParser_ComparisonOp(CondParser *par, ComparisonOp *out_op)
636 {
637         const char *p = par->p;
638
639         if (p[0] == '<' && p[1] == '=') {
640                 *out_op = LE;
641                 goto length_2;
642         } else if (p[0] == '<') {
643                 *out_op = LT;
644                 goto length_1;
645         } else if (p[0] == '>' && p[1] == '=') {
646                 *out_op = GE;
647                 goto length_2;
648         } else if (p[0] == '>') {
649                 *out_op = GT;
650                 goto length_1;
651         } else if (p[0] == '=' && p[1] == '=') {
652                 *out_op = EQ;
653                 goto length_2;
654         } else if (p[0] == '!' && p[1] == '=') {
655                 *out_op = NE;
656                 goto length_2;
657         }
658         return FALSE;
659
660 length_2:
661         par->p = p + 2;
662         return TRUE;
663 length_1:
664         par->p = p + 1;
665         return TRUE;
666 }
667
668 /*
669  * Parse a comparison condition such as:
670  *
671  *      0
672  *      ${VAR:Mpattern}
673  *      ${VAR} == value
674  *      ${VAR:U0} < 12345
675  */
676 static Token
677 CondParser_Comparison(CondParser *par, Boolean doEval)
678 {
679         Token t = TOK_ERROR;
680         FStr lhs, rhs;
681         ComparisonOp op;
682         Boolean lhsQuoted, rhsQuoted;
683
684         /*
685          * Parse the variable spec and skip over it, saving its
686          * value in lhs.
687          */
688         CondParser_String(par, doEval, lhsStrict, &lhs, &lhsQuoted);
689         if (lhs.str == NULL)
690                 goto done_lhs;
691
692         CondParser_SkipWhitespace(par);
693
694         if (!CondParser_ComparisonOp(par, &op)) {
695                 /* Unknown operator, compare against an empty string or 0. */
696                 t = ToToken(doEval && EvalNotEmpty(par, lhs.str, lhsQuoted));
697                 goto done_lhs;
698         }
699
700         CondParser_SkipWhitespace(par);
701
702         if (par->p[0] == '\0') {
703                 Parse_Error(PARSE_FATAL,
704                     "Missing right-hand-side of operator '%s'", opname[op]);
705                 par->printedError = TRUE;
706                 goto done_lhs;
707         }
708
709         CondParser_String(par, doEval, FALSE, &rhs, &rhsQuoted);
710         if (rhs.str == NULL)
711                 goto done_rhs;
712
713         if (!doEval) {
714                 t = TOK_FALSE;
715                 goto done_rhs;
716         }
717
718         t = EvalCompare(par, lhs.str, lhsQuoted, op, rhs.str, rhsQuoted);
719
720 done_rhs:
721         FStr_Done(&rhs);
722 done_lhs:
723         FStr_Done(&lhs);
724         return t;
725 }
726
727 /*
728  * The argument to empty() is a variable name, optionally followed by
729  * variable modifiers.
730  */
731 /*ARGSUSED*/
732 static size_t
733 ParseEmptyArg(CondParser *par MAKE_ATTR_UNUSED, const char **pp,
734               Boolean doEval, const char *func MAKE_ATTR_UNUSED,
735               char **out_arg)
736 {
737         FStr val;
738         size_t magic_res;
739
740         /* We do all the work here and return the result as the length */
741         *out_arg = NULL;
742
743         (*pp)--;                /* Make (*pp)[1] point to the '('. */
744         (void)Var_Parse(pp, SCOPE_CMDLINE, doEval ? VARE_WANTRES : VARE_NONE,
745             &val);
746         /* TODO: handle errors */
747         /* If successful, *pp points beyond the closing ')' now. */
748
749         if (val.str == var_Error) {
750                 FStr_Done(&val);
751                 return (size_t)-1;
752         }
753
754         /*
755          * A variable is empty when it just contains spaces...
756          * 4/15/92, christos
757          */
758         cpp_skip_whitespace(&val.str);
759
760         /*
761          * For consistency with the other functions we can't generate the
762          * true/false here.
763          */
764         magic_res = val.str[0] != '\0' ? 2 : 1;
765         FStr_Done(&val);
766         return magic_res;
767 }
768
769 /*ARGSUSED*/
770 static Boolean
771 FuncEmpty(size_t arglen, const char *arg MAKE_ATTR_UNUSED)
772 {
773         /* Magic values ahead, see ParseEmptyArg. */
774         return arglen == 1;
775 }
776
777 static Boolean
778 CondParser_Func(CondParser *par, Boolean doEval, Token *out_token)
779 {
780         static const struct fn_def {
781                 const char *fn_name;
782                 size_t fn_name_len;
783                 size_t (*fn_parse)(CondParser *, const char **, Boolean,
784                                    const char *, char **);
785                 Boolean (*fn_eval)(size_t, const char *);
786         } fns[] = {
787                 { "defined",  7, ParseFuncArg,  FuncDefined },
788                 { "make",     4, ParseFuncArg,  FuncMake },
789                 { "exists",   6, ParseFuncArg,  FuncExists },
790                 { "empty",    5, ParseEmptyArg, FuncEmpty },
791                 { "target",   6, ParseFuncArg,  FuncTarget },
792                 { "commands", 8, ParseFuncArg,  FuncCommands }
793         };
794         const struct fn_def *fn;
795         char *arg = NULL;
796         size_t arglen;
797         const char *cp = par->p;
798         const struct fn_def *fns_end = fns + sizeof fns / sizeof fns[0];
799
800         for (fn = fns; fn != fns_end; fn++) {
801                 if (!is_token(cp, fn->fn_name, fn->fn_name_len))
802                         continue;
803
804                 cp += fn->fn_name_len;
805                 cpp_skip_whitespace(&cp);
806                 if (*cp != '(')
807                         break;
808
809                 arglen = fn->fn_parse(par, &cp, doEval, fn->fn_name, &arg);
810                 if (arglen == 0 || arglen == (size_t)-1) {
811                         par->p = cp;
812                         *out_token = arglen == 0 ? TOK_FALSE : TOK_ERROR;
813                         return TRUE;
814                 }
815
816                 /* Evaluate the argument using the required function. */
817                 *out_token = ToToken(!doEval || fn->fn_eval(arglen, arg));
818                 free(arg);
819                 par->p = cp;
820                 return TRUE;
821         }
822
823         return FALSE;
824 }
825
826 /*
827  * Parse a function call, a number, a variable expression or a string
828  * literal.
829  */
830 static Token
831 CondParser_LeafToken(CondParser *par, Boolean doEval)
832 {
833         Token t;
834         char *arg = NULL;
835         size_t arglen;
836         const char *cp;
837         const char *cp1;
838
839         if (CondParser_Func(par, doEval, &t))
840                 return t;
841
842         /* Push anything numeric through the compare expression */
843         cp = par->p;
844         if (ch_isdigit(cp[0]) || cp[0] == '-' || cp[0] == '+')
845                 return CondParser_Comparison(par, doEval);
846
847         /*
848          * Most likely we have a naked token to apply the default function to.
849          * However ".if a == b" gets here when the "a" is unquoted and doesn't
850          * start with a '$'. This surprises people.
851          * If what follows the function argument is a '=' or '!' then the
852          * syntax would be invalid if we did "defined(a)" - so instead treat
853          * as an expression.
854          */
855         arglen = ParseFuncArg(par, &cp, doEval, NULL, &arg);
856         cp1 = cp;
857         cpp_skip_whitespace(&cp1);
858         if (*cp1 == '=' || *cp1 == '!')
859                 return CondParser_Comparison(par, doEval);
860         par->p = cp;
861
862         /*
863          * Evaluate the argument using the default function.
864          * This path always treats .if as .ifdef. To get here, the character
865          * after .if must have been taken literally, so the argument cannot
866          * be empty - even if it contained a variable expansion.
867          */
868         t = ToToken(!doEval || If_Eval(par, arg, arglen));
869         free(arg);
870         return t;
871 }
872
873 /* Return the next token or comparison result from the parser. */
874 static Token
875 CondParser_Token(CondParser *par, Boolean doEval)
876 {
877         Token t;
878
879         t = par->curr;
880         if (t != TOK_NONE) {
881                 par->curr = TOK_NONE;
882                 return t;
883         }
884
885         cpp_skip_hspace(&par->p);
886
887         switch (par->p[0]) {
888
889         case '(':
890                 par->p++;
891                 return TOK_LPAREN;
892
893         case ')':
894                 par->p++;
895                 return TOK_RPAREN;
896
897         case '|':
898                 par->p++;
899                 if (par->p[0] == '|')
900                         par->p++;
901                 else if (opts.strict) {
902                         Parse_Error(PARSE_FATAL, "Unknown operator '|'");
903                         par->printedError = TRUE;
904                         return TOK_ERROR;
905                 }
906                 return TOK_OR;
907
908         case '&':
909                 par->p++;
910                 if (par->p[0] == '&')
911                         par->p++;
912                 else if (opts.strict) {
913                         Parse_Error(PARSE_FATAL, "Unknown operator '&'");
914                         par->printedError = TRUE;
915                         return TOK_ERROR;
916                 }
917                 return TOK_AND;
918
919         case '!':
920                 par->p++;
921                 return TOK_NOT;
922
923         case '#':               /* XXX: see unit-tests/cond-token-plain.mk */
924         case '\n':              /* XXX: why should this end the condition? */
925                 /* Probably obsolete now, from 1993-03-21. */
926         case '\0':
927                 return TOK_EOF;
928
929         case '"':
930         case '$':
931                 return CondParser_Comparison(par, doEval);
932
933         default:
934                 return CondParser_LeafToken(par, doEval);
935         }
936 }
937
938 /*
939  * Term -> '(' Or ')'
940  * Term -> '!' Term
941  * Term -> Leaf Operator Leaf
942  * Term -> Leaf
943  */
944 static CondResult
945 CondParser_Term(CondParser *par, Boolean doEval)
946 {
947         CondResult res;
948         Token t;
949
950         t = CondParser_Token(par, doEval);
951         if (t == TOK_TRUE)
952                 return CR_TRUE;
953         if (t == TOK_FALSE)
954                 return CR_FALSE;
955
956         if (t == TOK_LPAREN) {
957                 res = CondParser_Or(par, doEval);
958                 if (res == CR_ERROR)
959                         return CR_ERROR;
960                 if (CondParser_Token(par, doEval) != TOK_RPAREN)
961                         return CR_ERROR;
962                 return res;
963         }
964
965         if (t == TOK_NOT) {
966                 res = CondParser_Term(par, doEval);
967                 if (res == CR_TRUE)
968                         res = CR_FALSE;
969                 else if (res == CR_FALSE)
970                         res = CR_TRUE;
971                 return res;
972         }
973
974         return CR_ERROR;
975 }
976
977 /*
978  * And -> Term '&&' And
979  * And -> Term
980  */
981 static CondResult
982 CondParser_And(CondParser *par, Boolean doEval)
983 {
984         CondResult res;
985         Token op;
986
987         res = CondParser_Term(par, doEval);
988         if (res == CR_ERROR)
989                 return CR_ERROR;
990
991         op = CondParser_Token(par, doEval);
992         if (op == TOK_AND) {
993                 if (res == CR_TRUE)
994                         return CondParser_And(par, doEval);
995                 if (CondParser_And(par, FALSE) == CR_ERROR)
996                         return CR_ERROR;
997                 return res;
998         }
999
1000         CondParser_PushBack(par, op);
1001         return res;
1002 }
1003
1004 /*
1005  * Or -> And '||' Or
1006  * Or -> And
1007  */
1008 static CondResult
1009 CondParser_Or(CondParser *par, Boolean doEval)
1010 {
1011         CondResult res;
1012         Token op;
1013
1014         res = CondParser_And(par, doEval);
1015         if (res == CR_ERROR)
1016                 return CR_ERROR;
1017
1018         op = CondParser_Token(par, doEval);
1019         if (op == TOK_OR) {
1020                 if (res == CR_FALSE)
1021                         return CondParser_Or(par, doEval);
1022                 if (CondParser_Or(par, FALSE) == CR_ERROR)
1023                         return CR_ERROR;
1024                 return res;
1025         }
1026
1027         CondParser_PushBack(par, op);
1028         return res;
1029 }
1030
1031 static CondEvalResult
1032 CondParser_Eval(CondParser *par, Boolean *out_value)
1033 {
1034         CondResult res;
1035
1036         DEBUG1(COND, "CondParser_Eval: %s\n", par->p);
1037
1038         res = CondParser_Or(par, TRUE);
1039         if (res == CR_ERROR)
1040                 return COND_INVALID;
1041
1042         if (CondParser_Token(par, FALSE) != TOK_EOF)
1043                 return COND_INVALID;
1044
1045         *out_value = res == CR_TRUE;
1046         return COND_PARSE;
1047 }
1048
1049 /*
1050  * Evaluate the condition, including any side effects from the variable
1051  * expressions in the condition. The condition consists of &&, ||, !,
1052  * function(arg), comparisons and parenthetical groupings thereof.
1053  *
1054  * Results:
1055  *      COND_PARSE      if the condition was valid grammatically
1056  *      COND_INVALID    if not a valid conditional.
1057  *
1058  *      (*value) is set to the boolean value of the condition
1059  */
1060 static CondEvalResult
1061 CondEvalExpression(const char *cond, Boolean *out_value, Boolean plain,
1062                    Boolean (*evalBare)(size_t, const char *), Boolean negate,
1063                    Boolean eprint, Boolean strictLHS)
1064 {
1065         CondParser par;
1066         CondEvalResult rval;
1067
1068         lhsStrict = strictLHS;
1069
1070         cpp_skip_hspace(&cond);
1071
1072         par.plain = plain;
1073         par.evalBare = evalBare;
1074         par.negateEvalBare = negate;
1075         par.p = cond;
1076         par.curr = TOK_NONE;
1077         par.printedError = FALSE;
1078
1079         rval = CondParser_Eval(&par, out_value);
1080
1081         if (rval == COND_INVALID && eprint && !par.printedError)
1082                 Parse_Error(PARSE_FATAL, "Malformed conditional (%s)", cond);
1083
1084         return rval;
1085 }
1086
1087 /*
1088  * Evaluate a condition in a :? modifier, such as
1089  * ${"${VAR}" == value:?yes:no}.
1090  */
1091 CondEvalResult
1092 Cond_EvalCondition(const char *cond, Boolean *out_value)
1093 {
1094         return CondEvalExpression(cond, out_value, TRUE,
1095             FuncDefined, FALSE, FALSE, FALSE);
1096 }
1097
1098 static Boolean
1099 IsEndif(const char *p)
1100 {
1101         return p[0] == 'e' && p[1] == 'n' && p[2] == 'd' &&
1102                p[3] == 'i' && p[4] == 'f' && !ch_isalpha(p[5]);
1103 }
1104
1105 static Boolean
1106 DetermineKindOfConditional(const char **pp, Boolean *out_plain,
1107                            Boolean (**out_evalBare)(size_t, const char *),
1108                            Boolean *out_negate)
1109 {
1110         const char *p = *pp;
1111
1112         p += 2;
1113         *out_plain = FALSE;
1114         *out_evalBare = FuncDefined;
1115         *out_negate = FALSE;
1116         if (*p == 'n') {
1117                 p++;
1118                 *out_negate = TRUE;
1119         }
1120         if (is_token(p, "def", 3)) {            /* .ifdef and .ifndef */
1121                 p += 3;
1122         } else if (is_token(p, "make", 4)) {    /* .ifmake and .ifnmake */
1123                 p += 4;
1124                 *out_evalBare = FuncMake;
1125         } else if (is_token(p, "", 0) && !*out_negate) { /* plain .if */
1126                 *out_plain = TRUE;
1127         } else {
1128                 /*
1129                  * TODO: Add error message about unknown directive,
1130                  * since there is no other known directive that starts
1131                  * with 'el' or 'if'.
1132                  *
1133                  * Example: .elifx 123
1134                  */
1135                 return FALSE;
1136         }
1137
1138         *pp = p;
1139         return TRUE;
1140 }
1141
1142 /*
1143  * Evaluate the conditional directive in the line, which is one of:
1144  *
1145  *      .if <cond>
1146  *      .ifmake <cond>
1147  *      .ifnmake <cond>
1148  *      .ifdef <cond>
1149  *      .ifndef <cond>
1150  *      .elif <cond>
1151  *      .elifmake <cond>
1152  *      .elifnmake <cond>
1153  *      .elifdef <cond>
1154  *      .elifndef <cond>
1155  *      .else
1156  *      .endif
1157  *
1158  * In these directives, <cond> consists of &&, ||, !, function(arg),
1159  * comparisons, expressions, bare words, numbers and strings, and
1160  * parenthetical groupings thereof.
1161  *
1162  * Results:
1163  *      COND_PARSE      to continue parsing the lines that follow the
1164  *                      conditional (when <cond> evaluates to TRUE)
1165  *      COND_SKIP       to skip the lines after the conditional
1166  *                      (when <cond> evaluates to FALSE, or when a previous
1167  *                      branch has already been taken)
1168  *      COND_INVALID    if the conditional was not valid, either because of
1169  *                      a syntax error or because some variable was undefined
1170  *                      or because the condition could not be evaluated
1171  */
1172 CondEvalResult
1173 Cond_EvalLine(const char *line)
1174 {
1175         typedef enum IfState {
1176
1177                 /* None of the previous <cond> evaluated to TRUE. */
1178                 IFS_INITIAL     = 0,
1179
1180                 /* The previous <cond> evaluated to TRUE.
1181                  * The lines following this condition are interpreted. */
1182                 IFS_ACTIVE      = 1 << 0,
1183
1184                 /* The previous directive was an '.else'. */
1185                 IFS_SEEN_ELSE   = 1 << 1,
1186
1187                 /* One of the previous <cond> evaluated to TRUE. */
1188                 IFS_WAS_ACTIVE  = 1 << 2
1189
1190         } IfState;
1191
1192         static enum IfState *cond_states = NULL;
1193         static unsigned int cond_states_cap = 128;
1194
1195         Boolean plain;
1196         Boolean (*evalBare)(size_t, const char *);
1197         Boolean negate;
1198         Boolean isElif;
1199         Boolean value;
1200         IfState state;
1201         const char *p = line;
1202
1203         if (cond_states == NULL) {
1204                 cond_states = bmake_malloc(
1205                     cond_states_cap * sizeof *cond_states);
1206                 cond_states[0] = IFS_ACTIVE;
1207         }
1208
1209         p++;                    /* skip the leading '.' */
1210         cpp_skip_hspace(&p);
1211
1212         if (IsEndif(p)) {       /* It is an '.endif'. */
1213                 if (p[5] != '\0') {
1214                         Parse_Error(PARSE_FATAL,
1215                             "The .endif directive does not take arguments.");
1216                 }
1217
1218                 if (cond_depth == cond_min_depth) {
1219                         Parse_Error(PARSE_FATAL, "if-less endif");
1220                         return COND_PARSE;
1221                 }
1222
1223                 /* Return state for previous conditional */
1224                 cond_depth--;
1225                 return cond_states[cond_depth] & IFS_ACTIVE
1226                     ? COND_PARSE : COND_SKIP;
1227         }
1228
1229         /* Parse the name of the directive, such as 'if', 'elif', 'endif'. */
1230         if (p[0] == 'e') {
1231                 if (p[1] != 'l') {
1232                         /*
1233                          * Unknown directive.  It might still be a
1234                          * transformation rule like '.elisp.scm',
1235                          * therefore no error message here.
1236                          */
1237                         return COND_INVALID;
1238                 }
1239
1240                 /* Quite likely this is 'else' or 'elif' */
1241                 p += 2;
1242                 if (is_token(p, "se", 2)) {     /* It is an 'else'. */
1243
1244                         if (p[2] != '\0')
1245                                 Parse_Error(PARSE_FATAL,
1246                                             "The .else directive "
1247                                             "does not take arguments.");
1248
1249                         if (cond_depth == cond_min_depth) {
1250                                 Parse_Error(PARSE_FATAL, "if-less else");
1251                                 return COND_PARSE;
1252                         }
1253
1254                         state = cond_states[cond_depth];
1255                         if (state == IFS_INITIAL) {
1256                                 state = IFS_ACTIVE | IFS_SEEN_ELSE;
1257                         } else {
1258                                 if (state & IFS_SEEN_ELSE)
1259                                         Parse_Error(PARSE_WARNING,
1260                                                     "extra else");
1261                                 state = IFS_WAS_ACTIVE | IFS_SEEN_ELSE;
1262                         }
1263                         cond_states[cond_depth] = state;
1264
1265                         return state & IFS_ACTIVE ? COND_PARSE : COND_SKIP;
1266                 }
1267                 /* Assume for now it is an elif */
1268                 isElif = TRUE;
1269         } else
1270                 isElif = FALSE;
1271
1272         if (p[0] != 'i' || p[1] != 'f') {
1273                 /*
1274                  * Unknown directive.  It might still be a transformation rule
1275                  * like '.elisp.scm', therefore no error message here.
1276                  */
1277                 return COND_INVALID;    /* Not an ifxxx or elifxxx line */
1278         }
1279
1280         if (!DetermineKindOfConditional(&p, &plain, &evalBare, &negate))
1281                 return COND_INVALID;
1282
1283         if (isElif) {
1284                 if (cond_depth == cond_min_depth) {
1285                         Parse_Error(PARSE_FATAL, "if-less elif");
1286                         return COND_PARSE;
1287                 }
1288                 state = cond_states[cond_depth];
1289                 if (state & IFS_SEEN_ELSE) {
1290                         Parse_Error(PARSE_WARNING, "extra elif");
1291                         cond_states[cond_depth] =
1292                             IFS_WAS_ACTIVE | IFS_SEEN_ELSE;
1293                         return COND_SKIP;
1294                 }
1295                 if (state != IFS_INITIAL) {
1296                         cond_states[cond_depth] = IFS_WAS_ACTIVE;
1297                         return COND_SKIP;
1298                 }
1299         } else {
1300                 /* Normal .if */
1301                 if (cond_depth + 1 >= cond_states_cap) {
1302                         /*
1303                          * This is rare, but not impossible.
1304                          * In meta mode, dirdeps.mk (only runs at level 0)
1305                          * can need more than the default.
1306                          */
1307                         cond_states_cap += 32;
1308                         cond_states = bmake_realloc(cond_states,
1309                                                     cond_states_cap *
1310                                                     sizeof *cond_states);
1311                 }
1312                 state = cond_states[cond_depth];
1313                 cond_depth++;
1314                 if (!(state & IFS_ACTIVE)) {
1315                         /*
1316                          * If we aren't parsing the data,
1317                          * treat as always false.
1318                          */
1319                         cond_states[cond_depth] = IFS_WAS_ACTIVE;
1320                         return COND_SKIP;
1321                 }
1322         }
1323
1324         /* And evaluate the conditional expression */
1325         if (CondEvalExpression(p, &value, plain, evalBare, negate,
1326             TRUE, TRUE) == COND_INVALID) {
1327                 /* Syntax error in conditional, error message already output. */
1328                 /* Skip everything to matching .endif */
1329                 /* XXX: An extra '.else' is not detected in this case. */
1330                 cond_states[cond_depth] = IFS_WAS_ACTIVE;
1331                 return COND_SKIP;
1332         }
1333
1334         if (!value) {
1335                 cond_states[cond_depth] = IFS_INITIAL;
1336                 return COND_SKIP;
1337         }
1338         cond_states[cond_depth] = IFS_ACTIVE;
1339         return COND_PARSE;
1340 }
1341
1342 void
1343 Cond_restore_depth(unsigned int saved_depth)
1344 {
1345         unsigned int open_conds = cond_depth - cond_min_depth;
1346
1347         if (open_conds != 0 || saved_depth > cond_depth) {
1348                 Parse_Error(PARSE_FATAL, "%u open conditional%s",
1349                             open_conds, open_conds == 1 ? "" : "s");
1350                 cond_depth = cond_min_depth;
1351         }
1352
1353         cond_min_depth = saved_depth;
1354 }
1355
1356 unsigned int
1357 Cond_save_depth(void)
1358 {
1359         unsigned int depth = cond_min_depth;
1360
1361         cond_min_depth = cond_depth;
1362         return depth;
1363 }