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