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