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