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