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