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