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