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