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