1 /* $NetBSD: cond.c,v 1.37 2007/02/04 19:23:49 dsl 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.37 2007/02/04 19:23:49 dsl 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.37 2007/02/04 19:23:49 dsl 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 const 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 { "def", 3, FALSE, CondDoDefined }, 162 { "ndef", 4, TRUE, CondDoDefined }, 163 { "make", 4, FALSE, CondDoMake }, 164 { "nmake", 5, TRUE, CondDoMake }, 165 { "", 0, 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 static unsigned int cond_depth = 0; /* current .if nesting level */ 176 static unsigned int cond_min_depth = 0; /* depth at makefile open */ 177 178 static int 179 istoken(const char *str, const char *tok, size_t len) 180 { 181 return strncmp(str, tok, len) == 0 && !isalpha((unsigned char)str[len]); 182 } 183 184 /*- 185 *----------------------------------------------------------------------- 186 * CondPushBack -- 187 * Push back the most recent token read. We only need one level of 188 * this, so the thing is just stored in 'condPushback'. 189 * 190 * Input: 191 * t Token to push back into the "stream" 192 * 193 * Results: 194 * None. 195 * 196 * Side Effects: 197 * condPushback is overwritten. 198 * 199 *----------------------------------------------------------------------- 200 */ 201 static void 202 CondPushBack(Token t) 203 { 204 condPushBack = t; 205 } 206 207 /*- 208 *----------------------------------------------------------------------- 209 * CondGetArg -- 210 * Find the argument of a built-in function. 211 * 212 * Input: 213 * parens TRUE if arg should be bounded by parens 214 * 215 * Results: 216 * The length of the argument and the address of the argument. 217 * 218 * Side Effects: 219 * The pointer is set to point to the closing parenthesis of the 220 * function call. 221 * 222 *----------------------------------------------------------------------- 223 */ 224 static int 225 CondGetArg(char **linePtr, char **argPtr, const char *func, Boolean parens) 226 { 227 char *cp; 228 int argLen; 229 Buffer buf; 230 231 cp = *linePtr; 232 if (parens) { 233 while (*cp != '(' && *cp != '\0') { 234 cp++; 235 } 236 if (*cp == '(') { 237 cp++; 238 } 239 } 240 241 if (*cp == '\0') { 242 /* 243 * No arguments whatsoever. Because 'make' and 'defined' aren't really 244 * "reserved words", we don't print a message. I think this is better 245 * than hitting the user with a warning message every time s/he uses 246 * the word 'make' or 'defined' at the beginning of a symbol... 247 */ 248 *argPtr = NULL; 249 return (0); 250 } 251 252 while (*cp == ' ' || *cp == '\t') { 253 cp++; 254 } 255 256 /* 257 * Create a buffer for the argument and start it out at 16 characters 258 * long. Why 16? Why not? 259 */ 260 buf = Buf_Init(16); 261 262 while ((strchr(" \t)&|", *cp) == NULL) && (*cp != '\0')) { 263 if (*cp == '$') { 264 /* 265 * Parse the variable spec and install it as part of the argument 266 * if it's valid. We tell Var_Parse to complain on an undefined 267 * variable, so we don't do it too. Nor do we return an error, 268 * though perhaps we should... 269 */ 270 char *cp2; 271 int len; 272 void *freeIt; 273 274 cp2 = Var_Parse(cp, VAR_CMD, TRUE, &len, &freeIt); 275 Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2); 276 if (freeIt) 277 free(freeIt); 278 cp += len; 279 } else { 280 Buf_AddByte(buf, (Byte)*cp); 281 cp++; 282 } 283 } 284 285 Buf_AddByte(buf, (Byte)'\0'); 286 *argPtr = (char *)Buf_GetAll(buf, &argLen); 287 Buf_Destroy(buf, FALSE); 288 289 while (*cp == ' ' || *cp == '\t') { 290 cp++; 291 } 292 if (parens && *cp != ')') { 293 Parse_Error(PARSE_WARNING, "Missing closing parenthesis for %s()", 294 func); 295 return (0); 296 } else if (parens) { 297 /* 298 * Advance pointer past close parenthesis. 299 */ 300 cp++; 301 } 302 303 *linePtr = cp; 304 return (argLen); 305 } 306 307 /*- 308 *----------------------------------------------------------------------- 309 * CondDoDefined -- 310 * Handle the 'defined' function for conditionals. 311 * 312 * Results: 313 * TRUE if the given variable is defined. 314 * 315 * Side Effects: 316 * None. 317 * 318 *----------------------------------------------------------------------- 319 */ 320 static Boolean 321 CondDoDefined(int argLen, char *arg) 322 { 323 char savec = arg[argLen]; 324 char *p1; 325 Boolean result; 326 327 arg[argLen] = '\0'; 328 if (Var_Value(arg, VAR_CMD, &p1) != NULL) { 329 result = TRUE; 330 } else { 331 result = FALSE; 332 } 333 if (p1) 334 free(p1); 335 arg[argLen] = savec; 336 return (result); 337 } 338 339 /*- 340 *----------------------------------------------------------------------- 341 * CondStrMatch -- 342 * Front-end for Str_Match so it returns 0 on match and non-zero 343 * on mismatch. Callback function for CondDoMake via Lst_Find 344 * 345 * Results: 346 * 0 if string matches pattern 347 * 348 * Side Effects: 349 * None 350 * 351 *----------------------------------------------------------------------- 352 */ 353 static int 354 CondStrMatch(ClientData string, ClientData pattern) 355 { 356 return(!Str_Match((char *)string,(char *)pattern)); 357 } 358 359 /*- 360 *----------------------------------------------------------------------- 361 * CondDoMake -- 362 * Handle the 'make' function for conditionals. 363 * 364 * Results: 365 * TRUE if the given target is being made. 366 * 367 * Side Effects: 368 * None. 369 * 370 *----------------------------------------------------------------------- 371 */ 372 static Boolean 373 CondDoMake(int argLen, char *arg) 374 { 375 char savec = arg[argLen]; 376 Boolean result; 377 378 arg[argLen] = '\0'; 379 if (Lst_Find(create, arg, CondStrMatch) == NILLNODE) { 380 result = FALSE; 381 } else { 382 result = TRUE; 383 } 384 arg[argLen] = savec; 385 return (result); 386 } 387 388 /*- 389 *----------------------------------------------------------------------- 390 * CondDoExists -- 391 * See if the given file exists. 392 * 393 * Results: 394 * TRUE if the file exists and FALSE if it does not. 395 * 396 * Side Effects: 397 * None. 398 * 399 *----------------------------------------------------------------------- 400 */ 401 static Boolean 402 CondDoExists(int argLen, char *arg) 403 { 404 char savec = arg[argLen]; 405 Boolean result; 406 char *path; 407 408 arg[argLen] = '\0'; 409 path = Dir_FindFile(arg, dirSearchPath); 410 if (path != NULL) { 411 result = TRUE; 412 free(path); 413 } else { 414 result = FALSE; 415 } 416 arg[argLen] = savec; 417 if (DEBUG(COND)) { 418 fprintf(debug_file, "exists(%s) result is \"%s\"\n", 419 arg, path ? path : ""); 420 } 421 return (result); 422 } 423 424 /*- 425 *----------------------------------------------------------------------- 426 * CondDoTarget -- 427 * See if the given node exists and is an actual target. 428 * 429 * Results: 430 * TRUE if the node exists as a target and FALSE if it does not. 431 * 432 * Side Effects: 433 * None. 434 * 435 *----------------------------------------------------------------------- 436 */ 437 static Boolean 438 CondDoTarget(int argLen, char *arg) 439 { 440 char savec = arg[argLen]; 441 Boolean result; 442 GNode *gn; 443 444 arg[argLen] = '\0'; 445 gn = Targ_FindNode(arg, TARG_NOCREATE); 446 if ((gn != NILGNODE) && !OP_NOP(gn->type)) { 447 result = TRUE; 448 } else { 449 result = FALSE; 450 } 451 arg[argLen] = savec; 452 return (result); 453 } 454 455 /*- 456 *----------------------------------------------------------------------- 457 * CondDoCommands -- 458 * See if the given node exists and is an actual target with commands 459 * associated with it. 460 * 461 * Results: 462 * TRUE if the node exists as a target and has commands associated with 463 * it and FALSE if it does not. 464 * 465 * Side Effects: 466 * None. 467 * 468 *----------------------------------------------------------------------- 469 */ 470 static Boolean 471 CondDoCommands(int argLen, char *arg) 472 { 473 char savec = arg[argLen]; 474 Boolean result; 475 GNode *gn; 476 477 arg[argLen] = '\0'; 478 gn = Targ_FindNode(arg, TARG_NOCREATE); 479 if ((gn != NILGNODE) && !OP_NOP(gn->type) && !Lst_IsEmpty(gn->commands)) { 480 result = TRUE; 481 } else { 482 result = FALSE; 483 } 484 arg[argLen] = savec; 485 return (result); 486 } 487 488 /*- 489 *----------------------------------------------------------------------- 490 * CondCvtArg -- 491 * Convert the given number into a double. If the number begins 492 * with 0x, it is interpreted as a hexadecimal integer 493 * and converted to a double from there. All other strings just have 494 * strtod called on them. 495 * 496 * Results: 497 * Sets 'value' to double value of string. 498 * Returns NULL if string was fully consumed, 499 * else returns remaining input. 500 * 501 * Side Effects: 502 * Can change 'value' even if string is not a valid number. 503 * 504 * 505 *----------------------------------------------------------------------- 506 */ 507 static char * 508 CondCvtArg(char *str, double *value) 509 { 510 if ((*str == '0') && (str[1] == 'x')) { 511 long i; 512 513 for (str += 2, i = 0; *str; str++) { 514 int x; 515 if (isdigit((unsigned char) *str)) 516 x = *str - '0'; 517 else if (isxdigit((unsigned char) *str)) 518 x = 10 + *str - isupper((unsigned char) *str) ? 'A' : 'a'; 519 else 520 break; 521 i = (i << 4) + x; 522 } 523 *value = (double) i; 524 return *str ? str : NULL; 525 } else { 526 char *eptr; 527 *value = strtod(str, &eptr); 528 return *eptr ? eptr : NULL; 529 } 530 } 531 532 /*- 533 *----------------------------------------------------------------------- 534 * CondGetString -- 535 * Get a string from a variable reference or an optionally quoted 536 * string. This is called for the lhs and rhs of string compares. 537 * 538 * Results: 539 * Sets freeIt if needed, 540 * Sets quoted if string was quoted, 541 * Returns NULL on error, 542 * else returns string - absent any quotes. 543 * 544 * Side Effects: 545 * Moves condExpr to end of this token. 546 * 547 * 548 *----------------------------------------------------------------------- 549 */ 550 /* coverity:[+alloc : arg-*2] */ 551 static char * 552 CondGetString(Boolean doEval, Boolean *quoted, void **freeIt) 553 { 554 Buffer buf; 555 char *cp; 556 char *str; 557 int len; 558 int qt; 559 char *start; 560 561 buf = Buf_Init(0); 562 str = NULL; 563 *freeIt = NULL; 564 *quoted = qt = *condExpr == '"' ? 1 : 0; 565 if (qt) 566 condExpr++; 567 for (start = condExpr; *condExpr && str == NULL; condExpr++) { 568 switch (*condExpr) { 569 case '\\': 570 if (condExpr[1] != '\0') { 571 condExpr++; 572 Buf_AddByte(buf, (Byte)*condExpr); 573 } 574 break; 575 case '"': 576 if (qt) { 577 condExpr++; /* we don't want the quotes */ 578 goto got_str; 579 } else 580 Buf_AddByte(buf, (Byte)*condExpr); /* likely? */ 581 break; 582 case ')': 583 case '!': 584 case '=': 585 case '>': 586 case '<': 587 case ' ': 588 case '\t': 589 if (!qt) 590 goto got_str; 591 else 592 Buf_AddByte(buf, (Byte)*condExpr); 593 break; 594 case '$': 595 /* if we are in quotes, then an undefined variable is ok */ 596 str = Var_Parse(condExpr, VAR_CMD, (qt ? 0 : doEval), 597 &len, freeIt); 598 if (str == var_Error) { 599 if (*freeIt) { 600 free(*freeIt); 601 *freeIt = NULL; 602 } 603 /* 604 * Even if !doEval, we still report syntax errors, which 605 * is what getting var_Error back with !doEval means. 606 */ 607 str = NULL; 608 goto cleanup; 609 } 610 condExpr += len; 611 /* 612 * If the '$' was first char (no quotes), and we are 613 * followed by space, the operator or end of expression, 614 * we are done. 615 */ 616 if ((condExpr == start + len) && 617 (*condExpr == '\0' || 618 isspace((unsigned char) *condExpr) || 619 strchr("!=><)", *condExpr))) { 620 goto cleanup; 621 } 622 /* 623 * Nope, we better copy str to buf 624 */ 625 for (cp = str; *cp; cp++) { 626 Buf_AddByte(buf, (Byte)*cp); 627 } 628 if (*freeIt) { 629 free(*freeIt); 630 *freeIt = NULL; 631 } 632 str = NULL; /* not finished yet */ 633 condExpr--; /* don't skip over next char */ 634 break; 635 default: 636 Buf_AddByte(buf, (Byte)*condExpr); 637 break; 638 } 639 } 640 got_str: 641 Buf_AddByte(buf, (Byte)'\0'); 642 str = (char *)Buf_GetAll(buf, NULL); 643 *freeIt = str; 644 cleanup: 645 Buf_Destroy(buf, FALSE); 646 return str; 647 } 648 649 /*- 650 *----------------------------------------------------------------------- 651 * CondToken -- 652 * Return the next token from the input. 653 * 654 * Results: 655 * A Token for the next lexical token in the stream. 656 * 657 * Side Effects: 658 * condPushback will be set back to None if it is used. 659 * 660 *----------------------------------------------------------------------- 661 */ 662 static Token 663 CondToken(Boolean doEval) 664 { 665 Token t; 666 667 if (condPushBack == None) { 668 while (*condExpr == ' ' || *condExpr == '\t') { 669 condExpr++; 670 } 671 switch (*condExpr) { 672 case '(': 673 t = LParen; 674 condExpr++; 675 break; 676 case ')': 677 t = RParen; 678 condExpr++; 679 break; 680 case '|': 681 if (condExpr[1] == '|') { 682 condExpr++; 683 } 684 condExpr++; 685 t = Or; 686 break; 687 case '&': 688 if (condExpr[1] == '&') { 689 condExpr++; 690 } 691 condExpr++; 692 t = And; 693 break; 694 case '!': 695 t = Not; 696 condExpr++; 697 break; 698 case '#': 699 case '\n': 700 case '\0': 701 t = EndOfFile; 702 break; 703 case '"': 704 case '$': { 705 char *lhs; 706 char *rhs; 707 char *op; 708 void *lhsFree; 709 void *rhsFree; 710 Boolean lhsQuoted; 711 Boolean rhsQuoted; 712 713 rhs = NULL; 714 lhsFree = rhsFree = FALSE; 715 lhsQuoted = rhsQuoted = FALSE; 716 717 /* 718 * Parse the variable spec and skip over it, saving its 719 * value in lhs. 720 */ 721 t = Err; 722 lhs = CondGetString(doEval, &lhsQuoted, &lhsFree); 723 if (!lhs) { 724 if (lhsFree) 725 free(lhsFree); 726 return Err; 727 } 728 /* 729 * Skip whitespace to get to the operator 730 */ 731 while (isspace((unsigned char) *condExpr)) 732 condExpr++; 733 734 /* 735 * Make sure the operator is a valid one. If it isn't a 736 * known relational operator, pretend we got a 737 * != 0 comparison. 738 */ 739 op = condExpr; 740 switch (*condExpr) { 741 case '!': 742 case '=': 743 case '<': 744 case '>': 745 if (condExpr[1] == '=') { 746 condExpr += 2; 747 } else { 748 condExpr += 1; 749 } 750 break; 751 default: 752 op = UNCONST("!="); 753 if (lhsQuoted) 754 rhs = UNCONST(""); 755 else 756 rhs = UNCONST("0"); 757 758 goto do_compare; 759 } 760 while (isspace((unsigned char) *condExpr)) { 761 condExpr++; 762 } 763 if (*condExpr == '\0') { 764 Parse_Error(PARSE_WARNING, 765 "Missing right-hand-side of operator"); 766 goto error; 767 } 768 rhs = CondGetString(doEval, &rhsQuoted, &rhsFree); 769 if (!rhs) { 770 if (lhsFree) 771 free(lhsFree); 772 if (rhsFree) 773 free(rhsFree); 774 return Err; 775 } 776 do_compare: 777 if (rhsQuoted || lhsQuoted) { 778 do_string_compare: 779 if (((*op != '!') && (*op != '=')) || (op[1] != '=')) { 780 Parse_Error(PARSE_WARNING, 781 "String comparison operator should be either == or !="); 782 goto error; 783 } 784 785 if (DEBUG(COND)) { 786 fprintf(debug_file, "lhs = \"%s\", rhs = \"%s\", op = %.2s\n", 787 lhs, rhs, op); 788 } 789 /* 790 * Null-terminate rhs and perform the comparison. 791 * t is set to the result. 792 */ 793 if (*op == '=') { 794 t = strcmp(lhs, rhs) ? False : True; 795 } else { 796 t = strcmp(lhs, rhs) ? True : False; 797 } 798 } else { 799 /* 800 * rhs is either a float or an integer. Convert both the 801 * lhs and the rhs to a double and compare the two. 802 */ 803 double left, right; 804 char *cp; 805 806 if (CondCvtArg(lhs, &left)) 807 goto do_string_compare; 808 if ((cp = CondCvtArg(rhs, &right)) && 809 cp == rhs) 810 goto do_string_compare; 811 812 if (DEBUG(COND)) { 813 fprintf(debug_file, "left = %f, right = %f, op = %.2s\n", left, 814 right, op); 815 } 816 switch(op[0]) { 817 case '!': 818 if (op[1] != '=') { 819 Parse_Error(PARSE_WARNING, 820 "Unknown operator"); 821 goto error; 822 } 823 t = (left != right ? True : False); 824 break; 825 case '=': 826 if (op[1] != '=') { 827 Parse_Error(PARSE_WARNING, 828 "Unknown operator"); 829 goto error; 830 } 831 t = (left == right ? True : False); 832 break; 833 case '<': 834 if (op[1] == '=') { 835 t = (left <= right ? True : False); 836 } else { 837 t = (left < right ? True : False); 838 } 839 break; 840 case '>': 841 if (op[1] == '=') { 842 t = (left >= right ? True : False); 843 } else { 844 t = (left > right ? True : False); 845 } 846 break; 847 } 848 } 849 error: 850 if (lhsFree) 851 free(lhsFree); 852 if (rhsFree) 853 free(rhsFree); 854 break; 855 } 856 default: { 857 Boolean (*evalProc)(int, char *); 858 Boolean invert = FALSE; 859 char *arg = NULL; 860 int arglen = 0; 861 862 if (istoken(condExpr, "defined", 7)) { 863 /* 864 * Use CondDoDefined to evaluate the argument and 865 * CondGetArg to extract the argument from the 'function 866 * call'. 867 */ 868 evalProc = CondDoDefined; 869 condExpr += 7; 870 arglen = CondGetArg(&condExpr, &arg, "defined", TRUE); 871 if (arglen == 0) { 872 condExpr -= 7; 873 goto use_default; 874 } 875 } else if (istoken(condExpr, "make", 4)) { 876 /* 877 * Use CondDoMake to evaluate the argument and 878 * CondGetArg to extract the argument from the 'function 879 * call'. 880 */ 881 evalProc = CondDoMake; 882 condExpr += 4; 883 arglen = CondGetArg(&condExpr, &arg, "make", TRUE); 884 if (arglen == 0) { 885 condExpr -= 4; 886 goto use_default; 887 } 888 } else if (istoken(condExpr, "exists", 6)) { 889 /* 890 * Use CondDoExists to evaluate the argument and 891 * CondGetArg to extract the argument from the 892 * 'function call'. 893 */ 894 evalProc = CondDoExists; 895 condExpr += 6; 896 arglen = CondGetArg(&condExpr, &arg, "exists", TRUE); 897 if (arglen == 0) { 898 condExpr -= 6; 899 goto use_default; 900 } 901 } else if (istoken(condExpr, "empty", 5)) { 902 /* 903 * Use Var_Parse to parse the spec in parens and return 904 * True if the resulting string is empty. 905 */ 906 int length; 907 void *freeIt; 908 char *val; 909 910 condExpr += 5; 911 912 for (arglen = 0; 913 condExpr[arglen] != '(' && condExpr[arglen] != '\0'; 914 arglen += 1) 915 continue; 916 917 if (condExpr[arglen] != '\0') { 918 val = Var_Parse(&condExpr[arglen - 1], VAR_CMD, 919 FALSE, &length, &freeIt); 920 if (val == var_Error) { 921 t = Err; 922 } else { 923 /* 924 * A variable is empty when it just contains 925 * spaces... 4/15/92, christos 926 */ 927 char *p; 928 for (p = val; *p && isspace((unsigned char)*p); p++) 929 continue; 930 t = (*p == '\0') ? True : False; 931 } 932 if (freeIt) { 933 free(freeIt); 934 } 935 /* 936 * Advance condExpr to beyond the closing ). Note that 937 * we subtract one from arglen + length b/c length 938 * is calculated from condExpr[arglen - 1]. 939 */ 940 condExpr += arglen + length - 1; 941 } else { 942 condExpr -= 5; 943 goto use_default; 944 } 945 break; 946 } else if (istoken(condExpr, "target", 6)) { 947 /* 948 * Use CondDoTarget to evaluate the argument and 949 * CondGetArg to extract the argument from the 950 * 'function call'. 951 */ 952 evalProc = CondDoTarget; 953 condExpr += 6; 954 arglen = CondGetArg(&condExpr, &arg, "target", TRUE); 955 if (arglen == 0) { 956 condExpr -= 6; 957 goto use_default; 958 } 959 } else if (istoken(condExpr, "commands", 8)) { 960 /* 961 * Use CondDoCommands to evaluate the argument and 962 * CondGetArg to extract the argument from the 963 * 'function call'. 964 */ 965 evalProc = CondDoCommands; 966 condExpr += 8; 967 arglen = CondGetArg(&condExpr, &arg, "commands", TRUE); 968 if (arglen == 0) { 969 condExpr -= 8; 970 goto use_default; 971 } 972 } else { 973 /* 974 * The symbol is itself the argument to the default 975 * function. We advance condExpr to the end of the symbol 976 * by hand (the next whitespace, closing paren or 977 * binary operator) and set to invert the evaluation 978 * function if condInvert is TRUE. 979 */ 980 use_default: 981 invert = condInvert; 982 evalProc = condDefProc; 983 arglen = CondGetArg(&condExpr, &arg, "", FALSE); 984 } 985 986 /* 987 * Evaluate the argument using the set function. If invert 988 * is TRUE, we invert the sense of the function. 989 */ 990 t = (!doEval || (* evalProc) (arglen, arg) ? 991 (invert ? False : True) : 992 (invert ? True : False)); 993 if (arg) 994 free(arg); 995 break; 996 } 997 } 998 } else { 999 t = condPushBack; 1000 condPushBack = None; 1001 } 1002 return (t); 1003 } 1004 1005 /*- 1006 *----------------------------------------------------------------------- 1007 * CondT -- 1008 * Parse a single term in the expression. This consists of a terminal 1009 * symbol or Not and a terminal symbol (not including the binary 1010 * operators): 1011 * T -> defined(variable) | make(target) | exists(file) | symbol 1012 * T -> ! T | ( E ) 1013 * 1014 * Results: 1015 * True, False or Err. 1016 * 1017 * Side Effects: 1018 * Tokens are consumed. 1019 * 1020 *----------------------------------------------------------------------- 1021 */ 1022 static Token 1023 CondT(Boolean doEval) 1024 { 1025 Token t; 1026 1027 t = CondToken(doEval); 1028 1029 if (t == EndOfFile) { 1030 /* 1031 * If we reached the end of the expression, the expression 1032 * is malformed... 1033 */ 1034 t = Err; 1035 } else if (t == LParen) { 1036 /* 1037 * T -> ( E ) 1038 */ 1039 t = CondE(doEval); 1040 if (t != Err) { 1041 if (CondToken(doEval) != RParen) { 1042 t = Err; 1043 } 1044 } 1045 } else if (t == Not) { 1046 t = CondT(doEval); 1047 if (t == True) { 1048 t = False; 1049 } else if (t == False) { 1050 t = True; 1051 } 1052 } 1053 return (t); 1054 } 1055 1056 /*- 1057 *----------------------------------------------------------------------- 1058 * CondF -- 1059 * Parse a conjunctive factor (nice name, wot?) 1060 * F -> T && F | T 1061 * 1062 * Results: 1063 * True, False or Err 1064 * 1065 * Side Effects: 1066 * Tokens are consumed. 1067 * 1068 *----------------------------------------------------------------------- 1069 */ 1070 static Token 1071 CondF(Boolean doEval) 1072 { 1073 Token l, o; 1074 1075 l = CondT(doEval); 1076 if (l != Err) { 1077 o = CondToken(doEval); 1078 1079 if (o == And) { 1080 /* 1081 * F -> T && F 1082 * 1083 * If T is False, the whole thing will be False, but we have to 1084 * parse the r.h.s. anyway (to throw it away). 1085 * If T is True, the result is the r.h.s., be it an Err or no. 1086 */ 1087 if (l == True) { 1088 l = CondF(doEval); 1089 } else { 1090 (void)CondF(FALSE); 1091 } 1092 } else { 1093 /* 1094 * F -> T 1095 */ 1096 CondPushBack(o); 1097 } 1098 } 1099 return (l); 1100 } 1101 1102 /*- 1103 *----------------------------------------------------------------------- 1104 * CondE -- 1105 * Main expression production. 1106 * E -> F || E | F 1107 * 1108 * Results: 1109 * True, False or Err. 1110 * 1111 * Side Effects: 1112 * Tokens are, of course, consumed. 1113 * 1114 *----------------------------------------------------------------------- 1115 */ 1116 static Token 1117 CondE(Boolean doEval) 1118 { 1119 Token l, o; 1120 1121 l = CondF(doEval); 1122 if (l != Err) { 1123 o = CondToken(doEval); 1124 1125 if (o == Or) { 1126 /* 1127 * E -> F || E 1128 * 1129 * A similar thing occurs for ||, except that here we make sure 1130 * the l.h.s. is False before we bother to evaluate the r.h.s. 1131 * Once again, if l is False, the result is the r.h.s. and once 1132 * again if l is True, we parse the r.h.s. to throw it away. 1133 */ 1134 if (l == False) { 1135 l = CondE(doEval); 1136 } else { 1137 (void)CondE(FALSE); 1138 } 1139 } else { 1140 /* 1141 * E -> F 1142 */ 1143 CondPushBack(o); 1144 } 1145 } 1146 return (l); 1147 } 1148 1149 /*- 1150 *----------------------------------------------------------------------- 1151 * Cond_EvalExpression -- 1152 * Evaluate an expression in the passed line. The expression 1153 * consists of &&, ||, !, make(target), defined(variable) 1154 * and parenthetical groupings thereof. 1155 * 1156 * Results: 1157 * COND_PARSE if the condition was valid grammatically 1158 * COND_INVALID if not a valid conditional. 1159 * 1160 * (*value) is set to the boolean value of the condition 1161 * 1162 * Side Effects: 1163 * None. 1164 * 1165 *----------------------------------------------------------------------- 1166 */ 1167 int 1168 Cond_EvalExpression(int dosetup, char *line, Boolean *value, int eprint) 1169 { 1170 if (dosetup) { 1171 condDefProc = CondDoDefined; 1172 condInvert = 0; 1173 } 1174 1175 while (*line == ' ' || *line == '\t') 1176 line++; 1177 1178 condExpr = line; 1179 condPushBack = None; 1180 1181 switch (CondE(TRUE)) { 1182 case True: 1183 if (CondToken(TRUE) == EndOfFile) { 1184 *value = TRUE; 1185 break; 1186 } 1187 goto err; 1188 /*FALLTHRU*/ 1189 case False: 1190 if (CondToken(TRUE) == EndOfFile) { 1191 *value = FALSE; 1192 break; 1193 } 1194 /*FALLTHRU*/ 1195 case Err: 1196 err: 1197 if (eprint) 1198 Parse_Error(PARSE_FATAL, "Malformed conditional (%s)", 1199 line); 1200 return (COND_INVALID); 1201 default: 1202 break; 1203 } 1204 1205 return COND_PARSE; 1206 } 1207 1208 1209 /*- 1210 *----------------------------------------------------------------------- 1211 * Cond_Eval -- 1212 * Evaluate the conditional in the passed line. The line 1213 * looks like this: 1214 * .<cond-type> <expr> 1215 * where <cond-type> is any of if, ifmake, ifnmake, ifdef, 1216 * ifndef, elif, elifmake, elifnmake, elifdef, elifndef 1217 * and <expr> consists of &&, ||, !, make(target), defined(variable) 1218 * and parenthetical groupings thereof. 1219 * 1220 * Input: 1221 * line Line to parse 1222 * 1223 * Results: 1224 * COND_PARSE if should parse lines after the conditional 1225 * COND_SKIP if should skip lines after the conditional 1226 * COND_INVALID if not a valid conditional. 1227 * 1228 * Side Effects: 1229 * None. 1230 * 1231 * Note that the states IF_ACTIVE and ELSE_ACTIVE are only different in order 1232 * to detect splurious .else lines (as are SKIP_TO_ELSE and SKIP_TO_ENDIF) 1233 * otherwise .else could be treated as '.elif 1'. 1234 * 1235 *----------------------------------------------------------------------- 1236 */ 1237 int 1238 Cond_Eval(char *line) 1239 { 1240 #define MAXIF 64 /* maximum depth of .if'ing */ 1241 enum if_states { 1242 IF_ACTIVE, /* .if or .elif part active */ 1243 ELSE_ACTIVE, /* .else part active */ 1244 SEARCH_FOR_ELIF, /* searching for .elif/else to execute */ 1245 SKIP_TO_ELSE, /* has been true, but not seen '.else' */ 1246 SKIP_TO_ENDIF /* nothing else to execute */ 1247 }; 1248 static enum if_states cond_state[MAXIF + 1] = { IF_ACTIVE }; 1249 1250 const struct If *ifp; 1251 Boolean isElif; 1252 Boolean value; 1253 int level; /* Level at which to report errors. */ 1254 enum if_states state; 1255 1256 level = PARSE_FATAL; 1257 1258 /* skip leading character (the '.') and any whitespace */ 1259 for (line++; *line == ' ' || *line == '\t'; line++) 1260 continue; 1261 1262 /* Find what type of if we're dealing with. */ 1263 if (line[0] == 'e') { 1264 if (line[1] != 'l') { 1265 if (!istoken(line + 1, "ndif", 4)) 1266 return COND_INVALID; 1267 /* End of conditional section */ 1268 if (cond_depth == cond_min_depth) { 1269 Parse_Error(level, "if-less endif"); 1270 return COND_PARSE; 1271 } 1272 /* Return state for previous conditional */ 1273 cond_depth--; 1274 return cond_state[cond_depth] <= ELSE_ACTIVE ? COND_PARSE : COND_SKIP; 1275 } 1276 1277 /* Quite likely this is 'else' or 'elif' */ 1278 line += 2; 1279 if (istoken(line, "se", 2)) { 1280 /* It is else... */ 1281 if (cond_depth == cond_min_depth) { 1282 Parse_Error(level, "if-less else"); 1283 return COND_INVALID; 1284 } 1285 1286 state = cond_state[cond_depth]; 1287 switch (state) { 1288 case SEARCH_FOR_ELIF: 1289 state = ELSE_ACTIVE; 1290 break; 1291 case ELSE_ACTIVE: 1292 case SKIP_TO_ENDIF: 1293 Parse_Error(PARSE_WARNING, "extra else"); 1294 /* FALLTHROUGH */ 1295 default: 1296 case IF_ACTIVE: 1297 case SKIP_TO_ELSE: 1298 state = SKIP_TO_ENDIF; 1299 break; 1300 } 1301 cond_state[cond_depth] = state; 1302 return state <= ELSE_ACTIVE ? COND_PARSE : COND_SKIP; 1303 } 1304 /* Assume for now it is an elif */ 1305 isElif = TRUE; 1306 } else 1307 isElif = FALSE; 1308 1309 if (line[0] != 'i' || line[1] != 'f') 1310 /* Not an ifxxx or elifxxx line */ 1311 return COND_INVALID; 1312 1313 /* 1314 * Figure out what sort of conditional it is -- what its default 1315 * function is, etc. -- by looking in the table of valid "ifs" 1316 */ 1317 line += 2; 1318 for (ifp = ifs; ; ifp++) { 1319 if (ifp->form == NULL) 1320 return COND_INVALID; 1321 if (istoken(ifp->form, line, ifp->formlen)) { 1322 line += ifp->formlen; 1323 break; 1324 } 1325 } 1326 1327 /* Now we know what sort of 'if' it is... */ 1328 state = cond_state[cond_depth]; 1329 1330 if (isElif) { 1331 if (cond_depth == cond_min_depth) { 1332 Parse_Error(level, "if-less elif"); 1333 return COND_INVALID; 1334 } 1335 if (state == SKIP_TO_ENDIF || state == ELSE_ACTIVE) 1336 Parse_Error(PARSE_WARNING, "extra elif"); 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 if (cond_depth >= MAXIF) { 1344 Parse_Error(PARSE_FATAL, "Too many nested if's. %d max.", MAXIF); 1345 return COND_INVALID; 1346 } 1347 cond_depth++; 1348 if (state > ELSE_ACTIVE) { 1349 /* If we aren't parsing the data, treat as always false */ 1350 cond_state[cond_depth] = SKIP_TO_ELSE; 1351 return COND_SKIP; 1352 } 1353 } 1354 1355 /* Initialize file-global variables for parsing the expression */ 1356 condDefProc = ifp->defProc; 1357 condInvert = ifp->doNot; 1358 1359 /* And evaluate the conditional expresssion */ 1360 if (Cond_EvalExpression(0, line, &value, 1) == COND_INVALID) { 1361 /* Although we get make to reprocess the line, set a state */ 1362 cond_state[cond_depth] = SEARCH_FOR_ELIF; 1363 return COND_INVALID; 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