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