1 /* 2 * Copyright (c) 1988, 1989, 1990, 1993 3 * The Regents of the University of California. All rights reserved. 4 * Copyright (c) 1989 by Berkeley Softworks 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Adam de Boor. 9 * 10 * %sccs.include.redist.c% 11 */ 12 13 #ifndef lint 14 static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 03/19/94"; 15 #endif /* not lint */ 16 17 /*- 18 * var.c -- 19 * Variable-handling functions 20 * 21 * Interface: 22 * Var_Set Set the value of a variable in the given 23 * context. The variable is created if it doesn't 24 * yet exist. The value and variable name need not 25 * be preserved. 26 * 27 * Var_Append Append more characters to an existing variable 28 * in the given context. The variable needn't 29 * exist already -- it will be created if it doesn't. 30 * A space is placed between the old value and the 31 * new one. 32 * 33 * Var_Exists See if a variable exists. 34 * 35 * Var_Value Return the value of a variable in a context or 36 * NULL if the variable is undefined. 37 * 38 * Var_Subst Substitute named variable, or all variables if 39 * NULL in a string using 40 * the given context as the top-most one. If the 41 * third argument is non-zero, Parse_Error is 42 * called if any variables are undefined. 43 * 44 * Var_Parse Parse a variable expansion from a string and 45 * return the result and the number of characters 46 * consumed. 47 * 48 * Var_Delete Delete a variable in a context. 49 * 50 * Var_Init Initialize this module. 51 * 52 * Debugging: 53 * Var_Dump Print out all variables defined in the given 54 * context. 55 * 56 * XXX: There's a lot of duplication in these functions. 57 */ 58 59 #include <ctype.h> 60 #include "make.h" 61 #include "buf.h" 62 63 /* 64 * This is a harmless return value for Var_Parse that can be used by Var_Subst 65 * to determine if there was an error in parsing -- easier than returning 66 * a flag, as things outside this module don't give a hoot. 67 */ 68 char var_Error[] = ""; 69 70 /* 71 * Similar to var_Error, but returned when the 'err' flag for Var_Parse is 72 * set false. Why not just use a constant? Well, gcc likes to condense 73 * identical string instances... 74 */ 75 static char varNoError[] = ""; 76 77 /* 78 * Internally, variables are contained in four different contexts. 79 * 1) the environment. They may not be changed. If an environment 80 * variable is appended-to, the result is placed in the global 81 * context. 82 * 2) the global context. Variables set in the Makefile are located in 83 * the global context. It is the penultimate context searched when 84 * substituting. 85 * 3) the command-line context. All variables set on the command line 86 * are placed in this context. They are UNALTERABLE once placed here. 87 * 4) the local context. Each target has associated with it a context 88 * list. On this list are located the structures describing such 89 * local variables as $(@) and $(*) 90 * The four contexts are searched in the reverse order from which they are 91 * listed. 92 */ 93 GNode *VAR_GLOBAL; /* variables from the makefile */ 94 GNode *VAR_CMD; /* variables defined on the command-line */ 95 96 #define FIND_CMD 0x1 /* look in VAR_CMD when searching */ 97 #define FIND_GLOBAL 0x2 /* look in VAR_GLOBAL as well */ 98 #define FIND_ENV 0x4 /* look in the environment also */ 99 100 typedef struct Var { 101 char *name; /* the variable's name */ 102 Buffer val; /* its value */ 103 int flags; /* miscellaneous status flags */ 104 #define VAR_IN_USE 1 /* Variable's value currently being used. 105 * Used to avoid recursion */ 106 #define VAR_FROM_ENV 2 /* Variable comes from the environment */ 107 #define VAR_JUNK 4 /* Variable is a junk variable that 108 * should be destroyed when done with 109 * it. Used by Var_Parse for undefined, 110 * modified variables */ 111 } Var; 112 113 typedef struct { 114 char *lhs; /* String to match */ 115 int leftLen; /* Length of string */ 116 char *rhs; /* Replacement string (w/ &'s removed) */ 117 int rightLen; /* Length of replacement */ 118 int flags; 119 #define VAR_SUB_GLOBAL 1 /* Apply substitution globally */ 120 #define VAR_MATCH_START 2 /* Match at start of word */ 121 #define VAR_MATCH_END 4 /* Match at end of word */ 122 #define VAR_NO_SUB 8 /* Substitution is non-global and already done */ 123 } VarPattern; 124 125 static int VarCmp __P((Var *, char *)); 126 static Var *VarFind __P((char *, GNode *, int)); 127 static void VarAdd __P((char *, char *, GNode *)); 128 static Boolean VarHead __P((char *, Boolean, Buffer)); 129 static Boolean VarTail __P((char *, Boolean, Buffer)); 130 static Boolean VarSuffix __P((char *, Boolean, Buffer)); 131 static Boolean VarRoot __P((char *, Boolean, Buffer)); 132 static Boolean VarMatch __P((char *, Boolean, Buffer, char *)); 133 static Boolean VarSYSVMatch __P((char *, Boolean, Buffer, VarPattern *)); 134 static Boolean VarNoMatch __P((char *, Boolean, Buffer, char *)); 135 static Boolean VarSubstitute __P((char *, Boolean, Buffer, VarPattern *)); 136 static char *VarModify __P((char *, Boolean (*modProc )(), ClientData)); 137 static int VarPrintVar __P((Var *)); 138 139 /*- 140 *----------------------------------------------------------------------- 141 * VarCmp -- 142 * See if the given variable matches the named one. Called from 143 * Lst_Find when searching for a variable of a given name. 144 * 145 * Results: 146 * 0 if they match. non-zero otherwise. 147 * 148 * Side Effects: 149 * none 150 *----------------------------------------------------------------------- 151 */ 152 static int 153 VarCmp (v, name) 154 Var *v; /* VAR structure to compare */ 155 char *name; /* name to look for */ 156 { 157 return (strcmp (name, v->name)); 158 } 159 160 /*- 161 *----------------------------------------------------------------------- 162 * VarFind -- 163 * Find the given variable in the given context and any other contexts 164 * indicated. 165 * 166 * Results: 167 * A pointer to the structure describing the desired variable or 168 * NIL if the variable does not exist. 169 * 170 * Side Effects: 171 * None 172 *----------------------------------------------------------------------- 173 */ 174 static Var * 175 VarFind (name, ctxt, flags) 176 char *name; /* name to find */ 177 GNode *ctxt; /* context in which to find it */ 178 int flags; /* FIND_GLOBAL set means to look in the 179 * VAR_GLOBAL context as well. 180 * FIND_CMD set means to look in the VAR_CMD 181 * context also. 182 * FIND_ENV set means to look in the 183 * environment */ 184 { 185 LstNode var; 186 Var *v; 187 188 /* 189 * If the variable name begins with a '.', it could very well be one of 190 * the local ones. We check the name against all the local variables 191 * and substitute the short version in for 'name' if it matches one of 192 * them. 193 */ 194 if (*name == '.' && isupper(name[1])) 195 switch (name[1]) { 196 case 'A': 197 if (!strcmp(name, ".ALLSRC")) 198 name = ALLSRC; 199 if (!strcmp(name, ".ARCHIVE")) 200 name = ARCHIVE; 201 break; 202 case 'I': 203 if (!strcmp(name, ".IMPSRC")) 204 name = IMPSRC; 205 break; 206 case 'M': 207 if (!strcmp(name, ".MEMBER")) 208 name = MEMBER; 209 break; 210 case 'O': 211 if (!strcmp(name, ".OODATE")) 212 name = OODATE; 213 break; 214 case 'P': 215 if (!strcmp(name, ".PREFIX")) 216 name = PREFIX; 217 break; 218 case 'T': 219 if (!strcmp(name, ".TARGET")) 220 name = TARGET; 221 break; 222 } 223 /* 224 * First look for the variable in the given context. If it's not there, 225 * look for it in VAR_CMD, VAR_GLOBAL and the environment, in that order, 226 * depending on the FIND_* flags in 'flags' 227 */ 228 var = Lst_Find (ctxt->context, (ClientData)name, VarCmp); 229 230 if ((var == NILLNODE) && (flags & FIND_CMD) && (ctxt != VAR_CMD)) { 231 var = Lst_Find (VAR_CMD->context, (ClientData)name, VarCmp); 232 } 233 if (!checkEnvFirst && (var == NILLNODE) && (flags & FIND_GLOBAL) && 234 (ctxt != VAR_GLOBAL)) 235 { 236 var = Lst_Find (VAR_GLOBAL->context, (ClientData)name, VarCmp); 237 } 238 if ((var == NILLNODE) && (flags & FIND_ENV)) { 239 char *env; 240 241 if ((env = getenv (name)) != NULL) { 242 /* 243 * If the variable is found in the environment, we only duplicate 244 * its value (since eVarVal was allocated on the stack). The name 245 * doesn't need duplication since it's always in the environment 246 */ 247 int len; 248 249 v = (Var *) emalloc(sizeof(Var)); 250 v->name = name; 251 252 len = strlen(env); 253 254 v->val = Buf_Init(len); 255 Buf_AddBytes(v->val, len, (Byte *)env); 256 257 v->flags = VAR_FROM_ENV; 258 return (v); 259 } else if (checkEnvFirst && (flags & FIND_GLOBAL) && 260 (ctxt != VAR_GLOBAL)) 261 { 262 var = Lst_Find (VAR_GLOBAL->context, (ClientData)name, VarCmp); 263 if (var == NILLNODE) { 264 return ((Var *) NIL); 265 } else { 266 return ((Var *)Lst_Datum(var)); 267 } 268 } else { 269 return((Var *)NIL); 270 } 271 } else if (var == NILLNODE) { 272 return ((Var *) NIL); 273 } else { 274 return ((Var *) Lst_Datum (var)); 275 } 276 } 277 278 /*- 279 *----------------------------------------------------------------------- 280 * VarAdd -- 281 * Add a new variable of name name and value val to the given context 282 * 283 * Results: 284 * None 285 * 286 * Side Effects: 287 * The new variable is placed at the front of the given context 288 * The name and val arguments are duplicated so they may 289 * safely be freed. 290 *----------------------------------------------------------------------- 291 */ 292 static void 293 VarAdd (name, val, ctxt) 294 char *name; /* name of variable to add */ 295 char *val; /* value to set it to */ 296 GNode *ctxt; /* context in which to set it */ 297 { 298 register Var *v; 299 int len; 300 301 v = (Var *) emalloc (sizeof (Var)); 302 303 v->name = strdup (name); 304 305 len = val ? strlen(val) : 0; 306 v->val = Buf_Init(len+1); 307 Buf_AddBytes(v->val, len, (Byte *)val); 308 309 v->flags = 0; 310 311 (void) Lst_AtFront (ctxt->context, (ClientData)v); 312 if (DEBUG(VAR)) { 313 printf("%s:%s = %s\n", ctxt->name, name, val); 314 } 315 } 316 317 /*- 318 *----------------------------------------------------------------------- 319 * Var_Delete -- 320 * Remove a variable from a context. 321 * 322 * Results: 323 * None. 324 * 325 * Side Effects: 326 * The Var structure is removed and freed. 327 * 328 *----------------------------------------------------------------------- 329 */ 330 void 331 Var_Delete(name, ctxt) 332 char *name; 333 GNode *ctxt; 334 { 335 LstNode ln; 336 337 if (DEBUG(VAR)) { 338 printf("%s:delete %s\n", ctxt->name, name); 339 } 340 ln = Lst_Find(ctxt->context, (ClientData)name, VarCmp); 341 if (ln != NILLNODE) { 342 register Var *v; 343 344 v = (Var *)Lst_Datum(ln); 345 Lst_Remove(ctxt->context, ln); 346 Buf_Destroy(v->val, TRUE); 347 free(v->name); 348 free((char *)v); 349 } 350 } 351 352 /*- 353 *----------------------------------------------------------------------- 354 * Var_Set -- 355 * Set the variable name to the value val in the given context. 356 * 357 * Results: 358 * None. 359 * 360 * Side Effects: 361 * If the variable doesn't yet exist, a new record is created for it. 362 * Else the old value is freed and the new one stuck in its place 363 * 364 * Notes: 365 * The variable is searched for only in its context before being 366 * created in that context. I.e. if the context is VAR_GLOBAL, 367 * only VAR_GLOBAL->context is searched. Likewise if it is VAR_CMD, only 368 * VAR_CMD->context is searched. This is done to avoid the literally 369 * thousands of unnecessary strcmp's that used to be done to 370 * set, say, $(@) or $(<). 371 *----------------------------------------------------------------------- 372 */ 373 void 374 Var_Set (name, val, ctxt) 375 char *name; /* name of variable to set */ 376 char *val; /* value to give to the variable */ 377 GNode *ctxt; /* context in which to set it */ 378 { 379 register Var *v; 380 381 /* 382 * We only look for a variable in the given context since anything set 383 * here will override anything in a lower context, so there's not much 384 * point in searching them all just to save a bit of memory... 385 */ 386 v = VarFind (name, ctxt, 0); 387 if (v == (Var *) NIL) { 388 VarAdd (name, val, ctxt); 389 } else { 390 Buf_Discard(v->val, Buf_Size(v->val)); 391 Buf_AddBytes(v->val, strlen(val), (Byte *)val); 392 393 if (DEBUG(VAR)) { 394 printf("%s:%s = %s\n", ctxt->name, name, val); 395 } 396 } 397 /* 398 * Any variables given on the command line are automatically exported 399 * to the environment (as per POSIX standard) 400 */ 401 if (ctxt == VAR_CMD) { 402 setenv(name, val, 1); 403 } 404 } 405 406 /*- 407 *----------------------------------------------------------------------- 408 * Var_Append -- 409 * The variable of the given name has the given value appended to it in 410 * the given context. 411 * 412 * Results: 413 * None 414 * 415 * Side Effects: 416 * If the variable doesn't exist, it is created. Else the strings 417 * are concatenated (with a space in between). 418 * 419 * Notes: 420 * Only if the variable is being sought in the global context is the 421 * environment searched. 422 * XXX: Knows its calling circumstances in that if called with ctxt 423 * an actual target, it will only search that context since only 424 * a local variable could be being appended to. This is actually 425 * a big win and must be tolerated. 426 *----------------------------------------------------------------------- 427 */ 428 void 429 Var_Append (name, val, ctxt) 430 char *name; /* Name of variable to modify */ 431 char *val; /* String to append to it */ 432 GNode *ctxt; /* Context in which this should occur */ 433 { 434 register Var *v; 435 436 v = VarFind (name, ctxt, (ctxt == VAR_GLOBAL) ? FIND_ENV : 0); 437 438 if (v == (Var *) NIL) { 439 VarAdd (name, val, ctxt); 440 } else { 441 Buf_AddByte(v->val, (Byte)' '); 442 Buf_AddBytes(v->val, strlen(val), (Byte *)val); 443 444 if (DEBUG(VAR)) { 445 printf("%s:%s = %s\n", ctxt->name, name, 446 (char *) Buf_GetAll(v->val, (int *)NULL)); 447 } 448 449 if (v->flags & VAR_FROM_ENV) { 450 /* 451 * If the original variable came from the environment, we 452 * have to install it in the global context (we could place 453 * it in the environment, but then we should provide a way to 454 * export other variables...) 455 */ 456 v->flags &= ~VAR_FROM_ENV; 457 Lst_AtFront(ctxt->context, (ClientData)v); 458 } 459 } 460 } 461 462 /*- 463 *----------------------------------------------------------------------- 464 * Var_Exists -- 465 * See if the given variable exists. 466 * 467 * Results: 468 * TRUE if it does, FALSE if it doesn't 469 * 470 * Side Effects: 471 * None. 472 * 473 *----------------------------------------------------------------------- 474 */ 475 Boolean 476 Var_Exists(name, ctxt) 477 char *name; /* Variable to find */ 478 GNode *ctxt; /* Context in which to start search */ 479 { 480 Var *v; 481 482 v = VarFind(name, ctxt, FIND_CMD|FIND_GLOBAL|FIND_ENV); 483 484 if (v == (Var *)NIL) { 485 return(FALSE); 486 } else if (v->flags & VAR_FROM_ENV) { 487 Buf_Destroy(v->val, TRUE); 488 free((char *)v); 489 } 490 return(TRUE); 491 } 492 493 /*- 494 *----------------------------------------------------------------------- 495 * Var_Value -- 496 * Return the value of the named variable in the given context 497 * 498 * Results: 499 * The value if the variable exists, NULL if it doesn't 500 * 501 * Side Effects: 502 * None 503 *----------------------------------------------------------------------- 504 */ 505 char * 506 Var_Value (name, ctxt) 507 char *name; /* name to find */ 508 GNode *ctxt; /* context in which to search for it */ 509 { 510 Var *v; 511 512 v = VarFind (name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD); 513 if (v != (Var *) NIL) { 514 return ((char *)Buf_GetAll(v->val, (int *)NULL)); 515 } else { 516 return ((char *) NULL); 517 } 518 } 519 520 /*- 521 *----------------------------------------------------------------------- 522 * VarHead -- 523 * Remove the tail of the given word and place the result in the given 524 * buffer. 525 * 526 * Results: 527 * TRUE if characters were added to the buffer (a space needs to be 528 * added to the buffer before the next word). 529 * 530 * Side Effects: 531 * The trimmed word is added to the buffer. 532 * 533 *----------------------------------------------------------------------- 534 */ 535 static Boolean 536 VarHead (word, addSpace, buf) 537 char *word; /* Word to trim */ 538 Boolean addSpace; /* True if need to add a space to the buffer 539 * before sticking in the head */ 540 Buffer buf; /* Buffer in which to store it */ 541 { 542 register char *slash; 543 544 slash = strrchr (word, '/'); 545 if (slash != (char *)NULL) { 546 if (addSpace) { 547 Buf_AddByte (buf, (Byte)' '); 548 } 549 *slash = '\0'; 550 Buf_AddBytes (buf, strlen (word), (Byte *)word); 551 *slash = '/'; 552 return (TRUE); 553 } else { 554 /* 555 * If no directory part, give . (q.v. the POSIX standard) 556 */ 557 if (addSpace) { 558 Buf_AddBytes(buf, 2, (Byte *)" ."); 559 } else { 560 Buf_AddByte(buf, (Byte)'.'); 561 } 562 return(TRUE); 563 } 564 } 565 566 /*- 567 *----------------------------------------------------------------------- 568 * VarTail -- 569 * Remove the head of the given word and place the result in the given 570 * buffer. 571 * 572 * Results: 573 * TRUE if characters were added to the buffer (a space needs to be 574 * added to the buffer before the next word). 575 * 576 * Side Effects: 577 * The trimmed word is added to the buffer. 578 * 579 *----------------------------------------------------------------------- 580 */ 581 static Boolean 582 VarTail (word, addSpace, buf) 583 char *word; /* Word to trim */ 584 Boolean addSpace; /* TRUE if need to stick a space in the 585 * buffer before adding the tail */ 586 Buffer buf; /* Buffer in which to store it */ 587 { 588 register char *slash; 589 590 if (addSpace) { 591 Buf_AddByte (buf, (Byte)' '); 592 } 593 594 slash = strrchr (word, '/'); 595 if (slash != (char *)NULL) { 596 *slash++ = '\0'; 597 Buf_AddBytes (buf, strlen(slash), (Byte *)slash); 598 slash[-1] = '/'; 599 } else { 600 Buf_AddBytes (buf, strlen(word), (Byte *)word); 601 } 602 return (TRUE); 603 } 604 605 /*- 606 *----------------------------------------------------------------------- 607 * VarSuffix -- 608 * Place the suffix of the given word in the given buffer. 609 * 610 * Results: 611 * TRUE if characters were added to the buffer (a space needs to be 612 * added to the buffer before the next word). 613 * 614 * Side Effects: 615 * The suffix from the word is placed in the buffer. 616 * 617 *----------------------------------------------------------------------- 618 */ 619 static Boolean 620 VarSuffix (word, addSpace, buf) 621 char *word; /* Word to trim */ 622 Boolean addSpace; /* TRUE if need to add a space before placing 623 * the suffix in the buffer */ 624 Buffer buf; /* Buffer in which to store it */ 625 { 626 register char *dot; 627 628 dot = strrchr (word, '.'); 629 if (dot != (char *)NULL) { 630 if (addSpace) { 631 Buf_AddByte (buf, (Byte)' '); 632 } 633 *dot++ = '\0'; 634 Buf_AddBytes (buf, strlen (dot), (Byte *)dot); 635 dot[-1] = '.'; 636 return (TRUE); 637 } else { 638 return (addSpace); 639 } 640 } 641 642 /*- 643 *----------------------------------------------------------------------- 644 * VarRoot -- 645 * Remove the suffix of the given word and place the result in the 646 * buffer. 647 * 648 * Results: 649 * TRUE if characters were added to the buffer (a space needs to be 650 * added to the buffer before the next word). 651 * 652 * Side Effects: 653 * The trimmed word is added to the buffer. 654 * 655 *----------------------------------------------------------------------- 656 */ 657 static Boolean 658 VarRoot (word, addSpace, buf) 659 char *word; /* Word to trim */ 660 Boolean addSpace; /* TRUE if need to add a space to the buffer 661 * before placing the root in it */ 662 Buffer buf; /* Buffer in which to store it */ 663 { 664 register char *dot; 665 666 if (addSpace) { 667 Buf_AddByte (buf, (Byte)' '); 668 } 669 670 dot = strrchr (word, '.'); 671 if (dot != (char *)NULL) { 672 *dot = '\0'; 673 Buf_AddBytes (buf, strlen (word), (Byte *)word); 674 *dot = '.'; 675 } else { 676 Buf_AddBytes (buf, strlen(word), (Byte *)word); 677 } 678 return (TRUE); 679 } 680 681 /*- 682 *----------------------------------------------------------------------- 683 * VarMatch -- 684 * Place the word in the buffer if it matches the given pattern. 685 * Callback function for VarModify to implement the :M modifier. 686 * 687 * Results: 688 * TRUE if a space should be placed in the buffer before the next 689 * word. 690 * 691 * Side Effects: 692 * The word may be copied to the buffer. 693 * 694 *----------------------------------------------------------------------- 695 */ 696 static Boolean 697 VarMatch (word, addSpace, buf, pattern) 698 char *word; /* Word to examine */ 699 Boolean addSpace; /* TRUE if need to add a space to the 700 * buffer before adding the word, if it 701 * matches */ 702 Buffer buf; /* Buffer in which to store it */ 703 char *pattern; /* Pattern the word must match */ 704 { 705 if (Str_Match(word, pattern)) { 706 if (addSpace) { 707 Buf_AddByte(buf, (Byte)' '); 708 } 709 addSpace = TRUE; 710 Buf_AddBytes(buf, strlen(word), (Byte *)word); 711 } 712 return(addSpace); 713 } 714 715 716 717 /*- 718 *----------------------------------------------------------------------- 719 * VarSYSVMatch -- 720 * Place the word in the buffer if it matches the given pattern. 721 * Callback function for VarModify to implement the System V % 722 * modifiers. 723 * 724 * Results: 725 * TRUE if a space should be placed in the buffer before the next 726 * word. 727 * 728 * Side Effects: 729 * The word may be copied to the buffer. 730 * 731 *----------------------------------------------------------------------- 732 */ 733 static Boolean 734 VarSYSVMatch (word, addSpace, buf, pat) 735 char *word; /* Word to examine */ 736 Boolean addSpace; /* TRUE if need to add a space to the 737 * buffer before adding the word, if it 738 * matches */ 739 Buffer buf; /* Buffer in which to store it */ 740 VarPattern *pat; /* Pattern the word must match */ 741 { 742 int len; 743 char *ptr; 744 745 if (addSpace) 746 Buf_AddByte(buf, (Byte)' '); 747 748 addSpace = TRUE; 749 750 if ((ptr = Str_SYSVMatch(word, pat->lhs, &len)) != NULL) 751 Str_SYSVSubst(buf, pat->rhs, ptr, len); 752 else 753 Buf_AddBytes(buf, strlen(word), (Byte *) word); 754 755 return(addSpace); 756 } 757 758 759 /*- 760 *----------------------------------------------------------------------- 761 * VarNoMatch -- 762 * Place the word in the buffer if it doesn't match the given pattern. 763 * Callback function for VarModify to implement the :N modifier. 764 * 765 * Results: 766 * TRUE if a space should be placed in the buffer before the next 767 * word. 768 * 769 * Side Effects: 770 * The word may be copied to the buffer. 771 * 772 *----------------------------------------------------------------------- 773 */ 774 static Boolean 775 VarNoMatch (word, addSpace, buf, pattern) 776 char *word; /* Word to examine */ 777 Boolean addSpace; /* TRUE if need to add a space to the 778 * buffer before adding the word, if it 779 * matches */ 780 Buffer buf; /* Buffer in which to store it */ 781 char *pattern; /* Pattern the word must match */ 782 { 783 if (!Str_Match(word, pattern)) { 784 if (addSpace) { 785 Buf_AddByte(buf, (Byte)' '); 786 } 787 addSpace = TRUE; 788 Buf_AddBytes(buf, strlen(word), (Byte *)word); 789 } 790 return(addSpace); 791 } 792 793 794 /*- 795 *----------------------------------------------------------------------- 796 * VarSubstitute -- 797 * Perform a string-substitution on the given word, placing the 798 * result in the passed buffer. 799 * 800 * Results: 801 * TRUE if a space is needed before more characters are added. 802 * 803 * Side Effects: 804 * None. 805 * 806 *----------------------------------------------------------------------- 807 */ 808 static Boolean 809 VarSubstitute (word, addSpace, buf, pattern) 810 char *word; /* Word to modify */ 811 Boolean addSpace; /* True if space should be added before 812 * other characters */ 813 Buffer buf; /* Buffer for result */ 814 register VarPattern *pattern; /* Pattern for substitution */ 815 { 816 register int wordLen; /* Length of word */ 817 register char *cp; /* General pointer */ 818 819 wordLen = strlen(word); 820 if ((pattern->flags & VAR_NO_SUB) == 0) { 821 /* 822 * Still substituting -- break it down into simple anchored cases 823 * and if none of them fits, perform the general substitution case. 824 */ 825 if ((pattern->flags & VAR_MATCH_START) && 826 (strncmp(word, pattern->lhs, pattern->leftLen) == 0)) { 827 /* 828 * Anchored at start and beginning of word matches pattern 829 */ 830 if ((pattern->flags & VAR_MATCH_END) && 831 (wordLen == pattern->leftLen)) { 832 /* 833 * Also anchored at end and matches to the end (word 834 * is same length as pattern) add space and rhs only 835 * if rhs is non-null. 836 */ 837 if (pattern->rightLen != 0) { 838 if (addSpace) { 839 Buf_AddByte(buf, (Byte)' '); 840 } 841 addSpace = TRUE; 842 Buf_AddBytes(buf, pattern->rightLen, 843 (Byte *)pattern->rhs); 844 } 845 } else if (pattern->flags & VAR_MATCH_END) { 846 /* 847 * Doesn't match to end -- copy word wholesale 848 */ 849 goto nosub; 850 } else { 851 /* 852 * Matches at start but need to copy in trailing characters 853 */ 854 if ((pattern->rightLen + wordLen - pattern->leftLen) != 0){ 855 if (addSpace) { 856 Buf_AddByte(buf, (Byte)' '); 857 } 858 addSpace = TRUE; 859 } 860 Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs); 861 Buf_AddBytes(buf, wordLen - pattern->leftLen, 862 (Byte *)(word + pattern->leftLen)); 863 } 864 } else if (pattern->flags & VAR_MATCH_START) { 865 /* 866 * Had to match at start of word and didn't -- copy whole word. 867 */ 868 goto nosub; 869 } else if (pattern->flags & VAR_MATCH_END) { 870 /* 871 * Anchored at end, Find only place match could occur (leftLen 872 * characters from the end of the word) and see if it does. Note 873 * that because the $ will be left at the end of the lhs, we have 874 * to use strncmp. 875 */ 876 cp = word + (wordLen - pattern->leftLen); 877 if ((cp >= word) && 878 (strncmp(cp, pattern->lhs, pattern->leftLen) == 0)) { 879 /* 880 * Match found. If we will place characters in the buffer, 881 * add a space before hand as indicated by addSpace, then 882 * stuff in the initial, unmatched part of the word followed 883 * by the right-hand-side. 884 */ 885 if (((cp - word) + pattern->rightLen) != 0) { 886 if (addSpace) { 887 Buf_AddByte(buf, (Byte)' '); 888 } 889 addSpace = TRUE; 890 } 891 Buf_AddBytes(buf, cp - word, (Byte *)word); 892 Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs); 893 } else { 894 /* 895 * Had to match at end and didn't. Copy entire word. 896 */ 897 goto nosub; 898 } 899 } else { 900 /* 901 * Pattern is unanchored: search for the pattern in the word using 902 * String_FindSubstring, copying unmatched portions and the 903 * right-hand-side for each match found, handling non-global 904 * subsititutions correctly, etc. When the loop is done, any 905 * remaining part of the word (word and wordLen are adjusted 906 * accordingly through the loop) is copied straight into the 907 * buffer. 908 * addSpace is set FALSE as soon as a space is added to the 909 * buffer. 910 */ 911 register Boolean done; 912 int origSize; 913 914 done = FALSE; 915 origSize = Buf_Size(buf); 916 while (!done) { 917 cp = Str_FindSubstring(word, pattern->lhs); 918 if (cp != (char *)NULL) { 919 if (addSpace && (((cp - word) + pattern->rightLen) != 0)){ 920 Buf_AddByte(buf, (Byte)' '); 921 addSpace = FALSE; 922 } 923 Buf_AddBytes(buf, cp-word, (Byte *)word); 924 Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs); 925 wordLen -= (cp - word) + pattern->leftLen; 926 word = cp + pattern->leftLen; 927 if (wordLen == 0) { 928 done = TRUE; 929 } 930 if ((pattern->flags & VAR_SUB_GLOBAL) == 0) { 931 done = TRUE; 932 pattern->flags |= VAR_NO_SUB; 933 } 934 } else { 935 done = TRUE; 936 } 937 } 938 if (wordLen != 0) { 939 if (addSpace) { 940 Buf_AddByte(buf, (Byte)' '); 941 } 942 Buf_AddBytes(buf, wordLen, (Byte *)word); 943 } 944 /* 945 * If added characters to the buffer, need to add a space 946 * before we add any more. If we didn't add any, just return 947 * the previous value of addSpace. 948 */ 949 return ((Buf_Size(buf) != origSize) || addSpace); 950 } 951 /* 952 * Common code for anchored substitutions: if performed a substitution 953 * and it's not supposed to be global, mark the pattern as requiring 954 * no more substitutions. addSpace was set TRUE if characters were 955 * added to the buffer. 956 */ 957 if ((pattern->flags & VAR_SUB_GLOBAL) == 0) { 958 pattern->flags |= VAR_NO_SUB; 959 } 960 return (addSpace); 961 } 962 nosub: 963 if (addSpace) { 964 Buf_AddByte(buf, (Byte)' '); 965 } 966 Buf_AddBytes(buf, wordLen, (Byte *)word); 967 return(TRUE); 968 } 969 970 /*- 971 *----------------------------------------------------------------------- 972 * VarModify -- 973 * Modify each of the words of the passed string using the given 974 * function. Used to implement all modifiers. 975 * 976 * Results: 977 * A string of all the words modified appropriately. 978 * 979 * Side Effects: 980 * None. 981 * 982 *----------------------------------------------------------------------- 983 */ 984 static char * 985 VarModify (str, modProc, datum) 986 char *str; /* String whose words should be trimmed */ 987 Boolean (*modProc)(); /* Function to use to modify them */ 988 ClientData datum; /* Datum to pass it */ 989 { 990 Buffer buf; /* Buffer for the new string */ 991 register char *cp; /* Pointer to end of current word */ 992 char endc; /* Character that ended the word */ 993 Boolean addSpace; /* TRUE if need to add a space to the 994 * buffer before adding the trimmed 995 * word */ 996 997 buf = Buf_Init (0); 998 cp = str; 999 addSpace = FALSE; 1000 1001 for (;;) { 1002 /* 1003 * Skip to next word and place cp at its end. 1004 */ 1005 while (isspace (*str)) { 1006 str++; 1007 } 1008 for (cp = str; *cp != '\0' && !isspace (*cp); cp++) 1009 continue; 1010 if (cp == str) { 1011 /* 1012 * If we didn't go anywhere, we must be done! 1013 */ 1014 Buf_AddByte (buf, '\0'); 1015 str = (char *)Buf_GetAll (buf, (int *)NULL); 1016 Buf_Destroy (buf, FALSE); 1017 return (str); 1018 } 1019 /* 1020 * Nuke terminating character, but save it in endc b/c if str was 1021 * some variable's value, it would not be good to screw it 1022 * over... 1023 */ 1024 endc = *cp; 1025 *cp = '\0'; 1026 1027 addSpace = (* modProc) (str, addSpace, buf, datum); 1028 1029 if (endc) { 1030 *cp++ = endc; 1031 } 1032 str = cp; 1033 } 1034 } 1035 1036 /*- 1037 *----------------------------------------------------------------------- 1038 * Var_Parse -- 1039 * Given the start of a variable invocation, extract the variable 1040 * name and find its value, then modify it according to the 1041 * specification. 1042 * 1043 * Results: 1044 * The (possibly-modified) value of the variable or var_Error if the 1045 * specification is invalid. The length of the specification is 1046 * placed in *lengthPtr (for invalid specifications, this is just 1047 * 2...?). 1048 * A Boolean in *freePtr telling whether the returned string should 1049 * be freed by the caller. 1050 * 1051 * Side Effects: 1052 * None. 1053 * 1054 *----------------------------------------------------------------------- 1055 */ 1056 char * 1057 Var_Parse (str, ctxt, err, lengthPtr, freePtr) 1058 char *str; /* The string to parse */ 1059 GNode *ctxt; /* The context for the variable */ 1060 Boolean err; /* TRUE if undefined variables are an error */ 1061 int *lengthPtr; /* OUT: The length of the specification */ 1062 Boolean *freePtr; /* OUT: TRUE if caller should free result */ 1063 { 1064 register char *tstr; /* Pointer into str */ 1065 Var *v; /* Variable in invocation */ 1066 register char *cp; /* Secondary pointer into str (place marker 1067 * for tstr) */ 1068 Boolean haveModifier;/* TRUE if have modifiers for the variable */ 1069 register char endc; /* Ending character when variable in parens 1070 * or braces */ 1071 char *start; 1072 Boolean dynamic; /* TRUE if the variable is local and we're 1073 * expanding it in a non-local context. This 1074 * is done to support dynamic sources. The 1075 * result is just the invocation, unaltered */ 1076 1077 *freePtr = FALSE; 1078 dynamic = FALSE; 1079 start = str; 1080 1081 if (str[1] != '(' && str[1] != '{') { 1082 /* 1083 * If it's not bounded by braces of some sort, life is much simpler. 1084 * We just need to check for the first character and return the 1085 * value if it exists. 1086 */ 1087 char name[2]; 1088 1089 name[0] = str[1]; 1090 name[1] = '\0'; 1091 1092 v = VarFind (name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD); 1093 if (v == (Var *)NIL) { 1094 *lengthPtr = 2; 1095 1096 if ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)) { 1097 /* 1098 * If substituting a local variable in a non-local context, 1099 * assume it's for dynamic source stuff. We have to handle 1100 * this specially and return the longhand for the variable 1101 * with the dollar sign escaped so it makes it back to the 1102 * caller. Only four of the local variables are treated 1103 * specially as they are the only four that will be set 1104 * when dynamic sources are expanded. 1105 */ 1106 switch (str[1]) { 1107 case '@': 1108 return("$(.TARGET)"); 1109 case '%': 1110 return("$(.ARCHIVE)"); 1111 case '*': 1112 return("$(.PREFIX)"); 1113 case '!': 1114 return("$(.MEMBER)"); 1115 } 1116 } 1117 /* 1118 * Error 1119 */ 1120 return (err ? var_Error : varNoError); 1121 } else { 1122 haveModifier = FALSE; 1123 tstr = &str[1]; 1124 endc = str[1]; 1125 } 1126 } else { 1127 endc = str[1] == '(' ? ')' : '}'; 1128 1129 /* 1130 * Skip to the end character or a colon, whichever comes first. 1131 */ 1132 for (tstr = str + 2; 1133 *tstr != '\0' && *tstr != endc && *tstr != ':'; 1134 tstr++) 1135 { 1136 continue; 1137 } 1138 if (*tstr == ':') { 1139 haveModifier = TRUE; 1140 } else if (*tstr != '\0') { 1141 haveModifier = FALSE; 1142 } else { 1143 /* 1144 * If we never did find the end character, return NULL 1145 * right now, setting the length to be the distance to 1146 * the end of the string, since that's what make does. 1147 */ 1148 *lengthPtr = tstr - str; 1149 return (var_Error); 1150 } 1151 *tstr = '\0'; 1152 1153 v = VarFind (str + 2, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD); 1154 if ((v == (Var *)NIL) && (ctxt != VAR_CMD) && (ctxt != VAR_GLOBAL) && 1155 ((tstr-str) == 4) && (str[3] == 'F' || str[3] == 'D')) 1156 { 1157 /* 1158 * Check for bogus D and F forms of local variables since we're 1159 * in a local context and the name is the right length. 1160 */ 1161 switch(str[2]) { 1162 case '@': 1163 case '%': 1164 case '*': 1165 case '!': 1166 case '>': 1167 case '<': 1168 { 1169 char vname[2]; 1170 char *val; 1171 1172 /* 1173 * Well, it's local -- go look for it. 1174 */ 1175 vname[0] = str[2]; 1176 vname[1] = '\0'; 1177 v = VarFind(vname, ctxt, 0); 1178 1179 if (v != (Var *)NIL) { 1180 /* 1181 * No need for nested expansion or anything, as we're 1182 * the only one who sets these things and we sure don't 1183 * but nested invocations in them... 1184 */ 1185 val = (char *)Buf_GetAll(v->val, (int *)NULL); 1186 1187 if (str[3] == 'D') { 1188 val = VarModify(val, VarHead, (ClientData)0); 1189 } else { 1190 val = VarModify(val, VarTail, (ClientData)0); 1191 } 1192 /* 1193 * Resulting string is dynamically allocated, so 1194 * tell caller to free it. 1195 */ 1196 *freePtr = TRUE; 1197 *lengthPtr = tstr-start+1; 1198 *tstr = endc; 1199 return(val); 1200 } 1201 break; 1202 } 1203 } 1204 } 1205 1206 if (v == (Var *)NIL) { 1207 if ((((tstr-str) == 3) || 1208 ((((tstr-str) == 4) && (str[3] == 'F' || 1209 str[3] == 'D')))) && 1210 ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL))) 1211 { 1212 /* 1213 * If substituting a local variable in a non-local context, 1214 * assume it's for dynamic source stuff. We have to handle 1215 * this specially and return the longhand for the variable 1216 * with the dollar sign escaped so it makes it back to the 1217 * caller. Only four of the local variables are treated 1218 * specially as they are the only four that will be set 1219 * when dynamic sources are expanded. 1220 */ 1221 switch (str[2]) { 1222 case '@': 1223 case '%': 1224 case '*': 1225 case '!': 1226 dynamic = TRUE; 1227 break; 1228 } 1229 } else if (((tstr-str) > 4) && (str[2] == '.') && 1230 isupper(str[3]) && 1231 ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL))) 1232 { 1233 int len; 1234 1235 len = (tstr-str) - 3; 1236 if ((strncmp(str+2, ".TARGET", len) == 0) || 1237 (strncmp(str+2, ".ARCHIVE", len) == 0) || 1238 (strncmp(str+2, ".PREFIX", len) == 0) || 1239 (strncmp(str+2, ".MEMBER", len) == 0)) 1240 { 1241 dynamic = TRUE; 1242 } 1243 } 1244 1245 if (!haveModifier) { 1246 /* 1247 * No modifiers -- have specification length so we can return 1248 * now. 1249 */ 1250 *lengthPtr = tstr - start + 1; 1251 *tstr = endc; 1252 if (dynamic) { 1253 str = emalloc(*lengthPtr + 1); 1254 strncpy(str, start, *lengthPtr); 1255 str[*lengthPtr] = '\0'; 1256 *freePtr = TRUE; 1257 return(str); 1258 } else { 1259 return (err ? var_Error : varNoError); 1260 } 1261 } else { 1262 /* 1263 * Still need to get to the end of the variable specification, 1264 * so kludge up a Var structure for the modifications 1265 */ 1266 v = (Var *) emalloc(sizeof(Var)); 1267 v->name = &str[1]; 1268 v->val = Buf_Init(1); 1269 v->flags = VAR_JUNK; 1270 } 1271 } 1272 } 1273 1274 if (v->flags & VAR_IN_USE) { 1275 Fatal("Variable %s is recursive.", v->name); 1276 /*NOTREACHED*/ 1277 } else { 1278 v->flags |= VAR_IN_USE; 1279 } 1280 /* 1281 * Before doing any modification, we have to make sure the value 1282 * has been fully expanded. If it looks like recursion might be 1283 * necessary (there's a dollar sign somewhere in the variable's value) 1284 * we just call Var_Subst to do any other substitutions that are 1285 * necessary. Note that the value returned by Var_Subst will have 1286 * been dynamically-allocated, so it will need freeing when we 1287 * return. 1288 */ 1289 str = (char *)Buf_GetAll(v->val, (int *)NULL); 1290 if (strchr (str, '$') != (char *)NULL) { 1291 str = Var_Subst(NULL, str, ctxt, err); 1292 *freePtr = TRUE; 1293 } 1294 1295 v->flags &= ~VAR_IN_USE; 1296 1297 /* 1298 * Now we need to apply any modifiers the user wants applied. 1299 * These are: 1300 * :M<pattern> words which match the given <pattern>. 1301 * <pattern> is of the standard file 1302 * wildcarding form. 1303 * :S<d><pat1><d><pat2><d>[g] 1304 * Substitute <pat2> for <pat1> in the value 1305 * :H Substitute the head of each word 1306 * :T Substitute the tail of each word 1307 * :E Substitute the extension (minus '.') of 1308 * each word 1309 * :R Substitute the root of each word 1310 * (pathname minus the suffix). 1311 * :lhs=rhs Like :S, but the rhs goes to the end of 1312 * the invocation. 1313 */ 1314 if ((str != (char *)NULL) && haveModifier) { 1315 /* 1316 * Skip initial colon while putting it back. 1317 */ 1318 *tstr++ = ':'; 1319 while (*tstr != endc) { 1320 char *newStr; /* New value to return */ 1321 char termc; /* Character which terminated scan */ 1322 1323 if (DEBUG(VAR)) { 1324 printf("Applying :%c to \"%s\"\n", *tstr, str); 1325 } 1326 switch (*tstr) { 1327 case 'N': 1328 case 'M': 1329 { 1330 char *pattern; 1331 char *cp2; 1332 Boolean copy; 1333 1334 copy = FALSE; 1335 for (cp = tstr + 1; 1336 *cp != '\0' && *cp != ':' && *cp != endc; 1337 cp++) 1338 { 1339 if (*cp == '\\' && (cp[1] == ':' || cp[1] == endc)){ 1340 copy = TRUE; 1341 cp++; 1342 } 1343 } 1344 termc = *cp; 1345 *cp = '\0'; 1346 if (copy) { 1347 /* 1348 * Need to compress the \:'s out of the pattern, so 1349 * allocate enough room to hold the uncompressed 1350 * pattern (note that cp started at tstr+1, so 1351 * cp - tstr takes the null byte into account) and 1352 * compress the pattern into the space. 1353 */ 1354 pattern = emalloc(cp - tstr); 1355 for (cp2 = pattern, cp = tstr + 1; 1356 *cp != '\0'; 1357 cp++, cp2++) 1358 { 1359 if ((*cp == '\\') && 1360 (cp[1] == ':' || cp[1] == endc)) { 1361 cp++; 1362 } 1363 *cp2 = *cp; 1364 } 1365 *cp2 = '\0'; 1366 } else { 1367 pattern = &tstr[1]; 1368 } 1369 if (*tstr == 'M' || *tstr == 'm') { 1370 newStr = VarModify(str, VarMatch, (ClientData)pattern); 1371 } else { 1372 newStr = VarModify(str, VarNoMatch, 1373 (ClientData)pattern); 1374 } 1375 if (copy) { 1376 free(pattern); 1377 } 1378 break; 1379 } 1380 case 'S': 1381 { 1382 VarPattern pattern; 1383 register char delim; 1384 Buffer buf; /* Buffer for patterns */ 1385 1386 pattern.flags = 0; 1387 delim = tstr[1]; 1388 tstr += 2; 1389 /* 1390 * If pattern begins with '^', it is anchored to the 1391 * start of the word -- skip over it and flag pattern. 1392 */ 1393 if (*tstr == '^') { 1394 pattern.flags |= VAR_MATCH_START; 1395 tstr += 1; 1396 } 1397 1398 buf = Buf_Init(0); 1399 1400 /* 1401 * Pass through the lhs looking for 1) escaped delimiters, 1402 * '$'s and backslashes (place the escaped character in 1403 * uninterpreted) and 2) unescaped $'s that aren't before 1404 * the delimiter (expand the variable substitution). 1405 * The result is left in the Buffer buf. 1406 */ 1407 for (cp = tstr; *cp != '\0' && *cp != delim; cp++) { 1408 if ((*cp == '\\') && 1409 ((cp[1] == delim) || 1410 (cp[1] == '$') || 1411 (cp[1] == '\\'))) 1412 { 1413 Buf_AddByte(buf, (Byte)cp[1]); 1414 cp++; 1415 } else if (*cp == '$') { 1416 if (cp[1] != delim) { 1417 /* 1418 * If unescaped dollar sign not before the 1419 * delimiter, assume it's a variable 1420 * substitution and recurse. 1421 */ 1422 char *cp2; 1423 int len; 1424 Boolean freeIt; 1425 1426 cp2 = Var_Parse(cp, ctxt, err, &len, &freeIt); 1427 Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2); 1428 if (freeIt) { 1429 free(cp2); 1430 } 1431 cp += len - 1; 1432 } else { 1433 /* 1434 * Unescaped $ at end of pattern => anchor 1435 * pattern at end. 1436 */ 1437 pattern.flags |= VAR_MATCH_END; 1438 } 1439 } else { 1440 Buf_AddByte(buf, (Byte)*cp); 1441 } 1442 } 1443 1444 Buf_AddByte(buf, (Byte)'\0'); 1445 1446 /* 1447 * If lhs didn't end with the delimiter, complain and 1448 * return NULL 1449 */ 1450 if (*cp != delim) { 1451 *lengthPtr = cp - start + 1; 1452 if (*freePtr) { 1453 free(str); 1454 } 1455 Buf_Destroy(buf, TRUE); 1456 Error("Unclosed substitution for %s (%c missing)", 1457 v->name, delim); 1458 return (var_Error); 1459 } 1460 1461 /* 1462 * Fetch pattern and destroy buffer, but preserve the data 1463 * in it, since that's our lhs. Note that Buf_GetAll 1464 * will return the actual number of bytes, which includes 1465 * the null byte, so we have to decrement the length by 1466 * one. 1467 */ 1468 pattern.lhs = (char *)Buf_GetAll(buf, &pattern.leftLen); 1469 pattern.leftLen--; 1470 Buf_Destroy(buf, FALSE); 1471 1472 /* 1473 * Now comes the replacement string. Three things need to 1474 * be done here: 1) need to compress escaped delimiters and 1475 * ampersands and 2) need to replace unescaped ampersands 1476 * with the l.h.s. (since this isn't regexp, we can do 1477 * it right here) and 3) expand any variable substitutions. 1478 */ 1479 buf = Buf_Init(0); 1480 1481 tstr = cp + 1; 1482 for (cp = tstr; *cp != '\0' && *cp != delim; cp++) { 1483 if ((*cp == '\\') && 1484 ((cp[1] == delim) || 1485 (cp[1] == '&') || 1486 (cp[1] == '\\') || 1487 (cp[1] == '$'))) 1488 { 1489 Buf_AddByte(buf, (Byte)cp[1]); 1490 cp++; 1491 } else if ((*cp == '$') && (cp[1] != delim)) { 1492 char *cp2; 1493 int len; 1494 Boolean freeIt; 1495 1496 cp2 = Var_Parse(cp, ctxt, err, &len, &freeIt); 1497 Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2); 1498 cp += len - 1; 1499 if (freeIt) { 1500 free(cp2); 1501 } 1502 } else if (*cp == '&') { 1503 Buf_AddBytes(buf, pattern.leftLen, 1504 (Byte *)pattern.lhs); 1505 } else { 1506 Buf_AddByte(buf, (Byte)*cp); 1507 } 1508 } 1509 1510 Buf_AddByte(buf, (Byte)'\0'); 1511 1512 /* 1513 * If didn't end in delimiter character, complain 1514 */ 1515 if (*cp != delim) { 1516 *lengthPtr = cp - start + 1; 1517 if (*freePtr) { 1518 free(str); 1519 } 1520 Buf_Destroy(buf, TRUE); 1521 Error("Unclosed substitution for %s (%c missing)", 1522 v->name, delim); 1523 return (var_Error); 1524 } 1525 1526 pattern.rhs = (char *)Buf_GetAll(buf, &pattern.rightLen); 1527 pattern.rightLen--; 1528 Buf_Destroy(buf, FALSE); 1529 1530 /* 1531 * Check for global substitution. If 'g' after the final 1532 * delimiter, substitution is global and is marked that 1533 * way. 1534 */ 1535 cp++; 1536 if (*cp == 'g') { 1537 pattern.flags |= VAR_SUB_GLOBAL; 1538 cp++; 1539 } 1540 1541 termc = *cp; 1542 newStr = VarModify(str, VarSubstitute, 1543 (ClientData)&pattern); 1544 /* 1545 * Free the two strings. 1546 */ 1547 free(pattern.lhs); 1548 free(pattern.rhs); 1549 break; 1550 } 1551 case 'T': 1552 if (tstr[1] == endc || tstr[1] == ':') { 1553 newStr = VarModify (str, VarTail, (ClientData)0); 1554 cp = tstr + 1; 1555 termc = *cp; 1556 break; 1557 } 1558 /*FALLTHRU*/ 1559 case 'H': 1560 if (tstr[1] == endc || tstr[1] == ':') { 1561 newStr = VarModify (str, VarHead, (ClientData)0); 1562 cp = tstr + 1; 1563 termc = *cp; 1564 break; 1565 } 1566 /*FALLTHRU*/ 1567 case 'E': 1568 if (tstr[1] == endc || tstr[1] == ':') { 1569 newStr = VarModify (str, VarSuffix, (ClientData)0); 1570 cp = tstr + 1; 1571 termc = *cp; 1572 break; 1573 } 1574 /*FALLTHRU*/ 1575 case 'R': 1576 if (tstr[1] == endc || tstr[1] == ':') { 1577 newStr = VarModify (str, VarRoot, (ClientData)0); 1578 cp = tstr + 1; 1579 termc = *cp; 1580 break; 1581 } 1582 /*FALLTHRU*/ 1583 default: { 1584 /* 1585 * This can either be a bogus modifier or a System-V 1586 * substitution command. 1587 */ 1588 VarPattern pattern; 1589 Boolean eqFound; 1590 1591 pattern.flags = 0; 1592 eqFound = FALSE; 1593 /* 1594 * First we make a pass through the string trying 1595 * to verify it is a SYSV-make-style translation: 1596 * it must be: <string1>=<string2>) 1597 */ 1598 for (cp = tstr; *cp != '\0' && *cp != endc; cp++) { 1599 if (*cp == '=') { 1600 eqFound = TRUE; 1601 /* continue looking for endc */ 1602 } 1603 } 1604 if (*cp == endc && eqFound) { 1605 1606 /* 1607 * Now we break this sucker into the lhs and 1608 * rhs. We must null terminate them of course. 1609 */ 1610 for (cp = tstr; *cp != '='; cp++) 1611 continue; 1612 pattern.lhs = tstr; 1613 pattern.leftLen = cp - tstr; 1614 *cp++ = '\0'; 1615 1616 pattern.rhs = cp; 1617 while (*cp != endc) { 1618 cp++; 1619 } 1620 pattern.rightLen = cp - pattern.rhs; 1621 *cp = '\0'; 1622 1623 /* 1624 * SYSV modifications happen through the whole 1625 * string. Note the pattern is anchored at the end. 1626 */ 1627 newStr = VarModify(str, VarSYSVMatch, 1628 (ClientData)&pattern); 1629 1630 /* 1631 * Restore the nulled characters 1632 */ 1633 pattern.lhs[pattern.leftLen] = '='; 1634 pattern.rhs[pattern.rightLen] = endc; 1635 termc = endc; 1636 } else { 1637 Error ("Unknown modifier '%c'\n", *tstr); 1638 for (cp = tstr+1; 1639 *cp != ':' && *cp != endc && *cp != '\0'; 1640 cp++) 1641 continue; 1642 termc = *cp; 1643 newStr = var_Error; 1644 } 1645 } 1646 } 1647 if (DEBUG(VAR)) { 1648 printf("Result is \"%s\"\n", newStr); 1649 } 1650 1651 if (*freePtr) { 1652 free (str); 1653 } 1654 str = newStr; 1655 if (str != var_Error) { 1656 *freePtr = TRUE; 1657 } else { 1658 *freePtr = FALSE; 1659 } 1660 if (termc == '\0') { 1661 Error("Unclosed variable specification for %s", v->name); 1662 } else if (termc == ':') { 1663 *cp++ = termc; 1664 } else { 1665 *cp = termc; 1666 } 1667 tstr = cp; 1668 } 1669 *lengthPtr = tstr - start + 1; 1670 } else { 1671 *lengthPtr = tstr - start + 1; 1672 *tstr = endc; 1673 } 1674 1675 if (v->flags & VAR_FROM_ENV) { 1676 Boolean destroy = FALSE; 1677 1678 if (str != (char *)Buf_GetAll(v->val, (int *)NULL)) { 1679 destroy = TRUE; 1680 } else { 1681 /* 1682 * Returning the value unmodified, so tell the caller to free 1683 * the thing. 1684 */ 1685 *freePtr = TRUE; 1686 } 1687 Buf_Destroy(v->val, destroy); 1688 free((Address)v); 1689 } else if (v->flags & VAR_JUNK) { 1690 /* 1691 * Perform any free'ing needed and set *freePtr to FALSE so the caller 1692 * doesn't try to free a static pointer. 1693 */ 1694 if (*freePtr) { 1695 free(str); 1696 } 1697 *freePtr = FALSE; 1698 free((Address)v); 1699 if (dynamic) { 1700 str = emalloc(*lengthPtr + 1); 1701 strncpy(str, start, *lengthPtr); 1702 str[*lengthPtr] = '\0'; 1703 *freePtr = TRUE; 1704 } else { 1705 str = var_Error; 1706 } 1707 } 1708 return (str); 1709 } 1710 1711 /*- 1712 *----------------------------------------------------------------------- 1713 * Var_Subst -- 1714 * Substitute for all variables in the given string in the given context 1715 * If undefErr is TRUE, Parse_Error will be called when an undefined 1716 * variable is encountered. 1717 * 1718 * Results: 1719 * The resulting string. 1720 * 1721 * Side Effects: 1722 * None. The old string must be freed by the caller 1723 *----------------------------------------------------------------------- 1724 */ 1725 char * 1726 Var_Subst (var, str, ctxt, undefErr) 1727 char *var; /* Named variable || NULL for all */ 1728 char *str; /* the string in which to substitute */ 1729 GNode *ctxt; /* the context wherein to find variables */ 1730 Boolean undefErr; /* TRUE if undefineds are an error */ 1731 { 1732 Buffer buf; /* Buffer for forming things */ 1733 char *val; /* Value to substitute for a variable */ 1734 int length; /* Length of the variable invocation */ 1735 Boolean doFree; /* Set true if val should be freed */ 1736 static Boolean errorReported; /* Set true if an error has already 1737 * been reported to prevent a plethora 1738 * of messages when recursing */ 1739 1740 buf = Buf_Init (MAKE_BSIZE); 1741 errorReported = FALSE; 1742 1743 while (*str) { 1744 if (var == NULL && (*str == '$') && (str[1] == '$')) { 1745 /* 1746 * A dollar sign may be escaped either with another dollar sign. 1747 * In such a case, we skip over the escape character and store the 1748 * dollar sign into the buffer directly. 1749 */ 1750 str++; 1751 Buf_AddByte(buf, (Byte)*str); 1752 str++; 1753 } else if (*str != '$') { 1754 /* 1755 * Skip as many characters as possible -- either to the end of 1756 * the string or to the next dollar sign (variable invocation). 1757 */ 1758 char *cp; 1759 1760 for (cp = str++; *str != '$' && *str != '\0'; str++) 1761 continue; 1762 Buf_AddBytes(buf, str - cp, (Byte *)cp); 1763 } else { 1764 if (var != NULL) { 1765 int expand; 1766 for (;;) { 1767 if (str[1] != '(' && str[1] != '{') { 1768 if (str[1] != *var) { 1769 Buf_AddBytes(buf, 2, (Byte *) str); 1770 str += 2; 1771 expand = FALSE; 1772 } 1773 else 1774 expand = TRUE; 1775 break; 1776 } 1777 else { 1778 char *p; 1779 1780 /* 1781 * Scan up to the end of the variable name. 1782 */ 1783 for (p = &str[2]; *p && 1784 *p != ':' && *p != ')' && *p != '}'; p++) 1785 if (*p == '$') 1786 break; 1787 /* 1788 * A variable inside the variable. We cannot expand 1789 * the external variable yet, so we try again with 1790 * the nested one 1791 */ 1792 if (*p == '$') { 1793 Buf_AddBytes(buf, p - str, (Byte *) str); 1794 str = p; 1795 continue; 1796 } 1797 1798 if (strncmp(var, str + 2, p - str - 2) != 0 || 1799 var[p - str - 2] != '\0') { 1800 /* 1801 * Not the variable we want to expand, scan 1802 * until the next variable 1803 */ 1804 for (;*p != '$' && *p != '\0'; p++) 1805 continue; 1806 Buf_AddBytes(buf, p - str, (Byte *) str); 1807 str = p; 1808 expand = FALSE; 1809 } 1810 else 1811 expand = TRUE; 1812 break; 1813 } 1814 } 1815 if (!expand) 1816 continue; 1817 } 1818 1819 val = Var_Parse (str, ctxt, undefErr, &length, &doFree); 1820 1821 /* 1822 * When we come down here, val should either point to the 1823 * value of this variable, suitably modified, or be NULL. 1824 * Length should be the total length of the potential 1825 * variable invocation (from $ to end character...) 1826 */ 1827 if (val == var_Error || val == varNoError) { 1828 /* 1829 * If performing old-time variable substitution, skip over 1830 * the variable and continue with the substitution. Otherwise, 1831 * store the dollar sign and advance str so we continue with 1832 * the string... 1833 */ 1834 if (oldVars) { 1835 str += length; 1836 } else if (undefErr) { 1837 /* 1838 * If variable is undefined, complain and skip the 1839 * variable. The complaint will stop us from doing anything 1840 * when the file is parsed. 1841 */ 1842 if (!errorReported) { 1843 Parse_Error (PARSE_FATAL, 1844 "Undefined variable \"%.*s\"",length,str); 1845 } 1846 str += length; 1847 errorReported = TRUE; 1848 } else { 1849 Buf_AddByte (buf, (Byte)*str); 1850 str += 1; 1851 } 1852 } else { 1853 /* 1854 * We've now got a variable structure to store in. But first, 1855 * advance the string pointer. 1856 */ 1857 str += length; 1858 1859 /* 1860 * Copy all the characters from the variable value straight 1861 * into the new string. 1862 */ 1863 Buf_AddBytes (buf, strlen (val), (Byte *)val); 1864 if (doFree) { 1865 free ((Address)val); 1866 } 1867 } 1868 } 1869 } 1870 1871 Buf_AddByte (buf, '\0'); 1872 str = (char *)Buf_GetAll (buf, (int *)NULL); 1873 Buf_Destroy (buf, FALSE); 1874 return (str); 1875 } 1876 1877 /*- 1878 *----------------------------------------------------------------------- 1879 * Var_GetTail -- 1880 * Return the tail from each of a list of words. Used to set the 1881 * System V local variables. 1882 * 1883 * Results: 1884 * The resulting string. 1885 * 1886 * Side Effects: 1887 * None. 1888 * 1889 *----------------------------------------------------------------------- 1890 */ 1891 char * 1892 Var_GetTail(file) 1893 char *file; /* Filename to modify */ 1894 { 1895 return(VarModify(file, VarTail, (ClientData)0)); 1896 } 1897 1898 /*- 1899 *----------------------------------------------------------------------- 1900 * Var_GetHead -- 1901 * Find the leading components of a (list of) filename(s). 1902 * XXX: VarHead does not replace foo by ., as (sun) System V make 1903 * does. 1904 * 1905 * Results: 1906 * The leading components. 1907 * 1908 * Side Effects: 1909 * None. 1910 * 1911 *----------------------------------------------------------------------- 1912 */ 1913 char * 1914 Var_GetHead(file) 1915 char *file; /* Filename to manipulate */ 1916 { 1917 return(VarModify(file, VarHead, (ClientData)0)); 1918 } 1919 1920 /*- 1921 *----------------------------------------------------------------------- 1922 * Var_Init -- 1923 * Initialize the module 1924 * 1925 * Results: 1926 * None 1927 * 1928 * Side Effects: 1929 * The VAR_CMD and VAR_GLOBAL contexts are created 1930 *----------------------------------------------------------------------- 1931 */ 1932 void 1933 Var_Init () 1934 { 1935 VAR_GLOBAL = Targ_NewGN ("Global"); 1936 VAR_CMD = Targ_NewGN ("Command"); 1937 1938 } 1939 1940 /****************** PRINT DEBUGGING INFO *****************/ 1941 static int 1942 VarPrintVar (v) 1943 Var *v; 1944 { 1945 printf ("%-16s = %s\n", v->name, (char *) Buf_GetAll(v->val, (int *)NULL)); 1946 return (0); 1947 } 1948 1949 /*- 1950 *----------------------------------------------------------------------- 1951 * Var_Dump -- 1952 * print all variables in a context 1953 *----------------------------------------------------------------------- 1954 */ 1955 void 1956 Var_Dump (ctxt) 1957 GNode *ctxt; 1958 { 1959 Lst_ForEach (ctxt->context, VarPrintVar); 1960 } 1961