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