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