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