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