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