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