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