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