1 /* $NetBSD: cond.c,v 1.64 2012/06/12 19:21:50 joerg 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.64 2012/06/12 19:21:50 joerg 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.64 2012/06/12 19:21:50 joerg 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 #include <errno.h> /* For strtoul() error checking */ 96 97 #include "make.h" 98 #include "hash.h" 99 #include "dir.h" 100 #include "buf.h" 101 102 /* 103 * The parsing of conditional expressions is based on this grammar: 104 * E -> F || E 105 * E -> F 106 * F -> T && F 107 * F -> T 108 * T -> defined(variable) 109 * T -> make(target) 110 * T -> exists(file) 111 * T -> empty(varspec) 112 * T -> target(name) 113 * T -> commands(name) 114 * T -> symbol 115 * T -> $(varspec) op value 116 * T -> $(varspec) == "string" 117 * T -> $(varspec) != "string" 118 * T -> "string" 119 * T -> ( E ) 120 * T -> ! T 121 * op -> == | != | > | < | >= | <= 122 * 123 * 'symbol' is some other symbol to which the default function (condDefProc) 124 * is applied. 125 * 126 * Tokens are scanned from the 'condExpr' string. The scanner (CondToken) 127 * will return TOK_AND for '&' and '&&', TOK_OR for '|' and '||', 128 * TOK_NOT for '!', TOK_LPAREN for '(', TOK_RPAREN for ')' and will evaluate 129 * the other terminal symbols, using either the default function or the 130 * function given in the terminal, and return the result as either TOK_TRUE 131 * or TOK_FALSE. 132 * 133 * TOK_FALSE is 0 and TOK_TRUE 1 so we can directly assign C comparisons. 134 * 135 * All Non-Terminal functions (CondE, CondF and CondT) return TOK_ERROR on 136 * error. 137 */ 138 typedef enum { 139 TOK_FALSE = 0, TOK_TRUE = 1, TOK_AND, TOK_OR, TOK_NOT, 140 TOK_LPAREN, TOK_RPAREN, TOK_EOF, TOK_NONE, TOK_ERROR 141 } Token; 142 143 /*- 144 * Structures to handle elegantly the different forms of #if's. The 145 * last two fields are stored in condInvert and condDefProc, respectively. 146 */ 147 static void CondPushBack(Token); 148 static int CondGetArg(char **, char **, const char *); 149 static Boolean CondDoDefined(int, const char *); 150 static int CondStrMatch(const void *, const void *); 151 static Boolean CondDoMake(int, const char *); 152 static Boolean CondDoExists(int, const char *); 153 static Boolean CondDoTarget(int, const char *); 154 static Boolean CondDoCommands(int, const char *); 155 static Boolean CondCvtArg(char *, double *); 156 static Token CondToken(Boolean); 157 static Token CondT(Boolean); 158 static Token CondF(Boolean); 159 static Token CondE(Boolean); 160 static int do_Cond_EvalExpression(Boolean *); 161 162 static const struct If { 163 const char *form; /* Form of if */ 164 int formlen; /* Length of form */ 165 Boolean doNot; /* TRUE if default function should be negated */ 166 Boolean (*defProc)(int, const char *); /* Default function to apply */ 167 } ifs[] = { 168 { "def", 3, FALSE, CondDoDefined }, 169 { "ndef", 4, TRUE, CondDoDefined }, 170 { "make", 4, FALSE, CondDoMake }, 171 { "nmake", 5, TRUE, CondDoMake }, 172 { "", 0, FALSE, CondDoDefined }, 173 { NULL, 0, FALSE, NULL } 174 }; 175 176 static const struct If *if_info; /* Info for current statement */ 177 static char *condExpr; /* The expression to parse */ 178 static Token condPushBack=TOK_NONE; /* Single push-back token used in 179 * parsing */ 180 181 static unsigned int cond_depth = 0; /* current .if nesting level */ 182 static unsigned int cond_min_depth = 0; /* depth at makefile open */ 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) 232 { 233 char *cp; 234 int argLen; 235 Buffer buf; 236 int paren_depth; 237 char ch; 238 239 cp = *linePtr; 240 if (func != NULL) 241 /* Skip opening '(' - verfied by caller */ 242 cp++; 243 244 if (*cp == '\0') { 245 /* 246 * No arguments whatsoever. Because 'make' and 'defined' aren't really 247 * "reserved words", we don't print a message. I think this is better 248 * than hitting the user with a warning message every time s/he uses 249 * the word 'make' or 'defined' at the beginning of a symbol... 250 */ 251 *argPtr = NULL; 252 return (0); 253 } 254 255 while (*cp == ' ' || *cp == '\t') { 256 cp++; 257 } 258 259 /* 260 * Create a buffer for the argument and start it out at 16 characters 261 * long. Why 16? Why not? 262 */ 263 Buf_Init(&buf, 16); 264 265 paren_depth = 0; 266 for (;;) { 267 ch = *cp; 268 if (ch == 0 || ch == ' ' || ch == '\t') 269 break; 270 if ((ch == '&' || ch == '|') && paren_depth == 0) 271 break; 272 if (*cp == '$') { 273 /* 274 * Parse the variable spec and install it as part of the argument 275 * if it's valid. We tell Var_Parse to complain on an undefined 276 * variable, so we don't do it too. Nor do we return an error, 277 * though perhaps we should... 278 */ 279 char *cp2; 280 int len; 281 void *freeIt; 282 283 cp2 = Var_Parse(cp, VAR_CMD, TRUE, &len, &freeIt); 284 Buf_AddBytes(&buf, strlen(cp2), cp2); 285 if (freeIt) 286 free(freeIt); 287 cp += len; 288 continue; 289 } 290 if (ch == '(') 291 paren_depth++; 292 else 293 if (ch == ')' && --paren_depth < 0) 294 break; 295 Buf_AddByte(&buf, *cp); 296 cp++; 297 } 298 299 *argPtr = Buf_GetAll(&buf, &argLen); 300 Buf_Destroy(&buf, FALSE); 301 302 while (*cp == ' ' || *cp == '\t') { 303 cp++; 304 } 305 306 if (func != NULL && *cp++ != ')') { 307 Parse_Error(PARSE_WARNING, "Missing closing parenthesis for %s()", 308 func); 309 return (0); 310 } 311 312 *linePtr = cp; 313 return (argLen); 314 } 315 316 /*- 317 *----------------------------------------------------------------------- 318 * CondDoDefined -- 319 * Handle the 'defined' function for conditionals. 320 * 321 * Results: 322 * TRUE if the given variable is defined. 323 * 324 * Side Effects: 325 * None. 326 * 327 *----------------------------------------------------------------------- 328 */ 329 static Boolean 330 CondDoDefined(int argLen MAKE_ATTR_UNUSED, const char *arg) 331 { 332 char *p1; 333 Boolean result; 334 335 if (Var_Value(arg, VAR_CMD, &p1) != NULL) { 336 result = TRUE; 337 } else { 338 result = FALSE; 339 } 340 if (p1) 341 free(p1); 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(const void *string, const void *pattern) 361 { 362 return(!Str_Match(string, 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 MAKE_ATTR_UNUSED, const char *arg) 380 { 381 return Lst_Find(create, arg, CondStrMatch) != NULL; 382 } 383 384 /*- 385 *----------------------------------------------------------------------- 386 * CondDoExists -- 387 * See if the given file exists. 388 * 389 * Results: 390 * TRUE if the file exists and FALSE if it does not. 391 * 392 * Side Effects: 393 * None. 394 * 395 *----------------------------------------------------------------------- 396 */ 397 static Boolean 398 CondDoExists(int argLen MAKE_ATTR_UNUSED, const char *arg) 399 { 400 Boolean result; 401 char *path; 402 403 path = Dir_FindFile(arg, dirSearchPath); 404 if (DEBUG(COND)) { 405 fprintf(debug_file, "exists(%s) result is \"%s\"\n", 406 arg, path ? path : ""); 407 } 408 if (path != NULL) { 409 result = TRUE; 410 free(path); 411 } else { 412 result = FALSE; 413 } 414 return (result); 415 } 416 417 /*- 418 *----------------------------------------------------------------------- 419 * CondDoTarget -- 420 * See if the given node exists and is an actual target. 421 * 422 * Results: 423 * TRUE if the node exists as a target and FALSE if it does not. 424 * 425 * Side Effects: 426 * None. 427 * 428 *----------------------------------------------------------------------- 429 */ 430 static Boolean 431 CondDoTarget(int argLen MAKE_ATTR_UNUSED, const char *arg) 432 { 433 GNode *gn; 434 435 gn = Targ_FindNode(arg, TARG_NOCREATE); 436 return (gn != NULL) && !OP_NOP(gn->type); 437 } 438 439 /*- 440 *----------------------------------------------------------------------- 441 * CondDoCommands -- 442 * See if the given node exists and is an actual target with commands 443 * associated with it. 444 * 445 * Results: 446 * TRUE if the node exists as a target and has commands associated with 447 * it and FALSE if it does not. 448 * 449 * Side Effects: 450 * None. 451 * 452 *----------------------------------------------------------------------- 453 */ 454 static Boolean 455 CondDoCommands(int argLen MAKE_ATTR_UNUSED, const char *arg) 456 { 457 GNode *gn; 458 459 gn = Targ_FindNode(arg, TARG_NOCREATE); 460 return (gn != NULL) && !OP_NOP(gn->type) && !Lst_IsEmpty(gn->commands); 461 } 462 463 /*- 464 *----------------------------------------------------------------------- 465 * CondCvtArg -- 466 * Convert the given number into a double. 467 * We try a base 10 or 16 integer conversion first, if that fails 468 * then we try a floating point conversion instead. 469 * 470 * Results: 471 * Sets 'value' to double value of string. 472 * Returns 'true' if the convertion suceeded 473 * 474 *----------------------------------------------------------------------- 475 */ 476 static Boolean 477 CondCvtArg(char *str, double *value) 478 { 479 char *eptr, ech; 480 unsigned long l_val; 481 double d_val; 482 483 errno = 0; 484 l_val = strtoul(str, &eptr, str[1] == 'x' ? 16 : 10); 485 ech = *eptr; 486 if (ech == 0 && errno != ERANGE) { 487 d_val = str[0] == '-' ? -(double)-l_val : (double)l_val; 488 } else { 489 if (ech != 0 && ech != '.' && ech != 'e' && ech != 'E') 490 return FALSE; 491 d_val = strtod(str, &eptr); 492 if (*eptr) 493 return FALSE; 494 } 495 496 *value = d_val; 497 return TRUE; 498 } 499 500 /*- 501 *----------------------------------------------------------------------- 502 * CondGetString -- 503 * Get a string from a variable reference or an optionally quoted 504 * string. This is called for the lhs and rhs of string compares. 505 * 506 * Results: 507 * Sets freeIt if needed, 508 * Sets quoted if string was quoted, 509 * Returns NULL on error, 510 * else returns string - absent any quotes. 511 * 512 * Side Effects: 513 * Moves condExpr to end of this token. 514 * 515 * 516 *----------------------------------------------------------------------- 517 */ 518 /* coverity:[+alloc : arg-*2] */ 519 static char * 520 CondGetString(Boolean doEval, Boolean *quoted, void **freeIt) 521 { 522 Buffer buf; 523 char *cp; 524 char *str; 525 int len; 526 int qt; 527 char *start; 528 529 Buf_Init(&buf, 0); 530 str = NULL; 531 *freeIt = NULL; 532 *quoted = qt = *condExpr == '"' ? 1 : 0; 533 if (qt) 534 condExpr++; 535 for (start = condExpr; *condExpr && str == NULL; condExpr++) { 536 switch (*condExpr) { 537 case '\\': 538 if (condExpr[1] != '\0') { 539 condExpr++; 540 Buf_AddByte(&buf, *condExpr); 541 } 542 break; 543 case '"': 544 if (qt) { 545 condExpr++; /* we don't want the quotes */ 546 goto got_str; 547 } else 548 Buf_AddByte(&buf, *condExpr); /* likely? */ 549 break; 550 case ')': 551 case '!': 552 case '=': 553 case '>': 554 case '<': 555 case ' ': 556 case '\t': 557 if (!qt) 558 goto got_str; 559 else 560 Buf_AddByte(&buf, *condExpr); 561 break; 562 case '$': 563 /* if we are in quotes, then an undefined variable is ok */ 564 str = Var_Parse(condExpr, VAR_CMD, (qt ? 0 : doEval), 565 &len, freeIt); 566 if (str == var_Error) { 567 if (*freeIt) { 568 free(*freeIt); 569 *freeIt = NULL; 570 } 571 /* 572 * Even if !doEval, we still report syntax errors, which 573 * is what getting var_Error back with !doEval means. 574 */ 575 str = NULL; 576 goto cleanup; 577 } 578 condExpr += len; 579 /* 580 * If the '$' was first char (no quotes), and we are 581 * followed by space, the operator or end of expression, 582 * we are done. 583 */ 584 if ((condExpr == start + len) && 585 (*condExpr == '\0' || 586 isspace((unsigned char) *condExpr) || 587 strchr("!=><)", *condExpr))) { 588 goto cleanup; 589 } 590 /* 591 * Nope, we better copy str to buf 592 */ 593 for (cp = str; *cp; cp++) { 594 Buf_AddByte(&buf, *cp); 595 } 596 if (*freeIt) { 597 free(*freeIt); 598 *freeIt = NULL; 599 } 600 str = NULL; /* not finished yet */ 601 condExpr--; /* don't skip over next char */ 602 break; 603 default: 604 Buf_AddByte(&buf, *condExpr); 605 break; 606 } 607 } 608 got_str: 609 str = Buf_GetAll(&buf, NULL); 610 *freeIt = str; 611 cleanup: 612 Buf_Destroy(&buf, FALSE); 613 return str; 614 } 615 616 /*- 617 *----------------------------------------------------------------------- 618 * CondToken -- 619 * Return the next token from the input. 620 * 621 * Results: 622 * A Token for the next lexical token in the stream. 623 * 624 * Side Effects: 625 * condPushback will be set back to TOK_NONE if it is used. 626 * 627 *----------------------------------------------------------------------- 628 */ 629 static Token 630 compare_expression(Boolean doEval) 631 { 632 Token t; 633 char *lhs; 634 char *rhs; 635 char *op; 636 void *lhsFree; 637 void *rhsFree; 638 Boolean lhsQuoted; 639 Boolean rhsQuoted; 640 double left, right; 641 642 t = TOK_ERROR; 643 rhs = NULL; 644 lhsFree = rhsFree = FALSE; 645 lhsQuoted = rhsQuoted = FALSE; 646 647 /* 648 * Parse the variable spec and skip over it, saving its 649 * value in lhs. 650 */ 651 lhs = CondGetString(doEval, &lhsQuoted, &lhsFree); 652 if (!lhs) 653 goto done; 654 655 /* 656 * Skip whitespace to get to the operator 657 */ 658 while (isspace((unsigned char) *condExpr)) 659 condExpr++; 660 661 /* 662 * Make sure the operator is a valid one. If it isn't a 663 * known relational operator, pretend we got a 664 * != 0 comparison. 665 */ 666 op = condExpr; 667 switch (*condExpr) { 668 case '!': 669 case '=': 670 case '<': 671 case '>': 672 if (condExpr[1] == '=') { 673 condExpr += 2; 674 } else { 675 condExpr += 1; 676 } 677 break; 678 default: 679 if (!doEval) { 680 t = TOK_FALSE; 681 goto done; 682 } 683 /* For .ifxxx "..." check for non-empty string. */ 684 if (lhsQuoted) { 685 t = lhs[0] != 0; 686 goto done; 687 } 688 /* For .ifxxx <number> compare against zero */ 689 if (CondCvtArg(lhs, &left)) { 690 t = left != 0.0; 691 goto done; 692 } 693 /* For .if ${...} check for non-empty string (defProc is ifdef). */ 694 if (if_info->form[0] == 0) { 695 t = lhs[0] != 0; 696 goto done; 697 } 698 /* Otherwise action default test ... */ 699 t = if_info->defProc(strlen(lhs), lhs) != if_info->doNot; 700 goto done; 701 } 702 703 while (isspace((unsigned char)*condExpr)) 704 condExpr++; 705 706 if (*condExpr == '\0') { 707 Parse_Error(PARSE_WARNING, 708 "Missing right-hand-side of operator"); 709 goto done; 710 } 711 712 rhs = CondGetString(doEval, &rhsQuoted, &rhsFree); 713 if (!rhs) 714 goto done; 715 716 if (rhsQuoted || lhsQuoted) { 717 do_string_compare: 718 if (((*op != '!') && (*op != '=')) || (op[1] != '=')) { 719 Parse_Error(PARSE_WARNING, 720 "String comparison operator should be either == or !="); 721 goto done; 722 } 723 724 if (DEBUG(COND)) { 725 fprintf(debug_file, "lhs = \"%s\", rhs = \"%s\", op = %.2s\n", 726 lhs, rhs, op); 727 } 728 /* 729 * Null-terminate rhs and perform the comparison. 730 * t is set to the result. 731 */ 732 if (*op == '=') { 733 t = strcmp(lhs, rhs) == 0; 734 } else { 735 t = strcmp(lhs, rhs) != 0; 736 } 737 } else { 738 /* 739 * rhs is either a float or an integer. Convert both the 740 * lhs and the rhs to a double and compare the two. 741 */ 742 743 if (!CondCvtArg(lhs, &left) || !CondCvtArg(rhs, &right)) 744 goto do_string_compare; 745 746 if (DEBUG(COND)) { 747 fprintf(debug_file, "left = %f, right = %f, op = %.2s\n", left, 748 right, op); 749 } 750 switch(op[0]) { 751 case '!': 752 if (op[1] != '=') { 753 Parse_Error(PARSE_WARNING, 754 "Unknown operator"); 755 goto done; 756 } 757 t = (left != right); 758 break; 759 case '=': 760 if (op[1] != '=') { 761 Parse_Error(PARSE_WARNING, 762 "Unknown operator"); 763 goto done; 764 } 765 t = (left == right); 766 break; 767 case '<': 768 if (op[1] == '=') { 769 t = (left <= right); 770 } else { 771 t = (left < right); 772 } 773 break; 774 case '>': 775 if (op[1] == '=') { 776 t = (left >= right); 777 } else { 778 t = (left > right); 779 } 780 break; 781 } 782 } 783 784 done: 785 if (lhsFree) 786 free(lhsFree); 787 if (rhsFree) 788 free(rhsFree); 789 return t; 790 } 791 792 static int 793 get_mpt_arg(char **linePtr, char **argPtr, const char *func MAKE_ATTR_UNUSED) 794 { 795 /* 796 * Use Var_Parse to parse the spec in parens and return 797 * TOK_TRUE if the resulting string is empty. 798 */ 799 int length; 800 void *freeIt; 801 char *val; 802 char *cp = *linePtr; 803 804 /* We do all the work here and return the result as the length */ 805 *argPtr = NULL; 806 807 val = Var_Parse(cp - 1, VAR_CMD, FALSE, &length, &freeIt); 808 /* 809 * Advance *linePtr to beyond the closing ). Note that 810 * we subtract one because 'length' is calculated from 'cp - 1'. 811 */ 812 *linePtr = cp - 1 + length; 813 814 if (val == var_Error) { 815 free(freeIt); 816 return -1; 817 } 818 819 /* A variable is empty when it just contains spaces... 4/15/92, christos */ 820 while (isspace(*(unsigned char *)val)) 821 val++; 822 823 /* 824 * For consistency with the other functions we can't generate the 825 * true/false here. 826 */ 827 length = *val ? 2 : 1; 828 if (freeIt) 829 free(freeIt); 830 return length; 831 } 832 833 static Boolean 834 CondDoEmpty(int arglen, const char *arg MAKE_ATTR_UNUSED) 835 { 836 return arglen == 1; 837 } 838 839 static Token 840 compare_function(Boolean doEval) 841 { 842 static const struct fn_def { 843 const char *fn_name; 844 int fn_name_len; 845 int (*fn_getarg)(char **, char **, const char *); 846 Boolean (*fn_proc)(int, const char *); 847 } fn_defs[] = { 848 { "defined", 7, CondGetArg, CondDoDefined }, 849 { "make", 4, CondGetArg, CondDoMake }, 850 { "exists", 6, CondGetArg, CondDoExists }, 851 { "empty", 5, get_mpt_arg, CondDoEmpty }, 852 { "target", 6, CondGetArg, CondDoTarget }, 853 { "commands", 8, CondGetArg, CondDoCommands }, 854 { NULL, 0, NULL, NULL }, 855 }; 856 const struct fn_def *fn_def; 857 Token t; 858 char *arg = NULL; 859 int arglen; 860 char *cp = condExpr; 861 char *cp1; 862 863 for (fn_def = fn_defs; fn_def->fn_name != NULL; fn_def++) { 864 if (!istoken(cp, fn_def->fn_name, fn_def->fn_name_len)) 865 continue; 866 cp += fn_def->fn_name_len; 867 /* There can only be whitespace before the '(' */ 868 while (isspace(*(unsigned char *)cp)) 869 cp++; 870 if (*cp != '(') 871 break; 872 873 arglen = fn_def->fn_getarg(&cp, &arg, fn_def->fn_name); 874 if (arglen <= 0) { 875 condExpr = cp; 876 return arglen < 0 ? TOK_ERROR : TOK_FALSE; 877 } 878 /* Evaluate the argument using the required function. */ 879 t = !doEval || fn_def->fn_proc(arglen, arg); 880 if (arg) 881 free(arg); 882 condExpr = cp; 883 return t; 884 } 885 886 /* Push anything numeric through the compare expression */ 887 cp = condExpr; 888 if (isdigit((unsigned char)cp[0]) || strchr("+-", cp[0])) 889 return compare_expression(doEval); 890 891 /* 892 * Most likely we have a naked token to apply the default function to. 893 * However ".if a == b" gets here when the "a" is unquoted and doesn't 894 * start with a '$'. This surprises people. 895 * If what follows the function argument is a '=' or '!' then the syntax 896 * would be invalid if we did "defined(a)" - so instead treat as an 897 * expression. 898 */ 899 arglen = CondGetArg(&cp, &arg, NULL); 900 for (cp1 = cp; isspace(*(unsigned char *)cp1); cp1++) 901 continue; 902 if (*cp1 == '=' || *cp1 == '!') 903 return compare_expression(doEval); 904 condExpr = cp; 905 906 /* 907 * Evaluate the argument using the default function. 908 * This path always treats .if as .ifdef. To get here the character 909 * after .if must have been taken literally, so the argument cannot 910 * be empty - even if it contained a variable expansion. 911 */ 912 t = !doEval || if_info->defProc(arglen, arg) != if_info->doNot; 913 if (arg) 914 free(arg); 915 return t; 916 } 917 918 static Token 919 CondToken(Boolean doEval) 920 { 921 Token t; 922 923 t = condPushBack; 924 if (t != TOK_NONE) { 925 condPushBack = TOK_NONE; 926 return t; 927 } 928 929 while (*condExpr == ' ' || *condExpr == '\t') { 930 condExpr++; 931 } 932 933 switch (*condExpr) { 934 935 case '(': 936 condExpr++; 937 return TOK_LPAREN; 938 939 case ')': 940 condExpr++; 941 return TOK_RPAREN; 942 943 case '|': 944 if (condExpr[1] == '|') { 945 condExpr++; 946 } 947 condExpr++; 948 return TOK_OR; 949 950 case '&': 951 if (condExpr[1] == '&') { 952 condExpr++; 953 } 954 condExpr++; 955 return TOK_AND; 956 957 case '!': 958 condExpr++; 959 return TOK_NOT; 960 961 case '#': 962 case '\n': 963 case '\0': 964 return TOK_EOF; 965 966 case '"': 967 case '$': 968 return compare_expression(doEval); 969 970 default: 971 return compare_function(doEval); 972 } 973 } 974 975 /*- 976 *----------------------------------------------------------------------- 977 * CondT -- 978 * Parse a single term in the expression. This consists of a terminal 979 * symbol or TOK_NOT and a terminal symbol (not including the binary 980 * operators): 981 * T -> defined(variable) | make(target) | exists(file) | symbol 982 * T -> ! T | ( E ) 983 * 984 * Results: 985 * TOK_TRUE, TOK_FALSE or TOK_ERROR. 986 * 987 * Side Effects: 988 * Tokens are consumed. 989 * 990 *----------------------------------------------------------------------- 991 */ 992 static Token 993 CondT(Boolean doEval) 994 { 995 Token t; 996 997 t = CondToken(doEval); 998 999 if (t == TOK_EOF) { 1000 /* 1001 * If we reached the end of the expression, the expression 1002 * is malformed... 1003 */ 1004 t = TOK_ERROR; 1005 } else if (t == TOK_LPAREN) { 1006 /* 1007 * T -> ( E ) 1008 */ 1009 t = CondE(doEval); 1010 if (t != TOK_ERROR) { 1011 if (CondToken(doEval) != TOK_RPAREN) { 1012 t = TOK_ERROR; 1013 } 1014 } 1015 } else if (t == TOK_NOT) { 1016 t = CondT(doEval); 1017 if (t == TOK_TRUE) { 1018 t = TOK_FALSE; 1019 } else if (t == TOK_FALSE) { 1020 t = TOK_TRUE; 1021 } 1022 } 1023 return (t); 1024 } 1025 1026 /*- 1027 *----------------------------------------------------------------------- 1028 * CondF -- 1029 * Parse a conjunctive factor (nice name, wot?) 1030 * F -> T && F | T 1031 * 1032 * Results: 1033 * TOK_TRUE, TOK_FALSE or TOK_ERROR 1034 * 1035 * Side Effects: 1036 * Tokens are consumed. 1037 * 1038 *----------------------------------------------------------------------- 1039 */ 1040 static Token 1041 CondF(Boolean doEval) 1042 { 1043 Token l, o; 1044 1045 l = CondT(doEval); 1046 if (l != TOK_ERROR) { 1047 o = CondToken(doEval); 1048 1049 if (o == TOK_AND) { 1050 /* 1051 * F -> T && F 1052 * 1053 * If T is TOK_FALSE, the whole thing will be TOK_FALSE, but we have to 1054 * parse the r.h.s. anyway (to throw it away). 1055 * If T is TOK_TRUE, the result is the r.h.s., be it an TOK_ERROR or no. 1056 */ 1057 if (l == TOK_TRUE) { 1058 l = CondF(doEval); 1059 } else { 1060 (void)CondF(FALSE); 1061 } 1062 } else { 1063 /* 1064 * F -> T 1065 */ 1066 CondPushBack(o); 1067 } 1068 } 1069 return (l); 1070 } 1071 1072 /*- 1073 *----------------------------------------------------------------------- 1074 * CondE -- 1075 * Main expression production. 1076 * E -> F || E | F 1077 * 1078 * Results: 1079 * TOK_TRUE, TOK_FALSE or TOK_ERROR. 1080 * 1081 * Side Effects: 1082 * Tokens are, of course, consumed. 1083 * 1084 *----------------------------------------------------------------------- 1085 */ 1086 static Token 1087 CondE(Boolean doEval) 1088 { 1089 Token l, o; 1090 1091 l = CondF(doEval); 1092 if (l != TOK_ERROR) { 1093 o = CondToken(doEval); 1094 1095 if (o == TOK_OR) { 1096 /* 1097 * E -> F || E 1098 * 1099 * A similar thing occurs for ||, except that here we make sure 1100 * the l.h.s. is TOK_FALSE before we bother to evaluate the r.h.s. 1101 * Once again, if l is TOK_FALSE, the result is the r.h.s. and once 1102 * again if l is TOK_TRUE, we parse the r.h.s. to throw it away. 1103 */ 1104 if (l == TOK_FALSE) { 1105 l = CondE(doEval); 1106 } else { 1107 (void)CondE(FALSE); 1108 } 1109 } else { 1110 /* 1111 * E -> F 1112 */ 1113 CondPushBack(o); 1114 } 1115 } 1116 return (l); 1117 } 1118 1119 /*- 1120 *----------------------------------------------------------------------- 1121 * Cond_EvalExpression -- 1122 * Evaluate an expression in the passed line. The expression 1123 * consists of &&, ||, !, make(target), defined(variable) 1124 * and parenthetical groupings thereof. 1125 * 1126 * Results: 1127 * COND_PARSE if the condition was valid grammatically 1128 * COND_INVALID if not a valid conditional. 1129 * 1130 * (*value) is set to the boolean value of the condition 1131 * 1132 * Side Effects: 1133 * None. 1134 * 1135 *----------------------------------------------------------------------- 1136 */ 1137 int 1138 Cond_EvalExpression(const struct If *info, char *line, Boolean *value, int eprint) 1139 { 1140 static const struct If *dflt_info; 1141 const struct If *sv_if_info = if_info; 1142 char *sv_condExpr = condExpr; 1143 Token sv_condPushBack = condPushBack; 1144 int rval; 1145 1146 while (*line == ' ' || *line == '\t') 1147 line++; 1148 1149 if (info == NULL && (info = dflt_info) == NULL) { 1150 /* Scan for the entry for .if - it can't be first */ 1151 for (info = ifs; ; info++) 1152 if (info->form[0] == 0) 1153 break; 1154 dflt_info = info; 1155 } 1156 1157 if_info = info != NULL ? info : ifs + 4; 1158 condExpr = line; 1159 condPushBack = TOK_NONE; 1160 1161 rval = do_Cond_EvalExpression(value); 1162 1163 if (rval == COND_INVALID && eprint) 1164 Parse_Error(PARSE_FATAL, "Malformed conditional (%s)", line); 1165 1166 if_info = sv_if_info; 1167 condExpr = sv_condExpr; 1168 condPushBack = sv_condPushBack; 1169 1170 return rval; 1171 } 1172 1173 static int 1174 do_Cond_EvalExpression(Boolean *value) 1175 { 1176 1177 switch (CondE(TRUE)) { 1178 case TOK_TRUE: 1179 if (CondToken(TRUE) == TOK_EOF) { 1180 *value = TRUE; 1181 return COND_PARSE; 1182 } 1183 break; 1184 case TOK_FALSE: 1185 if (CondToken(TRUE) == TOK_EOF) { 1186 *value = FALSE; 1187 return COND_PARSE; 1188 } 1189 break; 1190 default: 1191 case TOK_ERROR: 1192 break; 1193 } 1194 1195 return COND_INVALID; 1196 } 1197 1198 1199 /*- 1200 *----------------------------------------------------------------------- 1201 * Cond_Eval -- 1202 * Evaluate the conditional in the passed line. The line 1203 * looks like this: 1204 * .<cond-type> <expr> 1205 * where <cond-type> is any of if, ifmake, ifnmake, ifdef, 1206 * ifndef, elif, elifmake, elifnmake, elifdef, elifndef 1207 * and <expr> consists of &&, ||, !, make(target), defined(variable) 1208 * and parenthetical groupings thereof. 1209 * 1210 * Input: 1211 * line Line to parse 1212 * 1213 * Results: 1214 * COND_PARSE if should parse lines after the conditional 1215 * COND_SKIP if should skip lines after the conditional 1216 * COND_INVALID if not a valid conditional. 1217 * 1218 * Side Effects: 1219 * None. 1220 * 1221 * Note that the states IF_ACTIVE and ELSE_ACTIVE are only different in order 1222 * to detect splurious .else lines (as are SKIP_TO_ELSE and SKIP_TO_ENDIF) 1223 * otherwise .else could be treated as '.elif 1'. 1224 * 1225 *----------------------------------------------------------------------- 1226 */ 1227 int 1228 Cond_Eval(char *line) 1229 { 1230 #define MAXIF 128 /* maximum depth of .if'ing */ 1231 enum if_states { 1232 IF_ACTIVE, /* .if or .elif part active */ 1233 ELSE_ACTIVE, /* .else part active */ 1234 SEARCH_FOR_ELIF, /* searching for .elif/else to execute */ 1235 SKIP_TO_ELSE, /* has been true, but not seen '.else' */ 1236 SKIP_TO_ENDIF /* nothing else to execute */ 1237 }; 1238 static enum if_states cond_state[MAXIF + 1] = { IF_ACTIVE }; 1239 1240 const struct If *ifp; 1241 Boolean isElif; 1242 Boolean value; 1243 int level; /* Level at which to report errors. */ 1244 enum if_states state; 1245 1246 level = PARSE_FATAL; 1247 1248 /* skip leading character (the '.') and any whitespace */ 1249 for (line++; *line == ' ' || *line == '\t'; line++) 1250 continue; 1251 1252 /* Find what type of if we're dealing with. */ 1253 if (line[0] == 'e') { 1254 if (line[1] != 'l') { 1255 if (!istoken(line + 1, "ndif", 4)) 1256 return COND_INVALID; 1257 /* End of conditional section */ 1258 if (cond_depth == cond_min_depth) { 1259 Parse_Error(level, "if-less endif"); 1260 return COND_PARSE; 1261 } 1262 /* Return state for previous conditional */ 1263 cond_depth--; 1264 if (cond_depth > MAXIF) 1265 return COND_SKIP; 1266 return cond_state[cond_depth] <= ELSE_ACTIVE ? COND_PARSE : COND_SKIP; 1267 } 1268 1269 /* Quite likely this is 'else' or 'elif' */ 1270 line += 2; 1271 if (istoken(line, "se", 2)) { 1272 /* It is else... */ 1273 if (cond_depth == cond_min_depth) { 1274 Parse_Error(level, "if-less else"); 1275 return COND_PARSE; 1276 } 1277 1278 if (cond_depth > MAXIF) 1279 return COND_SKIP; 1280 state = cond_state[cond_depth]; 1281 switch (state) { 1282 case SEARCH_FOR_ELIF: 1283 state = ELSE_ACTIVE; 1284 break; 1285 case ELSE_ACTIVE: 1286 case SKIP_TO_ENDIF: 1287 Parse_Error(PARSE_WARNING, "extra else"); 1288 /* FALLTHROUGH */ 1289 default: 1290 case IF_ACTIVE: 1291 case SKIP_TO_ELSE: 1292 state = SKIP_TO_ENDIF; 1293 break; 1294 } 1295 cond_state[cond_depth] = state; 1296 return state <= ELSE_ACTIVE ? COND_PARSE : COND_SKIP; 1297 } 1298 /* Assume for now it is an elif */ 1299 isElif = TRUE; 1300 } else 1301 isElif = FALSE; 1302 1303 if (line[0] != 'i' || line[1] != 'f') 1304 /* Not an ifxxx or elifxxx line */ 1305 return COND_INVALID; 1306 1307 /* 1308 * Figure out what sort of conditional it is -- what its default 1309 * function is, etc. -- by looking in the table of valid "ifs" 1310 */ 1311 line += 2; 1312 for (ifp = ifs; ; ifp++) { 1313 if (ifp->form == NULL) 1314 return COND_INVALID; 1315 if (istoken(ifp->form, line, ifp->formlen)) { 1316 line += ifp->formlen; 1317 break; 1318 } 1319 } 1320 1321 /* Now we know what sort of 'if' it is... */ 1322 1323 if (isElif) { 1324 if (cond_depth == cond_min_depth) { 1325 Parse_Error(level, "if-less elif"); 1326 return COND_PARSE; 1327 } 1328 if (cond_depth > MAXIF) 1329 /* Error reported when we saw the .if ... */ 1330 return COND_SKIP; 1331 state = cond_state[cond_depth]; 1332 if (state == SKIP_TO_ENDIF || state == ELSE_ACTIVE) { 1333 Parse_Error(PARSE_WARNING, "extra elif"); 1334 cond_state[cond_depth] = SKIP_TO_ENDIF; 1335 return COND_SKIP; 1336 } 1337 if (state != SEARCH_FOR_ELIF) { 1338 /* Either just finished the 'true' block, or already SKIP_TO_ELSE */ 1339 cond_state[cond_depth] = SKIP_TO_ELSE; 1340 return COND_SKIP; 1341 } 1342 } else { 1343 /* Normal .if */ 1344 if (cond_depth >= MAXIF) { 1345 cond_depth++; 1346 Parse_Error(PARSE_FATAL, "Too many nested if's. %d max.", MAXIF); 1347 return COND_SKIP; 1348 } 1349 state = cond_state[cond_depth]; 1350 cond_depth++; 1351 if (state > ELSE_ACTIVE) { 1352 /* If we aren't parsing the data, treat as always false */ 1353 cond_state[cond_depth] = SKIP_TO_ELSE; 1354 return COND_SKIP; 1355 } 1356 } 1357 1358 /* And evaluate the conditional expresssion */ 1359 if (Cond_EvalExpression(ifp, line, &value, 1) == COND_INVALID) { 1360 /* Syntax error in conditional, error message already output. */ 1361 /* Skip everything to matching .endif */ 1362 cond_state[cond_depth] = SKIP_TO_ELSE; 1363 return COND_SKIP; 1364 } 1365 1366 if (!value) { 1367 cond_state[cond_depth] = SEARCH_FOR_ELIF; 1368 return COND_SKIP; 1369 } 1370 cond_state[cond_depth] = IF_ACTIVE; 1371 return COND_PARSE; 1372 } 1373 1374 1375 1376 /*- 1377 *----------------------------------------------------------------------- 1378 * Cond_End -- 1379 * Make sure everything's clean at the end of a makefile. 1380 * 1381 * Results: 1382 * None. 1383 * 1384 * Side Effects: 1385 * Parse_Error will be called if open conditionals are around. 1386 * 1387 *----------------------------------------------------------------------- 1388 */ 1389 void 1390 Cond_restore_depth(unsigned int saved_depth) 1391 { 1392 int open_conds = cond_depth - cond_min_depth; 1393 1394 if (open_conds != 0 || saved_depth > cond_depth) { 1395 Parse_Error(PARSE_FATAL, "%d open conditional%s", open_conds, 1396 open_conds == 1 ? "" : "s"); 1397 cond_depth = cond_min_depth; 1398 } 1399 1400 cond_min_depth = saved_depth; 1401 } 1402 1403 unsigned int 1404 Cond_save_depth(void) 1405 { 1406 int depth = cond_min_depth; 1407 1408 cond_min_depth = cond_depth; 1409 return depth; 1410 } 1411