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