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