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