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