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