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