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