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