cond.c revision 1.36 1 /* $NetBSD: cond.c,v 1.36 2006/12/02 15:50:45 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.36 2006/12/02 15:50:45 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.36 2006/12/02 15:50:45 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
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 -> "string"
118 * T -> ( E )
119 * T -> ! T
120 * op -> == | != | > | < | >= | <=
121 *
122 * 'symbol' is some other symbol to which the default function (condDefProc)
123 * is applied.
124 *
125 * Tokens are scanned from the 'condExpr' string. The scanner (CondToken)
126 * will return And for '&' and '&&', Or for '|' and '||', Not for '!',
127 * LParen for '(', RParen for ')' and will evaluate the other terminal
128 * symbols, using either the default function or the function given in the
129 * terminal, and return the result as either True or False.
130 *
131 * All Non-Terminal functions (CondE, CondF and CondT) return Err on error.
132 */
133 typedef enum {
134 And, Or, Not, True, False, LParen, RParen, EndOfFile, None, Err
135 } Token;
136
137 /*-
138 * Structures to handle elegantly the different forms of #if's. The
139 * last two fields are stored in condInvert and condDefProc, respectively.
140 */
141 static void CondPushBack(Token);
142 static int CondGetArg(char **, char **, const char *, Boolean);
143 static Boolean CondDoDefined(int, char *);
144 static int CondStrMatch(ClientData, ClientData);
145 static Boolean CondDoMake(int, char *);
146 static Boolean CondDoExists(int, char *);
147 static Boolean CondDoTarget(int, char *);
148 static Boolean CondDoCommands(int, char *);
149 static char * CondCvtArg(char *, double *);
150 static Token CondToken(Boolean);
151 static Token CondT(Boolean);
152 static Token CondF(Boolean);
153 static Token CondE(Boolean);
154
155 static const struct If {
156 const char *form; /* Form of if */
157 int formlen; /* Length of form */
158 Boolean doNot; /* TRUE if default function should be negated */
159 Boolean (*defProc)(int, char *); /* Default function to apply */
160 } ifs[] = {
161 { "def", 3, FALSE, CondDoDefined },
162 { "ndef", 4, TRUE, CondDoDefined },
163 { "make", 4, FALSE, CondDoMake },
164 { "nmake", 5, TRUE, CondDoMake },
165 { "", 0, FALSE, CondDoDefined },
166 { NULL, 0, FALSE, NULL }
167 };
168
169 static Boolean condInvert; /* Invert the default function */
170 static Boolean (*condDefProc)(int, char *); /* Default function to apply */
171 static char *condExpr; /* The expression to parse */
172 static Token condPushBack=None; /* Single push-back token used in
173 * parsing */
174
175 static int cond_depth = 0; /* current .if nesting level */
176
177 static int
178 istoken(const char *str, const char *tok, size_t len)
179 {
180 return strncmp(str, tok, len) == 0 && !isalpha((unsigned char)str[len]);
181 }
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 = NULL;
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) == 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 void *freeIt;
273
274 cp2 = Var_Parse(cp, VAR_CMD, TRUE, &len, &freeIt);
275 Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2);
276 if (freeIt)
277 free(freeIt);
278 cp += len;
279 } else {
280 Buf_AddByte(buf, (Byte)*cp);
281 cp++;
282 }
283 }
284
285 Buf_AddByte(buf, (Byte)'\0');
286 *argPtr = (char *)Buf_GetAll(buf, &argLen);
287 Buf_Destroy(buf, FALSE);
288
289 while (*cp == ' ' || *cp == '\t') {
290 cp++;
291 }
292 if (parens && *cp != ')') {
293 Parse_Error(PARSE_WARNING, "Missing closing parenthesis for %s()",
294 func);
295 return (0);
296 } else if (parens) {
297 /*
298 * Advance pointer past close parenthesis.
299 */
300 cp++;
301 }
302
303 *linePtr = cp;
304 return (argLen);
305 }
306
307 /*-
309 *-----------------------------------------------------------------------
310 * CondDoDefined --
311 * Handle the 'defined' function for conditionals.
312 *
313 * Results:
314 * TRUE if the given variable is defined.
315 *
316 * Side Effects:
317 * None.
318 *
319 *-----------------------------------------------------------------------
320 */
321 static Boolean
322 CondDoDefined(int argLen, char *arg)
323 {
324 char savec = arg[argLen];
325 char *p1;
326 Boolean result;
327
328 arg[argLen] = '\0';
329 if (Var_Value(arg, VAR_CMD, &p1) != NULL) {
330 result = TRUE;
331 } else {
332 result = FALSE;
333 }
334 if (p1)
335 free(p1);
336 arg[argLen] = savec;
337 return (result);
338 }
339
340 /*-
342 *-----------------------------------------------------------------------
343 * CondStrMatch --
344 * Front-end for Str_Match so it returns 0 on match and non-zero
345 * on mismatch. Callback function for CondDoMake via Lst_Find
346 *
347 * Results:
348 * 0 if string matches pattern
349 *
350 * Side Effects:
351 * None
352 *
353 *-----------------------------------------------------------------------
354 */
355 static int
356 CondStrMatch(ClientData string, ClientData pattern)
357 {
358 return(!Str_Match((char *)string,(char *)pattern));
359 }
360
361 /*-
363 *-----------------------------------------------------------------------
364 * CondDoMake --
365 * Handle the 'make' function for conditionals.
366 *
367 * Results:
368 * TRUE if the given target is being made.
369 *
370 * Side Effects:
371 * None.
372 *
373 *-----------------------------------------------------------------------
374 */
375 static Boolean
376 CondDoMake(int argLen, char *arg)
377 {
378 char savec = arg[argLen];
379 Boolean result;
380
381 arg[argLen] = '\0';
382 if (Lst_Find(create, arg, CondStrMatch) == NILLNODE) {
383 result = FALSE;
384 } else {
385 result = TRUE;
386 }
387 arg[argLen] = savec;
388 return (result);
389 }
390
391 /*-
393 *-----------------------------------------------------------------------
394 * CondDoExists --
395 * See if the given file exists.
396 *
397 * Results:
398 * TRUE if the file exists and FALSE if it does not.
399 *
400 * Side Effects:
401 * None.
402 *
403 *-----------------------------------------------------------------------
404 */
405 static Boolean
406 CondDoExists(int argLen, char *arg)
407 {
408 char savec = arg[argLen];
409 Boolean result;
410 char *path;
411
412 arg[argLen] = '\0';
413 path = Dir_FindFile(arg, dirSearchPath);
414 if (path != NULL) {
415 result = TRUE;
416 free(path);
417 } else {
418 result = FALSE;
419 }
420 arg[argLen] = savec;
421 if (DEBUG(COND)) {
422 fprintf(debug_file, "exists(%s) result is \"%s\"\n",
423 arg, path ? path : "");
424 }
425 return (result);
426 }
427
428 /*-
430 *-----------------------------------------------------------------------
431 * CondDoTarget --
432 * See if the given node exists and is an actual target.
433 *
434 * Results:
435 * TRUE if the node exists as a target and FALSE if it does not.
436 *
437 * Side Effects:
438 * None.
439 *
440 *-----------------------------------------------------------------------
441 */
442 static Boolean
443 CondDoTarget(int argLen, char *arg)
444 {
445 char savec = arg[argLen];
446 Boolean result;
447 GNode *gn;
448
449 arg[argLen] = '\0';
450 gn = Targ_FindNode(arg, TARG_NOCREATE);
451 if ((gn != NILGNODE) && !OP_NOP(gn->type)) {
452 result = TRUE;
453 } else {
454 result = FALSE;
455 }
456 arg[argLen] = savec;
457 return (result);
458 }
459
460 /*-
461 *-----------------------------------------------------------------------
462 * CondDoCommands --
463 * See if the given node exists and is an actual target with commands
464 * associated with it.
465 *
466 * Results:
467 * TRUE if the node exists as a target and has commands associated with
468 * it and FALSE if it does not.
469 *
470 * Side Effects:
471 * None.
472 *
473 *-----------------------------------------------------------------------
474 */
475 static Boolean
476 CondDoCommands(int argLen, char *arg)
477 {
478 char savec = arg[argLen];
479 Boolean result;
480 GNode *gn;
481
482 arg[argLen] = '\0';
483 gn = Targ_FindNode(arg, TARG_NOCREATE);
484 if ((gn != NILGNODE) && !OP_NOP(gn->type) && !Lst_IsEmpty(gn->commands)) {
485 result = TRUE;
486 } else {
487 result = FALSE;
488 }
489 arg[argLen] = savec;
490 return (result);
491 }
492
493 /*-
495 *-----------------------------------------------------------------------
496 * CondCvtArg --
497 * Convert the given number into a double. If the number begins
498 * with 0x, it is interpreted as a hexadecimal integer
499 * and converted to a double from there. All other strings just have
500 * strtod called on them.
501 *
502 * Results:
503 * Sets 'value' to double value of string.
504 * Returns NULL if string was fully consumed,
505 * else returns remaining input.
506 *
507 * Side Effects:
508 * Can change 'value' even if string is not a valid number.
509 *
510 *
511 *-----------------------------------------------------------------------
512 */
513 static char *
514 CondCvtArg(char *str, double *value)
515 {
516 if ((*str == '0') && (str[1] == 'x')) {
517 long i;
518
519 for (str += 2, i = 0; *str; str++) {
520 int x;
521 if (isdigit((unsigned char) *str))
522 x = *str - '0';
523 else if (isxdigit((unsigned char) *str))
524 x = 10 + *str - isupper((unsigned char) *str) ? 'A' : 'a';
525 else
526 break;
527 i = (i << 4) + x;
528 }
529 *value = (double) i;
530 return *str ? str : NULL;
531 } else {
532 char *eptr;
533 *value = strtod(str, &eptr);
534 return *eptr ? eptr : NULL;
535 }
536 }
537
538 /*-
540 *-----------------------------------------------------------------------
541 * CondGetString --
542 * Get a string from a variable reference or an optionally quoted
543 * string. This is called for the lhs and rhs of string compares.
544 *
545 * Results:
546 * Sets freeIt if needed,
547 * Sets quoted if string was quoted,
548 * Returns NULL on error,
549 * else returns string - absent any quotes.
550 *
551 * Side Effects:
552 * Moves condExpr to end of this token.
553 *
554 *
555 *-----------------------------------------------------------------------
556 */
557 /* coverity:[+alloc : arg-*2] */
558 static char *
559 CondGetString(Boolean doEval, Boolean *quoted, void **freeIt)
560 {
561 Buffer buf;
562 char *cp;
563 char *str;
564 int len;
565 int qt;
566 char *start;
567
568 buf = Buf_Init(0);
569 str = NULL;
570 *freeIt = NULL;
571 *quoted = qt = *condExpr == '"' ? 1 : 0;
572 if (qt)
573 condExpr++;
574 for (start = condExpr; *condExpr && str == NULL; condExpr++) {
575 switch (*condExpr) {
576 case '\\':
577 if (condExpr[1] != '\0') {
578 condExpr++;
579 Buf_AddByte(buf, (Byte)*condExpr);
580 }
581 break;
582 case '"':
583 if (qt) {
584 condExpr++; /* we don't want the quotes */
585 goto got_str;
586 } else
587 Buf_AddByte(buf, (Byte)*condExpr); /* likely? */
588 break;
589 case ')':
590 case '!':
591 case '=':
592 case '>':
593 case '<':
594 case ' ':
595 case '\t':
596 if (!qt)
597 goto got_str;
598 else
599 Buf_AddByte(buf, (Byte)*condExpr);
600 break;
601 case '$':
602 /* if we are in quotes, then an undefined variable is ok */
603 str = Var_Parse(condExpr, VAR_CMD, (qt ? 0 : doEval),
604 &len, freeIt);
605 if (str == var_Error) {
606 if (*freeIt) {
607 free(*freeIt);
608 *freeIt = NULL;
609 }
610 /*
611 * Even if !doEval, we still report syntax errors, which
612 * is what getting var_Error back with !doEval means.
613 */
614 str = NULL;
615 goto cleanup;
616 }
617 condExpr += len;
618 /*
619 * If the '$' was first char (no quotes), and we are
620 * followed by space, the operator or end of expression,
621 * we are done.
622 */
623 if ((condExpr == start + len) &&
624 (*condExpr == '\0' ||
625 isspace((unsigned char) *condExpr) ||
626 strchr("!=><)", *condExpr))) {
627 goto cleanup;
628 }
629 /*
630 * Nope, we better copy str to buf
631 */
632 for (cp = str; *cp; cp++) {
633 Buf_AddByte(buf, (Byte)*cp);
634 }
635 if (*freeIt) {
636 free(*freeIt);
637 *freeIt = NULL;
638 }
639 str = NULL; /* not finished yet */
640 condExpr--; /* don't skip over next char */
641 break;
642 default:
643 Buf_AddByte(buf, (Byte)*condExpr);
644 break;
645 }
646 }
647 got_str:
648 Buf_AddByte(buf, (Byte)'\0');
649 str = (char *)Buf_GetAll(buf, NULL);
650 *freeIt = str;
651 cleanup:
652 Buf_Destroy(buf, FALSE);
653 return str;
654 }
655
656 /*-
658 *-----------------------------------------------------------------------
659 * CondToken --
660 * Return the next token from the input.
661 *
662 * Results:
663 * A Token for the next lexical token in the stream.
664 *
665 * Side Effects:
666 * condPushback will be set back to None if it is used.
667 *
668 *-----------------------------------------------------------------------
669 */
670 static Token
671 CondToken(Boolean doEval)
672 {
673 Token t;
674
675 if (condPushBack == None) {
676 while (*condExpr == ' ' || *condExpr == '\t') {
677 condExpr++;
678 }
679 switch (*condExpr) {
680 case '(':
681 t = LParen;
682 condExpr++;
683 break;
684 case ')':
685 t = RParen;
686 condExpr++;
687 break;
688 case '|':
689 if (condExpr[1] == '|') {
690 condExpr++;
691 }
692 condExpr++;
693 t = Or;
694 break;
695 case '&':
696 if (condExpr[1] == '&') {
697 condExpr++;
698 }
699 condExpr++;
700 t = And;
701 break;
702 case '!':
703 t = Not;
704 condExpr++;
705 break;
706 case '#':
707 case '\n':
708 case '\0':
709 t = EndOfFile;
710 break;
711 case '"':
712 case '$': {
713 char *lhs;
714 char *rhs;
715 char *op;
716 void *lhsFree;
717 void *rhsFree;
718 Boolean lhsQuoted;
719 Boolean rhsQuoted;
720
721 rhs = NULL;
722 lhsFree = rhsFree = FALSE;
723 lhsQuoted = rhsQuoted = FALSE;
724
725 /*
726 * Parse the variable spec and skip over it, saving its
727 * value in lhs.
728 */
729 t = Err;
730 lhs = CondGetString(doEval, &lhsQuoted, &lhsFree);
731 if (!lhs) {
732 if (lhsFree)
733 free(lhsFree);
734 return Err;
735 }
736 /*
737 * Skip whitespace to get to the operator
738 */
739 while (isspace((unsigned char) *condExpr))
740 condExpr++;
741
742 /*
743 * Make sure the operator is a valid one. If it isn't a
744 * known relational operator, pretend we got a
745 * != 0 comparison.
746 */
747 op = condExpr;
748 switch (*condExpr) {
749 case '!':
750 case '=':
751 case '<':
752 case '>':
753 if (condExpr[1] == '=') {
754 condExpr += 2;
755 } else {
756 condExpr += 1;
757 }
758 break;
759 default:
760 op = UNCONST("!=");
761 if (lhsQuoted)
762 rhs = UNCONST("");
763 else
764 rhs = UNCONST("0");
765
766 goto do_compare;
767 }
768 while (isspace((unsigned char) *condExpr)) {
769 condExpr++;
770 }
771 if (*condExpr == '\0') {
772 Parse_Error(PARSE_WARNING,
773 "Missing right-hand-side of operator");
774 goto error;
775 }
776 rhs = CondGetString(doEval, &rhsQuoted, &rhsFree);
777 if (!rhs) {
778 if (lhsFree)
779 free(lhsFree);
780 if (rhsFree)
781 free(rhsFree);
782 return Err;
783 }
784 do_compare:
785 if (rhsQuoted || lhsQuoted) {
786 do_string_compare:
787 if (((*op != '!') && (*op != '=')) || (op[1] != '=')) {
788 Parse_Error(PARSE_WARNING,
789 "String comparison operator should be either == or !=");
790 goto error;
791 }
792
793 if (DEBUG(COND)) {
794 fprintf(debug_file, "lhs = \"%s\", rhs = \"%s\", op = %.2s\n",
795 lhs, rhs, op);
796 }
797 /*
798 * Null-terminate rhs and perform the comparison.
799 * t is set to the result.
800 */
801 if (*op == '=') {
802 t = strcmp(lhs, rhs) ? False : True;
803 } else {
804 t = strcmp(lhs, rhs) ? True : False;
805 }
806 } else {
807 /*
808 * rhs is either a float or an integer. Convert both the
809 * lhs and the rhs to a double and compare the two.
810 */
811 double left, right;
812 char *cp;
813
814 if (CondCvtArg(lhs, &left))
815 goto do_string_compare;
816 if ((cp = CondCvtArg(rhs, &right)) &&
817 cp == rhs)
818 goto do_string_compare;
819
820 if (DEBUG(COND)) {
821 fprintf(debug_file, "left = %f, right = %f, op = %.2s\n", left,
822 right, op);
823 }
824 switch(op[0]) {
825 case '!':
826 if (op[1] != '=') {
827 Parse_Error(PARSE_WARNING,
828 "Unknown operator");
829 goto error;
830 }
831 t = (left != right ? True : False);
832 break;
833 case '=':
834 if (op[1] != '=') {
835 Parse_Error(PARSE_WARNING,
836 "Unknown operator");
837 goto error;
838 }
839 t = (left == right ? True : False);
840 break;
841 case '<':
842 if (op[1] == '=') {
843 t = (left <= right ? True : False);
844 } else {
845 t = (left < right ? True : False);
846 }
847 break;
848 case '>':
849 if (op[1] == '=') {
850 t = (left >= right ? True : False);
851 } else {
852 t = (left > right ? True : False);
853 }
854 break;
855 }
856 }
857 error:
858 if (lhsFree)
859 free(lhsFree);
860 if (rhsFree)
861 free(rhsFree);
862 break;
863 }
864 default: {
865 Boolean (*evalProc)(int, char *);
866 Boolean invert = FALSE;
867 char *arg = NULL;
868 int arglen = 0;
869
870 if (istoken(condExpr, "defined", 7)) {
871 /*
872 * Use CondDoDefined to evaluate the argument and
873 * CondGetArg to extract the argument from the 'function
874 * call'.
875 */
876 evalProc = CondDoDefined;
877 condExpr += 7;
878 arglen = CondGetArg(&condExpr, &arg, "defined", TRUE);
879 if (arglen == 0) {
880 condExpr -= 7;
881 goto use_default;
882 }
883 } else if (istoken(condExpr, "make", 4)) {
884 /*
885 * Use CondDoMake to evaluate the argument and
886 * CondGetArg to extract the argument from the 'function
887 * call'.
888 */
889 evalProc = CondDoMake;
890 condExpr += 4;
891 arglen = CondGetArg(&condExpr, &arg, "make", TRUE);
892 if (arglen == 0) {
893 condExpr -= 4;
894 goto use_default;
895 }
896 } else if (istoken(condExpr, "exists", 6)) {
897 /*
898 * Use CondDoExists to evaluate the argument and
899 * CondGetArg to extract the argument from the
900 * 'function call'.
901 */
902 evalProc = CondDoExists;
903 condExpr += 6;
904 arglen = CondGetArg(&condExpr, &arg, "exists", TRUE);
905 if (arglen == 0) {
906 condExpr -= 6;
907 goto use_default;
908 }
909 } else if (istoken(condExpr, "empty", 5)) {
910 /*
911 * Use Var_Parse to parse the spec in parens and return
912 * True if the resulting string is empty.
913 */
914 int length;
915 void *freeIt;
916 char *val;
917
918 condExpr += 5;
919
920 for (arglen = 0;
921 condExpr[arglen] != '(' && condExpr[arglen] != '\0';
922 arglen += 1)
923 continue;
924
925 if (condExpr[arglen] != '\0') {
926 val = Var_Parse(&condExpr[arglen - 1], VAR_CMD,
927 FALSE, &length, &freeIt);
928 if (val == var_Error) {
929 t = Err;
930 } else {
931 /*
932 * A variable is empty when it just contains
933 * spaces... 4/15/92, christos
934 */
935 char *p;
936 for (p = val; *p && isspace((unsigned char)*p); p++)
937 continue;
938 t = (*p == '\0') ? True : False;
939 }
940 if (freeIt) {
941 free(freeIt);
942 }
943 /*
944 * Advance condExpr to beyond the closing ). Note that
945 * we subtract one from arglen + length b/c length
946 * is calculated from condExpr[arglen - 1].
947 */
948 condExpr += arglen + length - 1;
949 } else {
950 condExpr -= 5;
951 goto use_default;
952 }
953 break;
954 } else if (istoken(condExpr, "target", 6)) {
955 /*
956 * Use CondDoTarget to evaluate the argument and
957 * CondGetArg to extract the argument from the
958 * 'function call'.
959 */
960 evalProc = CondDoTarget;
961 condExpr += 6;
962 arglen = CondGetArg(&condExpr, &arg, "target", TRUE);
963 if (arglen == 0) {
964 condExpr -= 6;
965 goto use_default;
966 }
967 } else if (istoken(condExpr, "commands", 8)) {
968 /*
969 * Use CondDoCommands to evaluate the argument and
970 * CondGetArg to extract the argument from the
971 * 'function call'.
972 */
973 evalProc = CondDoCommands;
974 condExpr += 8;
975 arglen = CondGetArg(&condExpr, &arg, "commands", TRUE);
976 if (arglen == 0) {
977 condExpr -= 8;
978 goto use_default;
979 }
980 } else {
981 /*
982 * The symbol is itself the argument to the default
983 * function. We advance condExpr to the end of the symbol
984 * by hand (the next whitespace, closing paren or
985 * binary operator) and set to invert the evaluation
986 * function if condInvert is TRUE.
987 */
988 use_default:
989 invert = condInvert;
990 evalProc = condDefProc;
991 arglen = CondGetArg(&condExpr, &arg, "", FALSE);
992 }
993
994 /*
995 * Evaluate the argument using the set function. If invert
996 * is TRUE, we invert the sense of the function.
997 */
998 t = (!doEval || (* evalProc) (arglen, arg) ?
999 (invert ? False : True) :
1000 (invert ? True : False));
1001 if (arg)
1002 free(arg);
1003 break;
1004 }
1005 }
1006 } else {
1007 t = condPushBack;
1008 condPushBack = None;
1009 }
1010 return (t);
1011 }
1012
1013 /*-
1015 *-----------------------------------------------------------------------
1016 * CondT --
1017 * Parse a single term in the expression. This consists of a terminal
1018 * symbol or Not and a terminal symbol (not including the binary
1019 * operators):
1020 * T -> defined(variable) | make(target) | exists(file) | symbol
1021 * T -> ! T | ( E )
1022 *
1023 * Results:
1024 * True, False or Err.
1025 *
1026 * Side Effects:
1027 * Tokens are consumed.
1028 *
1029 *-----------------------------------------------------------------------
1030 */
1031 static Token
1032 CondT(Boolean doEval)
1033 {
1034 Token t;
1035
1036 t = CondToken(doEval);
1037
1038 if (t == EndOfFile) {
1039 /*
1040 * If we reached the end of the expression, the expression
1041 * is malformed...
1042 */
1043 t = Err;
1044 } else if (t == LParen) {
1045 /*
1046 * T -> ( E )
1047 */
1048 t = CondE(doEval);
1049 if (t != Err) {
1050 if (CondToken(doEval) != RParen) {
1051 t = Err;
1052 }
1053 }
1054 } else if (t == Not) {
1055 t = CondT(doEval);
1056 if (t == True) {
1057 t = False;
1058 } else if (t == False) {
1059 t = True;
1060 }
1061 }
1062 return (t);
1063 }
1064
1065 /*-
1067 *-----------------------------------------------------------------------
1068 * CondF --
1069 * Parse a conjunctive factor (nice name, wot?)
1070 * F -> T && F | T
1071 *
1072 * Results:
1073 * True, False or Err
1074 *
1075 * Side Effects:
1076 * Tokens are consumed.
1077 *
1078 *-----------------------------------------------------------------------
1079 */
1080 static Token
1081 CondF(Boolean doEval)
1082 {
1083 Token l, o;
1084
1085 l = CondT(doEval);
1086 if (l != Err) {
1087 o = CondToken(doEval);
1088
1089 if (o == And) {
1090 /*
1091 * F -> T && F
1092 *
1093 * If T is False, the whole thing will be False, but we have to
1094 * parse the r.h.s. anyway (to throw it away).
1095 * If T is True, the result is the r.h.s., be it an Err or no.
1096 */
1097 if (l == True) {
1098 l = CondF(doEval);
1099 } else {
1100 (void)CondF(FALSE);
1101 }
1102 } else {
1103 /*
1104 * F -> T
1105 */
1106 CondPushBack(o);
1107 }
1108 }
1109 return (l);
1110 }
1111
1112 /*-
1114 *-----------------------------------------------------------------------
1115 * CondE --
1116 * Main expression production.
1117 * E -> F || E | F
1118 *
1119 * Results:
1120 * True, False or Err.
1121 *
1122 * Side Effects:
1123 * Tokens are, of course, consumed.
1124 *
1125 *-----------------------------------------------------------------------
1126 */
1127 static Token
1128 CondE(Boolean doEval)
1129 {
1130 Token l, o;
1131
1132 l = CondF(doEval);
1133 if (l != Err) {
1134 o = CondToken(doEval);
1135
1136 if (o == Or) {
1137 /*
1138 * E -> F || E
1139 *
1140 * A similar thing occurs for ||, except that here we make sure
1141 * the l.h.s. is False before we bother to evaluate the r.h.s.
1142 * Once again, if l is False, the result is the r.h.s. and once
1143 * again if l is True, we parse the r.h.s. to throw it away.
1144 */
1145 if (l == False) {
1146 l = CondE(doEval);
1147 } else {
1148 (void)CondE(FALSE);
1149 }
1150 } else {
1151 /*
1152 * E -> F
1153 */
1154 CondPushBack(o);
1155 }
1156 }
1157 return (l);
1158 }
1159
1160 /*-
1161 *-----------------------------------------------------------------------
1162 * Cond_EvalExpression --
1163 * Evaluate an expression in the passed line. The expression
1164 * consists of &&, ||, !, make(target), defined(variable)
1165 * and parenthetical groupings thereof.
1166 *
1167 * Results:
1168 * COND_PARSE if the condition was valid grammatically
1169 * COND_INVALID if not a valid conditional.
1170 *
1171 * (*value) is set to the boolean value of the condition
1172 *
1173 * Side Effects:
1174 * None.
1175 *
1176 *-----------------------------------------------------------------------
1177 */
1178 int
1179 Cond_EvalExpression(int dosetup, char *line, Boolean *value, int eprint)
1180 {
1181 if (dosetup) {
1182 condDefProc = CondDoDefined;
1183 condInvert = 0;
1184 }
1185
1186 while (*line == ' ' || *line == '\t')
1187 line++;
1188
1189 condExpr = line;
1190 condPushBack = None;
1191
1192 switch (CondE(TRUE)) {
1193 case True:
1194 if (CondToken(TRUE) == EndOfFile) {
1195 *value = TRUE;
1196 break;
1197 }
1198 goto err;
1199 /*FALLTHRU*/
1200 case False:
1201 if (CondToken(TRUE) == EndOfFile) {
1202 *value = FALSE;
1203 break;
1204 }
1205 /*FALLTHRU*/
1206 case Err:
1207 err:
1208 if (eprint)
1209 Parse_Error(PARSE_FATAL, "Malformed conditional (%s)",
1210 line);
1211 return (COND_INVALID);
1212 default:
1213 break;
1214 }
1215
1216 return COND_PARSE;
1217 }
1218
1219
1220 /*-
1222 *-----------------------------------------------------------------------
1223 * Cond_Eval --
1224 * Evaluate the conditional in the passed line. The line
1225 * looks like this:
1226 * .<cond-type> <expr>
1227 * where <cond-type> is any of if, ifmake, ifnmake, ifdef,
1228 * ifndef, elif, elifmake, elifnmake, elifdef, elifndef
1229 * and <expr> consists of &&, ||, !, make(target), defined(variable)
1230 * and parenthetical groupings thereof.
1231 *
1232 * Input:
1233 * line Line to parse
1234 *
1235 * Results:
1236 * COND_PARSE if should parse lines after the conditional
1237 * COND_SKIP if should skip lines after the conditional
1238 * COND_INVALID if not a valid conditional.
1239 *
1240 * Side Effects:
1241 * None.
1242 *
1243 * Note that the states IF_ACTIVE and ELSE_ACTIVE are only different in order
1244 * to detect splurious .else lines (as are SKIP_TO_ELSE and SKIP_TO_ENDIF)
1245 * otherwise .else could be treated as '.elif 1'.
1246 *
1247 *-----------------------------------------------------------------------
1248 */
1249 int
1250 Cond_Eval(char *line)
1251 {
1252 #define MAXIF 64 /* maximum depth of .if'ing */
1253 enum if_states {
1254 IF_ACTIVE, /* .if or .elif part active */
1255 ELSE_ACTIVE, /* .else part active */
1256 SEARCH_FOR_ELIF, /* searching for .elif/else to execute */
1257 SKIP_TO_ELSE, /* has been true, but not seen '.else' */
1258 SKIP_TO_ENDIF /* nothing else to execute */
1259 };
1260 static enum if_states cond_state[MAXIF + 1] = { IF_ACTIVE };
1261
1262 const struct If *ifp;
1263 Boolean isElif;
1264 Boolean value;
1265 int level; /* Level at which to report errors. */
1266 enum if_states state;
1267
1268 level = PARSE_FATAL;
1269
1270 /* skip leading character (the '.') and any whitespace */
1271 for (line++; *line == ' ' || *line == '\t'; line++)
1272 continue;
1273
1274 /* Find what type of if we're dealing with. */
1275 if (line[0] == 'e') {
1276 if (line[1] != 'l') {
1277 if (!istoken(line + 1, "ndif", 4))
1278 return COND_INVALID;
1279 /* End of conditional section */
1280 if (cond_depth == 0) {
1281 Parse_Error(level, "if-less endif");
1282 return COND_PARSE;
1283 }
1284 /* Return state for previous conditional */
1285 cond_depth--;
1286 return cond_state[cond_depth] <= ELSE_ACTIVE ? COND_PARSE : COND_SKIP;
1287 }
1288
1289 /* Quite likely this is 'else' or 'elif' */
1290 line += 2;
1291 if (istoken(line, "se", 2)) {
1292 /* It is else... */
1293 if (cond_depth == 0) {
1294 Parse_Error(level, "if-less else");
1295 return COND_INVALID;
1296 }
1297
1298 state = cond_state[cond_depth];
1299 switch (state) {
1300 case SEARCH_FOR_ELIF:
1301 state = ELSE_ACTIVE;
1302 break;
1303 case ELSE_ACTIVE:
1304 case SKIP_TO_ENDIF:
1305 Parse_Error(PARSE_WARNING, "extra else");
1306 /* FALLTHROUGH */
1307 default:
1308 case IF_ACTIVE:
1309 case SKIP_TO_ELSE:
1310 state = SKIP_TO_ENDIF;
1311 break;
1312 }
1313 cond_state[cond_depth] = state;
1314 return state <= ELSE_ACTIVE ? COND_PARSE : COND_SKIP;
1315 }
1316 /* Assume for now it is an elif */
1317 isElif = TRUE;
1318 } else
1319 isElif = FALSE;
1320
1321 if (line[0] != 'i' || line[1] != 'f')
1322 /* Not an ifxxx or elifxxx line */
1323 return COND_INVALID;
1324
1325 /*
1326 * Figure out what sort of conditional it is -- what its default
1327 * function is, etc. -- by looking in the table of valid "ifs"
1328 */
1329 line += 2;
1330 for (ifp = ifs; ; ifp++) {
1331 if (ifp->form == NULL)
1332 return COND_INVALID;
1333 if (istoken(ifp->form, line, ifp->formlen)) {
1334 line += ifp->formlen;
1335 break;
1336 }
1337 }
1338
1339 /* Now we know what sort of 'if' it is... */
1340 state = cond_state[cond_depth];
1341
1342 if (isElif) {
1343 if (cond_depth == 0) {
1344 Parse_Error(level, "if-less elif");
1345 return COND_INVALID;
1346 }
1347 if (state == SKIP_TO_ENDIF || state == ELSE_ACTIVE)
1348 Parse_Error(PARSE_WARNING, "extra elif");
1349 if (state != SEARCH_FOR_ELIF) {
1350 /* Either just finished the 'true' block, or already SKIP_TO_ELSE */
1351 cond_state[cond_depth] = SKIP_TO_ELSE;
1352 return COND_SKIP;
1353 }
1354 } else {
1355 if (cond_depth >= MAXIF) {
1356 Parse_Error(PARSE_FATAL, "Too many nested if's. %d max.", MAXIF);
1357 return COND_INVALID;
1358 }
1359 cond_depth++;
1360 if (state > ELSE_ACTIVE) {
1361 /* If we aren't parsing the data, treat as always false */
1362 cond_state[cond_depth] = SKIP_TO_ELSE;
1363 return COND_SKIP;
1364 }
1365 }
1366
1367 /* Initialize file-global variables for parsing the expression */
1368 condDefProc = ifp->defProc;
1369 condInvert = ifp->doNot;
1370
1371 /* And evaluate the conditional expresssion */
1372 if (Cond_EvalExpression(0, line, &value, 1) == COND_INVALID) {
1373 /* Although we get make to reprocess the line, set a state */
1374 cond_state[cond_depth] = SEARCH_FOR_ELIF;
1375 return COND_INVALID;
1376 }
1377
1378 if (!value) {
1379 cond_state[cond_depth] = SEARCH_FOR_ELIF;
1380 return COND_SKIP;
1381 }
1382 cond_state[cond_depth] = IF_ACTIVE;
1383 return COND_PARSE;
1384 }
1385
1386
1387
1388 /*-
1390 *-----------------------------------------------------------------------
1391 * Cond_End --
1392 * Make sure everything's clean at the end of a makefile.
1393 *
1394 * Results:
1395 * None.
1396 *
1397 * Side Effects:
1398 * Parse_Error will be called if open conditionals are around.
1399 *
1400 *-----------------------------------------------------------------------
1401 */
1402 void
1403 Cond_End(void)
1404 {
1405 if (cond_depth != 0) {
1406 Parse_Error(PARSE_FATAL, "%d open conditional%s", cond_depth,
1407 cond_depth == 1 ? "" : "s");
1408 }
1409 cond_depth = 0;
1410 }
1411