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