xref: /trueos/usr.bin/make/cond.c (revision ec3ee28e7c3d46e2aa137fac569ec65515286098)
1 /*-
2  * Copyright (c) 1988, 1989, 1990, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  * Copyright (c) 1988, 1989 by Adam de Boor
5  * Copyright (c) 1989 by Berkeley Softworks
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to Berkeley by
9  * Adam de Boor.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *	This product includes software developed by the University of
22  *	California, Berkeley and its contributors.
23  * 4. Neither the name of the University nor the names of its contributors
24  *    may be used to endorse or promote products derived from this software
25  *    without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37  * SUCH DAMAGE.
38  *
39  * @(#)cond.c	8.2 (Berkeley) 1/2/94
40  */
41 
42 #include <sys/cdefs.h>
43 __FBSDID("$FreeBSD$");
44 
45 /*
46  * Functions to handle conditionals in a makefile.
47  *
48  * Interface:
49  *	Cond_Eval	Evaluate the conditional in the passed line.
50  */
51 
52 #include <ctype.h>
53 #include <string.h>
54 #include <stdlib.h>
55 
56 #include "buf.h"
57 #include "cond.h"
58 #include "dir.h"
59 #include "globals.h"
60 #include "GNode.h"
61 #include "make.h"
62 #include "parse.h"
63 #include "str.h"
64 #include "targ.h"
65 #include "util.h"
66 #include "var.h"
67 
68 /*
69  * The parsing of conditional expressions is based on this grammar:
70  *	E -> F || E
71  *	E -> F
72  *	F -> T && F
73  *	F -> T
74  *	T -> defined(variable)
75  *	T -> make(target)
76  *	T -> exists(file)
77  *	T -> empty(varspec)
78  *	T -> target(name)
79  *	T -> symbol
80  *	T -> $(varspec) op value
81  *	T -> $(varspec) == "string"
82  *	T -> $(varspec) != "string"
83  *	T -> ( E )
84  *	T -> ! T
85  *	op -> == | != | > | < | >= | <=
86  *
87  * 'symbol' is some other symbol to which the default function (condDefProc)
88  * is applied.
89  *
90  * Tokens are scanned from the 'condExpr' string. The scanner (CondToken)
91  * will return And for '&' and '&&', Or for '|' and '||', Not for '!',
92  * LParen for '(', RParen for ')' and will evaluate the other terminal
93  * symbols, using either the default function or the function given in the
94  * terminal, and return the result as either True or False.
95  *
96  * All Non-Terminal functions (CondE, CondF and CondT) return Err on error.
97  */
98 typedef enum {
99 	And,
100 	Or,
101 	Not,
102 	True,
103 	False,
104 	LParen,
105 	RParen,
106 	EndOfFile,
107 	None,
108 	Err
109 } Token;
110 
111 typedef Boolean CondProc(int, char *);
112 
113 /*-
114  * Structures to handle elegantly the different forms of #if's. The
115  * last two fields are stored in condInvert and condDefProc, respectively.
116  */
117 static void CondPushBack(Token);
118 static int CondGetArg(char **, char **, const char *, Boolean);
119 static CondProc	CondDoDefined;
120 static CondProc	CondDoMake;
121 static CondProc	CondDoExists;
122 static CondProc	CondDoTarget;
123 static char *CondCvtArg(char *, double *);
124 static Token CondToken(Boolean);
125 static Token CondT(Boolean);
126 static Token CondF(Boolean);
127 static Token CondE(Boolean);
128 
129 static const struct If {
130 	Boolean	doNot;		/* TRUE if default function should be negated */
131 	CondProc *defProc;	/* Default function to apply */
132 	Boolean	isElse;		/* actually el<XXX> */
133 } ifs[] = {
134 	[COND_IF] =		{ FALSE,	CondDoDefined,	FALSE },
135 	[COND_IFDEF] =		{ FALSE,	CondDoDefined,	FALSE },
136 	[COND_IFNDEF] =		{ TRUE,		CondDoDefined,	FALSE },
137 	[COND_IFMAKE] =		{ FALSE,	CondDoMake,	FALSE },
138 	[COND_IFNMAKE] =	{ TRUE,		CondDoMake,	FALSE },
139 	[COND_ELIF] =		{ FALSE,	CondDoDefined,	TRUE },
140 	[COND_ELIFDEF] =	{ FALSE,	CondDoDefined,	TRUE },
141 	[COND_ELIFNDEF] =	{ TRUE,		CondDoDefined,	TRUE },
142 	[COND_ELIFMAKE] =	{ FALSE,	CondDoMake,	TRUE },
143 	[COND_ELIFNMAKE] =	{ TRUE,		CondDoMake,	TRUE },
144 };
145 
146 static Boolean	condInvert;	/* Invert the default function */
147 static CondProc	*condDefProc;	/* default function to apply */
148 static char	*condExpr;	/* The expression to parse */
149 static Token	condPushBack = None; /* Single push-back token in parsing */
150 
151 #define MAXIF	30	/* greatest depth of #if'ing */
152 
153 static Boolean	condStack[MAXIF];	/* Stack of conditionals's values */
154 static int	condLineno[MAXIF];	/* Line numbers of the opening .if */
155 static int	condTop = MAXIF;	/* Top-most conditional */
156 static int	skipIfLevel = 0;	/* Depth of skipped conditionals */
157 static int	skipIfLineno[MAXIF];	/* Line numbers of skipped .ifs */
158 Boolean		skipLine = FALSE;	/* Whether the parse module is skipping
159 					 * lines */
160 
161 /**
162  * CondPushBack
163  *	Push back the most recent token read. We only need one level of
164  *	this, so the thing is just stored in 'condPushback'.
165  *
166  * Side Effects:
167  *	condPushback is overwritten.
168  */
169 static void
CondPushBack(Token t)170 CondPushBack(Token t)
171 {
172 
173 	condPushBack = t;
174 }
175 
176 /**
177  * CondGetArg
178  *	Find the argument of a built-in function.  parens is set to TRUE
179  *	if the arguments are bounded by parens.
180  *
181  * Results:
182  *	The length of the argument and the address of the argument.
183  *
184  * Side Effects:
185  *	The pointer is set to point to the closing parenthesis of the
186  *	function call.
187  */
188 static int
CondGetArg(char ** linePtr,char ** argPtr,const char * func,Boolean parens)189 CondGetArg(char **linePtr, char **argPtr, const char *func, Boolean parens)
190 {
191 	char	*cp;
192 	size_t	argLen;
193 	Buffer	*buf;
194 
195 	cp = *linePtr;
196 	if (parens) {
197 		while (*cp != '(' && *cp != '\0') {
198 			cp++;
199 		}
200 		if (*cp == '(') {
201 			cp++;
202 		}
203 	}
204 
205 	if (*cp == '\0') {
206 		/*
207 		 * No arguments whatsoever. Because 'make' and 'defined'
208 		 * aren't really "reserved words", we don't print a message.
209 		 * I think this is better than hitting the user with a warning
210 		 * message every time s/he uses the word 'make' or 'defined'
211 		 * at the beginning of a symbol...
212 		 */
213 		*argPtr = cp;
214 		return (0);
215 	}
216 
217 	while (*cp == ' ' || *cp == '\t') {
218 		cp++;
219 	}
220 
221 	/*
222 	 * Create a buffer for the argument and start it out at 16 characters
223 	 * long. Why 16? Why not?
224 	 */
225 	buf = Buf_Init(16);
226 
227 	while ((strchr(" \t)&|", *cp) == NULL) && (*cp != '\0')) {
228 		if (*cp == '$') {
229 			/*
230 			 * Parse the variable spec and install it as part of
231 			 * the argument if it's valid. We tell Var_Parse to
232 			 * complain on an undefined variable, so we don't do
233 			 * it too. Nor do we return an error, though perhaps
234 			 * we should...
235 			 */
236 			char	*cp2;
237 			size_t	len = 0;
238 			Boolean	doFree;
239 
240 			cp2 = Var_Parse(cp, VAR_CMD, TRUE, &len, &doFree);
241 
242 			Buf_Append(buf, cp2);
243 			if (doFree) {
244 				free(cp2);
245 			}
246 			cp += len;
247 		} else {
248 			Buf_AddByte(buf, (Byte)*cp);
249 			cp++;
250 		}
251 	}
252 
253 	Buf_AddByte(buf, (Byte)'\0');
254 	*argPtr = (char *)Buf_GetAll(buf, &argLen);
255 	Buf_Destroy(buf, FALSE);
256 
257 	while (*cp == ' ' || *cp == '\t') {
258 		cp++;
259 	}
260 	if (parens && *cp != ')') {
261 		Parse_Error(PARSE_WARNING,
262 		    "Missing closing parenthesis for %s()", func);
263 		return (0);
264 	} else if (parens) {
265 		/*
266 		 * Advance pointer past close parenthesis.
267 		 */
268 		cp++;
269 	}
270 
271 	*linePtr = cp;
272 	return (argLen);
273 }
274 
275 /**
276  * CondDoDefined
277  *	Handle the 'defined' function for conditionals.
278  *
279  * Results:
280  *	TRUE if the given variable is defined.
281  */
282 static Boolean
CondDoDefined(int argLen,char * arg)283 CondDoDefined(int argLen, char *arg)
284 {
285 	char	savec = arg[argLen];
286 	Boolean	result;
287 
288 	arg[argLen] = '\0';
289 	if (Var_Value(arg, VAR_CMD) != NULL) {
290 		result = TRUE;
291 	} else {
292 		result = FALSE;
293 	}
294 	arg[argLen] = savec;
295 	return (result);
296 }
297 
298 /**
299  * CondDoMake
300  *	Handle the 'make' function for conditionals.
301  *
302  * Results:
303  *	TRUE if the given target is being made.
304  */
305 static Boolean
CondDoMake(int argLen,char * arg)306 CondDoMake(int argLen, char *arg)
307 {
308 	char	savec = arg[argLen];
309 	Boolean	result;
310 	const LstNode *ln;
311 
312 	arg[argLen] = '\0';
313 	result = FALSE;
314 	LST_FOREACH(ln, &create) {
315 		if (Str_Match(Lst_Datum(ln), arg)) {
316 			result = TRUE;
317 			break;
318 		}
319 	}
320 	arg[argLen] = savec;
321 	return (result);
322 }
323 
324 /**
325  * CondDoExists
326  *	See if the given file exists.
327  *
328  * Results:
329  *	TRUE if the file exists and FALSE if it does not.
330  */
331 static Boolean
CondDoExists(int argLen,char * arg)332 CondDoExists(int argLen, char *arg)
333 {
334 	char	savec = arg[argLen];
335 	Boolean	result;
336 	char	*path;
337 
338 	arg[argLen] = '\0';
339 	path = Path_FindFile(arg, &dirSearchPath);
340 	if (path != NULL) {
341 		result = TRUE;
342 		free(path);
343 	} else {
344 		result = FALSE;
345 	}
346 	arg[argLen] = savec;
347 	return (result);
348 }
349 
350 /**
351  * CondDoTarget
352  *	See if the given node exists and is an actual target.
353  *
354  * Results:
355  *	TRUE if the node exists as a target and FALSE if it does not.
356  */
357 static Boolean
CondDoTarget(int argLen,char * arg)358 CondDoTarget(int argLen, char *arg)
359 {
360 	char	savec = arg[argLen];
361 	Boolean	result;
362 	GNode	*gn;
363 
364 	arg[argLen] = '\0';
365 	gn = Targ_FindNode(arg, TARG_NOCREATE);
366 	if ((gn != NULL) && !OP_NOP(gn->type)) {
367 		result = TRUE;
368 	} else {
369 		result = FALSE;
370 	}
371 	arg[argLen] = savec;
372 	return (result);
373 }
374 
375 /**
376  * CondCvtArg
377  *	Convert the given number into a double. If the number begins
378  *	with 0x, it is interpreted as a hexadecimal integer
379  *	and converted to a double from there. All other strings just have
380  *	strtod called on them.
381  *
382  * Results:
383  *	Sets 'value' to double value of string.
384  *	Returns address of the first character after the last valid
385  *	character of the converted number.
386  *
387  * Side Effects:
388  *	Can change 'value' even if string is not a valid number.
389  */
390 static char *
CondCvtArg(char * str,double * value)391 CondCvtArg(char *str, double *value)
392 {
393 
394 	if ((*str == '0') && (str[1] == 'x')) {
395 		long i;
396 
397 		for (str += 2, i = 0; ; str++) {
398 			int x;
399 
400 			if (isdigit((unsigned char)*str))
401 				x  = *str - '0';
402 			else if (isxdigit((unsigned char)*str))
403 				x = 10 + *str -
404 				    isupper((unsigned char)*str) ? 'A' : 'a';
405 			else {
406 				*value = (double)i;
407 				return (str);
408 			}
409 			i = (i << 4) + x;
410 		}
411 
412 	} else {
413 		char *eptr;
414 
415 		*value = strtod(str, &eptr);
416 		return (eptr);
417 	}
418 }
419 
420 /**
421  * CondToken
422  *	Return the next token from the input.
423  *
424  * Results:
425  *	A Token for the next lexical token in the stream.
426  *
427  * Side Effects:
428  *	condPushback will be set back to None if it is used.
429  */
430 static Token
CondToken(Boolean doEval)431 CondToken(Boolean doEval)
432 {
433 	Token	t;
434 
435 	if (condPushBack != None) {
436 		t = condPushBack;
437 		condPushBack = None;
438 		return (t);
439 	}
440 
441 	while (*condExpr == ' ' || *condExpr == '\t') {
442 		condExpr++;
443 	}
444 	switch (*condExpr) {
445 	  case '(':
446 		t = LParen;
447 		condExpr++;
448 		break;
449 	  case ')':
450 		t = RParen;
451 		condExpr++;
452 		break;
453 	  case '|':
454 		if (condExpr[1] == '|') {
455 			condExpr++;
456 		}
457 		condExpr++;
458 		t = Or;
459 		break;
460 	  case '&':
461 		if (condExpr[1] == '&') {
462 			condExpr++;
463 		}
464 		condExpr++;
465 		t = And;
466 		break;
467 	  case '!':
468 		t = Not;
469 		condExpr++;
470 		break;
471 	  case '\n':
472 	  case '\0':
473 		t = EndOfFile;
474 		break;
475 	  case '$': {
476 		char		*lhs;
477 		const char	*op;
478 		char		*rhs;
479 		char		zero[] = "0";
480 		size_t		varSpecLen = 0;
481 		Boolean		doFree;
482 
483 		/*
484 		 * Parse the variable spec and skip over it, saving its
485 		 * value in lhs.
486 		 */
487 		t = Err;
488 		lhs = Var_Parse(condExpr, VAR_CMD, doEval,
489 		    &varSpecLen, &doFree);
490 		if (lhs == var_Error) {
491 			/*
492 			 * Even if !doEval, we still report syntax
493 			 * errors, which is what getting var_Error
494 			 * back with !doEval means.
495 			 */
496 			return (Err);
497 		}
498 		condExpr += varSpecLen;
499 
500 		if (!isspace((unsigned char)*condExpr) &&
501 		    strchr("!=><", *condExpr) == NULL) {
502 			Buffer *buf;
503 
504 			buf = Buf_Init(0);
505 
506 			Buf_Append(buf, lhs);
507 
508 			if (doFree)
509 				free(lhs);
510 
511 			for (;*condExpr &&
512 			    !isspace((unsigned char)*condExpr);
513 			    condExpr++)
514 				Buf_AddByte(buf, (Byte)*condExpr);
515 
516 			Buf_AddByte(buf, (Byte)'\0');
517 			lhs = (char *)Buf_GetAll(buf, &varSpecLen);
518 			Buf_Destroy(buf, FALSE);
519 
520 			doFree = TRUE;
521 		}
522 
523 		/*
524 		 * Skip whitespace to get to the operator
525 		 */
526 		while (isspace((unsigned char)*condExpr))
527 			condExpr++;
528 
529 		/*
530 		 * Make sure the operator is a valid one. If it isn't a
531 		 * known relational operator, pretend we got a
532 		 * != 0 comparison.
533 		 */
534 		op = condExpr;
535 		switch (*condExpr) {
536 		  case '!':
537 		  case '=':
538 		  case '<':
539 		  case '>':
540 			if (condExpr[1] == '=') {
541 				condExpr += 2;
542 			} else {
543 				condExpr += 1;
544 			}
545 			while (isspace((unsigned char)*condExpr)) {
546 				condExpr++;
547 			}
548 			if (*condExpr == '\0') {
549 				Parse_Error(PARSE_WARNING,
550 				    "Missing right-hand-side of operator");
551 				goto error;
552 			}
553 			rhs = condExpr;
554 			break;
555 
556 		  default:
557 			op = "!=";
558 			rhs = zero;
559 			break;
560 		}
561 		if (*rhs == '"') {
562 			/*
563 			 * Doing a string comparison. Only allow == and
564 			 * != for * operators.
565 			 */
566 			char	*string;
567 			char	*cp, *cp2;
568 			int	qt;
569 			Buffer	*buf;
570 
571   do_string_compare:
572 			if (((*op != '!') && (*op != '=')) ||
573 			    (op[1] != '=')) {
574 				Parse_Error(PARSE_WARNING,
575 				    "String comparison operator should "
576 				    "be either == or !=");
577 				goto error;
578 			}
579 
580 			buf = Buf_Init(0);
581 			qt = *rhs == '"' ? 1 : 0;
582 
583 			for (cp = &rhs[qt];
584 			    ((qt && (*cp != '"')) ||
585 			    (!qt && strchr(" \t)", *cp) == NULL)) &&
586 			    (*cp != '\0'); cp++) {
587 				if ((*cp == '\\') && (cp[1] != '\0')) {
588 					/*
589 					 * Backslash escapes things --
590 					 * skip over next character,							 * if it exists.
591 					 */
592 					cp++;
593 					Buf_AddByte(buf, (Byte)*cp);
594 
595 				} else if (*cp == '$') {
596 					size_t	len = 0;
597 					Boolean	freeIt;
598 
599 					cp2 = Var_Parse(cp, VAR_CMD,
600 					    doEval, &len, &freeIt);
601 					if (cp2 != var_Error) {
602 						Buf_Append(buf, cp2);
603 						if (freeIt) {
604 							free(cp2);
605 						}
606 						cp += len - 1;
607 					} else {
608 						Buf_AddByte(buf,
609 						    (Byte)*cp);
610 					}
611 				} else {
612 					Buf_AddByte(buf, (Byte)*cp);
613 				}
614 			}
615 
616 			string = Buf_Peel(buf);
617 
618 			DEBUGF(COND, ("lhs = \"%s\", rhs = \"%s\", "
619 			    "op = %.2s\n", lhs, string, op));
620 			/*
621 			 * Null-terminate rhs and perform the
622 			 * comparison. t is set to the result.
623 			 */
624 			if (*op == '=') {
625 				t = strcmp(lhs, string) ? False : True;
626 			} else {
627 				t = strcmp(lhs, string) ? True : False;
628 			}
629 			free(string);
630 			if (rhs == condExpr) {
631 				if (*cp == '\0' || (!qt && *cp == ')'))
632 					condExpr = cp;
633 				else
634 					condExpr = cp + 1;
635 			}
636 		} else {
637 			/*
638 			 * rhs is either a float or an integer.
639 			 * Convert both the lhs and the rhs to a
640 			 * double and compare the two.
641 			 */
642 			double	left, right;
643 			char	*string;
644 
645 			if (*CondCvtArg(lhs, &left) != '\0')
646 				goto do_string_compare;
647 			if (*rhs == '$') {
648 				size_t	len = 0;
649 				Boolean	freeIt;
650 
651 				string = Var_Parse(rhs, VAR_CMD, doEval,
652 				    &len, &freeIt);
653 				if (string == var_Error) {
654 					right = 0.0;
655 				} else {
656 					if (*CondCvtArg(string,
657 					    &right) != '\0') {
658 						if (freeIt)
659 							free(string);
660 						goto do_string_compare;
661 					}
662 					if (freeIt)
663 						free(string);
664 					if (rhs == condExpr)
665 						condExpr += len;
666 				}
667 			} else {
668 				char *c = CondCvtArg(rhs, &right);
669 
670 				if (c == rhs)
671 					goto do_string_compare;
672 				if (rhs == condExpr) {
673 					/*
674 					 * Skip over the right-hand side
675 					 */
676 					condExpr = c;
677 				}
678 			}
679 
680 			DEBUGF(COND, ("left = %f, right = %f, "
681 			    "op = %.2s\n", left, right, op));
682 			switch (op[0]) {
683 			  case '!':
684 				if (op[1] != '=') {
685 					Parse_Error(PARSE_WARNING,
686 					    "Unknown operator");
687 					goto error;
688 				}
689 				t = (left != right ? True : False);
690 				break;
691 			  case '=':
692 				if (op[1] != '=') {
693 					Parse_Error(PARSE_WARNING,
694 					    "Unknown operator");
695 					goto error;
696 				}
697 				t = (left == right ? True : False);
698 				break;
699 			  case '<':
700 				if (op[1] == '=') {
701 					t = (left <= right?True:False);
702 				} else {
703 					t = (left < right?True:False);
704 				}
705 				break;
706 			case '>':
707 				if (op[1] == '=') {
708 					t = (left >= right?True:False);
709 				} else {
710 					t = (left > right?True:False);
711 				}
712 				break;
713 			default:
714 				break;
715 			}
716 		}
717   error:
718 		if (doFree)
719 			free(lhs);
720 		break;
721 		}
722 
723 	  default: {
724 		CondProc	*evalProc;
725 		Boolean		invert = FALSE;
726 		char		*arg;
727 		int		arglen;
728 
729 		if (strncmp(condExpr, "defined", 7) == 0) {
730 			/*
731 			 * Use CondDoDefined to evaluate the argument
732 			 * and CondGetArg to extract the argument from
733 			 * the 'function call'.
734 			 */
735 			evalProc = CondDoDefined;
736 			condExpr += 7;
737 			arglen = CondGetArg(&condExpr, &arg,
738 			    "defined", TRUE);
739 			if (arglen == 0) {
740 				condExpr -= 7;
741 				goto use_default;
742 			}
743 
744 		} else if (strncmp(condExpr, "make", 4) == 0) {
745 			/*
746 			 * Use CondDoMake to evaluate the argument and
747 			 * CondGetArg to extract the argument from the
748 			 * 'function call'.
749 			 */
750 			evalProc = CondDoMake;
751 			condExpr += 4;
752 			arglen = CondGetArg(&condExpr, &arg,
753 			    "make", TRUE);
754 			if (arglen == 0) {
755 				condExpr -= 4;
756 				goto use_default;
757 			}
758 
759 		} else if (strncmp(condExpr, "exists", 6) == 0) {
760 			/*
761 			 * Use CondDoExists to evaluate the argument and
762 			 * CondGetArg to extract the argument from the
763 			 * 'function call'.
764 			 */
765 			evalProc = CondDoExists;
766 			condExpr += 6;
767 			arglen = CondGetArg(&condExpr, &arg,
768 			    "exists", TRUE);
769 			if (arglen == 0) {
770 				condExpr -= 6;
771 				goto use_default;
772 			}
773 
774 		} else if (strncmp(condExpr, "empty", 5) == 0) {
775 			/*
776 			 * Use Var_Parse to parse the spec in parens and
777 			 * return True if the resulting string is empty.
778 			 */
779 			size_t	length;
780 			Boolean	doFree;
781 			char	*val;
782 
783 			condExpr += 5;
784 
785 			for (arglen = 0;
786 			    condExpr[arglen] != '(' &&
787 			    condExpr[arglen] != '\0'; arglen += 1)
788 				continue;
789 
790 			if (condExpr[arglen] != '\0') {
791 				length = 0;
792 				val = Var_Parse(&condExpr[arglen - 1],
793 				    VAR_CMD, FALSE, &length, &doFree);
794 				if (val == var_Error) {
795 					t = Err;
796 				} else {
797 					/*
798 					 * A variable is empty when it
799 					 * just contains spaces...
800 					 * 4/15/92, christos
801 					 */
802 					char *p;
803 
804 					for (p = val;
805 					    *p &&
806 					    isspace((unsigned char)*p);
807 					    p++)
808 						continue;
809 					t = (*p == '\0') ? True : False;
810 				}
811 				if (doFree) {
812 					free(val);
813 				}
814 				/*
815 				 * Advance condExpr to beyond the
816 				 * closing ). Note that we subtract
817 				 * one from arglen + length b/c length
818 				 * is calculated from
819 				 * condExpr[arglen - 1].
820 				 */
821 				condExpr += arglen + length - 1;
822 			} else {
823 				condExpr -= 5;
824 				goto use_default;
825 			}
826 			break;
827 
828 		} else if (strncmp(condExpr, "target", 6) == 0) {
829 			/*
830 			 * Use CondDoTarget to evaluate the argument and
831 			 * CondGetArg to extract the argument from the
832 			 * 'function call'.
833 			 */
834 			evalProc = CondDoTarget;
835 			condExpr += 6;
836 			arglen = CondGetArg(&condExpr, &arg,
837 			    "target", TRUE);
838 			if (arglen == 0) {
839 				condExpr -= 6;
840 				goto use_default;
841 			}
842 
843 		} else {
844 			/*
845 			 * The symbol is itself the argument to the
846 			 * default function. We advance condExpr to
847 			 * the end of the symbol by hand (the next
848 			 * whitespace, closing paren or binary operator)
849 			 * and set to invert the evaluation
850 			 * function if condInvert is TRUE.
851 			 */
852   use_default:
853 			invert = condInvert;
854 			evalProc = condDefProc;
855 			arglen = CondGetArg(&condExpr, &arg, "", FALSE);
856 		}
857 
858 		/*
859 		 * Evaluate the argument using the set function. If
860 		 * invert is TRUE, we invert the sense of the function.
861 		 */
862 		t = (!doEval || (* evalProc) (arglen, arg) ?
863 		    (invert ? False : True) :
864 		    (invert ? True : False));
865 		free(arg);
866 		break;
867 		}
868 	}
869 	return (t);
870 }
871 
872 /**
873  * CondT
874  *	Parse a single term in the expression. This consists of a terminal
875  *	symbol or Not and a terminal symbol (not including the binary
876  *	operators):
877  *	    T -> defined(variable) | make(target) | exists(file) | symbol
878  *	    T -> ! T | ( E )
879  *
880  * Results:
881  *	True, False or Err.
882  *
883  * Side Effects:
884  *	Tokens are consumed.
885  */
886 static Token
CondT(Boolean doEval)887 CondT(Boolean doEval)
888 {
889 	Token	t;
890 
891 	t = CondToken(doEval);
892 	if (t == EndOfFile) {
893 		/*
894 		 * If we reached the end of the expression, the expression
895 		 * is malformed...
896 		 */
897 		t = Err;
898 	} else if (t == LParen) {
899 		/*
900 		 * T -> ( E )
901 		 */
902 		t = CondE(doEval);
903 		if (t != Err) {
904 			if (CondToken(doEval) != RParen) {
905 				t = Err;
906 			}
907 		}
908 	} else if (t == Not) {
909 		t = CondT(doEval);
910 		if (t == True) {
911 			t = False;
912 		} else if (t == False) {
913 			t = True;
914 		}
915 	}
916 	return (t);
917 }
918 
919 /**
920  * CondF --
921  *	Parse a conjunctive factor (nice name, wot?)
922  *	    F -> T && F | T
923  *
924  * Results:
925  *	True, False or Err
926  *
927  * Side Effects:
928  *	Tokens are consumed.
929  */
930 static Token
CondF(Boolean doEval)931 CondF(Boolean doEval)
932 {
933 	Token	l, o;
934 
935 	l = CondT(doEval);
936 	if (l != Err) {
937 		o = CondToken(doEval);
938 
939 		if (o == And) {
940 			/*
941 			 * F -> T && F
942 			 *
943 			 * If T is False, the whole thing will be False, but
944 			 * we have to parse the r.h.s. anyway (to throw it
945 			 * away). If T is True, the result is the r.h.s.,
946 			 * be it an Err or no.
947 			 */
948 			if (l == True) {
949 				l = CondF(doEval);
950 			} else {
951 				CondF(FALSE);
952 			}
953 		} else {
954 			/*
955 			 * F -> T
956 			 */
957 			CondPushBack(o);
958 		}
959 	}
960 	return (l);
961 }
962 
963 /**
964  * CondE --
965  *	Main expression production.
966  *	    E -> F || E | F
967  *
968  * Results:
969  *	True, False or Err.
970  *
971  * Side Effects:
972  *	Tokens are, of course, consumed.
973  */
974 static Token
CondE(Boolean doEval)975 CondE(Boolean doEval)
976 {
977 	Token   l, o;
978 
979 	l = CondF(doEval);
980 	if (l != Err) {
981 		o = CondToken(doEval);
982 
983 		if (o == Or) {
984 			/*
985 			 * E -> F || E
986 			 *
987 			 * A similar thing occurs for ||, except that here we
988 			 * make sure the l.h.s. is False before we bother to
989 			 * evaluate the r.h.s. Once again, if l is False, the
990 			 * result is the r.h.s. and once again if l is True,
991 			 * we parse the r.h.s. to throw it away.
992 			 */
993 			if (l == False) {
994 				l = CondE(doEval);
995 			} else {
996 				CondE(FALSE);
997 			}
998 		} else {
999 			/*
1000 			 * E -> F
1001 			 */
1002 			CondPushBack(o);
1003 		}
1004 	}
1005 	return (l);
1006 }
1007 
1008 /**
1009  * Cond_If
1010  *	Handle .if<X> and .elif<X> directives.
1011  *	This function is called even when we're skipping.
1012  */
1013 void
Cond_If(char * line,int code,int lineno)1014 Cond_If(char *line, int code, int lineno)
1015 {
1016 	const struct If	*ifp;
1017 	Boolean value;
1018 
1019 	ifp = &ifs[code];
1020 
1021 	if (ifp->isElse) {
1022 		if (condTop == MAXIF) {
1023 			Parse_Error(PARSE_FATAL, "if-less elif");
1024 			return;
1025 		}
1026 		if (skipIfLevel != 0) {
1027 			/*
1028 			 * If skipping this conditional, just ignore
1029 			 * the whole thing. If we don't, the user
1030 			 * might be employing a variable that's
1031 			 * undefined, for which there's an enclosing
1032 			 * ifdef that we're skipping...
1033 			 */
1034 			skipIfLineno[skipIfLevel - 1] = lineno;
1035 			return;
1036 		}
1037 
1038 	} else if (skipLine) {
1039 		/*
1040 		 * Don't even try to evaluate a conditional that's
1041 		 * not an else if we're skipping things...
1042 		 */
1043 		skipIfLineno[skipIfLevel] = lineno;
1044 		skipIfLevel += 1;
1045 		return;
1046 	}
1047 
1048 	/*
1049 	 * Initialize file-global variables for parsing
1050 	 */
1051 	condDefProc = ifp->defProc;
1052 	condInvert = ifp->doNot;
1053 
1054 	while (*line == ' ' || *line == '\t') {
1055 		line++;
1056 	}
1057 
1058 	condExpr = line;
1059 	condPushBack = None;
1060 
1061 	switch (CondE(TRUE)) {
1062 	  case True:
1063 		if (CondToken(TRUE) != EndOfFile)
1064 			goto err;
1065 		value = TRUE;
1066 		break;
1067 
1068 	  case False:
1069 		if (CondToken(TRUE) != EndOfFile)
1070 			goto err;
1071 		value = FALSE;
1072 		break;
1073 
1074 	  case Err:
1075   err:		Parse_Error(PARSE_FATAL, "Malformed conditional (%s)", line);
1076 		return;
1077 
1078 	  default:
1079 		abort();
1080 	}
1081 
1082 	if (!ifp->isElse) {
1083 		/* push this value */
1084 		condTop -= 1;
1085 
1086 	} else if (skipIfLevel != 0 || condStack[condTop]) {
1087 		/*
1088 		 * If this is an else-type conditional, it should only take
1089 		 * effect if its corresponding if was evaluated and FALSE.
1090 		 * If its if was TRUE or skipped, we return COND_SKIP (and
1091 		 * start skipping in case we weren't already), leaving the
1092 		 * stack unmolested so later elif's don't screw up...
1093 		 */
1094 		skipLine = TRUE;
1095 		return;
1096 	}
1097 
1098 	if (condTop < 0) {
1099 		/*
1100 		 * This is the one case where we can definitely proclaim a fatal
1101 		 * error. If we don't, we're hosed.
1102 		 */
1103 		Parse_Error(PARSE_FATAL, "Too many nested if's. %d max.",MAXIF);
1104 		return;
1105 	}
1106 
1107 	/* push */
1108 	condStack[condTop] = value;
1109 	condLineno[condTop] = lineno;
1110 	skipLine = !value;
1111 }
1112 
1113 /**
1114  * Cond_Else
1115  *	Handle .else statement.
1116  */
1117 void
Cond_Else(char * line __unused,int code __unused,int lineno __unused)1118 Cond_Else(char *line __unused, int code __unused, int lineno __unused)
1119 {
1120 
1121 	while (isspace((u_char)*line))
1122 		line++;
1123 
1124 	if (*line != '\0' && (warn_flags & WARN_DIRSYNTAX)) {
1125 		Parse_Error(PARSE_WARNING, "junk after .else ignored '%s'",
1126 		    line);
1127 	}
1128 
1129 	if (condTop == MAXIF) {
1130 		Parse_Error(PARSE_FATAL, "if-less else");
1131 		return;
1132 	}
1133 	if (skipIfLevel != 0)
1134 		return;
1135 
1136 	if (skipIfLevel != 0 || condStack[condTop]) {
1137 		/*
1138 		 * An else should only take effect if its corresponding if was
1139 		 * evaluated and FALSE.
1140 		 * If its if was TRUE or skipped, we return COND_SKIP (and
1141 		 * start skipping in case we weren't already), leaving the
1142 		 * stack unmolested so later elif's don't screw up...
1143 		 * XXX How does this work with two .else's?
1144 		 */
1145 		skipLine = TRUE;
1146 		return;
1147 	}
1148 
1149 	/* inverse value */
1150 	condStack[condTop] = !condStack[condTop];
1151 	skipLine = !condStack[condTop];
1152 }
1153 
1154 /**
1155  * Cond_Endif
1156  *	Handle .endif statement.
1157  */
1158 void
Cond_Endif(char * line __unused,int code __unused,int lineno __unused)1159 Cond_Endif(char *line __unused, int code __unused, int lineno __unused)
1160 {
1161 
1162 	while (isspace((u_char)*line))
1163 		line++;
1164 
1165 	if (*line != '\0' && (warn_flags & WARN_DIRSYNTAX)) {
1166 		Parse_Error(PARSE_WARNING, "junk after .endif ignored '%s'",
1167 		    line);
1168 	}
1169 
1170 	/*
1171 	 * End of a conditional section. If skipIfLevel is non-zero,
1172 	 * that conditional was skipped, so lines following it should
1173 	 * also be skipped. Hence, we return COND_SKIP. Otherwise,
1174 	 * the conditional was read so succeeding lines should be
1175 	 * parsed (think about it...) so we return COND_PARSE, unless
1176 	 * this endif isn't paired with a decent if.
1177 	 */
1178 	if (skipIfLevel != 0) {
1179 		skipIfLevel -= 1;
1180 		return;
1181 	}
1182 
1183 	if (condTop == MAXIF) {
1184 		Parse_Error(PARSE_FATAL, "if-less endif");
1185 		return;
1186 	}
1187 
1188 	/* pop */
1189 	skipLine = FALSE;
1190 	condTop += 1;
1191 }
1192 
1193 /**
1194  * Cond_End
1195  *	Make sure everything's clean at the end of a makefile.
1196  *
1197  * Side Effects:
1198  *	Parse_Error will be called if open conditionals are around.
1199  */
1200 void
Cond_End(void)1201 Cond_End(void)
1202 {
1203 	int level;
1204 
1205 	if (condTop != MAXIF) {
1206 		Parse_Error(PARSE_FATAL, "%d open conditional%s:",
1207 		    MAXIF - condTop + skipIfLevel,
1208 		    MAXIF - condTop + skipIfLevel== 1 ? "" : "s");
1209 
1210 		for (level = skipIfLevel; level > 0; level--)
1211 			Parse_Error(PARSE_FATAL, "\t%*sat line %d (skipped)",
1212 			    MAXIF - condTop + level + 1, "",
1213 			    skipIfLineno[level - 1]);
1214 		for (level = condTop; level < MAXIF; level++)
1215 			Parse_Error(PARSE_FATAL, "\t%*sat line %d "
1216 			    "(evaluated to %s)", MAXIF - level + skipIfLevel,
1217 			    "", condLineno[level],
1218 			    condStack[level] ? "true" : "false");
1219 	}
1220 	condTop = MAXIF;
1221 }
1222