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