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