xref: /netbsd-src/usr.bin/make/cond.c (revision 404fbe5fb94ca1e054339640cabb2801ce52dd30)
1 /*	$NetBSD: cond.c,v 1.49 2008/12/13 15:19:29 dsl 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 #ifndef MAKE_NATIVE
73 static char rcsid[] = "$NetBSD: cond.c,v 1.49 2008/12/13 15:19:29 dsl Exp $";
74 #else
75 #include <sys/cdefs.h>
76 #ifndef lint
77 #if 0
78 static char sccsid[] = "@(#)cond.c	8.2 (Berkeley) 1/2/94";
79 #else
80 __RCSID("$NetBSD: cond.c,v 1.49 2008/12/13 15:19:29 dsl Exp $");
81 #endif
82 #endif /* not lint */
83 #endif
84 
85 /*-
86  * cond.c --
87  *	Functions to handle conditionals in a makefile.
88  *
89  * Interface:
90  *	Cond_Eval 	Evaluate the conditional in the passed line.
91  *
92  */
93 
94 #include    <ctype.h>
95 #include    <errno.h>    /* For strtoul() error checking */
96 
97 #include    "make.h"
98 #include    "hash.h"
99 #include    "dir.h"
100 #include    "buf.h"
101 
102 /*
103  * The parsing of conditional expressions is based on this grammar:
104  *	E -> F || E
105  *	E -> F
106  *	F -> T && F
107  *	F -> T
108  *	T -> defined(variable)
109  *	T -> make(target)
110  *	T -> exists(file)
111  *	T -> empty(varspec)
112  *	T -> target(name)
113  *	T -> commands(name)
114  *	T -> symbol
115  *	T -> $(varspec) op value
116  *	T -> $(varspec) == "string"
117  *	T -> $(varspec) != "string"
118  *	T -> "string"
119  *	T -> ( E )
120  *	T -> ! T
121  *	op -> == | != | > | < | >= | <=
122  *
123  * 'symbol' is some other symbol to which the default function (condDefProc)
124  * is applied.
125  *
126  * Tokens are scanned from the 'condExpr' string. The scanner (CondToken)
127  * will return And for '&' and '&&', Or for '|' and '||', Not for '!',
128  * LParen for '(', RParen for ')' and will evaluate the other terminal
129  * symbols, using either the default function or the function given in the
130  * terminal, and return the result as either True or False.
131  *
132  * All Non-Terminal functions (CondE, CondF and CondT) return Err on error.
133  */
134 typedef enum {
135     And, Or, Not, True, False, LParen, RParen, EndOfFile, None, Err
136 } Token;
137 
138 /*-
139  * Structures to handle elegantly the different forms of #if's. The
140  * last two fields are stored in condInvert and condDefProc, respectively.
141  */
142 static void CondPushBack(Token);
143 static int CondGetArg(char **, char **, const char *, Boolean);
144 static Boolean CondDoDefined(int, char *);
145 static int CondStrMatch(ClientData, ClientData);
146 static Boolean CondDoMake(int, char *);
147 static Boolean CondDoExists(int, char *);
148 static Boolean CondDoTarget(int, char *);
149 static Boolean CondDoCommands(int, char *);
150 static Boolean CondCvtArg(char *, double *);
151 static Token CondToken(Boolean);
152 static Token CondT(Boolean);
153 static Token CondF(Boolean);
154 static Token CondE(Boolean);
155 
156 static const struct If {
157     const char	*form;	      /* Form of if */
158     int		formlen;      /* Length of form */
159     Boolean	doNot;	      /* TRUE if default function should be negated */
160     Boolean	(*defProc)(int, char *); /* Default function to apply */
161 } ifs[] = {
162     { "def",	  3,	  FALSE,  CondDoDefined },
163     { "ndef",	  4,	  TRUE,	  CondDoDefined },
164     { "make",	  4,	  FALSE,  CondDoMake },
165     { "nmake",	  5,	  TRUE,	  CondDoMake },
166     { "",	  0,	  FALSE,  CondDoDefined },
167     { NULL,	  0,	  FALSE,  NULL }
168 };
169 
170 static Boolean	  condInvert;	    	/* Invert the default function */
171 static Boolean	  (*condDefProc)(int, char *);	/* Default function to apply */
172 static char 	  *condExpr;	    	/* The expression to parse */
173 static Token	  condPushBack=None;	/* Single push-back token used in
174 					 * parsing */
175 
176 static unsigned int	cond_depth = 0;  	/* current .if nesting level */
177 static unsigned int	cond_min_depth = 0;  	/* depth at makefile open */
178 
179 static int
180 istoken(const char *str, const char *tok, size_t len)
181 {
182 	return strncmp(str, tok, len) == 0 && !isalpha((unsigned char)str[len]);
183 }
184 
185 /*-
186  *-----------------------------------------------------------------------
187  * CondPushBack --
188  *	Push back the most recent token read. We only need one level of
189  *	this, so the thing is just stored in 'condPushback'.
190  *
191  * Input:
192  *	t		Token to push back into the "stream"
193  *
194  * Results:
195  *	None.
196  *
197  * Side Effects:
198  *	condPushback is overwritten.
199  *
200  *-----------------------------------------------------------------------
201  */
202 static void
203 CondPushBack(Token t)
204 {
205     condPushBack = t;
206 }
207 
208 /*-
209  *-----------------------------------------------------------------------
210  * CondGetArg --
211  *	Find the argument of a built-in function.
212  *
213  * Input:
214  *	parens		TRUE if arg should be bounded by parens
215  *
216  * Results:
217  *	The length of the argument and the address of the argument.
218  *
219  * Side Effects:
220  *	The pointer is set to point to the closing parenthesis of the
221  *	function call.
222  *
223  *-----------------------------------------------------------------------
224  */
225 static int
226 CondGetArg(char **linePtr, char **argPtr, const char *func, Boolean parens)
227 {
228     char	  *cp;
229     int	    	  argLen;
230     Buffer	  buf;
231 
232     cp = *linePtr;
233     if (parens) {
234 	while (*cp != '(' && *cp != '\0') {
235 	    cp++;
236 	}
237 	if (*cp == '(') {
238 	    cp++;
239 	}
240     }
241 
242     if (*cp == '\0') {
243 	/*
244 	 * No arguments whatsoever. Because 'make' and 'defined' aren't really
245 	 * "reserved words", we don't print a message. I think this is better
246 	 * than hitting the user with a warning message every time s/he uses
247 	 * the word 'make' or 'defined' at the beginning of a symbol...
248 	 */
249 	*argPtr = NULL;
250 	return (0);
251     }
252 
253     while (*cp == ' ' || *cp == '\t') {
254 	cp++;
255     }
256 
257     /*
258      * Create a buffer for the argument and start it out at 16 characters
259      * long. Why 16? Why not?
260      */
261     buf = Buf_Init(16);
262 
263     while ((strchr(" \t)&|", *cp) == NULL) && (*cp != '\0')) {
264 	if (*cp == '$') {
265 	    /*
266 	     * Parse the variable spec and install it as part of the argument
267 	     * if it's valid. We tell Var_Parse to complain on an undefined
268 	     * variable, so we don't do it too. Nor do we return an error,
269 	     * though perhaps we should...
270 	     */
271 	    char  	*cp2;
272 	    int		len;
273 	    void	*freeIt;
274 
275 	    cp2 = Var_Parse(cp, VAR_CMD, TRUE, &len, &freeIt);
276 	    Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2);
277 	    if (freeIt)
278 		free(freeIt);
279 	    cp += len;
280 	} else {
281 	    Buf_AddByte(buf, (Byte)*cp);
282 	    cp++;
283 	}
284     }
285 
286     Buf_AddByte(buf, (Byte)'\0');
287     *argPtr = (char *)Buf_GetAll(buf, &argLen);
288     Buf_Destroy(buf, FALSE);
289 
290     while (*cp == ' ' || *cp == '\t') {
291 	cp++;
292     }
293     if (parens && *cp != ')') {
294 	Parse_Error(PARSE_WARNING, "Missing closing parenthesis for %s()",
295 		     func);
296 	return (0);
297     } else if (parens) {
298 	/*
299 	 * Advance pointer past close parenthesis.
300 	 */
301 	cp++;
302     }
303 
304     *linePtr = cp;
305     return (argLen);
306 }
307 
308 /*-
309  *-----------------------------------------------------------------------
310  * CondDoDefined --
311  *	Handle the 'defined' function for conditionals.
312  *
313  * Results:
314  *	TRUE if the given variable is defined.
315  *
316  * Side Effects:
317  *	None.
318  *
319  *-----------------------------------------------------------------------
320  */
321 static Boolean
322 CondDoDefined(int argLen, char *arg)
323 {
324     char    savec = arg[argLen];
325     char    *p1;
326     Boolean result;
327 
328     arg[argLen] = '\0';
329     if (Var_Value(arg, VAR_CMD, &p1) != NULL) {
330 	result = TRUE;
331     } else {
332 	result = FALSE;
333     }
334     if (p1)
335 	free(p1);
336     arg[argLen] = savec;
337     return (result);
338 }
339 
340 /*-
341  *-----------------------------------------------------------------------
342  * CondStrMatch --
343  *	Front-end for Str_Match so it returns 0 on match and non-zero
344  *	on mismatch. Callback function for CondDoMake via Lst_Find
345  *
346  * Results:
347  *	0 if string matches pattern
348  *
349  * Side Effects:
350  *	None
351  *
352  *-----------------------------------------------------------------------
353  */
354 static int
355 CondStrMatch(ClientData string, ClientData pattern)
356 {
357     return(!Str_Match((char *)string,(char *)pattern));
358 }
359 
360 /*-
361  *-----------------------------------------------------------------------
362  * CondDoMake --
363  *	Handle the 'make' function for conditionals.
364  *
365  * Results:
366  *	TRUE if the given target is being made.
367  *
368  * Side Effects:
369  *	None.
370  *
371  *-----------------------------------------------------------------------
372  */
373 static Boolean
374 CondDoMake(int argLen, char *arg)
375 {
376     char    savec = arg[argLen];
377     Boolean result;
378 
379     arg[argLen] = '\0';
380     if (Lst_Find(create, arg, CondStrMatch) == NULL) {
381 	result = FALSE;
382     } else {
383 	result = TRUE;
384     }
385     arg[argLen] = savec;
386     return (result);
387 }
388 
389 /*-
390  *-----------------------------------------------------------------------
391  * CondDoExists --
392  *	See if the given file exists.
393  *
394  * Results:
395  *	TRUE if the file exists and FALSE if it does not.
396  *
397  * Side Effects:
398  *	None.
399  *
400  *-----------------------------------------------------------------------
401  */
402 static Boolean
403 CondDoExists(int argLen, char *arg)
404 {
405     char    savec = arg[argLen];
406     Boolean result;
407     char    *path;
408 
409     arg[argLen] = '\0';
410     path = Dir_FindFile(arg, dirSearchPath);
411     if (path != NULL) {
412 	result = TRUE;
413 	free(path);
414     } else {
415 	result = FALSE;
416     }
417     arg[argLen] = savec;
418     if (DEBUG(COND)) {
419 	fprintf(debug_file, "exists(%s) result is \"%s\"\n",
420 	       arg, path ? path : "");
421     }
422     return (result);
423 }
424 
425 /*-
426  *-----------------------------------------------------------------------
427  * CondDoTarget --
428  *	See if the given node exists and is an actual target.
429  *
430  * Results:
431  *	TRUE if the node exists as a target and FALSE if it does not.
432  *
433  * Side Effects:
434  *	None.
435  *
436  *-----------------------------------------------------------------------
437  */
438 static Boolean
439 CondDoTarget(int argLen, char *arg)
440 {
441     char    savec = arg[argLen];
442     Boolean result;
443     GNode   *gn;
444 
445     arg[argLen] = '\0';
446     gn = Targ_FindNode(arg, TARG_NOCREATE);
447     if ((gn != NULL) && !OP_NOP(gn->type)) {
448 	result = TRUE;
449     } else {
450 	result = FALSE;
451     }
452     arg[argLen] = savec;
453     return (result);
454 }
455 
456 /*-
457  *-----------------------------------------------------------------------
458  * CondDoCommands --
459  *	See if the given node exists and is an actual target with commands
460  *	associated with it.
461  *
462  * Results:
463  *	TRUE if the node exists as a target and has commands associated with
464  *	it and FALSE if it does not.
465  *
466  * Side Effects:
467  *	None.
468  *
469  *-----------------------------------------------------------------------
470  */
471 static Boolean
472 CondDoCommands(int argLen, char *arg)
473 {
474     char    savec = arg[argLen];
475     Boolean result;
476     GNode   *gn;
477 
478     arg[argLen] = '\0';
479     gn = Targ_FindNode(arg, TARG_NOCREATE);
480     if ((gn != NULL) && !OP_NOP(gn->type) && !Lst_IsEmpty(gn->commands)) {
481 	result = TRUE;
482     } else {
483 	result = FALSE;
484     }
485     arg[argLen] = savec;
486     return (result);
487 }
488 
489 /*-
490  *-----------------------------------------------------------------------
491  * CondCvtArg --
492  *	Convert the given number into a double.
493  *	We try a base 10 or 16 integer conversion first, if that fails
494  *	then we try a floating point conversion instead.
495  *
496  * Results:
497  *	Sets 'value' to double value of string.
498  *	Returns 'true' if the convertion suceeded
499  *
500  *-----------------------------------------------------------------------
501  */
502 static Boolean
503 CondCvtArg(char *str, double *value)
504 {
505     char *eptr, ech;
506     unsigned long l_val;
507     double d_val;
508 
509     errno = 0;
510     l_val = strtoul(str, &eptr, str[1] == 'x' ? 16 : 10);
511     ech = *eptr;
512     if (ech == 0 && errno != ERANGE) {
513 	d_val = str[0] == '-' ? -(double)-l_val : (double)l_val;
514     } else {
515 	if (ech != 0 && ech != '.' && ech != 'e' && ech != 'E')
516 	    return FALSE;
517 	d_val = strtod(str, &eptr);
518 	if (*eptr)
519 	    return FALSE;
520     }
521 
522     *value = d_val;
523     return TRUE;
524 }
525 
526 /*-
527  *-----------------------------------------------------------------------
528  * CondGetString --
529  *	Get a string from a variable reference or an optionally quoted
530  *	string.  This is called for the lhs and rhs of string compares.
531  *
532  * Results:
533  *	Sets freeIt if needed,
534  *	Sets quoted if string was quoted,
535  *	Returns NULL on error,
536  *	else returns string - absent any quotes.
537  *
538  * Side Effects:
539  *	Moves condExpr to end of this token.
540  *
541  *
542  *-----------------------------------------------------------------------
543  */
544 /* coverity:[+alloc : arg-*2] */
545 static char *
546 CondGetString(Boolean doEval, Boolean *quoted, void **freeIt)
547 {
548     Buffer buf;
549     char *cp;
550     char *str;
551     int	len;
552     int qt;
553     char *start;
554 
555     buf = Buf_Init(0);
556     str = NULL;
557     *freeIt = NULL;
558     *quoted = qt = *condExpr == '"' ? 1 : 0;
559     if (qt)
560 	condExpr++;
561     for (start = condExpr; *condExpr && str == NULL; condExpr++) {
562 	switch (*condExpr) {
563 	case '\\':
564 	    if (condExpr[1] != '\0') {
565 		condExpr++;
566 		Buf_AddByte(buf, (Byte)*condExpr);
567 	    }
568 	    break;
569 	case '"':
570 	    if (qt) {
571 		condExpr++;		/* we don't want the quotes */
572 		goto got_str;
573 	    } else
574 		Buf_AddByte(buf, (Byte)*condExpr); /* likely? */
575 	    break;
576 	case ')':
577 	case '!':
578 	case '=':
579 	case '>':
580 	case '<':
581 	case ' ':
582 	case '\t':
583 	    if (!qt)
584 		goto got_str;
585 	    else
586 		Buf_AddByte(buf, (Byte)*condExpr);
587 	    break;
588 	case '$':
589 	    /* if we are in quotes, then an undefined variable is ok */
590 	    str = Var_Parse(condExpr, VAR_CMD, (qt ? 0 : doEval),
591 			    &len, freeIt);
592 	    if (str == var_Error) {
593 		if (*freeIt) {
594 		    free(*freeIt);
595 		    *freeIt = NULL;
596 		}
597 		/*
598 		 * Even if !doEval, we still report syntax errors, which
599 		 * is what getting var_Error back with !doEval means.
600 		 */
601 		str = NULL;
602 		goto cleanup;
603 	    }
604 	    condExpr += len;
605 	    /*
606 	     * If the '$' was first char (no quotes), and we are
607 	     * followed by space, the operator or end of expression,
608 	     * we are done.
609 	     */
610 	    if ((condExpr == start + len) &&
611 		(*condExpr == '\0' ||
612 		 isspace((unsigned char) *condExpr) ||
613 		 strchr("!=><)", *condExpr))) {
614 		goto cleanup;
615 	    }
616 	    /*
617 	     * Nope, we better copy str to buf
618 	     */
619 	    for (cp = str; *cp; cp++) {
620 		Buf_AddByte(buf, (Byte)*cp);
621 	    }
622 	    if (*freeIt) {
623 		free(*freeIt);
624 		*freeIt = NULL;
625 	    }
626 	    str = NULL;			/* not finished yet */
627 	    condExpr--;			/* don't skip over next char */
628 	    break;
629 	default:
630 	    Buf_AddByte(buf, (Byte)*condExpr);
631 	    break;
632 	}
633     }
634  got_str:
635     Buf_AddByte(buf, (Byte)'\0');
636     str = (char *)Buf_GetAll(buf, NULL);
637     *freeIt = str;
638  cleanup:
639     Buf_Destroy(buf, FALSE);
640     return str;
641 }
642 
643 /*-
644  *-----------------------------------------------------------------------
645  * CondToken --
646  *	Return the next token from the input.
647  *
648  * Results:
649  *	A Token for the next lexical token in the stream.
650  *
651  * Side Effects:
652  *	condPushback will be set back to None if it is used.
653  *
654  *-----------------------------------------------------------------------
655  */
656 static Token
657 compare_expression(Boolean doEval)
658 {
659     Token	t;
660     char	*lhs;
661     char	*rhs;
662     char	*op;
663     void	*lhsFree;
664     void	*rhsFree;
665     Boolean lhsQuoted;
666     Boolean rhsQuoted;
667 
668     rhs = NULL;
669     lhsFree = rhsFree = FALSE;
670     lhsQuoted = rhsQuoted = FALSE;
671 
672     /*
673      * Parse the variable spec and skip over it, saving its
674      * value in lhs.
675      */
676     t = Err;
677     lhs = CondGetString(doEval, &lhsQuoted, &lhsFree);
678     if (!lhs) {
679 	if (lhsFree)
680 	    free(lhsFree);
681 	return Err;
682     }
683     /*
684      * Skip whitespace to get to the operator
685      */
686     while (isspace((unsigned char) *condExpr))
687 	condExpr++;
688 
689     /*
690      * Make sure the operator is a valid one. If it isn't a
691      * known relational operator, pretend we got a
692      * != 0 comparison.
693      */
694     op = condExpr;
695     switch (*condExpr) {
696 	case '!':
697 	case '=':
698 	case '<':
699 	case '>':
700 	    if (condExpr[1] == '=') {
701 		condExpr += 2;
702 	    } else {
703 		condExpr += 1;
704 	    }
705 	    break;
706 	default:
707 	    op = UNCONST("!=");
708 	    if (lhsQuoted)
709 		rhs = UNCONST("");
710 	    else
711 		rhs = UNCONST("0");
712 
713 	    goto do_compare;
714     }
715     while (isspace((unsigned char) *condExpr)) {
716 	condExpr++;
717     }
718     if (*condExpr == '\0') {
719 	Parse_Error(PARSE_WARNING,
720 		    "Missing right-hand-side of operator");
721 	goto error;
722     }
723     rhs = CondGetString(doEval, &rhsQuoted, &rhsFree);
724     if (!rhs) {
725 	if (lhsFree)
726 	    free(lhsFree);
727 	if (rhsFree)
728 	    free(rhsFree);
729 	return Err;
730     }
731 do_compare:
732     if (rhsQuoted || lhsQuoted) {
733 do_string_compare:
734 	if (((*op != '!') && (*op != '=')) || (op[1] != '=')) {
735 	    Parse_Error(PARSE_WARNING,
736     "String comparison operator should be either == or !=");
737 	    goto error;
738 	}
739 
740 	if (DEBUG(COND)) {
741 	    fprintf(debug_file, "lhs = \"%s\", rhs = \"%s\", op = %.2s\n",
742 		   lhs, rhs, op);
743 	}
744 	/*
745 	 * Null-terminate rhs and perform the comparison.
746 	 * t is set to the result.
747 	 */
748 	if (*op == '=') {
749 	    t = strcmp(lhs, rhs) ? False : True;
750 	} else {
751 	    t = strcmp(lhs, rhs) ? True : False;
752 	}
753     } else {
754 	/*
755 	 * rhs is either a float or an integer. Convert both the
756 	 * lhs and the rhs to a double and compare the two.
757 	 */
758 	double  	left, right;
759 
760 	if (!CondCvtArg(lhs, &left) || !CondCvtArg(rhs, &right))
761 	    goto do_string_compare;
762 
763 	if (DEBUG(COND)) {
764 	    fprintf(debug_file, "left = %f, right = %f, op = %.2s\n", left,
765 		   right, op);
766 	}
767 	switch(op[0]) {
768 	case '!':
769 	    if (op[1] != '=') {
770 		Parse_Error(PARSE_WARNING,
771 			    "Unknown operator");
772 		goto error;
773 	    }
774 	    t = (left != right ? True : False);
775 	    break;
776 	case '=':
777 	    if (op[1] != '=') {
778 		Parse_Error(PARSE_WARNING,
779 			    "Unknown operator");
780 		goto error;
781 	    }
782 	    t = (left == right ? True : False);
783 	    break;
784 	case '<':
785 	    if (op[1] == '=') {
786 		t = (left <= right ? True : False);
787 	    } else {
788 		t = (left < right ? True : False);
789 	    }
790 	    break;
791 	case '>':
792 	    if (op[1] == '=') {
793 		t = (left >= right ? True : False);
794 	    } else {
795 		t = (left > right ? True : False);
796 	    }
797 	    break;
798 	}
799     }
800 error:
801     if (lhsFree)
802 	free(lhsFree);
803     if (rhsFree)
804 	free(rhsFree);
805     return t;
806 }
807 
808 static int
809 get_mpt_arg(char **linePtr, char **argPtr, const char *func, Boolean parens)
810 {
811     /*
812      * Use Var_Parse to parse the spec in parens and return
813      * True if the resulting string is empty.
814      */
815     int	    length;
816     void    *freeIt;
817     char    *val;
818     char    *cp = *linePtr;
819 
820     /* We do all the work here and return the result as the length */
821     *argPtr = NULL;
822 
823     val = Var_Parse(cp - 1, VAR_CMD, FALSE, &length, &freeIt);
824     /*
825      * Advance *linePtr to beyond the closing ). Note that
826      * we subtract one because 'length' is calculated from 'cp - 1'.
827      */
828     *linePtr = cp - 1 + length;
829 
830     if (val == var_Error) {
831 	free(freeIt);
832 	return -1;
833     }
834 
835     /* A variable is empty when it just contains spaces... 4/15/92, christos */
836     while (isspace(*(unsigned char *)val))
837 	val++;
838 
839     /*
840      * For consistency with the other functions we can't generate the
841      * true/false here.
842      */
843     length = *val ? 2 : 1;
844     if (freeIt)
845 	free(freeIt);
846     return length;
847 }
848 
849 static Boolean
850 CondDoEmpty(int arglen, char *arg)
851 {
852     return arglen == 1;
853 }
854 
855 static Token
856 compare_function(Boolean doEval)
857 {
858     static const struct fn_def {
859 	const char  *fn_name;
860 	int         fn_name_len;
861         int         (*fn_getarg)(char **, char **, const char *, Boolean);
862 	Boolean     (*fn_proc)(int, char *);
863     } fn_defs[] = {
864 	{ "defined",   7, CondGetArg, CondDoDefined },
865 	{ "make",      4, CondGetArg, CondDoMake },
866 	{ "exists",    6, CondGetArg, CondDoExists },
867 	{ "empty",     5, get_mpt_arg, CondDoEmpty },
868 	{ "target",    6, CondGetArg, CondDoTarget },
869 	{ "commands",  8, CondGetArg, CondDoCommands },
870 	{ NULL,        0, NULL, NULL },
871     };
872     const struct fn_def *fn_def;
873     Token	t;
874     char	*arg = NULL;
875     int	arglen;
876     char *cp = condExpr;
877     char *cp1;
878 
879     for (fn_def = fn_defs; fn_def->fn_name != NULL; fn_def++) {
880 	if (!istoken(cp, fn_def->fn_name, fn_def->fn_name_len))
881 	    continue;
882 	cp += fn_def->fn_name_len;
883 	/* There can only be whitespace before the '(' */
884 	while (isspace(*(unsigned char *)cp))
885 	    cp++;
886 	if (*cp != '(')
887 	    break;
888 
889 	arglen = fn_def->fn_getarg(&cp, &arg, fn_def->fn_name, TRUE);
890 	if (arglen <= 0) {
891 	    if (arglen < 0) {
892 		condExpr = cp;
893 		return Err;
894 	    }
895 	    break;
896 	}
897 	/* Evaluate the argument using the required function. */
898 	t = !doEval || fn_def->fn_proc(arglen, arg) ? True : False;
899 	if (arg)
900 	    free(arg);
901 	condExpr = cp;
902 	return t;
903     }
904 
905     /* Push anything numeric through the compare expression */
906     cp = condExpr;
907     if (isdigit((unsigned char)cp[0]) || strchr("+-", cp[0]))
908 	return compare_expression(doEval);
909 
910     /*
911      * Most likely we have a naked token to apply the default function to.
912      * However ".if a == b" gets here when the "a" is unquoted and doesn't
913      * start with a '$'. This surprises people - especially given the way
914      * that for loops get expanded.
915      * If what follows the function argument is a '=' or '!' then the syntax
916      * would be invalid if we did "defined(a)" - so instead treat as an
917      * expression.
918      */
919     arglen = CondGetArg(&cp, &arg, "", FALSE);
920     for (cp1 = cp; isspace(*(unsigned char *)cp1); cp1++)
921 	continue;
922     if (*cp1 == '=' || *cp1 == '!')
923 	return compare_expression(doEval);
924     condExpr = cp;
925 
926     /*
927      * Evaluate the argument using the default function. If invert
928      * is TRUE, we invert the sense of the result.
929      */
930     t = !doEval || (* condDefProc)(arglen, arg) != condInvert ? True : False;
931     if (arg)
932 	free(arg);
933     return t;
934 }
935 
936 static Token
937 CondToken(Boolean doEval)
938 {
939     Token t;
940 
941     t = condPushBack;
942     if (t != None) {
943 	condPushBack = None;
944 	return t;
945     }
946 
947     while (*condExpr == ' ' || *condExpr == '\t') {
948 	condExpr++;
949     }
950 
951     switch (*condExpr) {
952 
953     case '(':
954 	condExpr++;
955 	return LParen;
956 
957     case ')':
958 	condExpr++;
959 	return RParen;
960 
961     case '|':
962 	if (condExpr[1] == '|') {
963 	    condExpr++;
964 	}
965 	condExpr++;
966 	return Or;
967 
968     case '&':
969 	if (condExpr[1] == '&') {
970 	    condExpr++;
971 	}
972 	condExpr++;
973 	return And;
974 
975     case '!':
976 	condExpr++;
977 	return Not;
978 
979     case '#':
980     case '\n':
981     case '\0':
982 	return EndOfFile;
983 
984     case '"':
985     case '$':
986 	return compare_expression(doEval);
987 
988     default:
989 	return compare_function(doEval);
990     }
991 }
992 
993 /*-
994  *-----------------------------------------------------------------------
995  * CondT --
996  *	Parse a single term in the expression. This consists of a terminal
997  *	symbol or Not and a terminal symbol (not including the binary
998  *	operators):
999  *	    T -> defined(variable) | make(target) | exists(file) | symbol
1000  *	    T -> ! T | ( E )
1001  *
1002  * Results:
1003  *	True, False or Err.
1004  *
1005  * Side Effects:
1006  *	Tokens are consumed.
1007  *
1008  *-----------------------------------------------------------------------
1009  */
1010 static Token
1011 CondT(Boolean doEval)
1012 {
1013     Token   t;
1014 
1015     t = CondToken(doEval);
1016 
1017     if (t == EndOfFile) {
1018 	/*
1019 	 * If we reached the end of the expression, the expression
1020 	 * is malformed...
1021 	 */
1022 	t = Err;
1023     } else if (t == LParen) {
1024 	/*
1025 	 * T -> ( E )
1026 	 */
1027 	t = CondE(doEval);
1028 	if (t != Err) {
1029 	    if (CondToken(doEval) != RParen) {
1030 		t = Err;
1031 	    }
1032 	}
1033     } else if (t == Not) {
1034 	t = CondT(doEval);
1035 	if (t == True) {
1036 	    t = False;
1037 	} else if (t == False) {
1038 	    t = True;
1039 	}
1040     }
1041     return (t);
1042 }
1043 
1044 /*-
1045  *-----------------------------------------------------------------------
1046  * CondF --
1047  *	Parse a conjunctive factor (nice name, wot?)
1048  *	    F -> T && F | T
1049  *
1050  * Results:
1051  *	True, False or Err
1052  *
1053  * Side Effects:
1054  *	Tokens are consumed.
1055  *
1056  *-----------------------------------------------------------------------
1057  */
1058 static Token
1059 CondF(Boolean doEval)
1060 {
1061     Token   l, o;
1062 
1063     l = CondT(doEval);
1064     if (l != Err) {
1065 	o = CondToken(doEval);
1066 
1067 	if (o == And) {
1068 	    /*
1069 	     * F -> T && F
1070 	     *
1071 	     * If T is False, the whole thing will be False, but we have to
1072 	     * parse the r.h.s. anyway (to throw it away).
1073 	     * If T is True, the result is the r.h.s., be it an Err or no.
1074 	     */
1075 	    if (l == True) {
1076 		l = CondF(doEval);
1077 	    } else {
1078 		(void)CondF(FALSE);
1079 	    }
1080 	} else {
1081 	    /*
1082 	     * F -> T
1083 	     */
1084 	    CondPushBack(o);
1085 	}
1086     }
1087     return (l);
1088 }
1089 
1090 /*-
1091  *-----------------------------------------------------------------------
1092  * CondE --
1093  *	Main expression production.
1094  *	    E -> F || E | F
1095  *
1096  * Results:
1097  *	True, False or Err.
1098  *
1099  * Side Effects:
1100  *	Tokens are, of course, consumed.
1101  *
1102  *-----------------------------------------------------------------------
1103  */
1104 static Token
1105 CondE(Boolean doEval)
1106 {
1107     Token   l, o;
1108 
1109     l = CondF(doEval);
1110     if (l != Err) {
1111 	o = CondToken(doEval);
1112 
1113 	if (o == Or) {
1114 	    /*
1115 	     * E -> F || E
1116 	     *
1117 	     * A similar thing occurs for ||, except that here we make sure
1118 	     * the l.h.s. is False before we bother to evaluate the r.h.s.
1119 	     * Once again, if l is False, the result is the r.h.s. and once
1120 	     * again if l is True, we parse the r.h.s. to throw it away.
1121 	     */
1122 	    if (l == False) {
1123 		l = CondE(doEval);
1124 	    } else {
1125 		(void)CondE(FALSE);
1126 	    }
1127 	} else {
1128 	    /*
1129 	     * E -> F
1130 	     */
1131 	    CondPushBack(o);
1132 	}
1133     }
1134     return (l);
1135 }
1136 
1137 /*-
1138  *-----------------------------------------------------------------------
1139  * Cond_EvalExpression --
1140  *	Evaluate an expression in the passed line. The expression
1141  *	consists of &&, ||, !, make(target), defined(variable)
1142  *	and parenthetical groupings thereof.
1143  *
1144  * Results:
1145  *	COND_PARSE	if the condition was valid grammatically
1146  *	COND_INVALID  	if not a valid conditional.
1147  *
1148  *	(*value) is set to the boolean value of the condition
1149  *
1150  * Side Effects:
1151  *	None.
1152  *
1153  *-----------------------------------------------------------------------
1154  */
1155 int
1156 Cond_EvalExpression(int dosetup, char *line, Boolean *value, int eprint)
1157 {
1158     if (dosetup) {
1159 	condDefProc = CondDoDefined;
1160 	condInvert = 0;
1161     }
1162 
1163     while (*line == ' ' || *line == '\t')
1164 	line++;
1165 
1166     condExpr = line;
1167     condPushBack = None;
1168 
1169     switch (CondE(TRUE)) {
1170     case True:
1171 	if (CondToken(TRUE) == EndOfFile) {
1172 	    *value = TRUE;
1173 	    break;
1174 	}
1175 	goto err;
1176 	/*FALLTHRU*/
1177     case False:
1178 	if (CondToken(TRUE) == EndOfFile) {
1179 	    *value = FALSE;
1180 	    break;
1181 	}
1182 	/*FALLTHRU*/
1183     case Err:
1184 err:
1185 	if (eprint)
1186 	    Parse_Error(PARSE_FATAL, "Malformed conditional (%s)",
1187 			 line);
1188 	return (COND_INVALID);
1189     default:
1190 	break;
1191     }
1192 
1193     return COND_PARSE;
1194 }
1195 
1196 
1197 /*-
1198  *-----------------------------------------------------------------------
1199  * Cond_Eval --
1200  *	Evaluate the conditional in the passed line. The line
1201  *	looks like this:
1202  *	    .<cond-type> <expr>
1203  *	where <cond-type> is any of if, ifmake, ifnmake, ifdef,
1204  *	ifndef, elif, elifmake, elifnmake, elifdef, elifndef
1205  *	and <expr> consists of &&, ||, !, make(target), defined(variable)
1206  *	and parenthetical groupings thereof.
1207  *
1208  * Input:
1209  *	line		Line to parse
1210  *
1211  * Results:
1212  *	COND_PARSE	if should parse lines after the conditional
1213  *	COND_SKIP	if should skip lines after the conditional
1214  *	COND_INVALID  	if not a valid conditional.
1215  *
1216  * Side Effects:
1217  *	None.
1218  *
1219  * Note that the states IF_ACTIVE and ELSE_ACTIVE are only different in order
1220  * to detect splurious .else lines (as are SKIP_TO_ELSE and SKIP_TO_ENDIF)
1221  * otherwise .else could be treated as '.elif 1'.
1222  *
1223  *-----------------------------------------------------------------------
1224  */
1225 int
1226 Cond_Eval(char *line)
1227 {
1228     #define	    MAXIF	64	/* maximum depth of .if'ing */
1229     enum if_states {
1230 	IF_ACTIVE,		/* .if or .elif part active */
1231 	ELSE_ACTIVE,		/* .else part active */
1232 	SEARCH_FOR_ELIF,	/* searching for .elif/else to execute */
1233 	SKIP_TO_ELSE,           /* has been true, but not seen '.else' */
1234 	SKIP_TO_ENDIF		/* nothing else to execute */
1235     };
1236     static enum if_states cond_state[MAXIF + 1] = { IF_ACTIVE };
1237 
1238     const struct If *ifp;
1239     Boolean 	    isElif;
1240     Boolean 	    value;
1241     int	    	    level;  	/* Level at which to report errors. */
1242     enum if_states  state;
1243 
1244     level = PARSE_FATAL;
1245 
1246     /* skip leading character (the '.') and any whitespace */
1247     for (line++; *line == ' ' || *line == '\t'; line++)
1248 	continue;
1249 
1250     /* Find what type of if we're dealing with.  */
1251     if (line[0] == 'e') {
1252 	if (line[1] != 'l') {
1253 	    if (!istoken(line + 1, "ndif", 4))
1254 		return COND_INVALID;
1255 	    /* End of conditional section */
1256 	    if (cond_depth == cond_min_depth) {
1257 		Parse_Error(level, "if-less endif");
1258 		return COND_PARSE;
1259 	    }
1260 	    /* Return state for previous conditional */
1261 	    cond_depth--;
1262 	    if (cond_depth > MAXIF)
1263 		return COND_SKIP;
1264 	    return cond_state[cond_depth] <= ELSE_ACTIVE ? COND_PARSE : COND_SKIP;
1265 	}
1266 
1267 	/* Quite likely this is 'else' or 'elif' */
1268 	line += 2;
1269 	if (istoken(line, "se", 2)) {
1270 	    /* It is else... */
1271 	    if (cond_depth == cond_min_depth) {
1272 		Parse_Error(level, "if-less else");
1273 		return COND_PARSE;
1274 	    }
1275 
1276 	    if (cond_depth > MAXIF)
1277 		return COND_SKIP;
1278 	    state = cond_state[cond_depth];
1279 	    switch (state) {
1280 	    case SEARCH_FOR_ELIF:
1281 		state = ELSE_ACTIVE;
1282 		break;
1283 	    case ELSE_ACTIVE:
1284 	    case SKIP_TO_ENDIF:
1285 		Parse_Error(PARSE_WARNING, "extra else");
1286 		/* FALLTHROUGH */
1287 	    default:
1288 	    case IF_ACTIVE:
1289 	    case SKIP_TO_ELSE:
1290 		state = SKIP_TO_ENDIF;
1291 		break;
1292 	    }
1293 	    cond_state[cond_depth] = state;
1294 	    return state <= ELSE_ACTIVE ? COND_PARSE : COND_SKIP;
1295 	}
1296 	/* Assume for now it is an elif */
1297 	isElif = TRUE;
1298     } else
1299 	isElif = FALSE;
1300 
1301     if (line[0] != 'i' || line[1] != 'f')
1302 	/* Not an ifxxx or elifxxx line */
1303 	return COND_INVALID;
1304 
1305     /*
1306      * Figure out what sort of conditional it is -- what its default
1307      * function is, etc. -- by looking in the table of valid "ifs"
1308      */
1309     line += 2;
1310     for (ifp = ifs; ; ifp++) {
1311 	if (ifp->form == NULL)
1312 	    return COND_INVALID;
1313 	if (istoken(ifp->form, line, ifp->formlen)) {
1314 	    line += ifp->formlen;
1315 	    break;
1316 	}
1317     }
1318 
1319     /* Now we know what sort of 'if' it is... */
1320 
1321     if (isElif) {
1322 	if (cond_depth == cond_min_depth) {
1323 	    Parse_Error(level, "if-less elif");
1324 	    return COND_PARSE;
1325 	}
1326 	if (cond_depth > MAXIF)
1327 	    /* Error reported when we saw the .if ... */
1328 	    return COND_SKIP;
1329 	state = cond_state[cond_depth];
1330 	if (state == SKIP_TO_ENDIF || state == ELSE_ACTIVE) {
1331 	    Parse_Error(PARSE_WARNING, "extra elif");
1332 	    cond_state[cond_depth] = SKIP_TO_ENDIF;
1333 	    return COND_SKIP;
1334 	}
1335 	if (state != SEARCH_FOR_ELIF) {
1336 	    /* Either just finished the 'true' block, or already SKIP_TO_ELSE */
1337 	    cond_state[cond_depth] = SKIP_TO_ELSE;
1338 	    return COND_SKIP;
1339 	}
1340     } else {
1341 	/* Normal .if */
1342 	if (cond_depth >= MAXIF) {
1343 	    cond_depth++;
1344 	    Parse_Error(PARSE_FATAL, "Too many nested if's. %d max.", MAXIF);
1345 	    return COND_SKIP;
1346 	}
1347 	state = cond_state[cond_depth];
1348 	cond_depth++;
1349 	if (state > ELSE_ACTIVE) {
1350 	    /* If we aren't parsing the data, treat as always false */
1351 	    cond_state[cond_depth] = SKIP_TO_ELSE;
1352 	    return COND_SKIP;
1353 	}
1354     }
1355 
1356     /* Initialize file-global variables for parsing the expression */
1357     condDefProc = ifp->defProc;
1358     condInvert = ifp->doNot;
1359 
1360     /* And evaluate the conditional expresssion */
1361     if (Cond_EvalExpression(0, line, &value, 1) == COND_INVALID) {
1362 	/* Syntax error in conditional, error message already output. */
1363 	/* Skip everything to matching .endif */
1364 	cond_state[cond_depth] = SKIP_TO_ELSE;
1365 	return COND_SKIP;
1366     }
1367 
1368     if (!value) {
1369 	cond_state[cond_depth] = SEARCH_FOR_ELIF;
1370 	return COND_SKIP;
1371     }
1372     cond_state[cond_depth] = IF_ACTIVE;
1373     return COND_PARSE;
1374 }
1375 
1376 
1377 
1378 /*-
1379  *-----------------------------------------------------------------------
1380  * Cond_End --
1381  *	Make sure everything's clean at the end of a makefile.
1382  *
1383  * Results:
1384  *	None.
1385  *
1386  * Side Effects:
1387  *	Parse_Error will be called if open conditionals are around.
1388  *
1389  *-----------------------------------------------------------------------
1390  */
1391 void
1392 Cond_restore_depth(unsigned int saved_depth)
1393 {
1394     int open_conds = cond_depth - cond_min_depth;
1395 
1396     if (open_conds != 0 || saved_depth > cond_depth) {
1397 	Parse_Error(PARSE_FATAL, "%d open conditional%s", open_conds,
1398 		    open_conds == 1 ? "" : "s");
1399 	cond_depth = cond_min_depth;
1400     }
1401 
1402     cond_min_depth = saved_depth;
1403 }
1404 
1405 unsigned int
1406 Cond_save_depth(void)
1407 {
1408     int depth = cond_min_depth;
1409 
1410     cond_min_depth = cond_depth;
1411     return depth;
1412 }
1413