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