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