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