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