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