1 /* $NetBSD: cond.c,v 1.41 2008/02/15 21:29:50 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.41 2008/02/15 21:29:50 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.41 2008/02/15 21:29:50 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 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 did_warn, length; 907 void *freeIt; 908 char *val; 909 910 condExpr += 5; 911 912 did_warn = 0; 913 for (arglen = 0; condExpr[arglen] != '\0'; arglen += 1) { 914 if (condExpr[arglen] == '(') 915 break; 916 if (!isspace((unsigned char)condExpr[arglen]) && 917 !did_warn) { 918 919 Parse_Error(PARSE_WARNING, 920 "Extra characters after \"empty\""); 921 did_warn = 1; 922 } 923 } 924 925 if (condExpr[arglen] != '\0') { 926 val = Var_Parse(&condExpr[arglen - 1], VAR_CMD, 927 FALSE, &length, &freeIt); 928 if (val == var_Error) { 929 t = Err; 930 } else { 931 /* 932 * A variable is empty when it just contains 933 * spaces... 4/15/92, christos 934 */ 935 char *p; 936 for (p = val; *p && isspace((unsigned char)*p); p++) 937 continue; 938 t = (*p == '\0') ? True : False; 939 } 940 if (freeIt) { 941 free(freeIt); 942 } 943 /* 944 * Advance condExpr to beyond the closing ). Note that 945 * we subtract one from arglen + length b/c length 946 * is calculated from condExpr[arglen - 1]. 947 */ 948 condExpr += arglen + length - 1; 949 } else { 950 condExpr -= 5; 951 goto use_default; 952 } 953 break; 954 } else if (istoken(condExpr, "target", 6)) { 955 /* 956 * Use CondDoTarget to evaluate the argument and 957 * CondGetArg to extract the argument from the 958 * 'function call'. 959 */ 960 evalProc = CondDoTarget; 961 condExpr += 6; 962 arglen = CondGetArg(&condExpr, &arg, "target", TRUE); 963 if (arglen == 0) { 964 condExpr -= 6; 965 goto use_default; 966 } 967 } else if (istoken(condExpr, "commands", 8)) { 968 /* 969 * Use CondDoCommands to evaluate the argument and 970 * CondGetArg to extract the argument from the 971 * 'function call'. 972 */ 973 evalProc = CondDoCommands; 974 condExpr += 8; 975 arglen = CondGetArg(&condExpr, &arg, "commands", TRUE); 976 if (arglen == 0) { 977 condExpr -= 8; 978 goto use_default; 979 } 980 } else { 981 /* 982 * The symbol is itself the argument to the default 983 * function. We advance condExpr to the end of the symbol 984 * by hand (the next whitespace, closing paren or 985 * binary operator) and set to invert the evaluation 986 * function if condInvert is TRUE. 987 */ 988 use_default: 989 invert = condInvert; 990 evalProc = condDefProc; 991 arglen = CondGetArg(&condExpr, &arg, "", FALSE); 992 } 993 994 /* 995 * Evaluate the argument using the set function. If invert 996 * is TRUE, we invert the sense of the function. 997 */ 998 t = (!doEval || (* evalProc) (arglen, arg) ? 999 (invert ? False : True) : 1000 (invert ? True : False)); 1001 if (arg) 1002 free(arg); 1003 break; 1004 } 1005 } 1006 } else { 1007 t = condPushBack; 1008 condPushBack = None; 1009 } 1010 return (t); 1011 } 1012 1013 /*- 1014 *----------------------------------------------------------------------- 1015 * CondT -- 1016 * Parse a single term in the expression. This consists of a terminal 1017 * symbol or Not and a terminal symbol (not including the binary 1018 * operators): 1019 * T -> defined(variable) | make(target) | exists(file) | symbol 1020 * T -> ! T | ( E ) 1021 * 1022 * Results: 1023 * True, False or Err. 1024 * 1025 * Side Effects: 1026 * Tokens are consumed. 1027 * 1028 *----------------------------------------------------------------------- 1029 */ 1030 static Token 1031 CondT(Boolean doEval) 1032 { 1033 Token t; 1034 1035 t = CondToken(doEval); 1036 1037 if (t == EndOfFile) { 1038 /* 1039 * If we reached the end of the expression, the expression 1040 * is malformed... 1041 */ 1042 t = Err; 1043 } else if (t == LParen) { 1044 /* 1045 * T -> ( E ) 1046 */ 1047 t = CondE(doEval); 1048 if (t != Err) { 1049 if (CondToken(doEval) != RParen) { 1050 t = Err; 1051 } 1052 } 1053 } else if (t == Not) { 1054 t = CondT(doEval); 1055 if (t == True) { 1056 t = False; 1057 } else if (t == False) { 1058 t = True; 1059 } 1060 } 1061 return (t); 1062 } 1063 1064 /*- 1065 *----------------------------------------------------------------------- 1066 * CondF -- 1067 * Parse a conjunctive factor (nice name, wot?) 1068 * F -> T && F | T 1069 * 1070 * Results: 1071 * True, False or Err 1072 * 1073 * Side Effects: 1074 * Tokens are consumed. 1075 * 1076 *----------------------------------------------------------------------- 1077 */ 1078 static Token 1079 CondF(Boolean doEval) 1080 { 1081 Token l, o; 1082 1083 l = CondT(doEval); 1084 if (l != Err) { 1085 o = CondToken(doEval); 1086 1087 if (o == And) { 1088 /* 1089 * F -> T && F 1090 * 1091 * If T is False, the whole thing will be False, but we have to 1092 * parse the r.h.s. anyway (to throw it away). 1093 * If T is True, the result is the r.h.s., be it an Err or no. 1094 */ 1095 if (l == True) { 1096 l = CondF(doEval); 1097 } else { 1098 (void)CondF(FALSE); 1099 } 1100 } else { 1101 /* 1102 * F -> T 1103 */ 1104 CondPushBack(o); 1105 } 1106 } 1107 return (l); 1108 } 1109 1110 /*- 1111 *----------------------------------------------------------------------- 1112 * CondE -- 1113 * Main expression production. 1114 * E -> F || E | F 1115 * 1116 * Results: 1117 * True, False or Err. 1118 * 1119 * Side Effects: 1120 * Tokens are, of course, consumed. 1121 * 1122 *----------------------------------------------------------------------- 1123 */ 1124 static Token 1125 CondE(Boolean doEval) 1126 { 1127 Token l, o; 1128 1129 l = CondF(doEval); 1130 if (l != Err) { 1131 o = CondToken(doEval); 1132 1133 if (o == Or) { 1134 /* 1135 * E -> F || E 1136 * 1137 * A similar thing occurs for ||, except that here we make sure 1138 * the l.h.s. is False before we bother to evaluate the r.h.s. 1139 * Once again, if l is False, the result is the r.h.s. and once 1140 * again if l is True, we parse the r.h.s. to throw it away. 1141 */ 1142 if (l == False) { 1143 l = CondE(doEval); 1144 } else { 1145 (void)CondE(FALSE); 1146 } 1147 } else { 1148 /* 1149 * E -> F 1150 */ 1151 CondPushBack(o); 1152 } 1153 } 1154 return (l); 1155 } 1156 1157 /*- 1158 *----------------------------------------------------------------------- 1159 * Cond_EvalExpression -- 1160 * Evaluate an expression in the passed line. The expression 1161 * consists of &&, ||, !, make(target), defined(variable) 1162 * and parenthetical groupings thereof. 1163 * 1164 * Results: 1165 * COND_PARSE if the condition was valid grammatically 1166 * COND_INVALID if not a valid conditional. 1167 * 1168 * (*value) is set to the boolean value of the condition 1169 * 1170 * Side Effects: 1171 * None. 1172 * 1173 *----------------------------------------------------------------------- 1174 */ 1175 int 1176 Cond_EvalExpression(int dosetup, char *line, Boolean *value, int eprint) 1177 { 1178 if (dosetup) { 1179 condDefProc = CondDoDefined; 1180 condInvert = 0; 1181 } 1182 1183 while (*line == ' ' || *line == '\t') 1184 line++; 1185 1186 condExpr = line; 1187 condPushBack = None; 1188 1189 switch (CondE(TRUE)) { 1190 case True: 1191 if (CondToken(TRUE) == EndOfFile) { 1192 *value = TRUE; 1193 break; 1194 } 1195 goto err; 1196 /*FALLTHRU*/ 1197 case False: 1198 if (CondToken(TRUE) == EndOfFile) { 1199 *value = FALSE; 1200 break; 1201 } 1202 /*FALLTHRU*/ 1203 case Err: 1204 err: 1205 if (eprint) 1206 Parse_Error(PARSE_FATAL, "Malformed conditional (%s)", 1207 line); 1208 return (COND_INVALID); 1209 default: 1210 break; 1211 } 1212 1213 return COND_PARSE; 1214 } 1215 1216 1217 /*- 1218 *----------------------------------------------------------------------- 1219 * Cond_Eval -- 1220 * Evaluate the conditional in the passed line. The line 1221 * looks like this: 1222 * .<cond-type> <expr> 1223 * where <cond-type> is any of if, ifmake, ifnmake, ifdef, 1224 * ifndef, elif, elifmake, elifnmake, elifdef, elifndef 1225 * and <expr> consists of &&, ||, !, make(target), defined(variable) 1226 * and parenthetical groupings thereof. 1227 * 1228 * Input: 1229 * line Line to parse 1230 * 1231 * Results: 1232 * COND_PARSE if should parse lines after the conditional 1233 * COND_SKIP if should skip lines after the conditional 1234 * COND_INVALID if not a valid conditional. 1235 * 1236 * Side Effects: 1237 * None. 1238 * 1239 * Note that the states IF_ACTIVE and ELSE_ACTIVE are only different in order 1240 * to detect splurious .else lines (as are SKIP_TO_ELSE and SKIP_TO_ENDIF) 1241 * otherwise .else could be treated as '.elif 1'. 1242 * 1243 *----------------------------------------------------------------------- 1244 */ 1245 int 1246 Cond_Eval(char *line) 1247 { 1248 #define MAXIF 64 /* maximum depth of .if'ing */ 1249 enum if_states { 1250 IF_ACTIVE, /* .if or .elif part active */ 1251 ELSE_ACTIVE, /* .else part active */ 1252 SEARCH_FOR_ELIF, /* searching for .elif/else to execute */ 1253 SKIP_TO_ELSE, /* has been true, but not seen '.else' */ 1254 SKIP_TO_ENDIF /* nothing else to execute */ 1255 }; 1256 static enum if_states cond_state[MAXIF + 1] = { IF_ACTIVE }; 1257 1258 const struct If *ifp; 1259 Boolean isElif; 1260 Boolean value; 1261 int level; /* Level at which to report errors. */ 1262 enum if_states state; 1263 1264 level = PARSE_FATAL; 1265 1266 /* skip leading character (the '.') and any whitespace */ 1267 for (line++; *line == ' ' || *line == '\t'; line++) 1268 continue; 1269 1270 /* Find what type of if we're dealing with. */ 1271 if (line[0] == 'e') { 1272 if (line[1] != 'l') { 1273 if (!istoken(line + 1, "ndif", 4)) 1274 return COND_INVALID; 1275 /* End of conditional section */ 1276 if (cond_depth == cond_min_depth) { 1277 Parse_Error(level, "if-less endif"); 1278 return COND_PARSE; 1279 } 1280 /* Return state for previous conditional */ 1281 cond_depth--; 1282 return cond_state[cond_depth] <= ELSE_ACTIVE ? COND_PARSE : COND_SKIP; 1283 } 1284 1285 /* Quite likely this is 'else' or 'elif' */ 1286 line += 2; 1287 if (istoken(line, "se", 2)) { 1288 /* It is else... */ 1289 if (cond_depth == cond_min_depth) { 1290 Parse_Error(level, "if-less else"); 1291 return COND_INVALID; 1292 } 1293 1294 state = cond_state[cond_depth]; 1295 switch (state) { 1296 case SEARCH_FOR_ELIF: 1297 state = ELSE_ACTIVE; 1298 break; 1299 case ELSE_ACTIVE: 1300 case SKIP_TO_ENDIF: 1301 Parse_Error(PARSE_WARNING, "extra else"); 1302 /* FALLTHROUGH */ 1303 default: 1304 case IF_ACTIVE: 1305 case SKIP_TO_ELSE: 1306 state = SKIP_TO_ENDIF; 1307 break; 1308 } 1309 cond_state[cond_depth] = state; 1310 return state <= ELSE_ACTIVE ? COND_PARSE : COND_SKIP; 1311 } 1312 /* Assume for now it is an elif */ 1313 isElif = TRUE; 1314 } else 1315 isElif = FALSE; 1316 1317 if (line[0] != 'i' || line[1] != 'f') 1318 /* Not an ifxxx or elifxxx line */ 1319 return COND_INVALID; 1320 1321 /* 1322 * Figure out what sort of conditional it is -- what its default 1323 * function is, etc. -- by looking in the table of valid "ifs" 1324 */ 1325 line += 2; 1326 for (ifp = ifs; ; ifp++) { 1327 if (ifp->form == NULL) 1328 return COND_INVALID; 1329 if (istoken(ifp->form, line, ifp->formlen)) { 1330 line += ifp->formlen; 1331 break; 1332 } 1333 } 1334 1335 /* Now we know what sort of 'if' it is... */ 1336 state = cond_state[cond_depth]; 1337 1338 if (isElif) { 1339 if (cond_depth == cond_min_depth) { 1340 Parse_Error(level, "if-less elif"); 1341 return COND_INVALID; 1342 } 1343 if (state == SKIP_TO_ENDIF || state == ELSE_ACTIVE) 1344 Parse_Error(PARSE_WARNING, "extra elif"); 1345 if (state != SEARCH_FOR_ELIF) { 1346 /* Either just finished the 'true' block, or already SKIP_TO_ELSE */ 1347 cond_state[cond_depth] = SKIP_TO_ELSE; 1348 return COND_SKIP; 1349 } 1350 } else { 1351 if (cond_depth >= MAXIF) { 1352 Parse_Error(PARSE_FATAL, "Too many nested if's. %d max.", MAXIF); 1353 return COND_INVALID; 1354 } 1355 cond_depth++; 1356 if (state > ELSE_ACTIVE) { 1357 /* If we aren't parsing the data, treat as always false */ 1358 cond_state[cond_depth] = SKIP_TO_ELSE; 1359 return COND_SKIP; 1360 } 1361 } 1362 1363 /* Initialize file-global variables for parsing the expression */ 1364 condDefProc = ifp->defProc; 1365 condInvert = ifp->doNot; 1366 1367 /* And evaluate the conditional expresssion */ 1368 if (Cond_EvalExpression(0, line, &value, 1) == COND_INVALID) { 1369 /* Although we get make to reprocess the line, set a state */ 1370 cond_state[cond_depth] = SEARCH_FOR_ELIF; 1371 return COND_INVALID; 1372 } 1373 1374 if (!value) { 1375 cond_state[cond_depth] = SEARCH_FOR_ELIF; 1376 return COND_SKIP; 1377 } 1378 cond_state[cond_depth] = IF_ACTIVE; 1379 return COND_PARSE; 1380 } 1381 1382 1383 1384 /*- 1385 *----------------------------------------------------------------------- 1386 * Cond_End -- 1387 * Make sure everything's clean at the end of a makefile. 1388 * 1389 * Results: 1390 * None. 1391 * 1392 * Side Effects: 1393 * Parse_Error will be called if open conditionals are around. 1394 * 1395 *----------------------------------------------------------------------- 1396 */ 1397 void 1398 Cond_restore_depth(unsigned int saved_depth) 1399 { 1400 int open_conds = cond_depth - cond_min_depth; 1401 1402 if (open_conds != 0 || saved_depth > cond_depth) { 1403 Parse_Error(PARSE_FATAL, "%d open conditional%s", open_conds, 1404 open_conds == 1 ? "" : "s"); 1405 cond_depth = cond_min_depth; 1406 } 1407 1408 cond_min_depth = saved_depth; 1409 } 1410 1411 unsigned int 1412 Cond_save_depth(void) 1413 { 1414 int depth = cond_min_depth; 1415 1416 cond_min_depth = cond_depth; 1417 return depth; 1418 } 1419