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