cond.c revision 1.19.2.1 1 /* $NetBSD: cond.c,v 1.19.2.1 2004/05/10 15:23:41 tron 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 #ifdef MAKE_BOOTSTRAP
73 static char rcsid[] = "$NetBSD: cond.c,v 1.19.2.1 2004/05/10 15:23:41 tron 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.19.2.1 2004/05/10 15:23:41 tron 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
96 #include "make.h"
97 #include "hash.h"
98 #include "dir.h"
99 #include "buf.h"
100
101 /*
102 * The parsing of conditional expressions is based on this grammar:
103 * E -> F || E
104 * E -> F
105 * F -> T && F
106 * F -> T
107 * T -> defined(variable)
108 * T -> make(target)
109 * T -> exists(file)
110 * T -> empty(varspec)
111 * T -> target(name)
112 * T -> commands(name)
113 * T -> symbol
114 * T -> $(varspec) op value
115 * T -> $(varspec) == "string"
116 * T -> $(varspec) != "string"
117 * T -> ( E )
118 * T -> ! T
119 * op -> == | != | > | < | >= | <=
120 *
121 * 'symbol' is some other symbol to which the default function (condDefProc)
122 * is applied.
123 *
124 * Tokens are scanned from the 'condExpr' string. The scanner (CondToken)
125 * will return And for '&' and '&&', Or for '|' and '||', Not for '!',
126 * LParen for '(', RParen for ')' and will evaluate the other terminal
127 * symbols, using either the default function or the function given in the
128 * terminal, and return the result as either True or False.
129 *
130 * All Non-Terminal functions (CondE, CondF and CondT) return Err on error.
131 */
132 typedef enum {
133 And, Or, Not, True, False, LParen, RParen, EndOfFile, None, Err
134 } Token;
135
136 /*-
137 * Structures to handle elegantly the different forms of #if's. The
138 * last two fields are stored in condInvert and condDefProc, respectively.
139 */
140 static void CondPushBack(Token);
141 static int CondGetArg(char **, char **, const char *, Boolean);
142 static Boolean CondDoDefined(int, char *);
143 static int CondStrMatch(ClientData, ClientData);
144 static Boolean CondDoMake(int, char *);
145 static Boolean CondDoExists(int, char *);
146 static Boolean CondDoTarget(int, char *);
147 static Boolean CondDoCommands(int, char *);
148 static char * CondCvtArg(char *, double *);
149 static Token CondToken(Boolean);
150 static Token CondT(Boolean);
151 static Token CondF(Boolean);
152 static Token CondE(Boolean);
153
154 static struct If {
155 const char *form; /* Form of if */
156 int formlen; /* Length of form */
157 Boolean doNot; /* TRUE if default function should be negated */
158 Boolean (*defProc)(int, char *); /* Default function to apply */
159 } ifs[] = {
160 { "ifdef", 5, FALSE, CondDoDefined },
161 { "ifndef", 6, TRUE, CondDoDefined },
162 { "ifmake", 6, FALSE, CondDoMake },
163 { "ifnmake", 7, TRUE, CondDoMake },
164 { "if", 2, FALSE, CondDoDefined },
165 { NULL, 0, FALSE, NULL }
166 };
167
168 static Boolean condInvert; /* Invert the default function */
169 static Boolean (*condDefProc)(int, char *); /* Default function to apply */
170 static char *condExpr; /* The expression to parse */
171 static Token condPushBack=None; /* Single push-back token used in
172 * parsing */
173
174 #define MAXIF 30 /* greatest depth of #if'ing */
175
176 static Boolean finalElse[MAXIF+1]; /* Seen final else (stack) */
177 static Boolean condStack[MAXIF]; /* Stack of conditionals's values */
178 static int condTop = MAXIF; /* Top-most conditional */
179 static int skipIfLevel=0; /* Depth of skipped conditionals */
180 static Boolean skipLine = FALSE; /* Whether the parse module is skipping
181 * lines */
182
183 /*-
184 *-----------------------------------------------------------------------
185 * CondPushBack --
186 * Push back the most recent token read. We only need one level of
187 * this, so the thing is just stored in 'condPushback'.
188 *
189 * Input:
190 * t Token to push back into the "stream"
191 *
192 * Results:
193 * None.
194 *
195 * Side Effects:
196 * condPushback is overwritten.
197 *
198 *-----------------------------------------------------------------------
199 */
200 static void
201 CondPushBack(Token t)
202 {
203 condPushBack = t;
204 }
205
206 /*-
208 *-----------------------------------------------------------------------
209 * CondGetArg --
210 * Find the argument of a built-in function.
211 *
212 * Input:
213 * parens TRUE if arg should be bounded by parens
214 *
215 * Results:
216 * The length of the argument and the address of the argument.
217 *
218 * Side Effects:
219 * The pointer is set to point to the closing parenthesis of the
220 * function call.
221 *
222 *-----------------------------------------------------------------------
223 */
224 static int
225 CondGetArg(char **linePtr, char **argPtr, const char *func, Boolean parens)
226 {
227 char *cp;
228 int argLen;
229 Buffer buf;
230
231 cp = *linePtr;
232 if (parens) {
233 while (*cp != '(' && *cp != '\0') {
234 cp++;
235 }
236 if (*cp == '(') {
237 cp++;
238 }
239 }
240
241 if (*cp == '\0') {
242 /*
243 * No arguments whatsoever. Because 'make' and 'defined' aren't really
244 * "reserved words", we don't print a message. I think this is better
245 * than hitting the user with a warning message every time s/he uses
246 * the word 'make' or 'defined' at the beginning of a symbol...
247 */
248 *argPtr = cp;
249 return (0);
250 }
251
252 while (*cp == ' ' || *cp == '\t') {
253 cp++;
254 }
255
256 /*
257 * Create a buffer for the argument and start it out at 16 characters
258 * long. Why 16? Why not?
259 */
260 buf = Buf_Init(16);
261
262 while ((strchr(" \t)&|", *cp) == (char *)NULL) && (*cp != '\0')) {
263 if (*cp == '$') {
264 /*
265 * Parse the variable spec and install it as part of the argument
266 * if it's valid. We tell Var_Parse to complain on an undefined
267 * variable, so we don't do it too. Nor do we return an error,
268 * though perhaps we should...
269 */
270 char *cp2;
271 int len;
272 Boolean doFree;
273
274 cp2 = Var_Parse(cp, VAR_CMD, TRUE, &len, &doFree);
275
276 Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2);
277 if (doFree) {
278 free(cp2);
279 }
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) != (char *)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, (ClientData)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 != (char *)NULL) {
417 result = TRUE;
418 free(path);
419 } else {
420 result = FALSE;
421 }
422 arg[argLen] = savec;
423 return (result);
424 }
425
426 /*-
428 *-----------------------------------------------------------------------
429 * CondDoTarget --
430 * See if the given node exists and is an actual target.
431 *
432 * Results:
433 * TRUE if the node exists as a target and FALSE if it does not.
434 *
435 * Side Effects:
436 * None.
437 *
438 *-----------------------------------------------------------------------
439 */
440 static Boolean
441 CondDoTarget(int argLen, char *arg)
442 {
443 char savec = arg[argLen];
444 Boolean result;
445 GNode *gn;
446
447 arg[argLen] = '\0';
448 gn = Targ_FindNode(arg, TARG_NOCREATE);
449 if ((gn != NILGNODE) && !OP_NOP(gn->type)) {
450 result = TRUE;
451 } else {
452 result = FALSE;
453 }
454 arg[argLen] = savec;
455 return (result);
456 }
457
458 /*-
459 *-----------------------------------------------------------------------
460 * CondDoCommands --
461 * See if the given node exists and is an actual target with commands
462 * associated with it.
463 *
464 * Results:
465 * TRUE if the node exists as a target and has commands associated with
466 * it and FALSE if it does not.
467 *
468 * Side Effects:
469 * None.
470 *
471 *-----------------------------------------------------------------------
472 */
473 static Boolean
474 CondDoCommands(int argLen, char *arg)
475 {
476 char savec = arg[argLen];
477 Boolean result;
478 GNode *gn;
479
480 arg[argLen] = '\0';
481 gn = Targ_FindNode(arg, TARG_NOCREATE);
482 if ((gn != NILGNODE) && !OP_NOP(gn->type) && !Lst_IsEmpty(gn->commands)) {
483 result = TRUE;
484 } else {
485 result = FALSE;
486 }
487 arg[argLen] = savec;
488 return (result);
489 }
490
491 /*-
493 *-----------------------------------------------------------------------
494 * CondCvtArg --
495 * Convert the given number into a double. If the number begins
496 * with 0x, it is interpreted as a hexadecimal integer
497 * and converted to a double from there. All other strings just have
498 * strtod called on them.
499 *
500 * Results:
501 * Sets 'value' to double value of string.
502 * Returns NULL if string was fully consumed,
503 * else returns remaining input.
504 *
505 * Side Effects:
506 * Can change 'value' even if string is not a valid number.
507 *
508 *
509 *-----------------------------------------------------------------------
510 */
511 static char *
512 CondCvtArg(char *str, double *value)
513 {
514 if ((*str == '0') && (str[1] == 'x')) {
515 long i;
516
517 for (str += 2, i = 0; *str; str++) {
518 int x;
519 if (isdigit((unsigned char) *str))
520 x = *str - '0';
521 else if (isxdigit((unsigned char) *str))
522 x = 10 + *str - isupper((unsigned char) *str) ? 'A' : 'a';
523 else
524 break;
525 i = (i << 4) + x;
526 }
527 *value = (double) i;
528 return *str ? str : NULL;
529 } else {
530 char *eptr;
531 *value = strtod(str, &eptr);
532 return *eptr ? eptr : NULL;
533 }
534 }
535
536 /*-
538 *-----------------------------------------------------------------------
539 * CondToken --
540 * Return the next token from the input.
541 *
542 * Results:
543 * A Token for the next lexical token in the stream.
544 *
545 * Side Effects:
546 * condPushback will be set back to None if it is used.
547 *
548 *-----------------------------------------------------------------------
549 */
550 static Token
551 CondToken(Boolean doEval)
552 {
553 Token t;
554
555 if (condPushBack == None) {
556 while (*condExpr == ' ' || *condExpr == '\t') {
557 condExpr++;
558 }
559 switch (*condExpr) {
560 case '(':
561 t = LParen;
562 condExpr++;
563 break;
564 case ')':
565 t = RParen;
566 condExpr++;
567 break;
568 case '|':
569 if (condExpr[1] == '|') {
570 condExpr++;
571 }
572 condExpr++;
573 t = Or;
574 break;
575 case '&':
576 if (condExpr[1] == '&') {
577 condExpr++;
578 }
579 condExpr++;
580 t = And;
581 break;
582 case '!':
583 t = Not;
584 condExpr++;
585 break;
586 case '#':
587 case '\n':
588 case '\0':
589 t = EndOfFile;
590 break;
591 case '$': {
592 char *lhs;
593 char *rhs;
594 char *op;
595 int varSpecLen;
596 Boolean doFree;
597
598 /*
599 * Parse the variable spec and skip over it, saving its
600 * value in lhs.
601 */
602 t = Err;
603 lhs = Var_Parse(condExpr, VAR_CMD, doEval,&varSpecLen,&doFree);
604 if (lhs == var_Error) {
605 /*
606 * Even if !doEval, we still report syntax errors, which
607 * is what getting var_Error back with !doEval means.
608 */
609 return(Err);
610 }
611 condExpr += varSpecLen;
612
613 if (!isspace((unsigned char) *condExpr) &&
614 strchr("!=><", *condExpr) == NULL) {
615 Buffer buf;
616 char *cp;
617
618 buf = Buf_Init(0);
619
620 for (cp = lhs; *cp; cp++)
621 Buf_AddByte(buf, (Byte)*cp);
622
623 if (doFree)
624 free(lhs);
625
626 for (;*condExpr && !isspace((unsigned char) *condExpr);
627 condExpr++)
628 Buf_AddByte(buf, (Byte)*condExpr);
629
630 Buf_AddByte(buf, (Byte)'\0');
631 lhs = (char *)Buf_GetAll(buf, &varSpecLen);
632 Buf_Destroy(buf, FALSE);
633
634 doFree = TRUE;
635 }
636
637 /*
638 * Skip whitespace to get to the operator
639 */
640 while (isspace((unsigned char) *condExpr))
641 condExpr++;
642
643 /*
644 * Make sure the operator is a valid one. If it isn't a
645 * known relational operator, pretend we got a
646 * != 0 comparison.
647 */
648 op = condExpr;
649 switch (*condExpr) {
650 case '!':
651 case '=':
652 case '<':
653 case '>':
654 if (condExpr[1] == '=') {
655 condExpr += 2;
656 } else {
657 condExpr += 1;
658 }
659 break;
660 default:
661 op = UNCONST("!=");
662 rhs = UNCONST("0");
663
664 goto do_compare;
665 }
666 while (isspace((unsigned char) *condExpr)) {
667 condExpr++;
668 }
669 if (*condExpr == '\0') {
670 Parse_Error(PARSE_WARNING,
671 "Missing right-hand-side of operator");
672 goto error;
673 }
674 rhs = condExpr;
675 do_compare:
676 if (*rhs == '"') {
677 /*
678 * Doing a string comparison. Only allow == and != for
679 * operators.
680 */
681 char *string;
682 char *cp, *cp2;
683 int qt;
684 Buffer buf;
685
686 do_string_compare:
687 if (((*op != '!') && (*op != '=')) || (op[1] != '=')) {
688 Parse_Error(PARSE_WARNING,
689 "String comparison operator should be either == or !=");
690 goto error;
691 }
692
693 buf = Buf_Init(0);
694 qt = *rhs == '"' ? 1 : 0;
695
696 for (cp = &rhs[qt];
697 ((qt && (*cp != '"')) ||
698 (!qt && strchr(" \t)", *cp) == NULL)) &&
699 (*cp != '\0'); cp++) {
700 if ((*cp == '\\') && (cp[1] != '\0')) {
701 /*
702 * Backslash escapes things -- skip over next
703 * character, if it exists.
704 */
705 cp++;
706 Buf_AddByte(buf, (Byte)*cp);
707 } else if (*cp == '$') {
708 int len;
709 Boolean freeIt;
710
711 cp2 = Var_Parse(cp, VAR_CMD, doEval,&len, &freeIt);
712 if (cp2 != var_Error) {
713 Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2);
714 if (freeIt) {
715 free(cp2);
716 }
717 cp += len - 1;
718 } else {
719 Buf_AddByte(buf, (Byte)*cp);
720 }
721 } else {
722 Buf_AddByte(buf, (Byte)*cp);
723 }
724 }
725
726 Buf_AddByte(buf, (Byte)0);
727
728 string = (char *)Buf_GetAll(buf, (int *)0);
729 Buf_Destroy(buf, FALSE);
730
731 if (DEBUG(COND)) {
732 printf("lhs = \"%s\", rhs = \"%s\", op = %.2s\n",
733 lhs, string, op);
734 }
735 /*
736 * Null-terminate rhs and perform the comparison.
737 * t is set to the result.
738 */
739 if (*op == '=') {
740 t = strcmp(lhs, string) ? False : True;
741 } else {
742 t = strcmp(lhs, string) ? True : False;
743 }
744 free(string);
745 if (rhs == condExpr) {
746 if (!qt && *cp == ')')
747 condExpr = cp;
748 else
749 condExpr = cp + 1;
750 }
751 } else {
752 /*
753 * rhs is either a float or an integer. Convert both the
754 * lhs and the rhs to a double and compare the two.
755 */
756 double left, right;
757 char *string;
758
759 if (CondCvtArg(lhs, &left))
760 goto do_string_compare;
761 if (*rhs == '$') {
762 int len;
763 Boolean freeIt;
764
765 string = Var_Parse(rhs, VAR_CMD, doEval,&len,&freeIt);
766 if (string == var_Error) {
767 right = 0.0;
768 } else {
769 if (CondCvtArg(string, &right)) {
770 if (freeIt)
771 free(string);
772 goto do_string_compare;
773 }
774 if (freeIt)
775 free(string);
776 if (rhs == condExpr)
777 condExpr += len;
778 }
779 } else {
780 char *cp;
781
782 if ((cp = CondCvtArg(rhs, &right)) &&
783 cp == rhs)
784 goto do_string_compare;
785 if (rhs == condExpr) {
786 /*
787 * Skip over the right-hand side
788 */
789 if (cp)
790 condExpr = cp;
791 else
792 condExpr = strchr(rhs, '\0');
793 }
794 }
795
796 if (DEBUG(COND)) {
797 printf("left = %f, right = %f, op = %.2s\n", left,
798 right, op);
799 }
800 switch(op[0]) {
801 case '!':
802 if (op[1] != '=') {
803 Parse_Error(PARSE_WARNING,
804 "Unknown operator");
805 goto error;
806 }
807 t = (left != right ? True : False);
808 break;
809 case '=':
810 if (op[1] != '=') {
811 Parse_Error(PARSE_WARNING,
812 "Unknown operator");
813 goto error;
814 }
815 t = (left == right ? True : False);
816 break;
817 case '<':
818 if (op[1] == '=') {
819 t = (left <= right ? True : False);
820 } else {
821 t = (left < right ? True : False);
822 }
823 break;
824 case '>':
825 if (op[1] == '=') {
826 t = (left >= right ? True : False);
827 } else {
828 t = (left > right ? True : False);
829 }
830 break;
831 }
832 }
833 error:
834 if (doFree)
835 free(lhs);
836 break;
837 }
838 default: {
839 Boolean (*evalProc)(int, char *);
840 Boolean invert = FALSE;
841 char *arg;
842 int arglen;
843
844 if (strncmp (condExpr, "defined", 7) == 0) {
845 /*
846 * Use CondDoDefined to evaluate the argument and
847 * CondGetArg to extract the argument from the 'function
848 * call'.
849 */
850 evalProc = CondDoDefined;
851 condExpr += 7;
852 arglen = CondGetArg (&condExpr, &arg, "defined", TRUE);
853 if (arglen == 0) {
854 condExpr -= 7;
855 goto use_default;
856 }
857 } else if (strncmp (condExpr, "make", 4) == 0) {
858 /*
859 * Use CondDoMake to evaluate the argument and
860 * CondGetArg to extract the argument from the 'function
861 * call'.
862 */
863 evalProc = CondDoMake;
864 condExpr += 4;
865 arglen = CondGetArg (&condExpr, &arg, "make", TRUE);
866 if (arglen == 0) {
867 condExpr -= 4;
868 goto use_default;
869 }
870 } else if (strncmp (condExpr, "exists", 6) == 0) {
871 /*
872 * Use CondDoExists to evaluate the argument and
873 * CondGetArg to extract the argument from the
874 * 'function call'.
875 */
876 evalProc = CondDoExists;
877 condExpr += 6;
878 arglen = CondGetArg(&condExpr, &arg, "exists", TRUE);
879 if (arglen == 0) {
880 condExpr -= 6;
881 goto use_default;
882 }
883 } else if (strncmp(condExpr, "empty", 5) == 0) {
884 /*
885 * Use Var_Parse to parse the spec in parens and return
886 * True if the resulting string is empty.
887 */
888 int length;
889 Boolean doFree;
890 char *val;
891
892 condExpr += 5;
893
894 for (arglen = 0;
895 condExpr[arglen] != '(' && condExpr[arglen] != '\0';
896 arglen += 1)
897 continue;
898
899 if (condExpr[arglen] != '\0') {
900 val = Var_Parse(&condExpr[arglen - 1], VAR_CMD,
901 FALSE, &length, &doFree);
902 if (val == var_Error) {
903 t = Err;
904 } else {
905 /*
906 * A variable is empty when it just contains
907 * spaces... 4/15/92, christos
908 */
909 char *p;
910 for (p = val; *p && isspace((unsigned char)*p); p++)
911 continue;
912 t = (*p == '\0') ? True : False;
913 }
914 if (doFree) {
915 free(val);
916 }
917 /*
918 * Advance condExpr to beyond the closing ). Note that
919 * we subtract one from arglen + length b/c length
920 * is calculated from condExpr[arglen - 1].
921 */
922 condExpr += arglen + length - 1;
923 } else {
924 condExpr -= 5;
925 goto use_default;
926 }
927 break;
928 } else if (strncmp (condExpr, "target", 6) == 0) {
929 /*
930 * Use CondDoTarget to evaluate the argument and
931 * CondGetArg to extract the argument from the
932 * 'function call'.
933 */
934 evalProc = CondDoTarget;
935 condExpr += 6;
936 arglen = CondGetArg(&condExpr, &arg, "target", TRUE);
937 if (arglen == 0) {
938 condExpr -= 6;
939 goto use_default;
940 }
941 } else if (strncmp (condExpr, "commands", 8) == 0) {
942 /*
943 * Use CondDoCommands to evaluate the argument and
944 * CondGetArg to extract the argument from the
945 * 'function call'.
946 */
947 evalProc = CondDoCommands;
948 condExpr += 8;
949 arglen = CondGetArg(&condExpr, &arg, "commands", TRUE);
950 if (arglen == 0) {
951 condExpr -= 8;
952 goto use_default;
953 }
954 } else {
955 /*
956 * The symbol is itself the argument to the default
957 * function. We advance condExpr to the end of the symbol
958 * by hand (the next whitespace, closing paren or
959 * binary operator) and set to invert the evaluation
960 * function if condInvert is TRUE.
961 */
962 use_default:
963 invert = condInvert;
964 evalProc = condDefProc;
965 arglen = CondGetArg(&condExpr, &arg, "", FALSE);
966 }
967
968 /*
969 * Evaluate the argument using the set function. If invert
970 * is TRUE, we invert the sense of the function.
971 */
972 t = (!doEval || (* evalProc) (arglen, arg) ?
973 (invert ? False : True) :
974 (invert ? True : False));
975 free(arg);
976 break;
977 }
978 }
979 } else {
980 t = condPushBack;
981 condPushBack = None;
982 }
983 return (t);
984 }
985
986 /*-
988 *-----------------------------------------------------------------------
989 * CondT --
990 * Parse a single term in the expression. This consists of a terminal
991 * symbol or Not and a terminal symbol (not including the binary
992 * operators):
993 * T -> defined(variable) | make(target) | exists(file) | symbol
994 * T -> ! T | ( E )
995 *
996 * Results:
997 * True, False or Err.
998 *
999 * Side Effects:
1000 * Tokens are consumed.
1001 *
1002 *-----------------------------------------------------------------------
1003 */
1004 static Token
1005 CondT(Boolean doEval)
1006 {
1007 Token t;
1008
1009 t = CondToken(doEval);
1010
1011 if (t == EndOfFile) {
1012 /*
1013 * If we reached the end of the expression, the expression
1014 * is malformed...
1015 */
1016 t = Err;
1017 } else if (t == LParen) {
1018 /*
1019 * T -> ( E )
1020 */
1021 t = CondE(doEval);
1022 if (t != Err) {
1023 if (CondToken(doEval) != RParen) {
1024 t = Err;
1025 }
1026 }
1027 } else if (t == Not) {
1028 t = CondT(doEval);
1029 if (t == True) {
1030 t = False;
1031 } else if (t == False) {
1032 t = True;
1033 }
1034 }
1035 return (t);
1036 }
1037
1038 /*-
1040 *-----------------------------------------------------------------------
1041 * CondF --
1042 * Parse a conjunctive factor (nice name, wot?)
1043 * F -> T && F | T
1044 *
1045 * Results:
1046 * True, False or Err
1047 *
1048 * Side Effects:
1049 * Tokens are consumed.
1050 *
1051 *-----------------------------------------------------------------------
1052 */
1053 static Token
1054 CondF(Boolean doEval)
1055 {
1056 Token l, o;
1057
1058 l = CondT(doEval);
1059 if (l != Err) {
1060 o = CondToken(doEval);
1061
1062 if (o == And) {
1063 /*
1064 * F -> T && F
1065 *
1066 * If T is False, the whole thing will be False, but we have to
1067 * parse the r.h.s. anyway (to throw it away).
1068 * If T is True, the result is the r.h.s., be it an Err or no.
1069 */
1070 if (l == True) {
1071 l = CondF(doEval);
1072 } else {
1073 (void) CondF(FALSE);
1074 }
1075 } else {
1076 /*
1077 * F -> T
1078 */
1079 CondPushBack (o);
1080 }
1081 }
1082 return (l);
1083 }
1084
1085 /*-
1087 *-----------------------------------------------------------------------
1088 * CondE --
1089 * Main expression production.
1090 * E -> F || E | F
1091 *
1092 * Results:
1093 * True, False or Err.
1094 *
1095 * Side Effects:
1096 * Tokens are, of course, consumed.
1097 *
1098 *-----------------------------------------------------------------------
1099 */
1100 static Token
1101 CondE(Boolean doEval)
1102 {
1103 Token l, o;
1104
1105 l = CondF(doEval);
1106 if (l != Err) {
1107 o = CondToken(doEval);
1108
1109 if (o == Or) {
1110 /*
1111 * E -> F || E
1112 *
1113 * A similar thing occurs for ||, except that here we make sure
1114 * the l.h.s. is False before we bother to evaluate the r.h.s.
1115 * Once again, if l is False, the result is the r.h.s. and once
1116 * again if l is True, we parse the r.h.s. to throw it away.
1117 */
1118 if (l == False) {
1119 l = CondE(doEval);
1120 } else {
1121 (void) CondE(FALSE);
1122 }
1123 } else {
1124 /*
1125 * E -> F
1126 */
1127 CondPushBack (o);
1128 }
1129 }
1130 return (l);
1131 }
1132
1133 /*-
1134 *-----------------------------------------------------------------------
1135 * Cond_EvalExpression --
1136 * Evaluate an expression in the passed line. The expression
1137 * consists of &&, ||, !, make(target), defined(variable)
1138 * and parenthetical groupings thereof.
1139 *
1140 * Results:
1141 * COND_PARSE if the condition was valid grammatically
1142 * COND_INVALID if not a valid conditional.
1143 *
1144 * (*value) is set to the boolean value of the condition
1145 *
1146 * Side Effects:
1147 * None.
1148 *
1149 *-----------------------------------------------------------------------
1150 */
1151 int
1152 Cond_EvalExpression(int dosetup, char *line, Boolean *value, int eprint)
1153 {
1154 if (dosetup) {
1155 condDefProc = CondDoDefined;
1156 condInvert = 0;
1157 }
1158
1159 while (*line == ' ' || *line == '\t')
1160 line++;
1161
1162 condExpr = line;
1163 condPushBack = None;
1164
1165 switch (CondE(TRUE)) {
1166 case True:
1167 if (CondToken(TRUE) == EndOfFile) {
1168 *value = TRUE;
1169 break;
1170 }
1171 goto err;
1172 /*FALLTHRU*/
1173 case False:
1174 if (CondToken(TRUE) == EndOfFile) {
1175 *value = FALSE;
1176 break;
1177 }
1178 /*FALLTHRU*/
1179 case Err:
1180 err:
1181 if (eprint)
1182 Parse_Error (PARSE_FATAL, "Malformed conditional (%s)",
1183 line);
1184 return (COND_INVALID);
1185 default:
1186 break;
1187 }
1188
1189 return COND_PARSE;
1190 }
1191
1192
1193 /*-
1195 *-----------------------------------------------------------------------
1196 * Cond_Eval --
1197 * Evaluate the conditional in the passed line. The line
1198 * looks like this:
1199 * #<cond-type> <expr>
1200 * where <cond-type> is any of if, ifmake, ifnmake, ifdef,
1201 * ifndef, elif, elifmake, elifnmake, elifdef, elifndef
1202 * and <expr> consists of &&, ||, !, make(target), defined(variable)
1203 * and parenthetical groupings thereof.
1204 *
1205 * Input:
1206 * line Line to parse
1207 *
1208 * Results:
1209 * COND_PARSE if should parse lines after the conditional
1210 * COND_SKIP if should skip lines after the conditional
1211 * COND_INVALID if not a valid conditional.
1212 *
1213 * Side Effects:
1214 * None.
1215 *
1216 *-----------------------------------------------------------------------
1217 */
1218 int
1219 Cond_Eval(char *line)
1220 {
1221 struct If *ifp;
1222 Boolean isElse;
1223 Boolean value = FALSE;
1224 int level; /* Level at which to report errors. */
1225
1226 level = PARSE_FATAL;
1227
1228 for (line++; *line == ' ' || *line == '\t'; line++) {
1229 continue;
1230 }
1231
1232 /*
1233 * Find what type of if we're dealing with. The result is left
1234 * in ifp and isElse is set TRUE if it's an elif line.
1235 */
1236 if (line[0] == 'e' && line[1] == 'l') {
1237 line += 2;
1238 isElse = TRUE;
1239 } else if (strncmp (line, "endif", 5) == 0) {
1240 /*
1241 * End of a conditional section. If skipIfLevel is non-zero, that
1242 * conditional was skipped, so lines following it should also be
1243 * skipped. Hence, we return COND_SKIP. Otherwise, the conditional
1244 * was read so succeeding lines should be parsed (think about it...)
1245 * so we return COND_PARSE, unless this endif isn't paired with
1246 * a decent if.
1247 */
1248 finalElse[condTop] = FALSE;
1249 if (skipIfLevel != 0) {
1250 skipIfLevel -= 1;
1251 return (COND_SKIP);
1252 } else {
1253 if (condTop == MAXIF) {
1254 Parse_Error (level, "if-less endif");
1255 return (COND_INVALID);
1256 } else {
1257 skipLine = FALSE;
1258 condTop += 1;
1259 return (COND_PARSE);
1260 }
1261 }
1262 } else {
1263 isElse = FALSE;
1264 }
1265
1266 /*
1267 * Figure out what sort of conditional it is -- what its default
1268 * function is, etc. -- by looking in the table of valid "ifs"
1269 */
1270 for (ifp = ifs; ifp->form != (char *)0; ifp++) {
1271 if (strncmp (ifp->form, line, ifp->formlen) == 0) {
1272 break;
1273 }
1274 }
1275
1276 if (ifp->form == (char *) 0) {
1277 /*
1278 * Nothing fit. If the first word on the line is actually
1279 * "else", it's a valid conditional whose value is the inverse
1280 * of the previous if we parsed.
1281 */
1282 if (isElse && (line[0] == 's') && (line[1] == 'e')) {
1283 if (finalElse[condTop]) {
1284 Parse_Error (PARSE_WARNING, "extra else");
1285 } else {
1286 finalElse[condTop] = TRUE;
1287 }
1288 if (condTop == MAXIF) {
1289 Parse_Error (level, "if-less else");
1290 return (COND_INVALID);
1291 } else if (skipIfLevel == 0) {
1292 value = !condStack[condTop];
1293 } else {
1294 return (COND_SKIP);
1295 }
1296 } else {
1297 /*
1298 * Not a valid conditional type. No error...
1299 */
1300 return (COND_INVALID);
1301 }
1302 } else {
1303 if (isElse) {
1304 if (condTop == MAXIF) {
1305 Parse_Error (level, "if-less elif");
1306 return (COND_INVALID);
1307 } else if (skipIfLevel != 0) {
1308 /*
1309 * If skipping this conditional, just ignore the whole thing.
1310 * If we don't, the user might be employing a variable that's
1311 * undefined, for which there's an enclosing ifdef that
1312 * we're skipping...
1313 */
1314 return(COND_SKIP);
1315 }
1316 } else if (skipLine) {
1317 /*
1318 * Don't even try to evaluate a conditional that's not an else if
1319 * we're skipping things...
1320 */
1321 skipIfLevel += 1;
1322 return(COND_SKIP);
1323 }
1324
1325 /*
1326 * Initialize file-global variables for parsing
1327 */
1328 condDefProc = ifp->defProc;
1329 condInvert = ifp->doNot;
1330
1331 line += ifp->formlen;
1332 if (Cond_EvalExpression(0, line, &value, 1) == COND_INVALID)
1333 return COND_INVALID;
1334 }
1335 if (!isElse) {
1336 condTop -= 1;
1337 finalElse[condTop] = FALSE;
1338 } else if ((skipIfLevel != 0) || condStack[condTop]) {
1339 /*
1340 * If this is an else-type conditional, it should only take effect
1341 * if its corresponding if was evaluated and FALSE. If its if was
1342 * TRUE or skipped, we return COND_SKIP (and start skipping in case
1343 * we weren't already), leaving the stack unmolested so later elif's
1344 * don't screw up...
1345 */
1346 skipLine = TRUE;
1347 return (COND_SKIP);
1348 }
1349
1350 if (condTop < 0) {
1351 /*
1352 * This is the one case where we can definitely proclaim a fatal
1353 * error. If we don't, we're hosed.
1354 */
1355 Parse_Error (PARSE_FATAL, "Too many nested if's. %d max.", MAXIF);
1356 return (COND_INVALID);
1357 } else {
1358 condStack[condTop] = value;
1359 skipLine = !value;
1360 return (value ? COND_PARSE : COND_SKIP);
1361 }
1362 }
1363
1364
1365
1366 /*-
1368 *-----------------------------------------------------------------------
1369 * Cond_End --
1370 * Make sure everything's clean at the end of a makefile.
1371 *
1372 * Results:
1373 * None.
1374 *
1375 * Side Effects:
1376 * Parse_Error will be called if open conditionals are around.
1377 *
1378 *-----------------------------------------------------------------------
1379 */
1380 void
1381 Cond_End(void)
1382 {
1383 if (condTop != MAXIF) {
1384 Parse_Error(PARSE_FATAL, "%d open conditional%s", MAXIF-condTop,
1385 MAXIF-condTop == 1 ? "" : "s");
1386 }
1387 condTop = MAXIF;
1388 }
1389