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