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