1 /* 2 * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. 3 * Copyright (c) 1988, 1989 by Adam de Boor 4 * Copyright (c) 1989 by Berkeley Softworks 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Adam de Boor. 9 * 10 * %sccs.include.redist.c% 11 */ 12 13 #ifndef lint 14 static char sccsid[] = "@(#)var.c 5.8 (Berkeley) 11/18/91"; 15 #endif /* not lint */ 16 17 /*- 18 * var.c -- 19 * Variable-handling functions 20 * 21 * Interface: 22 * Var_Set Set the value of a variable in the given 23 * context. The variable is created if it doesn't 24 * yet exist. The value and variable name need not 25 * be preserved. 26 * 27 * Var_Append Append more characters to an existing variable 28 * in the given context. The variable needn't 29 * exist already -- it will be created if it doesn't. 30 * A space is placed between the old value and the 31 * new one. 32 * 33 * Var_Exists See if a variable exists. 34 * 35 * Var_Value Return the value of a variable in a context or 36 * NULL if the variable is undefined. 37 * 38 * Var_Subst Substitute for all variables in a string using 39 * the given context as the top-most one. If the 40 * third argument is non-zero, Parse_Error is 41 * called if any variables are undefined. 42 * 43 * Var_Parse Parse a variable expansion from a string and 44 * return the result and the number of characters 45 * consumed. 46 * 47 * Var_Delete Delete a variable in a context. 48 * 49 * Var_Init Initialize this module. 50 * 51 * Debugging: 52 * Var_Dump Print out all variables defined in the given 53 * context. 54 * 55 * XXX: There's a lot of duplication in these functions. 56 */ 57 58 #include <ctype.h> 59 #include "make.h" 60 #include "buf.h" 61 extern char *getenv(); 62 63 /* 64 * This is a harmless return value for Var_Parse that can be used by Var_Subst 65 * to determine if there was an error in parsing -- easier than returning 66 * a flag, as things outside this module don't give a hoot. 67 */ 68 char var_Error[] = ""; 69 70 /* 71 * Similar to var_Error, but returned when the 'err' flag for Var_Parse is 72 * set false. Why not just use a constant? Well, gcc likes to condense 73 * identical string instances... 74 */ 75 char varNoError[] = ""; 76 77 /* 78 * Internally, variables are contained in four different contexts. 79 * 1) the environment. They may not be changed. If an environment 80 * variable is appended-to, the result is placed in the global 81 * context. 82 * 2) the global context. Variables set in the Makefile are located in 83 * the global context. It is the penultimate context searched when 84 * substituting. 85 * 3) the command-line context. All variables set on the command line 86 * are placed in this context. They are UNALTERABLE once placed here. 87 * 4) the local context. Each target has associated with it a context 88 * list. On this list are located the structures describing such 89 * local variables as $(@) and $(*) 90 * The four contexts are searched in the reverse order from which they are 91 * listed. 92 */ 93 GNode *VAR_GLOBAL; /* variables from the makefile */ 94 GNode *VAR_CMD; /* variables defined on the command-line */ 95 96 #define FIND_CMD 0x1 /* look in VAR_CMD when searching */ 97 #define FIND_GLOBAL 0x2 /* look in VAR_GLOBAL as well */ 98 #define FIND_ENV 0x4 /* look in the environment also */ 99 100 typedef struct Var { 101 char *name; /* the variable's name */ 102 Buffer val; /* its value */ 103 int flags; /* miscellaneous status flags */ 104 #define VAR_IN_USE 1 /* Variable's value currently being used. 105 * Used to avoid recursion */ 106 #define VAR_FROM_ENV 2 /* Variable comes from the environment */ 107 #define VAR_JUNK 4 /* Variable is a junk variable that 108 * should be destroyed when done with 109 * it. Used by Var_Parse for undefined, 110 * modified variables */ 111 } Var; 112 113 /*- 114 *----------------------------------------------------------------------- 115 * VarCmp -- 116 * See if the given variable matches the named one. Called from 117 * Lst_Find when searching for a variable of a given name. 118 * 119 * Results: 120 * 0 if they match. non-zero otherwise. 121 * 122 * Side Effects: 123 * none 124 *----------------------------------------------------------------------- 125 */ 126 static int 127 VarCmp (v, name) 128 Var *v; /* VAR structure to compare */ 129 char *name; /* name to look for */ 130 { 131 return (strcmp (name, v->name)); 132 } 133 134 /*- 135 *----------------------------------------------------------------------- 136 * VarFind -- 137 * Find the given variable in the given context and any other contexts 138 * indicated. 139 * 140 * Results: 141 * A pointer to the structure describing the desired variable or 142 * NIL if the variable does not exist. 143 * 144 * Side Effects: 145 * None 146 *----------------------------------------------------------------------- 147 */ 148 static Var * 149 VarFind (name, ctxt, flags) 150 char *name; /* name to find */ 151 GNode *ctxt; /* context in which to find it */ 152 int flags; /* FIND_GLOBAL set means to look in the 153 * VAR_GLOBAL context as well. 154 * FIND_CMD set means to look in the VAR_CMD 155 * context also. 156 * FIND_ENV set means to look in the 157 * environment */ 158 { 159 LstNode var; 160 Var *v; 161 162 /* 163 * If the variable name begins with a '.', it could very well be one of 164 * the local ones. We check the name against all the local variables 165 * and substitute the short version in for 'name' if it matches one of 166 * them. 167 */ 168 if (*name == '.' && isupper(name[1])) 169 switch (name[1]) { 170 case 'A': 171 if (!strcmp(name, ".ALLSRC")) 172 name = ALLSRC; 173 if (!strcmp(name, ".ARCHIVE")) 174 name = ARCHIVE; 175 break; 176 case 'I': 177 if (!strcmp(name, ".IMPSRC")) 178 name = IMPSRC; 179 break; 180 case 'M': 181 if (!strcmp(name, ".MEMBER")) 182 name = MEMBER; 183 break; 184 case 'O': 185 if (!strcmp(name, ".OODATE")) 186 name = OODATE; 187 break; 188 case 'P': 189 if (!strcmp(name, ".PREFIX")) 190 name = PREFIX; 191 break; 192 case 'T': 193 if (!strcmp(name, ".TARGET")) 194 name = TARGET; 195 break; 196 } 197 /* 198 * First look for the variable in the given context. If it's not there, 199 * look for it in VAR_CMD, VAR_GLOBAL and the environment, in that order, 200 * depending on the FIND_* flags in 'flags' 201 */ 202 var = Lst_Find (ctxt->context, (ClientData)name, VarCmp); 203 204 if ((var == NILLNODE) && (flags & FIND_CMD) && (ctxt != VAR_CMD)) { 205 var = Lst_Find (VAR_CMD->context, (ClientData)name, VarCmp); 206 } 207 if (!checkEnvFirst && (var == NILLNODE) && (flags & FIND_GLOBAL) && 208 (ctxt != VAR_GLOBAL)) 209 { 210 var = Lst_Find (VAR_GLOBAL->context, (ClientData)name, VarCmp); 211 } 212 if ((var == NILLNODE) && (flags & FIND_ENV)) { 213 char *env; 214 215 if ((env = getenv (name)) != NULL) { 216 /* 217 * If the variable is found in the environment, we only duplicate 218 * its value (since eVarVal was allocated on the stack). The name 219 * doesn't need duplication since it's always in the environment 220 */ 221 int len; 222 223 v = (Var *) emalloc(sizeof(Var)); 224 v->name = name; 225 226 len = strlen(env); 227 228 v->val = Buf_Init(len); 229 Buf_AddBytes(v->val, len, (Byte *)env); 230 231 v->flags = VAR_FROM_ENV; 232 return (v); 233 } else if (checkEnvFirst && (flags & FIND_GLOBAL) && 234 (ctxt != VAR_GLOBAL)) 235 { 236 var = Lst_Find (VAR_GLOBAL->context, (ClientData)name, VarCmp); 237 if (var == NILLNODE) { 238 return ((Var *) NIL); 239 } else { 240 return ((Var *)Lst_Datum(var)); 241 } 242 } else { 243 return((Var *)NIL); 244 } 245 } else if (var == NILLNODE) { 246 return ((Var *) NIL); 247 } else { 248 return ((Var *) Lst_Datum (var)); 249 } 250 } 251 252 /*- 253 *----------------------------------------------------------------------- 254 * VarAdd -- 255 * Add a new variable of name name and value val to the given context 256 * 257 * Results: 258 * None 259 * 260 * Side Effects: 261 * The new variable is placed at the front of the given context 262 * The name and val arguments are duplicated so they may 263 * safely be freed. 264 *----------------------------------------------------------------------- 265 */ 266 static 267 VarAdd (name, val, ctxt) 268 char *name; /* name of variable to add */ 269 char *val; /* value to set it to */ 270 GNode *ctxt; /* context in which to set it */ 271 { 272 register Var *v; 273 int len; 274 275 v = (Var *) emalloc (sizeof (Var)); 276 277 v->name = strdup (name); 278 279 len = strlen(val); 280 v->val = Buf_Init(len+1); 281 Buf_AddBytes(v->val, len, (Byte *)val); 282 283 v->flags = 0; 284 285 (void) Lst_AtFront (ctxt->context, (ClientData)v); 286 if (DEBUG(VAR)) { 287 printf("%s:%s = %s\n", ctxt->name, name, val); 288 } 289 } 290 291 /*- 292 *----------------------------------------------------------------------- 293 * Var_Delete -- 294 * Remove a variable from a context. 295 * 296 * Results: 297 * None. 298 * 299 * Side Effects: 300 * The Var structure is removed and freed. 301 * 302 *----------------------------------------------------------------------- 303 */ 304 void 305 Var_Delete(name, ctxt) 306 char *name; 307 GNode *ctxt; 308 { 309 LstNode ln; 310 311 if (DEBUG(VAR)) { 312 printf("%s:delete %s\n", ctxt->name, name); 313 } 314 ln = Lst_Find(ctxt->context, (ClientData)name, VarCmp); 315 if (ln != NILLNODE) { 316 register Var *v; 317 318 v = (Var *)Lst_Datum(ln); 319 Lst_Remove(ctxt->context, ln); 320 Buf_Destroy(v->val, TRUE); 321 free(v->name); 322 free((char *)v); 323 } 324 } 325 326 /*- 327 *----------------------------------------------------------------------- 328 * Var_Set -- 329 * Set the variable name to the value val in the given context. 330 * 331 * Results: 332 * None. 333 * 334 * Side Effects: 335 * If the variable doesn't yet exist, a new record is created for it. 336 * Else the old value is freed and the new one stuck in its place 337 * 338 * Notes: 339 * The variable is searched for only in its context before being 340 * created in that context. I.e. if the context is VAR_GLOBAL, 341 * only VAR_GLOBAL->context is searched. Likewise if it is VAR_CMD, only 342 * VAR_CMD->context is searched. This is done to avoid the literally 343 * thousands of unnecessary strcmp's that used to be done to 344 * set, say, $(@) or $(<). 345 *----------------------------------------------------------------------- 346 */ 347 void 348 Var_Set (name, val, ctxt) 349 char *name; /* name of variable to set */ 350 char *val; /* value to give to the variable */ 351 GNode *ctxt; /* context in which to set it */ 352 { 353 register Var *v; 354 355 /* 356 * We only look for a variable in the given context since anything set 357 * here will override anything in a lower context, so there's not much 358 * point in searching them all just to save a bit of memory... 359 */ 360 v = VarFind (name, ctxt, 0); 361 if (v == (Var *) NIL) { 362 VarAdd (name, val, ctxt); 363 } else { 364 Buf_Discard(v->val, Buf_Size(v->val)); 365 Buf_AddBytes(v->val, strlen(val), (Byte *)val); 366 367 if (DEBUG(VAR)) { 368 printf("%s:%s = %s\n", ctxt->name, name, val); 369 } 370 } 371 /* 372 * Any variables given on the command line are automatically exported 373 * to the environment (as per POSIX standard) 374 */ 375 if (ctxt == VAR_CMD) { 376 setenv(name, val, 1); 377 } 378 } 379 380 /*- 381 *----------------------------------------------------------------------- 382 * Var_Append -- 383 * The variable of the given name has the given value appended to it in 384 * the given context. 385 * 386 * Results: 387 * None 388 * 389 * Side Effects: 390 * If the variable doesn't exist, it is created. Else the strings 391 * are concatenated (with a space in between). 392 * 393 * Notes: 394 * Only if the variable is being sought in the global context is the 395 * environment searched. 396 * XXX: Knows its calling circumstances in that if called with ctxt 397 * an actual target, it will only search that context since only 398 * a local variable could be being appended to. This is actually 399 * a big win and must be tolerated. 400 *----------------------------------------------------------------------- 401 */ 402 void 403 Var_Append (name, val, ctxt) 404 char *name; /* Name of variable to modify */ 405 char *val; /* String to append to it */ 406 GNode *ctxt; /* Context in which this should occur */ 407 { 408 register Var *v; 409 register char *cp; 410 411 v = VarFind (name, ctxt, (ctxt == VAR_GLOBAL) ? FIND_ENV : 0); 412 413 if (v == (Var *) NIL) { 414 VarAdd (name, val, ctxt); 415 } else { 416 Buf_AddByte(v->val, (Byte)' '); 417 Buf_AddBytes(v->val, strlen(val), (Byte *)val); 418 419 if (DEBUG(VAR)) { 420 printf("%s:%s = %s\n", ctxt->name, name, 421 Buf_GetAll(v->val, (int *)NULL)); 422 } 423 424 if (v->flags & VAR_FROM_ENV) { 425 /* 426 * If the original variable came from the environment, we 427 * have to install it in the global context (we could place 428 * it in the environment, but then we should provide a way to 429 * export other variables...) 430 */ 431 v->flags &= ~VAR_FROM_ENV; 432 Lst_AtFront(ctxt->context, (ClientData)v); 433 } 434 } 435 } 436 437 /*- 438 *----------------------------------------------------------------------- 439 * Var_Exists -- 440 * See if the given variable exists. 441 * 442 * Results: 443 * TRUE if it does, FALSE if it doesn't 444 * 445 * Side Effects: 446 * None. 447 * 448 *----------------------------------------------------------------------- 449 */ 450 Boolean 451 Var_Exists(name, ctxt) 452 char *name; /* Variable to find */ 453 GNode *ctxt; /* Context in which to start search */ 454 { 455 Var *v; 456 457 v = VarFind(name, ctxt, FIND_CMD|FIND_GLOBAL|FIND_ENV); 458 459 if (v == (Var *)NIL) { 460 return(FALSE); 461 } else if (v->flags & VAR_FROM_ENV) { 462 Buf_Destroy(v->val, TRUE); 463 free((char *)v); 464 } 465 return(TRUE); 466 } 467 468 /*- 469 *----------------------------------------------------------------------- 470 * Var_Value -- 471 * Return the value of the named variable in the given context 472 * 473 * Results: 474 * The value if the variable exists, NULL if it doesn't 475 * 476 * Side Effects: 477 * None 478 *----------------------------------------------------------------------- 479 */ 480 char * 481 Var_Value (name, ctxt) 482 char *name; /* name to find */ 483 GNode *ctxt; /* context in which to search for it */ 484 { 485 Var *v; 486 487 v = VarFind (name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD); 488 if (v != (Var *) NIL) { 489 return ((char *)Buf_GetAll(v->val, (int *)NULL)); 490 } else { 491 return ((char *) NULL); 492 } 493 } 494 495 /*- 496 *----------------------------------------------------------------------- 497 * VarHead -- 498 * Remove the tail of the given word and place the result in the given 499 * buffer. 500 * 501 * Results: 502 * TRUE if characters were added to the buffer (a space needs to be 503 * added to the buffer before the next word). 504 * 505 * Side Effects: 506 * The trimmed word is added to the buffer. 507 * 508 *----------------------------------------------------------------------- 509 */ 510 static Boolean 511 VarHead (word, addSpace, buf) 512 char *word; /* Word to trim */ 513 Boolean addSpace; /* True if need to add a space to the buffer 514 * before sticking in the head */ 515 Buffer buf; /* Buffer in which to store it */ 516 { 517 register char *slash; 518 519 slash = rindex (word, '/'); 520 if (slash != (char *)NULL) { 521 if (addSpace) { 522 Buf_AddByte (buf, (Byte)' '); 523 } 524 *slash = '\0'; 525 Buf_AddBytes (buf, strlen (word), (Byte *)word); 526 *slash = '/'; 527 return (TRUE); 528 } else { 529 /* 530 * If no directory part, give . (q.v. the POSIX standard) 531 */ 532 if (addSpace) { 533 Buf_AddBytes(buf, 2, (Byte *)" ."); 534 } else { 535 Buf_AddByte(buf, (Byte)'.'); 536 } 537 return(TRUE); 538 } 539 } 540 541 /*- 542 *----------------------------------------------------------------------- 543 * VarTail -- 544 * Remove the head of the given word and place the result in the given 545 * buffer. 546 * 547 * Results: 548 * TRUE if characters were added to the buffer (a space needs to be 549 * added to the buffer before the next word). 550 * 551 * Side Effects: 552 * The trimmed word is added to the buffer. 553 * 554 *----------------------------------------------------------------------- 555 */ 556 static Boolean 557 VarTail (word, addSpace, buf) 558 char *word; /* Word to trim */ 559 Boolean addSpace; /* TRUE if need to stick a space in the 560 * buffer before adding the tail */ 561 Buffer buf; /* Buffer in which to store it */ 562 { 563 register char *slash; 564 565 if (addSpace) { 566 Buf_AddByte (buf, (Byte)' '); 567 } 568 569 slash = rindex (word, '/'); 570 if (slash != (char *)NULL) { 571 *slash++ = '\0'; 572 Buf_AddBytes (buf, strlen(slash), (Byte *)slash); 573 slash[-1] = '/'; 574 } else { 575 Buf_AddBytes (buf, strlen(word), (Byte *)word); 576 } 577 return (TRUE); 578 } 579 580 /*- 581 *----------------------------------------------------------------------- 582 * VarSuffix -- 583 * Place the suffix of the given word in the given buffer. 584 * 585 * Results: 586 * TRUE if characters were added to the buffer (a space needs to be 587 * added to the buffer before the next word). 588 * 589 * Side Effects: 590 * The suffix from the word is placed in the buffer. 591 * 592 *----------------------------------------------------------------------- 593 */ 594 static Boolean 595 VarSuffix (word, addSpace, buf) 596 char *word; /* Word to trim */ 597 Boolean addSpace; /* TRUE if need to add a space before placing 598 * the suffix in the buffer */ 599 Buffer buf; /* Buffer in which to store it */ 600 { 601 register char *dot; 602 603 dot = rindex (word, '.'); 604 if (dot != (char *)NULL) { 605 if (addSpace) { 606 Buf_AddByte (buf, (Byte)' '); 607 } 608 *dot++ = '\0'; 609 Buf_AddBytes (buf, strlen (dot), (Byte *)dot); 610 dot[-1] = '.'; 611 return (TRUE); 612 } else { 613 return (addSpace); 614 } 615 } 616 617 /*- 618 *----------------------------------------------------------------------- 619 * VarRoot -- 620 * Remove the suffix of the given word and place the result in the 621 * buffer. 622 * 623 * Results: 624 * TRUE if characters were added to the buffer (a space needs to be 625 * added to the buffer before the next word). 626 * 627 * Side Effects: 628 * The trimmed word is added to the buffer. 629 * 630 *----------------------------------------------------------------------- 631 */ 632 static Boolean 633 VarRoot (word, addSpace, buf) 634 char *word; /* Word to trim */ 635 Boolean addSpace; /* TRUE if need to add a space to the buffer 636 * before placing the root in it */ 637 Buffer buf; /* Buffer in which to store it */ 638 { 639 register char *dot; 640 641 if (addSpace) { 642 Buf_AddByte (buf, (Byte)' '); 643 } 644 645 dot = rindex (word, '.'); 646 if (dot != (char *)NULL) { 647 *dot = '\0'; 648 Buf_AddBytes (buf, strlen (word), (Byte *)word); 649 *dot = '.'; 650 } else { 651 Buf_AddBytes (buf, strlen(word), (Byte *)word); 652 } 653 return (TRUE); 654 } 655 656 /*- 657 *----------------------------------------------------------------------- 658 * VarMatch -- 659 * Place the word in the buffer if it matches the given pattern. 660 * Callback function for VarModify to implement the :M modifier. 661 * 662 * Results: 663 * TRUE if a space should be placed in the buffer before the next 664 * word. 665 * 666 * Side Effects: 667 * The word may be copied to the buffer. 668 * 669 *----------------------------------------------------------------------- 670 */ 671 static Boolean 672 VarMatch (word, addSpace, buf, pattern) 673 char *word; /* Word to examine */ 674 Boolean addSpace; /* TRUE if need to add a space to the 675 * buffer before adding the word, if it 676 * matches */ 677 Buffer buf; /* Buffer in which to store it */ 678 char *pattern; /* Pattern the word must match */ 679 { 680 if (Str_Match(word, pattern)) { 681 if (addSpace) { 682 Buf_AddByte(buf, (Byte)' '); 683 } 684 addSpace = TRUE; 685 Buf_AddBytes(buf, strlen(word), (Byte *)word); 686 } 687 return(addSpace); 688 } 689 690 /*- 691 *----------------------------------------------------------------------- 692 * VarNoMatch -- 693 * Place the word in the buffer if it doesn't match the given pattern. 694 * Callback function for VarModify to implement the :N modifier. 695 * 696 * Results: 697 * TRUE if a space should be placed in the buffer before the next 698 * word. 699 * 700 * Side Effects: 701 * The word may be copied to the buffer. 702 * 703 *----------------------------------------------------------------------- 704 */ 705 static Boolean 706 VarNoMatch (word, addSpace, buf, pattern) 707 char *word; /* Word to examine */ 708 Boolean addSpace; /* TRUE if need to add a space to the 709 * buffer before adding the word, if it 710 * matches */ 711 Buffer buf; /* Buffer in which to store it */ 712 char *pattern; /* Pattern the word must match */ 713 { 714 if (!Str_Match(word, pattern)) { 715 if (addSpace) { 716 Buf_AddByte(buf, (Byte)' '); 717 } 718 addSpace = TRUE; 719 Buf_AddBytes(buf, strlen(word), (Byte *)word); 720 } 721 return(addSpace); 722 } 723 724 typedef struct { 725 char *lhs; /* String to match */ 726 int leftLen; /* Length of string */ 727 char *rhs; /* Replacement string (w/ &'s removed) */ 728 int rightLen; /* Length of replacement */ 729 int flags; 730 #define VAR_SUB_GLOBAL 1 /* Apply substitution globally */ 731 #define VAR_MATCH_START 2 /* Match at start of word */ 732 #define VAR_MATCH_END 4 /* Match at end of word */ 733 #define VAR_NO_SUB 8 /* Substitution is non-global and already done */ 734 } VarPattern; 735 736 /*- 737 *----------------------------------------------------------------------- 738 * VarSubstitute -- 739 * Perform a string-substitution on the given word, placing the 740 * result in the passed buffer. 741 * 742 * Results: 743 * TRUE if a space is needed before more characters are added. 744 * 745 * Side Effects: 746 * None. 747 * 748 *----------------------------------------------------------------------- 749 */ 750 static Boolean 751 VarSubstitute (word, addSpace, buf, pattern) 752 char *word; /* Word to modify */ 753 Boolean addSpace; /* True if space should be added before 754 * other characters */ 755 Buffer buf; /* Buffer for result */ 756 register VarPattern *pattern; /* Pattern for substitution */ 757 { 758 register int wordLen; /* Length of word */ 759 register char *cp; /* General pointer */ 760 761 wordLen = strlen(word); 762 if ((pattern->flags & VAR_NO_SUB) == 0) { 763 /* 764 * Still substituting -- break it down into simple anchored cases 765 * and if none of them fits, perform the general substitution case. 766 */ 767 if ((pattern->flags & VAR_MATCH_START) && 768 (strncmp(word, pattern->lhs, pattern->leftLen) == 0)) { 769 /* 770 * Anchored at start and beginning of word matches pattern 771 */ 772 if ((pattern->flags & VAR_MATCH_END) && 773 (wordLen == pattern->leftLen)) { 774 /* 775 * Also anchored at end and matches to the end (word 776 * is same length as pattern) add space and rhs only 777 * if rhs is non-null. 778 */ 779 if (pattern->rightLen != 0) { 780 if (addSpace) { 781 Buf_AddByte(buf, (Byte)' '); 782 } 783 addSpace = TRUE; 784 Buf_AddBytes(buf, pattern->rightLen, 785 (Byte *)pattern->rhs); 786 } 787 } else if (pattern->flags & VAR_MATCH_END) { 788 /* 789 * Doesn't match to end -- copy word wholesale 790 */ 791 goto nosub; 792 } else { 793 /* 794 * Matches at start but need to copy in trailing characters 795 */ 796 if ((pattern->rightLen + wordLen - pattern->leftLen) != 0){ 797 if (addSpace) { 798 Buf_AddByte(buf, (Byte)' '); 799 } 800 addSpace = TRUE; 801 } 802 Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs); 803 Buf_AddBytes(buf, wordLen - pattern->leftLen, 804 (Byte *)(word + pattern->leftLen)); 805 } 806 } else if (pattern->flags & VAR_MATCH_START) { 807 /* 808 * Had to match at start of word and didn't -- copy whole word. 809 */ 810 goto nosub; 811 } else if (pattern->flags & VAR_MATCH_END) { 812 /* 813 * Anchored at end, Find only place match could occur (leftLen 814 * characters from the end of the word) and see if it does. Note 815 * that because the $ will be left at the end of the lhs, we have 816 * to use strncmp. 817 */ 818 cp = word + (wordLen - pattern->leftLen); 819 if ((cp >= word) && 820 (strncmp(cp, pattern->lhs, pattern->leftLen) == 0)) { 821 /* 822 * Match found. If we will place characters in the buffer, 823 * add a space before hand as indicated by addSpace, then 824 * stuff in the initial, unmatched part of the word followed 825 * by the right-hand-side. 826 */ 827 if (((cp - word) + pattern->rightLen) != 0) { 828 if (addSpace) { 829 Buf_AddByte(buf, (Byte)' '); 830 } 831 addSpace = TRUE; 832 } 833 Buf_AddBytes(buf, cp - word, (Byte *)word); 834 Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs); 835 } else { 836 /* 837 * Had to match at end and didn't. Copy entire word. 838 */ 839 goto nosub; 840 } 841 } else { 842 /* 843 * Pattern is unanchored: search for the pattern in the word using 844 * String_FindSubstring, copying unmatched portions and the 845 * right-hand-side for each match found, handling non-global 846 * subsititutions correctly, etc. When the loop is done, any 847 * remaining part of the word (word and wordLen are adjusted 848 * accordingly through the loop) is copied straight into the 849 * buffer. 850 * addSpace is set FALSE as soon as a space is added to the 851 * buffer. 852 */ 853 register Boolean done; 854 int origSize; 855 856 done = FALSE; 857 origSize = Buf_Size(buf); 858 while (!done) { 859 cp = Str_FindSubstring(word, pattern->lhs); 860 if (cp != (char *)NULL) { 861 if (addSpace && (((cp - word) + pattern->rightLen) != 0)){ 862 Buf_AddByte(buf, (Byte)' '); 863 addSpace = FALSE; 864 } 865 Buf_AddBytes(buf, cp-word, (Byte *)word); 866 Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs); 867 wordLen -= (cp - word) + pattern->leftLen; 868 word = cp + pattern->leftLen; 869 if (wordLen == 0) { 870 done = TRUE; 871 } 872 if ((pattern->flags & VAR_SUB_GLOBAL) == 0) { 873 done = TRUE; 874 pattern->flags |= VAR_NO_SUB; 875 } 876 } else { 877 done = TRUE; 878 } 879 } 880 if (wordLen != 0) { 881 if (addSpace) { 882 Buf_AddByte(buf, (Byte)' '); 883 } 884 Buf_AddBytes(buf, wordLen, (Byte *)word); 885 } 886 /* 887 * If added characters to the buffer, need to add a space 888 * before we add any more. If we didn't add any, just return 889 * the previous value of addSpace. 890 */ 891 return ((Buf_Size(buf) != origSize) || addSpace); 892 } 893 /* 894 * Common code for anchored substitutions: if performed a substitution 895 * and it's not supposed to be global, mark the pattern as requiring 896 * no more substitutions. addSpace was set TRUE if characters were 897 * added to the buffer. 898 */ 899 if ((pattern->flags & VAR_SUB_GLOBAL) == 0) { 900 pattern->flags |= VAR_NO_SUB; 901 } 902 return (addSpace); 903 } 904 nosub: 905 if (addSpace) { 906 Buf_AddByte(buf, (Byte)' '); 907 } 908 Buf_AddBytes(buf, wordLen, (Byte *)word); 909 return(TRUE); 910 } 911 912 /*- 913 *----------------------------------------------------------------------- 914 * VarModify -- 915 * Modify each of the words of the passed string using the given 916 * function. Used to implement all modifiers. 917 * 918 * Results: 919 * A string of all the words modified appropriately. 920 * 921 * Side Effects: 922 * None. 923 * 924 *----------------------------------------------------------------------- 925 */ 926 static char * 927 VarModify (str, modProc, datum) 928 char *str; /* String whose words should be trimmed */ 929 Boolean (*modProc)(); /* Function to use to modify them */ 930 ClientData datum; /* Datum to pass it */ 931 { 932 Buffer buf; /* Buffer for the new string */ 933 register char *cp; /* Pointer to end of current word */ 934 char endc; /* Character that ended the word */ 935 Boolean addSpace; /* TRUE if need to add a space to the 936 * buffer before adding the trimmed 937 * word */ 938 939 buf = Buf_Init (0); 940 cp = str; 941 addSpace = FALSE; 942 943 while (1) { 944 /* 945 * Skip to next word and place cp at its end. 946 */ 947 while (isspace (*str)) { 948 str++; 949 } 950 for (cp = str; *cp != '\0' && !isspace (*cp); cp++) { 951 /* void */ ; 952 } 953 if (cp == str) { 954 /* 955 * If we didn't go anywhere, we must be done! 956 */ 957 Buf_AddByte (buf, '\0'); 958 str = (char *)Buf_GetAll (buf, (int *)NULL); 959 Buf_Destroy (buf, FALSE); 960 return (str); 961 } 962 /* 963 * Nuke terminating character, but save it in endc b/c if str was 964 * some variable's value, it would not be good to screw it 965 * over... 966 */ 967 endc = *cp; 968 *cp = '\0'; 969 970 addSpace = (* modProc) (str, addSpace, buf, datum); 971 972 if (endc) { 973 *cp++ = endc; 974 } 975 str = cp; 976 } 977 } 978 979 /*- 980 *----------------------------------------------------------------------- 981 * Var_Parse -- 982 * Given the start of a variable invocation, extract the variable 983 * name and find its value, then modify it according to the 984 * specification. 985 * 986 * Results: 987 * The (possibly-modified) value of the variable or var_Error if the 988 * specification is invalid. The length of the specification is 989 * placed in *lengthPtr (for invalid specifications, this is just 990 * 2...?). 991 * A Boolean in *freePtr telling whether the returned string should 992 * be freed by the caller. 993 * 994 * Side Effects: 995 * None. 996 * 997 *----------------------------------------------------------------------- 998 */ 999 char * 1000 Var_Parse (str, ctxt, err, lengthPtr, freePtr) 1001 char *str; /* The string to parse */ 1002 GNode *ctxt; /* The context for the variable */ 1003 Boolean err; /* TRUE if undefined variables are an error */ 1004 int *lengthPtr; /* OUT: The length of the specification */ 1005 Boolean *freePtr; /* OUT: TRUE if caller should free result */ 1006 { 1007 register char *tstr; /* Pointer into str */ 1008 Var *v; /* Variable in invocation */ 1009 register char *cp; /* Secondary pointer into str (place marker 1010 * for tstr) */ 1011 Boolean haveModifier;/* TRUE if have modifiers for the variable */ 1012 register char endc; /* Ending character when variable in parens 1013 * or braces */ 1014 char *start; 1015 Boolean dynamic; /* TRUE if the variable is local and we're 1016 * expanding it in a non-local context. This 1017 * is done to support dynamic sources. The 1018 * result is just the invocation, unaltered */ 1019 1020 *freePtr = FALSE; 1021 dynamic = FALSE; 1022 start = str; 1023 1024 if (str[1] != '(' && str[1] != '{') { 1025 /* 1026 * If it's not bounded by braces of some sort, life is much simpler. 1027 * We just need to check for the first character and return the 1028 * value if it exists. 1029 */ 1030 char name[2]; 1031 1032 name[0] = str[1]; 1033 name[1] = '\0'; 1034 1035 v = VarFind (name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD); 1036 if (v == (Var *)NIL) { 1037 *lengthPtr = 2; 1038 1039 if ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)) { 1040 /* 1041 * If substituting a local variable in a non-local context, 1042 * assume it's for dynamic source stuff. We have to handle 1043 * this specially and return the longhand for the variable 1044 * with the dollar sign escaped so it makes it back to the 1045 * caller. Only four of the local variables are treated 1046 * specially as they are the only four that will be set 1047 * when dynamic sources are expanded. 1048 */ 1049 switch (str[1]) { 1050 case '@': 1051 return("$(.TARGET)"); 1052 case '%': 1053 return("$(.ARCHIVE)"); 1054 case '*': 1055 return("$(.PREFIX)"); 1056 case '!': 1057 return("$(.MEMBER)"); 1058 } 1059 } 1060 /* 1061 * Error 1062 */ 1063 return (err ? var_Error : varNoError); 1064 } else { 1065 haveModifier = FALSE; 1066 tstr = &str[1]; 1067 endc = str[1]; 1068 } 1069 } else { 1070 endc = str[1] == '(' ? ')' : '}'; 1071 1072 /* 1073 * Skip to the end character or a colon, whichever comes first. 1074 */ 1075 for (tstr = str + 2; 1076 *tstr != '\0' && *tstr != endc && *tstr != ':'; 1077 tstr++) 1078 { 1079 continue; 1080 } 1081 if (*tstr == ':') { 1082 haveModifier = TRUE; 1083 } else if (*tstr != '\0') { 1084 haveModifier = FALSE; 1085 } else { 1086 /* 1087 * If we never did find the end character, return NULL 1088 * right now, setting the length to be the distance to 1089 * the end of the string, since that's what make does. 1090 */ 1091 *lengthPtr = tstr - str; 1092 return (var_Error); 1093 } 1094 *tstr = '\0'; 1095 1096 v = VarFind (str + 2, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD); 1097 if ((v == (Var *)NIL) && (ctxt != VAR_CMD) && (ctxt != VAR_GLOBAL) && 1098 ((tstr-str) == 4) && (str[3] == 'F' || str[3] == 'D')) 1099 { 1100 /* 1101 * Check for bogus D and F forms of local variables since we're 1102 * in a local context and the name is the right length. 1103 */ 1104 switch(str[2]) { 1105 case '@': 1106 case '%': 1107 case '*': 1108 case '!': 1109 case '>': 1110 case '<': 1111 { 1112 char vname[2]; 1113 char *val; 1114 1115 /* 1116 * Well, it's local -- go look for it. 1117 */ 1118 vname[0] = str[2]; 1119 vname[1] = '\0'; 1120 v = VarFind(vname, ctxt, 0); 1121 1122 if (v != (Var *)NIL) { 1123 /* 1124 * No need for nested expansion or anything, as we're 1125 * the only one who sets these things and we sure don't 1126 * but nested invocations in them... 1127 */ 1128 val = (char *)Buf_GetAll(v->val, (int *)NULL); 1129 1130 if (str[3] == 'D') { 1131 val = VarModify(val, VarHead, (ClientData)0); 1132 } else { 1133 val = VarModify(val, VarTail, (ClientData)0); 1134 } 1135 /* 1136 * Resulting string is dynamically allocated, so 1137 * tell caller to free it. 1138 */ 1139 *freePtr = TRUE; 1140 *lengthPtr = tstr-start+1; 1141 *tstr = endc; 1142 return(val); 1143 } 1144 break; 1145 } 1146 } 1147 } 1148 1149 if (v == (Var *)NIL) { 1150 if ((((tstr-str) == 3) || 1151 ((((tstr-str) == 4) && (str[3] == 'F' || 1152 str[3] == 'D')))) && 1153 ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL))) 1154 { 1155 /* 1156 * If substituting a local variable in a non-local context, 1157 * assume it's for dynamic source stuff. We have to handle 1158 * this specially and return the longhand for the variable 1159 * with the dollar sign escaped so it makes it back to the 1160 * caller. Only four of the local variables are treated 1161 * specially as they are the only four that will be set 1162 * when dynamic sources are expanded. 1163 */ 1164 switch (str[2]) { 1165 case '@': 1166 case '%': 1167 case '*': 1168 case '!': 1169 dynamic = TRUE; 1170 break; 1171 } 1172 } else if (((tstr-str) > 4) && (str[2] == '.') && 1173 isupper(str[3]) && 1174 ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL))) 1175 { 1176 int len; 1177 1178 len = (tstr-str) - 3; 1179 if ((strncmp(str+2, ".TARGET", len) == 0) || 1180 (strncmp(str+2, ".ARCHIVE", len) == 0) || 1181 (strncmp(str+2, ".PREFIX", len) == 0) || 1182 (strncmp(str+2, ".MEMBER", len) == 0)) 1183 { 1184 dynamic = TRUE; 1185 } 1186 } 1187 1188 if (!haveModifier) { 1189 /* 1190 * No modifiers -- have specification length so we can return 1191 * now. 1192 */ 1193 *lengthPtr = tstr - start + 1; 1194 *tstr = endc; 1195 if (dynamic) { 1196 str = emalloc(*lengthPtr + 1); 1197 strncpy(str, start, *lengthPtr); 1198 str[*lengthPtr] = '\0'; 1199 *freePtr = TRUE; 1200 return(str); 1201 } else { 1202 return (err ? var_Error : varNoError); 1203 } 1204 } else { 1205 /* 1206 * Still need to get to the end of the variable specification, 1207 * so kludge up a Var structure for the modifications 1208 */ 1209 v = (Var *) emalloc(sizeof(Var)); 1210 v->name = &str[1]; 1211 v->val = Buf_Init(1); 1212 v->flags = VAR_JUNK; 1213 } 1214 } 1215 } 1216 1217 if (v->flags & VAR_IN_USE) { 1218 Fatal("Variable %s is recursive.", v->name); 1219 /*NOTREACHED*/ 1220 } else { 1221 v->flags |= VAR_IN_USE; 1222 } 1223 /* 1224 * Before doing any modification, we have to make sure the value 1225 * has been fully expanded. If it looks like recursion might be 1226 * necessary (there's a dollar sign somewhere in the variable's value) 1227 * we just call Var_Subst to do any other substitutions that are 1228 * necessary. Note that the value returned by Var_Subst will have 1229 * been dynamically-allocated, so it will need freeing when we 1230 * return. 1231 */ 1232 str = (char *)Buf_GetAll(v->val, (int *)NULL); 1233 if (index (str, '$') != (char *)NULL) { 1234 str = Var_Subst(str, ctxt, err); 1235 *freePtr = TRUE; 1236 } 1237 1238 v->flags &= ~VAR_IN_USE; 1239 1240 /* 1241 * Now we need to apply any modifiers the user wants applied. 1242 * These are: 1243 * :M<pattern> words which match the given <pattern>. 1244 * <pattern> is of the standard file 1245 * wildcarding form. 1246 * :S<d><pat1><d><pat2><d>[g] 1247 * Substitute <pat2> for <pat1> in the value 1248 * :H Substitute the head of each word 1249 * :T Substitute the tail of each word 1250 * :E Substitute the extension (minus '.') of 1251 * each word 1252 * :R Substitute the root of each word 1253 * (pathname minus the suffix). 1254 * :lhs=rhs Like :S, but the rhs goes to the end of 1255 * the invocation. 1256 */ 1257 if ((str != (char *)NULL) && haveModifier) { 1258 /* 1259 * Skip initial colon while putting it back. 1260 */ 1261 *tstr++ = ':'; 1262 while (*tstr != endc) { 1263 char *newStr; /* New value to return */ 1264 char termc; /* Character which terminated scan */ 1265 1266 if (DEBUG(VAR)) { 1267 printf("Applying :%c to \"%s\"\n", *tstr, str); 1268 } 1269 switch (*tstr) { 1270 case 'N': 1271 case 'M': 1272 { 1273 char *pattern; 1274 char *cp2; 1275 Boolean copy; 1276 1277 copy = FALSE; 1278 for (cp = tstr + 1; 1279 *cp != '\0' && *cp != ':' && *cp != endc; 1280 cp++) 1281 { 1282 if (*cp == '\\' && (cp[1] == ':' || cp[1] == endc)){ 1283 copy = TRUE; 1284 cp++; 1285 } 1286 } 1287 termc = *cp; 1288 *cp = '\0'; 1289 if (copy) { 1290 /* 1291 * Need to compress the \:'s out of the pattern, so 1292 * allocate enough room to hold the uncompressed 1293 * pattern (note that cp started at tstr+1, so 1294 * cp - tstr takes the null byte into account) and 1295 * compress the pattern into the space. 1296 */ 1297 pattern = emalloc(cp - tstr); 1298 for (cp2 = pattern, cp = tstr + 1; 1299 *cp != '\0'; 1300 cp++, cp2++) 1301 { 1302 if ((*cp == '\\') && 1303 (cp[1] == ':' || cp[1] == endc)) { 1304 cp++; 1305 } 1306 *cp2 = *cp; 1307 } 1308 *cp2 = '\0'; 1309 } else { 1310 pattern = &tstr[1]; 1311 } 1312 if (*tstr == 'M' || *tstr == 'm') { 1313 newStr = VarModify(str, VarMatch, (ClientData)pattern); 1314 } else { 1315 newStr = VarModify(str, VarNoMatch, 1316 (ClientData)pattern); 1317 } 1318 if (copy) { 1319 free(pattern); 1320 } 1321 break; 1322 } 1323 case 'S': 1324 { 1325 VarPattern pattern; 1326 register char delim; 1327 Buffer buf; /* Buffer for patterns */ 1328 register char *cp2; 1329 int lefts; 1330 1331 pattern.flags = 0; 1332 delim = tstr[1]; 1333 tstr += 2; 1334 /* 1335 * If pattern begins with '^', it is anchored to the 1336 * start of the word -- skip over it and flag pattern. 1337 */ 1338 if (*tstr == '^') { 1339 pattern.flags |= VAR_MATCH_START; 1340 tstr += 1; 1341 } 1342 1343 buf = Buf_Init(0); 1344 1345 /* 1346 * Pass through the lhs looking for 1) escaped delimiters, 1347 * '$'s and backslashes (place the escaped character in 1348 * uninterpreted) and 2) unescaped $'s that aren't before 1349 * the delimiter (expand the variable substitution). 1350 * The result is left in the Buffer buf. 1351 */ 1352 for (cp = tstr; *cp != '\0' && *cp != delim; cp++) { 1353 if ((*cp == '\\') && 1354 ((cp[1] == delim) || 1355 (cp[1] == '$') || 1356 (cp[1] == '\\'))) 1357 { 1358 Buf_AddByte(buf, (Byte)cp[1]); 1359 cp++; 1360 } else if (*cp == '$') { 1361 if (cp[1] != delim) { 1362 /* 1363 * If unescaped dollar sign not before the 1364 * delimiter, assume it's a variable 1365 * substitution and recurse. 1366 */ 1367 char *cp2; 1368 int len; 1369 Boolean freeIt; 1370 1371 cp2 = Var_Parse(cp, ctxt, err, &len, &freeIt); 1372 Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2); 1373 if (freeIt) { 1374 free(cp2); 1375 } 1376 cp += len - 1; 1377 } else { 1378 /* 1379 * Unescaped $ at end of pattern => anchor 1380 * pattern at end. 1381 */ 1382 pattern.flags |= VAR_MATCH_END; 1383 } 1384 } else { 1385 Buf_AddByte(buf, (Byte)*cp); 1386 } 1387 } 1388 1389 Buf_AddByte(buf, (Byte)'\0'); 1390 1391 /* 1392 * If lhs didn't end with the delimiter, complain and 1393 * return NULL 1394 */ 1395 if (*cp != delim) { 1396 *lengthPtr = cp - start + 1; 1397 if (*freePtr) { 1398 free(str); 1399 } 1400 Buf_Destroy(buf, TRUE); 1401 Error("Unclosed substitution for %s (%c missing)", 1402 v->name, delim); 1403 return (var_Error); 1404 } 1405 1406 /* 1407 * Fetch pattern and destroy buffer, but preserve the data 1408 * in it, since that's our lhs. Note that Buf_GetAll 1409 * will return the actual number of bytes, which includes 1410 * the null byte, so we have to decrement the length by 1411 * one. 1412 */ 1413 pattern.lhs = (char *)Buf_GetAll(buf, &pattern.leftLen); 1414 pattern.leftLen--; 1415 Buf_Destroy(buf, FALSE); 1416 1417 /* 1418 * Now comes the replacement string. Three things need to 1419 * be done here: 1) need to compress escaped delimiters and 1420 * ampersands and 2) need to replace unescaped ampersands 1421 * with the l.h.s. (since this isn't regexp, we can do 1422 * it right here) and 3) expand any variable substitutions. 1423 */ 1424 buf = Buf_Init(0); 1425 1426 tstr = cp + 1; 1427 for (cp = tstr; *cp != '\0' && *cp != delim; cp++) { 1428 if ((*cp == '\\') && 1429 ((cp[1] == delim) || 1430 (cp[1] == '&') || 1431 (cp[1] == '\\') || 1432 (cp[1] == '$'))) 1433 { 1434 Buf_AddByte(buf, (Byte)cp[1]); 1435 cp++; 1436 } else if ((*cp == '$') && (cp[1] != delim)) { 1437 char *cp2; 1438 int len; 1439 Boolean freeIt; 1440 1441 cp2 = Var_Parse(cp, ctxt, err, &len, &freeIt); 1442 Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2); 1443 cp += len - 1; 1444 if (freeIt) { 1445 free(cp2); 1446 } 1447 } else if (*cp == '&') { 1448 Buf_AddBytes(buf, pattern.leftLen, 1449 (Byte *)pattern.lhs); 1450 } else { 1451 Buf_AddByte(buf, (Byte)*cp); 1452 } 1453 } 1454 1455 Buf_AddByte(buf, (Byte)'\0'); 1456 1457 /* 1458 * If didn't end in delimiter character, complain 1459 */ 1460 if (*cp != delim) { 1461 *lengthPtr = cp - start + 1; 1462 if (*freePtr) { 1463 free(str); 1464 } 1465 Buf_Destroy(buf, TRUE); 1466 Error("Unclosed substitution for %s (%c missing)", 1467 v->name, delim); 1468 return (var_Error); 1469 } 1470 1471 pattern.rhs = (char *)Buf_GetAll(buf, &pattern.rightLen); 1472 pattern.rightLen--; 1473 Buf_Destroy(buf, FALSE); 1474 1475 /* 1476 * Check for global substitution. If 'g' after the final 1477 * delimiter, substitution is global and is marked that 1478 * way. 1479 */ 1480 cp++; 1481 if (*cp == 'g') { 1482 pattern.flags |= VAR_SUB_GLOBAL; 1483 cp++; 1484 } 1485 1486 termc = *cp; 1487 newStr = VarModify(str, VarSubstitute, 1488 (ClientData)&pattern); 1489 /* 1490 * Free the two strings. 1491 */ 1492 free(pattern.lhs); 1493 free(pattern.rhs); 1494 break; 1495 } 1496 case 'T': 1497 if (tstr[1] == endc || tstr[1] == ':') { 1498 newStr = VarModify (str, VarTail, (ClientData)0); 1499 cp = tstr + 1; 1500 termc = *cp; 1501 break; 1502 } 1503 /*FALLTHRU*/ 1504 case 'H': 1505 if (tstr[1] == endc || tstr[1] == ':') { 1506 newStr = VarModify (str, VarHead, (ClientData)0); 1507 cp = tstr + 1; 1508 termc = *cp; 1509 break; 1510 } 1511 /*FALLTHRU*/ 1512 case 'E': 1513 if (tstr[1] == endc || tstr[1] == ':') { 1514 newStr = VarModify (str, VarSuffix, (ClientData)0); 1515 cp = tstr + 1; 1516 termc = *cp; 1517 break; 1518 } 1519 /*FALLTHRU*/ 1520 case 'R': 1521 if (tstr[1] == endc || tstr[1] == ':') { 1522 newStr = VarModify (str, VarRoot, (ClientData)0); 1523 cp = tstr + 1; 1524 termc = *cp; 1525 break; 1526 } 1527 /*FALLTHRU*/ 1528 default: { 1529 /* 1530 * This can either be a bogus modifier or a System-V 1531 * substitution command. 1532 */ 1533 VarPattern pattern; 1534 Boolean eqFound; 1535 1536 pattern.flags = 0; 1537 eqFound = FALSE; 1538 /* 1539 * First we make a pass through the string trying 1540 * to verify it is a SYSV-make-style translation: 1541 * it must be: <string1>=<string2>) 1542 */ 1543 for (cp = tstr; *cp != '\0' && *cp != endc; cp++) { 1544 if (*cp == '=') { 1545 eqFound = TRUE; 1546 /* continue looking for endc */ 1547 } 1548 } 1549 if (*cp == endc && eqFound) { 1550 1551 /* 1552 * Now we break this sucker into the lhs and 1553 * rhs. We must null terminate them of course. 1554 */ 1555 for (cp = tstr; *cp != '='; cp++) { 1556 ; 1557 } 1558 pattern.lhs = tstr; 1559 pattern.leftLen = cp - tstr; 1560 *cp++ = '\0'; 1561 1562 pattern.rhs = cp; 1563 while (*cp != endc) { 1564 cp++; 1565 } 1566 pattern.rightLen = cp - pattern.rhs; 1567 *cp = '\0'; 1568 1569 /* 1570 * SYSV modifications happen through the whole 1571 * string. Note the pattern is anchored at the end. 1572 */ 1573 pattern.flags |= VAR_SUB_GLOBAL|VAR_MATCH_END; 1574 1575 newStr = VarModify(str, VarSubstitute, 1576 (ClientData)&pattern); 1577 1578 /* 1579 * Restore the nulled characters 1580 */ 1581 pattern.lhs[pattern.leftLen] = '='; 1582 pattern.rhs[pattern.rightLen] = endc; 1583 termc = endc; 1584 } else { 1585 Error ("Unknown modifier '%c'\n", *tstr); 1586 for (cp = tstr+1; 1587 *cp != ':' && *cp != endc && *cp != '\0'; 1588 cp++) { 1589 ; 1590 } 1591 termc = *cp; 1592 newStr = var_Error; 1593 } 1594 } 1595 } 1596 if (DEBUG(VAR)) { 1597 printf("Result is \"%s\"\n", newStr); 1598 } 1599 1600 if (*freePtr) { 1601 free (str); 1602 } 1603 str = newStr; 1604 if (str != var_Error) { 1605 *freePtr = TRUE; 1606 } else { 1607 *freePtr = FALSE; 1608 } 1609 if (termc == '\0') { 1610 Error("Unclosed variable specification for %s", v->name); 1611 } else if (termc == ':') { 1612 *cp++ = termc; 1613 } else { 1614 *cp = termc; 1615 } 1616 tstr = cp; 1617 } 1618 *lengthPtr = tstr - start + 1; 1619 } else { 1620 *lengthPtr = tstr - start + 1; 1621 *tstr = endc; 1622 } 1623 1624 if (v->flags & VAR_FROM_ENV) { 1625 Boolean destroy = FALSE; 1626 1627 if (str != (char *)Buf_GetAll(v->val, (int *)NULL)) { 1628 destroy = TRUE; 1629 } else { 1630 /* 1631 * Returning the value unmodified, so tell the caller to free 1632 * the thing. 1633 */ 1634 *freePtr = TRUE; 1635 } 1636 Buf_Destroy(v->val, destroy); 1637 free((Address)v); 1638 } else if (v->flags & VAR_JUNK) { 1639 /* 1640 * Perform any free'ing needed and set *freePtr to FALSE so the caller 1641 * doesn't try to free a static pointer. 1642 */ 1643 if (*freePtr) { 1644 free(str); 1645 } 1646 *freePtr = FALSE; 1647 free((Address)v); 1648 if (dynamic) { 1649 str = emalloc(*lengthPtr + 1); 1650 strncpy(str, start, *lengthPtr); 1651 str[*lengthPtr] = '\0'; 1652 *freePtr = TRUE; 1653 } else { 1654 str = var_Error; 1655 } 1656 } 1657 return (str); 1658 } 1659 1660 /*- 1661 *----------------------------------------------------------------------- 1662 * Var_Subst -- 1663 * Substitute for all variables in the given string in the given context 1664 * If undefErr is TRUE, Parse_Error will be called when an undefined 1665 * variable is encountered. 1666 * 1667 * Results: 1668 * The resulting string. 1669 * 1670 * Side Effects: 1671 * None. The old string must be freed by the caller 1672 *----------------------------------------------------------------------- 1673 */ 1674 char * 1675 Var_Subst (str, ctxt, undefErr) 1676 register char *str; /* the string in which to substitute */ 1677 GNode *ctxt; /* the context wherein to find variables */ 1678 Boolean undefErr; /* TRUE if undefineds are an error */ 1679 { 1680 Buffer buf; /* Buffer for forming things */ 1681 char *val; /* Value to substitute for a variable */ 1682 int length; /* Length of the variable invocation */ 1683 Boolean doFree; /* Set true if val should be freed */ 1684 static Boolean errorReported; /* Set true if an error has already 1685 * been reported to prevent a plethora 1686 * of messages when recursing */ 1687 1688 buf = Buf_Init (BSIZE); 1689 errorReported = FALSE; 1690 1691 while (*str) { 1692 if ((*str == '$') && (str[1] == '$')) { 1693 /* 1694 * A dollar sign may be escaped either with another dollar sign. 1695 * In such a case, we skip over the escape character and store the 1696 * dollar sign into the buffer directly. 1697 */ 1698 str++; 1699 Buf_AddByte(buf, (Byte)*str); 1700 str++; 1701 } else if (*str != '$') { 1702 /* 1703 * Skip as many characters as possible -- either to the end of 1704 * the string or to the next dollar sign (variable invocation). 1705 */ 1706 char *cp; 1707 1708 for (cp = str++; *str != '$' && *str != '\0'; str++) { 1709 ; 1710 } 1711 Buf_AddBytes(buf, str - cp, (Byte *)cp); 1712 } else { 1713 val = Var_Parse (str, ctxt, undefErr, &length, &doFree); 1714 1715 /* 1716 * When we come down here, val should either point to the 1717 * value of this variable, suitably modified, or be NULL. 1718 * Length should be the total length of the potential 1719 * variable invocation (from $ to end character...) 1720 */ 1721 if (val == var_Error || val == varNoError) { 1722 /* 1723 * If performing old-time variable substitution, skip over 1724 * the variable and continue with the substitution. Otherwise, 1725 * store the dollar sign and advance str so we continue with 1726 * the string... 1727 */ 1728 if (oldVars) { 1729 str += length; 1730 } else if (undefErr) { 1731 /* 1732 * If variable is undefined, complain and skip the 1733 * variable. The complaint will stop us from doing anything 1734 * when the file is parsed. 1735 */ 1736 if (!errorReported) { 1737 Parse_Error (PARSE_FATAL, 1738 "Undefined variable \"%.*s\"",length,str); 1739 } 1740 str += length; 1741 errorReported = TRUE; 1742 } else { 1743 Buf_AddByte (buf, (Byte)*str); 1744 str += 1; 1745 } 1746 } else { 1747 /* 1748 * We've now got a variable structure to store in. But first, 1749 * advance the string pointer. 1750 */ 1751 str += length; 1752 1753 /* 1754 * Copy all the characters from the variable value straight 1755 * into the new string. 1756 */ 1757 Buf_AddBytes (buf, strlen (val), (Byte *)val); 1758 if (doFree) { 1759 free ((Address)val); 1760 } 1761 } 1762 } 1763 } 1764 1765 Buf_AddByte (buf, '\0'); 1766 str = (char *)Buf_GetAll (buf, (int *)NULL); 1767 Buf_Destroy (buf, FALSE); 1768 return (str); 1769 } 1770 1771 /*- 1772 *----------------------------------------------------------------------- 1773 * Var_GetTail -- 1774 * Return the tail from each of a list of words. Used to set the 1775 * System V local variables. 1776 * 1777 * Results: 1778 * The resulting string. 1779 * 1780 * Side Effects: 1781 * None. 1782 * 1783 *----------------------------------------------------------------------- 1784 */ 1785 char * 1786 Var_GetTail(file) 1787 char *file; /* Filename to modify */ 1788 { 1789 return(VarModify(file, VarTail, (ClientData)0)); 1790 } 1791 1792 /*- 1793 *----------------------------------------------------------------------- 1794 * Var_GetHead -- 1795 * Find the leading components of a (list of) filename(s). 1796 * XXX: VarHead does not replace foo by ., as (sun) System V make 1797 * does. 1798 * 1799 * Results: 1800 * The leading components. 1801 * 1802 * Side Effects: 1803 * None. 1804 * 1805 *----------------------------------------------------------------------- 1806 */ 1807 char * 1808 Var_GetHead(file) 1809 char *file; /* Filename to manipulate */ 1810 { 1811 return(VarModify(file, VarHead, (ClientData)0)); 1812 } 1813 1814 /*- 1815 *----------------------------------------------------------------------- 1816 * Var_Init -- 1817 * Initialize the module 1818 * 1819 * Results: 1820 * None 1821 * 1822 * Side Effects: 1823 * The VAR_CMD and VAR_GLOBAL contexts are created 1824 *----------------------------------------------------------------------- 1825 */ 1826 void 1827 Var_Init () 1828 { 1829 VAR_GLOBAL = Targ_NewGN ("Global"); 1830 VAR_CMD = Targ_NewGN ("Command"); 1831 1832 } 1833 1834 /****************** PRINT DEBUGGING INFO *****************/ 1835 static 1836 VarPrintVar (v) 1837 Var *v; 1838 { 1839 printf ("%-16s = %s\n", v->name, Buf_GetAll(v->val, (int *)NULL)); 1840 return (0); 1841 } 1842 1843 /*- 1844 *----------------------------------------------------------------------- 1845 * Var_Dump -- 1846 * print all variables in a context 1847 *----------------------------------------------------------------------- 1848 */ 1849 Var_Dump (ctxt) 1850 GNode *ctxt; 1851 { 1852 Lst_ForEach (ctxt->context, VarPrintVar); 1853 } 1854