source: trunk/src/kmk/cond.c@ 33

Last change on this file since 33 was 25, checked in by bird, 23 years ago

This commit was generated by cvs2svn to compensate for changes in r24,
which included commits to RCS files with non-trunk default branches.

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