cond.c revision 1.52 1 /* $NetBSD: cond.c,v 1.52 2009/01/18 17:30:19 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.52 2009/01/18 17:30:19 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.52 2009/01/18 17:30:19 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_Init(&buf, 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), cp2);
278 if (freeIt)
279 free(freeIt);
280 cp += len;
281 } else {
282 Buf_AddByte(&buf, *cp);
283 cp++;
284 }
285 }
286
287 *argPtr = Buf_GetAll(&buf, &argLen);
288 Buf_Destroy(&buf, FALSE);
289
290 while (*cp == ' ' || *cp == '\t') {
291 cp++;
292 }
293 if (parens && *cp != ')') {
294 Parse_Error(PARSE_WARNING, "Missing closing parenthesis for %s()",
295 func);
296 return (0);
297 }
298
299 if (parens) {
300 /*
301 * Advance pointer past close parenthesis.
302 */
303 cp++;
304 }
305
306 *linePtr = cp;
307 return (argLen);
308 }
309
310 /*-
312 *-----------------------------------------------------------------------
313 * CondDoDefined --
314 * Handle the 'defined' function for conditionals.
315 *
316 * Results:
317 * TRUE if the given variable is defined.
318 *
319 * Side Effects:
320 * None.
321 *
322 *-----------------------------------------------------------------------
323 */
324 static Boolean
325 CondDoDefined(int argLen, char *arg)
326 {
327 char savec = arg[argLen];
328 char *p1;
329 Boolean result;
330
331 arg[argLen] = '\0';
332 if (Var_Value(arg, VAR_CMD, &p1) != NULL) {
333 result = TRUE;
334 } else {
335 result = FALSE;
336 }
337 if (p1)
338 free(p1);
339 arg[argLen] = savec;
340 return (result);
341 }
342
343 /*-
345 *-----------------------------------------------------------------------
346 * CondStrMatch --
347 * Front-end for Str_Match so it returns 0 on match and non-zero
348 * on mismatch. Callback function for CondDoMake via Lst_Find
349 *
350 * Results:
351 * 0 if string matches pattern
352 *
353 * Side Effects:
354 * None
355 *
356 *-----------------------------------------------------------------------
357 */
358 static int
359 CondStrMatch(ClientData string, ClientData pattern)
360 {
361 return(!Str_Match((char *)string,(char *)pattern));
362 }
363
364 /*-
366 *-----------------------------------------------------------------------
367 * CondDoMake --
368 * Handle the 'make' function for conditionals.
369 *
370 * Results:
371 * TRUE if the given target is being made.
372 *
373 * Side Effects:
374 * None.
375 *
376 *-----------------------------------------------------------------------
377 */
378 static Boolean
379 CondDoMake(int argLen, char *arg)
380 {
381 char savec = arg[argLen];
382 Boolean result;
383
384 arg[argLen] = '\0';
385 if (Lst_Find(create, arg, CondStrMatch) == NULL) {
386 result = FALSE;
387 } else {
388 result = TRUE;
389 }
390 arg[argLen] = savec;
391 return (result);
392 }
393
394 /*-
396 *-----------------------------------------------------------------------
397 * CondDoExists --
398 * See if the given file exists.
399 *
400 * Results:
401 * TRUE if the file exists and FALSE if it does not.
402 *
403 * Side Effects:
404 * None.
405 *
406 *-----------------------------------------------------------------------
407 */
408 static Boolean
409 CondDoExists(int argLen, char *arg)
410 {
411 char savec = arg[argLen];
412 Boolean result;
413 char *path;
414
415 arg[argLen] = '\0';
416 path = Dir_FindFile(arg, dirSearchPath);
417 if (path != NULL) {
418 result = TRUE;
419 free(path);
420 } else {
421 result = FALSE;
422 }
423 arg[argLen] = savec;
424 if (DEBUG(COND)) {
425 fprintf(debug_file, "exists(%s) result is \"%s\"\n",
426 arg, path ? path : "");
427 }
428 return (result);
429 }
430
431 /*-
433 *-----------------------------------------------------------------------
434 * CondDoTarget --
435 * See if the given node exists and is an actual target.
436 *
437 * Results:
438 * TRUE if the node exists as a target and FALSE if it does not.
439 *
440 * Side Effects:
441 * None.
442 *
443 *-----------------------------------------------------------------------
444 */
445 static Boolean
446 CondDoTarget(int argLen, char *arg)
447 {
448 char savec = arg[argLen];
449 Boolean result;
450 GNode *gn;
451
452 arg[argLen] = '\0';
453 gn = Targ_FindNode(arg, TARG_NOCREATE);
454 if ((gn != NULL) && !OP_NOP(gn->type)) {
455 result = TRUE;
456 } else {
457 result = FALSE;
458 }
459 arg[argLen] = savec;
460 return (result);
461 }
462
463 /*-
464 *-----------------------------------------------------------------------
465 * CondDoCommands --
466 * See if the given node exists and is an actual target with commands
467 * associated with it.
468 *
469 * Results:
470 * TRUE if the node exists as a target and has commands associated with
471 * it and FALSE if it does not.
472 *
473 * Side Effects:
474 * None.
475 *
476 *-----------------------------------------------------------------------
477 */
478 static Boolean
479 CondDoCommands(int argLen, char *arg)
480 {
481 char savec = arg[argLen];
482 Boolean result;
483 GNode *gn;
484
485 arg[argLen] = '\0';
486 gn = Targ_FindNode(arg, TARG_NOCREATE);
487 if ((gn != NULL) && !OP_NOP(gn->type) && !Lst_IsEmpty(gn->commands)) {
488 result = TRUE;
489 } else {
490 result = FALSE;
491 }
492 arg[argLen] = savec;
493 return (result);
494 }
495
496 /*-
498 *-----------------------------------------------------------------------
499 * CondCvtArg --
500 * Convert the given number into a double.
501 * We try a base 10 or 16 integer conversion first, if that fails
502 * then we try a floating point conversion instead.
503 *
504 * Results:
505 * Sets 'value' to double value of string.
506 * Returns 'true' if the convertion suceeded
507 *
508 *-----------------------------------------------------------------------
509 */
510 static Boolean
511 CondCvtArg(char *str, double *value)
512 {
513 char *eptr, ech;
514 unsigned long l_val;
515 double d_val;
516
517 errno = 0;
518 l_val = strtoul(str, &eptr, str[1] == 'x' ? 16 : 10);
519 ech = *eptr;
520 if (ech == 0 && errno != ERANGE) {
521 d_val = str[0] == '-' ? -(double)-l_val : (double)l_val;
522 } else {
523 if (ech != 0 && ech != '.' && ech != 'e' && ech != 'E')
524 return FALSE;
525 d_val = strtod(str, &eptr);
526 if (*eptr)
527 return FALSE;
528 }
529
530 *value = d_val;
531 return TRUE;
532 }
533
534 /*-
535 *-----------------------------------------------------------------------
536 * CondGetString --
537 * Get a string from a variable reference or an optionally quoted
538 * string. This is called for the lhs and rhs of string compares.
539 *
540 * Results:
541 * Sets freeIt if needed,
542 * Sets quoted if string was quoted,
543 * Returns NULL on error,
544 * else returns string - absent any quotes.
545 *
546 * Side Effects:
547 * Moves condExpr to end of this token.
548 *
549 *
550 *-----------------------------------------------------------------------
551 */
552 /* coverity:[+alloc : arg-*2] */
553 static char *
554 CondGetString(Boolean doEval, Boolean *quoted, void **freeIt)
555 {
556 Buffer buf;
557 char *cp;
558 char *str;
559 int len;
560 int qt;
561 char *start;
562
563 Buf_Init(&buf, 0);
564 str = NULL;
565 *freeIt = NULL;
566 *quoted = qt = *condExpr == '"' ? 1 : 0;
567 if (qt)
568 condExpr++;
569 for (start = condExpr; *condExpr && str == NULL; condExpr++) {
570 switch (*condExpr) {
571 case '\\':
572 if (condExpr[1] != '\0') {
573 condExpr++;
574 Buf_AddByte(&buf, *condExpr);
575 }
576 break;
577 case '"':
578 if (qt) {
579 condExpr++; /* we don't want the quotes */
580 goto got_str;
581 } else
582 Buf_AddByte(&buf, *condExpr); /* likely? */
583 break;
584 case ')':
585 case '!':
586 case '=':
587 case '>':
588 case '<':
589 case ' ':
590 case '\t':
591 if (!qt)
592 goto got_str;
593 else
594 Buf_AddByte(&buf, *condExpr);
595 break;
596 case '$':
597 /* if we are in quotes, then an undefined variable is ok */
598 str = Var_Parse(condExpr, VAR_CMD, (qt ? 0 : doEval),
599 &len, freeIt);
600 if (str == var_Error) {
601 if (*freeIt) {
602 free(*freeIt);
603 *freeIt = NULL;
604 }
605 /*
606 * Even if !doEval, we still report syntax errors, which
607 * is what getting var_Error back with !doEval means.
608 */
609 str = NULL;
610 goto cleanup;
611 }
612 condExpr += len;
613 /*
614 * If the '$' was first char (no quotes), and we are
615 * followed by space, the operator or end of expression,
616 * we are done.
617 */
618 if ((condExpr == start + len) &&
619 (*condExpr == '\0' ||
620 isspace((unsigned char) *condExpr) ||
621 strchr("!=><)", *condExpr))) {
622 goto cleanup;
623 }
624 /*
625 * Nope, we better copy str to buf
626 */
627 for (cp = str; *cp; cp++) {
628 Buf_AddByte(&buf, *cp);
629 }
630 if (*freeIt) {
631 free(*freeIt);
632 *freeIt = NULL;
633 }
634 str = NULL; /* not finished yet */
635 condExpr--; /* don't skip over next char */
636 break;
637 default:
638 Buf_AddByte(&buf, *condExpr);
639 break;
640 }
641 }
642 got_str:
643 str = 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 int
817 get_mpt_arg(char **linePtr, char **argPtr, const char *func, Boolean parens)
818 {
819 /*
820 * Use Var_Parse to parse the spec in parens and return
821 * True if the resulting string is empty.
822 */
823 int length;
824 void *freeIt;
825 char *val;
826 char *cp = *linePtr;
827
828 /* We do all the work here and return the result as the length */
829 *argPtr = NULL;
830
831 val = Var_Parse(cp - 1, VAR_CMD, FALSE, &length, &freeIt);
832 /*
833 * Advance *linePtr to beyond the closing ). Note that
834 * we subtract one because 'length' is calculated from 'cp - 1'.
835 */
836 *linePtr = cp - 1 + length;
837
838 if (val == var_Error) {
839 free(freeIt);
840 return -1;
841 }
842
843 /* A variable is empty when it just contains spaces... 4/15/92, christos */
844 while (isspace(*(unsigned char *)val))
845 val++;
846
847 /*
848 * For consistency with the other functions we can't generate the
849 * true/false here.
850 */
851 length = *val ? 2 : 1;
852 if (freeIt)
853 free(freeIt);
854 return length;
855 }
856
857 static Boolean
858 CondDoEmpty(int arglen, char *arg)
859 {
860 return arglen == 1;
861 }
862
863 static Token
864 compare_function(Boolean doEval)
865 {
866 static const struct fn_def {
867 const char *fn_name;
868 int fn_name_len;
869 int (*fn_getarg)(char **, char **, const char *, Boolean);
870 Boolean (*fn_proc)(int, char *);
871 } fn_defs[] = {
872 { "defined", 7, CondGetArg, CondDoDefined },
873 { "make", 4, CondGetArg, CondDoMake },
874 { "exists", 6, CondGetArg, CondDoExists },
875 { "empty", 5, get_mpt_arg, CondDoEmpty },
876 { "target", 6, CondGetArg, CondDoTarget },
877 { "commands", 8, CondGetArg, CondDoCommands },
878 { NULL, 0, NULL, NULL },
879 };
880 const struct fn_def *fn_def;
881 Token t;
882 char *arg = NULL;
883 int arglen;
884 char *cp = condExpr;
885 char *cp1;
886
887 for (fn_def = fn_defs; fn_def->fn_name != NULL; fn_def++) {
888 if (!istoken(cp, fn_def->fn_name, fn_def->fn_name_len))
889 continue;
890 cp += fn_def->fn_name_len;
891 /* There can only be whitespace before the '(' */
892 while (isspace(*(unsigned char *)cp))
893 cp++;
894 if (*cp != '(')
895 break;
896
897 arglen = fn_def->fn_getarg(&cp, &arg, fn_def->fn_name, TRUE);
898 if (arglen <= 0) {
899 condExpr = cp;
900 return arglen < 0 ? Err : False;
901 }
902 /* Evaluate the argument using the required function. */
903 t = !doEval || fn_def->fn_proc(arglen, arg) ? True : False;
904 if (arg)
905 free(arg);
906 condExpr = cp;
907 return t;
908 }
909
910 /* Push anything numeric through the compare expression */
911 cp = condExpr;
912 if (isdigit((unsigned char)cp[0]) || strchr("+-", cp[0]))
913 return compare_expression(doEval);
914
915 /*
916 * Most likely we have a naked token to apply the default function to.
917 * However ".if a == b" gets here when the "a" is unquoted and doesn't
918 * start with a '$'. This surprises people - especially given the way
919 * that for loops get expanded.
920 * If what follows the function argument is a '=' or '!' then the syntax
921 * would be invalid if we did "defined(a)" - so instead treat as an
922 * expression.
923 */
924 arglen = CondGetArg(&cp, &arg, "", FALSE);
925 for (cp1 = cp; isspace(*(unsigned char *)cp1); cp1++)
926 continue;
927 if (*cp1 == '=' || *cp1 == '!')
928 return compare_expression(doEval);
929 condExpr = cp;
930
931 /*
932 * Evaluate the argument using the default function. If invert
933 * is TRUE, we invert the sense of the result.
934 */
935 t = !doEval || (* condDefProc)(arglen, arg) != condInvert ? True : False;
936 if (arg)
937 free(arg);
938 return t;
939 }
940
941 static Token
942 CondToken(Boolean doEval)
943 {
944 Token t;
945
946 t = condPushBack;
947 if (t != None) {
948 condPushBack = None;
949 return t;
950 }
951
952 while (*condExpr == ' ' || *condExpr == '\t') {
953 condExpr++;
954 }
955
956 switch (*condExpr) {
957
958 case '(':
959 condExpr++;
960 return LParen;
961
962 case ')':
963 condExpr++;
964 return RParen;
965
966 case '|':
967 if (condExpr[1] == '|') {
968 condExpr++;
969 }
970 condExpr++;
971 return Or;
972
973 case '&':
974 if (condExpr[1] == '&') {
975 condExpr++;
976 }
977 condExpr++;
978 return And;
979
980 case '!':
981 condExpr++;
982 return Not;
983
984 case '#':
985 case '\n':
986 case '\0':
987 return EndOfFile;
988
989 case '"':
990 case '$':
991 return compare_expression(doEval);
992
993 default:
994 return compare_function(doEval);
995 }
996 }
997
998 /*-
999 *-----------------------------------------------------------------------
1000 * CondT --
1001 * Parse a single term in the expression. This consists of a terminal
1002 * symbol or Not and a terminal symbol (not including the binary
1003 * operators):
1004 * T -> defined(variable) | make(target) | exists(file) | symbol
1005 * T -> ! T | ( E )
1006 *
1007 * Results:
1008 * True, False or Err.
1009 *
1010 * Side Effects:
1011 * Tokens are consumed.
1012 *
1013 *-----------------------------------------------------------------------
1014 */
1015 static Token
1016 CondT(Boolean doEval)
1017 {
1018 Token t;
1019
1020 t = CondToken(doEval);
1021
1022 if (t == EndOfFile) {
1023 /*
1024 * If we reached the end of the expression, the expression
1025 * is malformed...
1026 */
1027 t = Err;
1028 } else if (t == LParen) {
1029 /*
1030 * T -> ( E )
1031 */
1032 t = CondE(doEval);
1033 if (t != Err) {
1034 if (CondToken(doEval) != RParen) {
1035 t = Err;
1036 }
1037 }
1038 } else if (t == Not) {
1039 t = CondT(doEval);
1040 if (t == True) {
1041 t = False;
1042 } else if (t == False) {
1043 t = True;
1044 }
1045 }
1046 return (t);
1047 }
1048
1049 /*-
1051 *-----------------------------------------------------------------------
1052 * CondF --
1053 * Parse a conjunctive factor (nice name, wot?)
1054 * F -> T && F | T
1055 *
1056 * Results:
1057 * True, False or Err
1058 *
1059 * Side Effects:
1060 * Tokens are consumed.
1061 *
1062 *-----------------------------------------------------------------------
1063 */
1064 static Token
1065 CondF(Boolean doEval)
1066 {
1067 Token l, o;
1068
1069 l = CondT(doEval);
1070 if (l != Err) {
1071 o = CondToken(doEval);
1072
1073 if (o == And) {
1074 /*
1075 * F -> T && F
1076 *
1077 * If T is False, the whole thing will be False, but we have to
1078 * parse the r.h.s. anyway (to throw it away).
1079 * If T is True, the result is the r.h.s., be it an Err or no.
1080 */
1081 if (l == True) {
1082 l = CondF(doEval);
1083 } else {
1084 (void)CondF(FALSE);
1085 }
1086 } else {
1087 /*
1088 * F -> T
1089 */
1090 CondPushBack(o);
1091 }
1092 }
1093 return (l);
1094 }
1095
1096 /*-
1098 *-----------------------------------------------------------------------
1099 * CondE --
1100 * Main expression production.
1101 * E -> F || E | F
1102 *
1103 * Results:
1104 * True, False or Err.
1105 *
1106 * Side Effects:
1107 * Tokens are, of course, consumed.
1108 *
1109 *-----------------------------------------------------------------------
1110 */
1111 static Token
1112 CondE(Boolean doEval)
1113 {
1114 Token l, o;
1115
1116 l = CondF(doEval);
1117 if (l != Err) {
1118 o = CondToken(doEval);
1119
1120 if (o == Or) {
1121 /*
1122 * E -> F || E
1123 *
1124 * A similar thing occurs for ||, except that here we make sure
1125 * the l.h.s. is False before we bother to evaluate the r.h.s.
1126 * Once again, if l is False, the result is the r.h.s. and once
1127 * again if l is True, we parse the r.h.s. to throw it away.
1128 */
1129 if (l == False) {
1130 l = CondE(doEval);
1131 } else {
1132 (void)CondE(FALSE);
1133 }
1134 } else {
1135 /*
1136 * E -> F
1137 */
1138 CondPushBack(o);
1139 }
1140 }
1141 return (l);
1142 }
1143
1144 /*-
1145 *-----------------------------------------------------------------------
1146 * Cond_EvalExpression --
1147 * Evaluate an expression in the passed line. The expression
1148 * consists of &&, ||, !, make(target), defined(variable)
1149 * and parenthetical groupings thereof.
1150 *
1151 * Results:
1152 * COND_PARSE if the condition was valid grammatically
1153 * COND_INVALID if not a valid conditional.
1154 *
1155 * (*value) is set to the boolean value of the condition
1156 *
1157 * Side Effects:
1158 * None.
1159 *
1160 *-----------------------------------------------------------------------
1161 */
1162 int
1163 Cond_EvalExpression(int dosetup, char *line, Boolean *value, int eprint)
1164 {
1165 if (dosetup) {
1166 condDefProc = CondDoDefined;
1167 condInvert = 0;
1168 }
1169
1170 while (*line == ' ' || *line == '\t')
1171 line++;
1172
1173 condExpr = line;
1174 condPushBack = None;
1175
1176 switch (CondE(TRUE)) {
1177 case True:
1178 if (CondToken(TRUE) == EndOfFile) {
1179 *value = TRUE;
1180 return COND_PARSE;
1181 }
1182 break;
1183 case False:
1184 if (CondToken(TRUE) == EndOfFile) {
1185 *value = FALSE;
1186 return COND_PARSE;
1187 }
1188 break;
1189 case Err:
1190 break;
1191 default:
1192 return COND_PARSE;
1193 }
1194
1195 if (eprint)
1196 Parse_Error(PARSE_FATAL, "Malformed conditional (%s)", line);
1197 return COND_INVALID;
1198 }
1199
1200
1201 /*-
1203 *-----------------------------------------------------------------------
1204 * Cond_Eval --
1205 * Evaluate the conditional in the passed line. The line
1206 * looks like this:
1207 * .<cond-type> <expr>
1208 * where <cond-type> is any of if, ifmake, ifnmake, ifdef,
1209 * ifndef, elif, elifmake, elifnmake, elifdef, elifndef
1210 * and <expr> consists of &&, ||, !, make(target), defined(variable)
1211 * and parenthetical groupings thereof.
1212 *
1213 * Input:
1214 * line Line to parse
1215 *
1216 * Results:
1217 * COND_PARSE if should parse lines after the conditional
1218 * COND_SKIP if should skip lines after the conditional
1219 * COND_INVALID if not a valid conditional.
1220 *
1221 * Side Effects:
1222 * None.
1223 *
1224 * Note that the states IF_ACTIVE and ELSE_ACTIVE are only different in order
1225 * to detect splurious .else lines (as are SKIP_TO_ELSE and SKIP_TO_ENDIF)
1226 * otherwise .else could be treated as '.elif 1'.
1227 *
1228 *-----------------------------------------------------------------------
1229 */
1230 int
1231 Cond_Eval(char *line)
1232 {
1233 #define MAXIF 64 /* maximum depth of .if'ing */
1234 enum if_states {
1235 IF_ACTIVE, /* .if or .elif part active */
1236 ELSE_ACTIVE, /* .else part active */
1237 SEARCH_FOR_ELIF, /* searching for .elif/else to execute */
1238 SKIP_TO_ELSE, /* has been true, but not seen '.else' */
1239 SKIP_TO_ENDIF /* nothing else to execute */
1240 };
1241 static enum if_states cond_state[MAXIF + 1] = { IF_ACTIVE };
1242
1243 const struct If *ifp;
1244 Boolean isElif;
1245 Boolean value;
1246 int level; /* Level at which to report errors. */
1247 enum if_states state;
1248
1249 level = PARSE_FATAL;
1250
1251 /* skip leading character (the '.') and any whitespace */
1252 for (line++; *line == ' ' || *line == '\t'; line++)
1253 continue;
1254
1255 /* Find what type of if we're dealing with. */
1256 if (line[0] == 'e') {
1257 if (line[1] != 'l') {
1258 if (!istoken(line + 1, "ndif", 4))
1259 return COND_INVALID;
1260 /* End of conditional section */
1261 if (cond_depth == cond_min_depth) {
1262 Parse_Error(level, "if-less endif");
1263 return COND_PARSE;
1264 }
1265 /* Return state for previous conditional */
1266 cond_depth--;
1267 if (cond_depth > MAXIF)
1268 return COND_SKIP;
1269 return cond_state[cond_depth] <= ELSE_ACTIVE ? COND_PARSE : COND_SKIP;
1270 }
1271
1272 /* Quite likely this is 'else' or 'elif' */
1273 line += 2;
1274 if (istoken(line, "se", 2)) {
1275 /* It is else... */
1276 if (cond_depth == cond_min_depth) {
1277 Parse_Error(level, "if-less else");
1278 return COND_PARSE;
1279 }
1280
1281 if (cond_depth > MAXIF)
1282 return COND_SKIP;
1283 state = cond_state[cond_depth];
1284 switch (state) {
1285 case SEARCH_FOR_ELIF:
1286 state = ELSE_ACTIVE;
1287 break;
1288 case ELSE_ACTIVE:
1289 case SKIP_TO_ENDIF:
1290 Parse_Error(PARSE_WARNING, "extra else");
1291 /* FALLTHROUGH */
1292 default:
1293 case IF_ACTIVE:
1294 case SKIP_TO_ELSE:
1295 state = SKIP_TO_ENDIF;
1296 break;
1297 }
1298 cond_state[cond_depth] = state;
1299 return state <= ELSE_ACTIVE ? COND_PARSE : COND_SKIP;
1300 }
1301 /* Assume for now it is an elif */
1302 isElif = TRUE;
1303 } else
1304 isElif = FALSE;
1305
1306 if (line[0] != 'i' || line[1] != 'f')
1307 /* Not an ifxxx or elifxxx line */
1308 return COND_INVALID;
1309
1310 /*
1311 * Figure out what sort of conditional it is -- what its default
1312 * function is, etc. -- by looking in the table of valid "ifs"
1313 */
1314 line += 2;
1315 for (ifp = ifs; ; ifp++) {
1316 if (ifp->form == NULL)
1317 return COND_INVALID;
1318 if (istoken(ifp->form, line, ifp->formlen)) {
1319 line += ifp->formlen;
1320 break;
1321 }
1322 }
1323
1324 /* Now we know what sort of 'if' it is... */
1325
1326 if (isElif) {
1327 if (cond_depth == cond_min_depth) {
1328 Parse_Error(level, "if-less elif");
1329 return COND_PARSE;
1330 }
1331 if (cond_depth > MAXIF)
1332 /* Error reported when we saw the .if ... */
1333 return COND_SKIP;
1334 state = cond_state[cond_depth];
1335 if (state == SKIP_TO_ENDIF || state == ELSE_ACTIVE) {
1336 Parse_Error(PARSE_WARNING, "extra elif");
1337 cond_state[cond_depth] = SKIP_TO_ENDIF;
1338 return COND_SKIP;
1339 }
1340 if (state != SEARCH_FOR_ELIF) {
1341 /* Either just finished the 'true' block, or already SKIP_TO_ELSE */
1342 cond_state[cond_depth] = SKIP_TO_ELSE;
1343 return COND_SKIP;
1344 }
1345 } else {
1346 /* Normal .if */
1347 if (cond_depth >= MAXIF) {
1348 cond_depth++;
1349 Parse_Error(PARSE_FATAL, "Too many nested if's. %d max.", MAXIF);
1350 return COND_SKIP;
1351 }
1352 state = cond_state[cond_depth];
1353 cond_depth++;
1354 if (state > ELSE_ACTIVE) {
1355 /* If we aren't parsing the data, treat as always false */
1356 cond_state[cond_depth] = SKIP_TO_ELSE;
1357 return COND_SKIP;
1358 }
1359 }
1360
1361 /* Initialize file-global variables for parsing the expression */
1362 condDefProc = ifp->defProc;
1363 condInvert = ifp->doNot;
1364
1365 /* And evaluate the conditional expresssion */
1366 if (Cond_EvalExpression(0, line, &value, 1) == COND_INVALID) {
1367 /* Syntax error in conditional, error message already output. */
1368 /* Skip everything to matching .endif */
1369 cond_state[cond_depth] = SKIP_TO_ELSE;
1370 return COND_SKIP;
1371 }
1372
1373 if (!value) {
1374 cond_state[cond_depth] = SEARCH_FOR_ELIF;
1375 return COND_SKIP;
1376 }
1377 cond_state[cond_depth] = IF_ACTIVE;
1378 return COND_PARSE;
1379 }
1380
1381
1382
1383 /*-
1385 *-----------------------------------------------------------------------
1386 * Cond_End --
1387 * Make sure everything's clean at the end of a makefile.
1388 *
1389 * Results:
1390 * None.
1391 *
1392 * Side Effects:
1393 * Parse_Error will be called if open conditionals are around.
1394 *
1395 *-----------------------------------------------------------------------
1396 */
1397 void
1398 Cond_restore_depth(unsigned int saved_depth)
1399 {
1400 int open_conds = cond_depth - cond_min_depth;
1401
1402 if (open_conds != 0 || saved_depth > cond_depth) {
1403 Parse_Error(PARSE_FATAL, "%d open conditional%s", open_conds,
1404 open_conds == 1 ? "" : "s");
1405 cond_depth = cond_min_depth;
1406 }
1407
1408 cond_min_depth = saved_depth;
1409 }
1410
1411 unsigned int
1412 Cond_save_depth(void)
1413 {
1414 int depth = cond_min_depth;
1415
1416 cond_min_depth = cond_depth;
1417 return depth;
1418 }
1419