]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - usr.bin/make/cond.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.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  */
41
42 #include <sys/cdefs.h>
43 __FBSDID("$FreeBSD$");
44
45 /*
46  * Functions to handle conditionals in a makefile.
47  *
48  * Interface:
49  *      Cond_Eval       Evaluate the conditional in the passed line.
50  */
51
52 #include <ctype.h>
53 #include <string.h>
54 #include <stdlib.h>
55
56 #include "buf.h"
57 #include "cond.h"
58 #include "dir.h"
59 #include "globals.h"
60 #include "GNode.h"
61 #include "make.h"
62 #include "parse.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         Boolean result;
287
288         arg[argLen] = '\0';
289         if (Var_Value(arg, VAR_CMD) != NULL) {
290                 result = TRUE;
291         } else {
292                 result = FALSE;
293         }
294         arg[argLen] = savec;
295         return (result);
296 }
297
298 /**
299  * CondDoMake
300  *      Handle the 'make' function for conditionals.
301  *
302  * Results:
303  *      TRUE if the given target is being made.
304  */
305 static Boolean
306 CondDoMake(int argLen, char *arg)
307 {
308         char    savec = arg[argLen];
309         Boolean result;
310         const LstNode *ln;
311
312         arg[argLen] = '\0';
313         result = FALSE;
314         LST_FOREACH(ln, &create) {
315                 if (Str_Match(Lst_Datum(ln), arg)) {
316                         result = TRUE;
317                         break;
318                 }
319         }
320         arg[argLen] = savec;
321         return (result);
322 }
323
324 /**
325  * CondDoExists
326  *      See if the given file exists.
327  *
328  * Results:
329  *      TRUE if the file exists and FALSE if it does not.
330  */
331 static Boolean
332 CondDoExists(int argLen, char *arg)
333 {
334         char    savec = arg[argLen];
335         Boolean result;
336         char    *path;
337
338         arg[argLen] = '\0';
339         path = Path_FindFile(arg, &dirSearchPath);
340         if (path != NULL) {
341                 result = TRUE;
342                 free(path);
343         } else {
344                 result = FALSE;
345         }
346         arg[argLen] = savec;
347         return (result);
348 }
349
350 /**
351  * CondDoTarget
352  *      See if the given node exists and is an actual target.
353  *
354  * Results:
355  *      TRUE if the node exists as a target and FALSE if it does not.
356  */
357 static Boolean
358 CondDoTarget(int argLen, char *arg)
359 {
360         char    savec = arg[argLen];
361         Boolean result;
362         GNode   *gn;
363
364         arg[argLen] = '\0';
365         gn = Targ_FindNode(arg, TARG_NOCREATE);
366         if ((gn != NULL) && !OP_NOP(gn->type)) {
367                 result = TRUE;
368         } else {
369                 result = FALSE;
370         }
371         arg[argLen] = savec;
372         return (result);
373 }
374
375 /**
376  * CondCvtArg
377  *      Convert the given number into a double. If the number begins
378  *      with 0x, it is interpreted as a hexadecimal integer
379  *      and converted to a double from there. All other strings just have
380  *      strtod called on them.
381  *
382  * Results:
383  *      Sets 'value' to double value of string.
384  *      Returns address of the first character after the last valid
385  *      character of the converted number.
386  *
387  * Side Effects:
388  *      Can change 'value' even if string is not a valid number.
389  */
390 static char *
391 CondCvtArg(char *str, double *value)
392 {
393
394         if ((*str == '0') && (str[1] == 'x')) {
395                 long i;
396
397                 for (str += 2, i = 0; ; str++) {
398                         int x;
399
400                         if (isdigit((unsigned char)*str))
401                                 x  = *str - '0';
402                         else if (isxdigit((unsigned char)*str))
403                                 x = 10 + *str -
404                                     isupper((unsigned char)*str) ? 'A' : 'a';
405                         else {
406                                 *value = (double)i;
407                                 return (str);
408                         }
409                         i = (i << 4) + x;
410                 }
411
412         } else {
413                 char *eptr;
414
415                 *value = strtod(str, &eptr);
416                 return (eptr);
417         }
418 }
419
420 /**
421  * CondToken
422  *      Return the next token from the input.
423  *
424  * Results:
425  *      A Token for the next lexical token in the stream.
426  *
427  * Side Effects:
428  *      condPushback will be set back to None if it is used.
429  */
430 static Token
431 CondToken(Boolean doEval)
432 {
433         Token   t;
434
435         if (condPushBack != None) {
436                 t = condPushBack;
437                 condPushBack = None;
438                 return (t);
439         }
440
441         while (*condExpr == ' ' || *condExpr == '\t') {
442                 condExpr++;
443         }
444         switch (*condExpr) {
445           case '(':
446                 t = LParen;
447                 condExpr++;
448                 break;
449           case ')':
450                 t = RParen;
451                 condExpr++;
452                 break;
453           case '|':
454                 if (condExpr[1] == '|') {
455                         condExpr++;
456                 }
457                 condExpr++;
458                 t = Or;
459                 break;
460           case '&':
461                 if (condExpr[1] == '&') {
462                         condExpr++;
463                 }
464                 condExpr++;
465                 t = And;
466                 break;
467           case '!':
468                 t = Not;
469                 condExpr++;
470                 break;
471           case '\n':
472           case '\0':
473                 t = EndOfFile;
474                 break;
475           case '$': {
476                 char            *lhs;
477                 const char      *op;
478                 char            *rhs;
479                 char            zero[] = "0";
480                 size_t          varSpecLen = 0;
481                 Boolean         doFree;
482
483                 /*
484                  * Parse the variable spec and skip over it, saving its
485                  * value in lhs.
486                  */
487                 t = Err;
488                 lhs = Var_Parse(condExpr, VAR_CMD, doEval,
489                     &varSpecLen, &doFree);
490                 if (lhs == var_Error) {
491                         /*
492                          * Even if !doEval, we still report syntax
493                          * errors, which is what getting var_Error
494                          * back with !doEval means.
495                          */
496                         return (Err);
497                 }
498                 condExpr += varSpecLen;
499
500                 if (!isspace((unsigned char)*condExpr) &&
501                     strchr("!=><", *condExpr) == NULL) {
502                         Buffer *buf;
503
504                         buf = Buf_Init(0);
505
506                         Buf_Append(buf, lhs);
507
508                         if (doFree)
509                                 free(lhs);
510
511                         for (;*condExpr &&
512                             !isspace((unsigned char)*condExpr);
513                             condExpr++)
514                                 Buf_AddByte(buf, (Byte)*condExpr);
515
516                         Buf_AddByte(buf, (Byte)'\0');
517                         lhs = (char *)Buf_GetAll(buf, &varSpecLen);
518                         Buf_Destroy(buf, FALSE);
519
520                         doFree = TRUE;
521                 }
522
523                 /*
524                  * Skip whitespace to get to the operator
525                  */
526                 while (isspace((unsigned char)*condExpr))
527                         condExpr++;
528
529                 /*
530                  * Make sure the operator is a valid one. If it isn't a
531                  * known relational operator, pretend we got a
532                  * != 0 comparison.
533                  */
534                 op = condExpr;
535                 switch (*condExpr) {
536                   case '!':
537                   case '=':
538                   case '<':
539                   case '>':
540                         if (condExpr[1] == '=') {
541                                 condExpr += 2;
542                         } else {
543                                 condExpr += 1;
544                         }
545                         while (isspace((unsigned char)*condExpr)) {
546                                 condExpr++;
547                         }
548                         if (*condExpr == '\0') {
549                                 Parse_Error(PARSE_WARNING,
550                                     "Missing right-hand-side of operator");
551                                 goto error;
552                         }
553                         rhs = condExpr;
554                         break;
555
556                   default:
557                         op = "!=";
558                         rhs = zero;
559                         break;
560                 }
561                 if (*rhs == '"') {
562                         /*
563                          * Doing a string comparison. Only allow == and
564                          * != for * operators.
565                          */
566                         char    *string;
567                         char    *cp, *cp2;
568                         int     qt;
569                         Buffer  *buf;
570
571   do_string_compare:
572                         if (((*op != '!') && (*op != '=')) ||
573                             (op[1] != '=')) {
574                                 Parse_Error(PARSE_WARNING,
575                                     "String comparison operator should "
576                                     "be either == or !=");
577                                 goto error;
578                         }
579
580                         buf = Buf_Init(0);
581                         qt = *rhs == '"' ? 1 : 0;
582
583                         for (cp = &rhs[qt];
584                             ((qt && (*cp != '"')) ||
585                             (!qt && strchr(" \t)", *cp) == NULL)) &&
586                             (*cp != '\0'); cp++) {
587                                 if ((*cp == '\\') && (cp[1] != '\0')) {
588                                         /*
589                                          * Backslash escapes things --
590                                          * skip over next character,                                                     * if it exists.
591                                          */
592                                         cp++;
593                                         Buf_AddByte(buf, (Byte)*cp);
594
595                                 } else if (*cp == '$') {
596                                         size_t  len = 0;
597                                         Boolean freeIt;
598
599                                         cp2 = Var_Parse(cp, VAR_CMD,
600                                             doEval, &len, &freeIt);
601                                         if (cp2 != var_Error) {
602                                                 Buf_Append(buf, cp2);
603                                                 if (freeIt) {
604                                                         free(cp2);
605                                                 }
606                                                 cp += len - 1;
607                                         } else {
608                                                 Buf_AddByte(buf,
609                                                     (Byte)*cp);
610                                         }
611                                 } else {
612                                         Buf_AddByte(buf, (Byte)*cp);
613                                 }
614                         }
615
616                         string = Buf_Peel(buf);
617
618                         DEBUGF(COND, ("lhs = \"%s\", rhs = \"%s\", "
619                             "op = %.2s\n", lhs, string, op));
620                         /*
621                          * Null-terminate rhs and perform the
622                          * comparison. t is set to the result.
623                          */
624                         if (*op == '=') {
625                                 t = strcmp(lhs, string) ? False : True;
626                         } else {
627                                 t = strcmp(lhs, string) ? True : False;
628                         }
629                         free(string);
630                         if (rhs == condExpr) {
631                                 if (*cp == '\0' || (!qt && *cp == ')'))
632                                         condExpr = cp;
633                                 else
634                                         condExpr = cp + 1;
635                         }
636                 } else {
637                         /*
638                          * rhs is either a float or an integer.
639                          * Convert both the lhs and the rhs to a
640                          * double and compare the two.
641                          */
642                         double  left, right;
643                         char    *string;
644
645                         if (*CondCvtArg(lhs, &left) != '\0')
646                                 goto do_string_compare;
647                         if (*rhs == '$') {
648                                 size_t  len = 0;
649                                 Boolean freeIt;
650
651                                 string = Var_Parse(rhs, VAR_CMD, doEval,
652                                     &len, &freeIt);
653                                 if (string == var_Error) {
654                                         right = 0.0;
655                                 } else {
656                                         if (*CondCvtArg(string,
657                                             &right) != '\0') {
658                                                 if (freeIt)
659                                                         free(string);
660                                                 goto do_string_compare;
661                                         }
662                                         if (freeIt)
663                                                 free(string);
664                                         if (rhs == condExpr)
665                                                 condExpr += len;
666                                 }
667                         } else {
668                                 char *c = CondCvtArg(rhs, &right);
669
670                                 if (c == rhs)
671                                         goto do_string_compare;
672                                 if (rhs == condExpr) {
673                                         /*
674                                          * Skip over the right-hand side
675                                          */
676                                         condExpr = c;
677                                 }
678                         }
679
680                         DEBUGF(COND, ("left = %f, right = %f, "
681                             "op = %.2s\n", left, right, op));
682                         switch (op[0]) {
683                           case '!':
684                                 if (op[1] != '=') {
685                                         Parse_Error(PARSE_WARNING,
686                                             "Unknown operator");
687                                         goto error;
688                                 }
689                                 t = (left != right ? True : False);
690                                 break;
691                           case '=':
692                                 if (op[1] != '=') {
693                                         Parse_Error(PARSE_WARNING,
694                                             "Unknown operator");
695                                         goto error;
696                                 }
697                                 t = (left == right ? True : False);
698                                 break;
699                           case '<':
700                                 if (op[1] == '=') {
701                                         t = (left <= right?True:False);
702                                 } else {
703                                         t = (left < right?True:False);
704                                 }
705                                 break;
706                         case '>':
707                                 if (op[1] == '=') {
708                                         t = (left >= right?True:False);
709                                 } else {
710                                         t = (left > right?True:False);
711                                 }
712                                 break;
713                         default:
714                                 break;
715                         }
716                 }
717   error:
718                 if (doFree)
719                         free(lhs);
720                 break;
721                 }
722
723           default: {
724                 CondProc        *evalProc;
725                 Boolean         invert = FALSE;
726                 char            *arg;
727                 int             arglen;
728
729                 if (strncmp(condExpr, "defined", 7) == 0) {
730                         /*
731                          * Use CondDoDefined to evaluate the argument
732                          * and CondGetArg to extract the argument from
733                          * the 'function call'.
734                          */
735                         evalProc = CondDoDefined;
736                         condExpr += 7;
737                         arglen = CondGetArg(&condExpr, &arg,
738                             "defined", TRUE);
739                         if (arglen == 0) {
740                                 condExpr -= 7;
741                                 goto use_default;
742                         }
743
744                 } else if (strncmp(condExpr, "make", 4) == 0) {
745                         /*
746                          * Use CondDoMake to evaluate the argument and
747                          * CondGetArg to extract the argument from the
748                          * 'function call'.
749                          */
750                         evalProc = CondDoMake;
751                         condExpr += 4;
752                         arglen = CondGetArg(&condExpr, &arg,
753                             "make", TRUE);
754                         if (arglen == 0) {
755                                 condExpr -= 4;
756                                 goto use_default;
757                         }
758
759                 } else if (strncmp(condExpr, "exists", 6) == 0) {
760                         /*
761                          * Use CondDoExists to evaluate the argument and
762                          * CondGetArg to extract the argument from the
763                          * 'function call'.
764                          */
765                         evalProc = CondDoExists;
766                         condExpr += 6;
767                         arglen = CondGetArg(&condExpr, &arg,
768                             "exists", TRUE);
769                         if (arglen == 0) {
770                                 condExpr -= 6;
771                                 goto use_default;
772                         }
773
774                 } else if (strncmp(condExpr, "empty", 5) == 0) {
775                         /*
776                          * Use Var_Parse to parse the spec in parens and
777                          * return True if the resulting string is empty.
778                          */
779                         size_t  length;
780                         Boolean doFree;
781                         char    *val;
782
783                         condExpr += 5;
784
785                         for (arglen = 0;
786                             condExpr[arglen] != '(' &&
787                             condExpr[arglen] != '\0'; arglen += 1)
788                                 continue;
789
790                         if (condExpr[arglen] != '\0') {
791                                 length = 0;
792                                 val = Var_Parse(&condExpr[arglen - 1],
793                                     VAR_CMD, FALSE, &length, &doFree);
794                                 if (val == var_Error) {
795                                         t = Err;
796                                 } else {
797                                         /*
798                                          * A variable is empty when it
799                                          * just contains spaces...
800                                          * 4/15/92, christos
801                                          */
802                                         char *p;
803
804                                         for (p = val;
805                                             *p &&
806                                             isspace((unsigned char)*p);
807                                             p++)
808                                                 continue;
809                                         t = (*p == '\0') ? True : False;
810                                 }
811                                 if (doFree) {
812                                         free(val);
813                                 }
814                                 /*
815                                  * Advance condExpr to beyond the
816                                  * closing ). Note that we subtract
817                                  * one from arglen + length b/c length
818                                  * is calculated from
819                                  * condExpr[arglen - 1].
820                                  */
821                                 condExpr += arglen + length - 1;
822                         } else {
823                                 condExpr -= 5;
824                                 goto use_default;
825                         }
826                         break;
827
828                 } else if (strncmp(condExpr, "target", 6) == 0) {
829                         /*
830                          * Use CondDoTarget to evaluate the argument and
831                          * CondGetArg to extract the argument from the
832                          * 'function call'.
833                          */
834                         evalProc = CondDoTarget;
835                         condExpr += 6;
836                         arglen = CondGetArg(&condExpr, &arg,
837                             "target", TRUE);
838                         if (arglen == 0) {
839                                 condExpr -= 6;
840                                 goto use_default;
841                         }
842
843                 } else {
844                         /*
845                          * The symbol is itself the argument to the
846                          * default function. We advance condExpr to
847                          * the end of the symbol by hand (the next
848                          * whitespace, closing paren or binary operator)
849                          * and set to invert the evaluation
850                          * function if condInvert is TRUE.
851                          */
852   use_default:
853                         invert = condInvert;
854                         evalProc = condDefProc;
855                         arglen = CondGetArg(&condExpr, &arg, "", FALSE);
856                 }
857
858                 /*
859                  * Evaluate the argument using the set function. If
860                  * invert is TRUE, we invert the sense of the function.
861                  */
862                 t = (!doEval || (* evalProc) (arglen, arg) ?
863                     (invert ? False : True) :
864                     (invert ? True : False));
865                 free(arg);
866                 break;
867                 }
868         }
869         return (t);
870 }
871
872 /**
873  * CondT
874  *      Parse a single term in the expression. This consists of a terminal
875  *      symbol or Not and a terminal symbol (not including the binary
876  *      operators):
877  *          T -> defined(variable) | make(target) | exists(file) | symbol
878  *          T -> ! T | ( E )
879  *
880  * Results:
881  *      True, False or Err.
882  *
883  * Side Effects:
884  *      Tokens are consumed.
885  */
886 static Token
887 CondT(Boolean doEval)
888 {
889         Token   t;
890
891         t = CondToken(doEval);
892         if (t == EndOfFile) {
893                 /*
894                  * If we reached the end of the expression, the expression
895                  * is malformed...
896                  */
897                 t = Err;
898         } else if (t == LParen) {
899                 /*
900                  * T -> ( E )
901                  */
902                 t = CondE(doEval);
903                 if (t != Err) {
904                         if (CondToken(doEval) != RParen) {
905                                 t = Err;
906                         }
907                 }
908         } else if (t == Not) {
909                 t = CondT(doEval);
910                 if (t == True) {
911                         t = False;
912                 } else if (t == False) {
913                         t = True;
914                 }
915         }
916         return (t);
917 }
918
919 /**
920  * CondF --
921  *      Parse a conjunctive factor (nice name, wot?)
922  *          F -> T && F | T
923  *
924  * Results:
925  *      True, False or Err
926  *
927  * Side Effects:
928  *      Tokens are consumed.
929  */
930 static Token
931 CondF(Boolean doEval)
932 {
933         Token   l, o;
934
935         l = CondT(doEval);
936         if (l != Err) {
937                 o = CondToken(doEval);
938
939                 if (o == And) {
940                         /*
941                          * F -> T && F
942                          *
943                          * If T is False, the whole thing will be False, but
944                          * we have to parse the r.h.s. anyway (to throw it
945                          * away). If T is True, the result is the r.h.s.,
946                          * be it an Err or no.
947                          */
948                         if (l == True) {
949                                 l = CondF(doEval);
950                         } else {
951                                 CondF(FALSE);
952                         }
953                 } else {
954                         /*
955                          * F -> T
956                          */
957                         CondPushBack(o);
958                 }
959         }
960         return (l);
961 }
962
963 /**
964  * CondE --
965  *      Main expression production.
966  *          E -> F || E | F
967  *
968  * Results:
969  *      True, False or Err.
970  *
971  * Side Effects:
972  *      Tokens are, of course, consumed.
973  */
974 static Token
975 CondE(Boolean doEval)
976 {
977         Token   l, o;
978
979         l = CondF(doEval);
980         if (l != Err) {
981                 o = CondToken(doEval);
982
983                 if (o == Or) {
984                         /*
985                          * E -> F || E
986                          *
987                          * A similar thing occurs for ||, except that here we
988                          * make sure the l.h.s. is False before we bother to
989                          * evaluate the r.h.s. Once again, if l is False, the
990                          * result is the r.h.s. and once again if l is True,
991                          * we parse the r.h.s. to throw it away.
992                          */
993                         if (l == False) {
994                                 l = CondE(doEval);
995                         } else {
996                                 CondE(FALSE);
997                         }
998                 } else {
999                         /*
1000                          * E -> F
1001                          */
1002                         CondPushBack(o);
1003                 }
1004         }
1005         return (l);
1006 }
1007
1008 /**
1009  * Cond_If
1010  *      Handle .if<X> and .elif<X> directives.
1011  *      This function is called even when we're skipping.
1012  */
1013 void
1014 Cond_If(char *line, int code, int lineno)
1015 {
1016         const struct If *ifp;
1017         Boolean value;
1018
1019         ifp = &ifs[code];
1020
1021         if (ifp->isElse) {
1022                 if (condTop == MAXIF) {
1023                         Parse_Error(PARSE_FATAL, "if-less elif");
1024                         return;
1025                 }
1026                 if (skipIfLevel != 0) {
1027                         /*
1028                          * If skipping this conditional, just ignore
1029                          * the whole thing. If we don't, the user
1030                          * might be employing a variable that's
1031                          * undefined, for which there's an enclosing
1032                          * ifdef that we're skipping...
1033                          */
1034                         skipIfLineno[skipIfLevel - 1] = lineno;
1035                         return;
1036                 }
1037
1038         } else if (skipLine) {
1039                 /*
1040                  * Don't even try to evaluate a conditional that's
1041                  * not an else if we're skipping things...
1042                  */
1043                 skipIfLineno[skipIfLevel] = lineno;
1044                 skipIfLevel += 1;
1045                 return;
1046         }
1047
1048         /*
1049          * Initialize file-global variables for parsing
1050          */
1051         condDefProc = ifp->defProc;
1052         condInvert = ifp->doNot;
1053
1054         while (*line == ' ' || *line == '\t') {
1055                 line++;
1056         }
1057
1058         condExpr = line;
1059         condPushBack = None;
1060
1061         switch (CondE(TRUE)) {
1062           case True:
1063                 if (CondToken(TRUE) != EndOfFile)
1064                         goto err;
1065                 value = TRUE;
1066                 break;
1067
1068           case False:
1069                 if (CondToken(TRUE) != EndOfFile)
1070                         goto err;
1071                 value = FALSE;
1072                 break;
1073
1074           case Err:
1075   err:          Parse_Error(PARSE_FATAL, "Malformed conditional (%s)", line);
1076                 return;
1077
1078           default:
1079                 abort();
1080         }
1081
1082         if (!ifp->isElse) {
1083                 /* push this value */
1084                 condTop -= 1;
1085
1086         } else if (skipIfLevel != 0 || condStack[condTop]) {
1087                 /*
1088                  * If this is an else-type conditional, it should only take
1089                  * effect if its corresponding if was evaluated and FALSE.
1090                  * If its if was TRUE or skipped, we return COND_SKIP (and
1091                  * start skipping in case we weren't already), leaving the
1092                  * stack unmolested so later elif's don't screw up...
1093                  */
1094                 skipLine = TRUE;
1095                 return;
1096         }
1097
1098         if (condTop < 0) {
1099                 /*
1100                  * This is the one case where we can definitely proclaim a fatal
1101                  * error. If we don't, we're hosed.
1102                  */
1103                 Parse_Error(PARSE_FATAL, "Too many nested if's. %d max.",MAXIF);
1104                 return;
1105         }
1106
1107         /* push */
1108         condStack[condTop] = value;
1109         condLineno[condTop] = lineno;
1110         skipLine = !value;
1111 }
1112
1113 /**
1114  * Cond_Else
1115  *      Handle .else statement.
1116  */
1117 void
1118 Cond_Else(char *line __unused, int code __unused, int lineno __unused)
1119 {
1120
1121         while (isspace((u_char)*line))
1122                 line++;
1123
1124         if (*line != '\0' && (warn_flags & WARN_DIRSYNTAX)) {
1125                 Parse_Error(PARSE_WARNING, "junk after .else ignored '%s'",
1126                     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' && (warn_flags & WARN_DIRSYNTAX)) {
1166                 Parse_Error(PARSE_WARNING, "junk after .endif ignored '%s'",
1167                     line);
1168         }
1169
1170         /*
1171          * End of a conditional section. If skipIfLevel is non-zero,
1172          * that conditional was skipped, so lines following it should
1173          * also be skipped. Hence, we return COND_SKIP. Otherwise,
1174          * the conditional was read so succeeding lines should be
1175          * parsed (think about it...) so we return COND_PARSE, unless
1176          * this endif isn't paired with a decent if.
1177          */
1178         if (skipIfLevel != 0) {
1179                 skipIfLevel -= 1;
1180                 return;
1181         }
1182
1183         if (condTop == MAXIF) {
1184                 Parse_Error(PARSE_FATAL, "if-less endif");
1185                 return;
1186         }
1187
1188         /* pop */
1189         skipLine = FALSE;
1190         condTop += 1;
1191 }
1192
1193 /**
1194  * Cond_End
1195  *      Make sure everything's clean at the end of a makefile.
1196  *
1197  * Side Effects:
1198  *      Parse_Error will be called if open conditionals are around.
1199  */
1200 void
1201 Cond_End(void)
1202 {
1203         int level;
1204
1205         if (condTop != MAXIF) {
1206                 Parse_Error(PARSE_FATAL, "%d open conditional%s:",
1207                     MAXIF - condTop + skipIfLevel,
1208                     MAXIF - condTop + skipIfLevel== 1 ? "" : "s");
1209
1210                 for (level = skipIfLevel; level > 0; level--)
1211                         Parse_Error(PARSE_FATAL, "\t%*sat line %d (skipped)",
1212                             MAXIF - condTop + level + 1, "",
1213                             skipIfLineno[level - 1]);
1214                 for (level = condTop; level < MAXIF; level++)
1215                         Parse_Error(PARSE_FATAL, "\t%*sat line %d "
1216                             "(evaluated to %s)", MAXIF - level + skipIfLevel,
1217                             "", condLineno[level],
1218                             condStack[level] ? "true" : "false");
1219         }
1220         condTop = MAXIF;
1221 }