var.c revision 1.236 1 /* $NetBSD: var.c,v 1.236 2020/07/03 14:14:04 rillig Exp $ */
2
3 /*
4 * Copyright (c) 1988, 1989, 1990, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Adam de Boor.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 /*
36 * Copyright (c) 1989 by Berkeley Softworks
37 * All rights reserved.
38 *
39 * This code is derived from software contributed to Berkeley by
40 * Adam de Boor.
41 *
42 * Redistribution and use in source and binary forms, with or without
43 * modification, are permitted provided that the following conditions
44 * are met:
45 * 1. Redistributions of source code must retain the above copyright
46 * notice, this list of conditions and the following disclaimer.
47 * 2. Redistributions in binary form must reproduce the above copyright
48 * notice, this list of conditions and the following disclaimer in the
49 * documentation and/or other materials provided with the distribution.
50 * 3. All advertising materials mentioning features or use of this software
51 * must display the following acknowledgement:
52 * This product includes software developed by the University of
53 * California, Berkeley and its contributors.
54 * 4. Neither the name of the University nor the names of its contributors
55 * may be used to endorse or promote products derived from this software
56 * without specific prior written permission.
57 *
58 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
59 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
60 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
61 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
62 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
63 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
64 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
65 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
66 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
67 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
68 * SUCH DAMAGE.
69 */
70
71 #ifndef MAKE_NATIVE
72 static char rcsid[] = "$NetBSD: var.c,v 1.236 2020/07/03 14:14:04 rillig Exp $";
73 #else
74 #include <sys/cdefs.h>
75 #ifndef lint
76 #if 0
77 static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 3/19/94";
78 #else
79 __RCSID("$NetBSD: var.c,v 1.236 2020/07/03 14:14:04 rillig Exp $");
80 #endif
81 #endif /* not lint */
82 #endif
83
84 /*-
85 * var.c --
86 * Variable-handling functions
87 *
88 * Interface:
89 * Var_Set Set the value of a variable in the given
90 * context. The variable is created if it doesn't
91 * yet exist. The value and variable name need not
92 * be preserved.
93 *
94 * Var_Append Append more characters to an existing variable
95 * in the given context. The variable needn't
96 * exist already -- it will be created if it doesn't.
97 * A space is placed between the old value and the
98 * new one.
99 *
100 * Var_Exists See if a variable exists.
101 *
102 * Var_Value Return the value of a variable in a context or
103 * NULL if the variable is undefined.
104 *
105 * Var_Subst Substitute named variable, or all variables if
106 * NULL in a string using
107 * the given context as the top-most one. If the
108 * third argument is non-zero, Parse_Error is
109 * called if any variables are undefined.
110 *
111 * Var_Parse Parse a variable expansion from a string and
112 * return the result and the number of characters
113 * consumed.
114 *
115 * Var_Delete Delete a variable in a context.
116 *
117 * Var_Init Initialize this module.
118 *
119 * Debugging:
120 * Var_Dump Print out all variables defined in the given
121 * context.
122 *
123 * XXX: There's a lot of duplication in these functions.
124 */
125
126 #include <sys/stat.h>
127 #ifndef NO_REGEX
128 #include <sys/types.h>
129 #include <regex.h>
130 #endif
131 #include <ctype.h>
132 #include <inttypes.h>
133 #include <stdlib.h>
134 #include <limits.h>
135 #include <time.h>
136
137 #include "make.h"
138 #include "buf.h"
139 #include "dir.h"
140 #include "job.h"
141 #include "metachar.h"
142
143 extern int makelevel;
144 /*
145 * This lets us tell if we have replaced the original environ
146 * (which we cannot free).
147 */
148 char **savedEnv = NULL;
149
150 /*
151 * This is a harmless return value for Var_Parse that can be used by Var_Subst
152 * to determine if there was an error in parsing -- easier than returning
153 * a flag, as things outside this module don't give a hoot.
154 */
155 char var_Error[] = "";
156
157 /*
158 * Similar to var_Error, but returned when the 'VARF_UNDEFERR' flag for
159 * Var_Parse is not set. Why not just use a constant? Well, gcc likes
160 * to condense identical string instances...
161 */
162 static char varNoError[] = "";
163
164 /*
165 * Traditionally we consume $$ during := like any other expansion.
166 * Other make's do not.
167 * This knob allows controlling the behavior.
168 * FALSE for old behavior.
169 * TRUE for new compatible.
170 */
171 #define SAVE_DOLLARS ".MAKE.SAVE_DOLLARS"
172 static Boolean save_dollars = TRUE;
173
174 /*
175 * Internally, variables are contained in four different contexts.
176 * 1) the environment. They may not be changed. If an environment
177 * variable is appended-to, the result is placed in the global
178 * context.
179 * 2) the global context. Variables set in the Makefile are located in
180 * the global context. It is the penultimate context searched when
181 * substituting.
182 * 3) the command-line context. All variables set on the command line
183 * are placed in this context. They are UNALTERABLE once placed here.
184 * 4) the local context. Each target has associated with it a context
185 * list. On this list are located the structures describing such
186 * local variables as $(@) and $(*)
187 * The four contexts are searched in the reverse order from which they are
188 * listed.
189 */
190 GNode *VAR_INTERNAL; /* variables from make itself */
191 GNode *VAR_GLOBAL; /* variables from the makefile */
192 GNode *VAR_CMD; /* variables defined on the command-line */
193
194 #define FIND_CMD 0x1 /* look in VAR_CMD when searching */
195 #define FIND_GLOBAL 0x2 /* look in VAR_GLOBAL as well */
196 #define FIND_ENV 0x4 /* look in the environment also */
197
198 typedef enum {
199 VAR_IN_USE = 0x01, /* Variable's value is currently being used.
200 * Used to avoid endless recursion */
201 VAR_FROM_ENV = 0x02, /* Variable comes from the environment */
202 VAR_JUNK = 0x04, /* Variable is a junk variable that
203 * should be destroyed when done with
204 * it. Used by Var_Parse for undefined,
205 * modified variables */
206 VAR_KEEP = 0x08, /* Variable is VAR_JUNK, but we found
207 * a use for it in some modifier and
208 * the value is therefore valid */
209 VAR_EXPORTED = 0x10, /* Variable is exported */
210 VAR_REEXPORT = 0x20, /* Indicate if var needs re-export.
211 * This would be true if it contains $'s */
212 VAR_FROM_CMD = 0x40 /* Variable came from command line */
213 } Var_Flags;
214
215 typedef struct Var {
216 char *name; /* the variable's name */
217 Buffer val; /* its value */
218 Var_Flags flags; /* miscellaneous status flags */
219 } Var;
220
221 /*
222 * Exporting vars is expensive so skip it if we can
223 */
224 #define VAR_EXPORTED_NONE 0
225 #define VAR_EXPORTED_YES 1
226 #define VAR_EXPORTED_ALL 2
227 static int var_exportedVars = VAR_EXPORTED_NONE;
228 /*
229 * We pass this to Var_Export when doing the initial export
230 * or after updating an exported var.
231 */
232 #define VAR_EXPORT_PARENT 1
233 /*
234 * We pass this to Var_Export1 to tell it to leave the value alone.
235 */
236 #define VAR_EXPORT_LITERAL 2
237
238 typedef enum {
239 VAR_SUB_GLOBAL = 0x01, /* Apply substitution globally */
240 VAR_SUB_ONE = 0x02, /* Apply substitution to one word */
241 VAR_SUB_MATCHED = 0x04, /* There was a match */
242 VAR_MATCH_START = 0x08, /* Match at start of word */
243 VAR_MATCH_END = 0x10, /* Match at end of word */
244 VAR_NOSUBST = 0x20 /* don't expand vars in VarGetPattern */
245 } VarPattern_Flags;
246
247 typedef enum {
248 VAR_NO_EXPORT = 0x01 /* do not export */
249 } VarSet_Flags;
250
251 typedef struct {
252 /*
253 * The following fields are set by Var_Parse() when it
254 * encounters modifiers that need to keep state for use by
255 * subsequent modifiers within the same variable expansion.
256 */
257 Byte varSpace; /* Word separator in expansions */
258 Boolean oneBigWord; /* TRUE if we will treat the variable as a
259 * single big word, even if it contains
260 * embedded spaces (as opposed to the
261 * usual behaviour of treating it as
262 * several space-separated words). */
263 } Var_Parse_State;
264
265 /* struct passed as 'void *' to VarSubstitute() for ":S/lhs/rhs/",
266 * to VarSYSVMatch() for ":lhs=rhs". */
267 typedef struct {
268 const char *lhs; /* String to match */
269 int leftLen; /* Length of string */
270 const char *rhs; /* Replacement string (w/ &'s removed) */
271 int rightLen; /* Length of replacement */
272 VarPattern_Flags flags;
273 } VarPattern;
274
275 /* struct passed as 'void *' to VarLoopExpand() for ":@tvar@str@" */
276 typedef struct {
277 GNode *ctxt; /* variable context */
278 char *tvar; /* name of temp var */
279 int tvarLen;
280 char *str; /* string to expand */
281 int strLen;
282 Varf_Flags flags;
283 } VarLoop_t;
284
285 #ifndef NO_REGEX
286 /* struct passed as 'void *' to VarRESubstitute() for ":C///" */
287 typedef struct {
288 regex_t re;
289 int nsub;
290 regmatch_t *matches;
291 char *replace;
292 int flags;
293 } VarREPattern;
294 #endif
295
296 /* struct passed to VarSelectWords() for ":[start..end]" */
297 typedef struct {
298 int start; /* first word to select */
299 int end; /* last word to select */
300 } VarSelectWords_t;
301
302 static Var *VarFind(const char *, GNode *, int);
303 static void VarAdd(const char *, const char *, GNode *);
304 static Boolean VarHead(GNode *, Var_Parse_State *,
305 char *, Boolean, Buffer *, void *);
306 static Boolean VarTail(GNode *, Var_Parse_State *,
307 char *, Boolean, Buffer *, void *);
308 static Boolean VarSuffix(GNode *, Var_Parse_State *,
309 char *, Boolean, Buffer *, void *);
310 static Boolean VarRoot(GNode *, Var_Parse_State *,
311 char *, Boolean, Buffer *, void *);
312 static Boolean VarMatch(GNode *, Var_Parse_State *,
313 char *, Boolean, Buffer *, void *);
314 #ifdef SYSVVARSUB
315 static Boolean VarSYSVMatch(GNode *, Var_Parse_State *,
316 char *, Boolean, Buffer *, void *);
317 #endif
318 static Boolean VarNoMatch(GNode *, Var_Parse_State *,
319 char *, Boolean, Buffer *, void *);
320 #ifndef NO_REGEX
321 static void VarREError(int, regex_t *, const char *);
322 static Boolean VarRESubstitute(GNode *, Var_Parse_State *,
323 char *, Boolean, Buffer *, void *);
324 #endif
325 static Boolean VarSubstitute(GNode *, Var_Parse_State *,
326 char *, Boolean, Buffer *, void *);
327 static Boolean VarLoopExpand(GNode *, Var_Parse_State *,
328 char *, Boolean, Buffer *, void *);
329 static char *VarGetPattern(GNode *, Var_Parse_State *,
330 VarPattern_Flags, const char **, int,
331 VarPattern_Flags *, int *, VarPattern *);
332 static char *VarQuote(char *, Boolean);
333 static char *VarHash(char *);
334 static char *VarModify(GNode *, Var_Parse_State *,
335 const char *,
336 Boolean (*)(GNode *, Var_Parse_State *, char *, Boolean, Buffer *, void *),
337 void *);
338 static char *VarOrder(const char *, const char);
339 static char *VarUniq(const char *);
340 static int VarWordCompare(const void *, const void *);
341 static void VarPrintVar(void *);
342
343 #define BROPEN '{'
344 #define BRCLOSE '}'
345 #define PROPEN '('
346 #define PRCLOSE ')'
347
348 /*-
349 *-----------------------------------------------------------------------
350 * VarFind --
351 * Find the given variable in the given context and any other contexts
352 * indicated.
353 *
354 * Input:
355 * name name to find
356 * ctxt context in which to find it
357 * flags FIND_GLOBAL set means to look in the
358 * VAR_GLOBAL context as well. FIND_CMD set means
359 * to look in the VAR_CMD context also. FIND_ENV
360 * set means to look in the environment
361 *
362 * Results:
363 * A pointer to the structure describing the desired variable or
364 * NULL if the variable does not exist.
365 *
366 * Side Effects:
367 * None
368 *-----------------------------------------------------------------------
369 */
370 static Var *
371 VarFind(const char *name, GNode *ctxt, int flags)
372 {
373 Hash_Entry *var;
374 Var *v;
375
376 /*
377 * If the variable name begins with a '.', it could very well be one of
378 * the local ones. We check the name against all the local variables
379 * and substitute the short version in for 'name' if it matches one of
380 * them.
381 */
382 if (*name == '.' && isupper((unsigned char) name[1]))
383 switch (name[1]) {
384 case 'A':
385 if (!strcmp(name, ".ALLSRC"))
386 name = ALLSRC;
387 if (!strcmp(name, ".ARCHIVE"))
388 name = ARCHIVE;
389 break;
390 case 'I':
391 if (!strcmp(name, ".IMPSRC"))
392 name = IMPSRC;
393 break;
394 case 'M':
395 if (!strcmp(name, ".MEMBER"))
396 name = MEMBER;
397 break;
398 case 'O':
399 if (!strcmp(name, ".OODATE"))
400 name = OODATE;
401 break;
402 case 'P':
403 if (!strcmp(name, ".PREFIX"))
404 name = PREFIX;
405 break;
406 case 'T':
407 if (!strcmp(name, ".TARGET"))
408 name = TARGET;
409 break;
410 }
411 #ifdef notyet
412 /* for compatibility with gmake */
413 if (name[0] == '^' && name[1] == '\0')
414 name = ALLSRC;
415 #endif
416
417 /*
418 * First look for the variable in the given context. If it's not there,
419 * look for it in VAR_CMD, VAR_GLOBAL and the environment, in that order,
420 * depending on the FIND_* flags in 'flags'
421 */
422 var = Hash_FindEntry(&ctxt->context, name);
423
424 if (var == NULL && (flags & FIND_CMD) && ctxt != VAR_CMD) {
425 var = Hash_FindEntry(&VAR_CMD->context, name);
426 }
427 if (!checkEnvFirst && var == NULL && (flags & FIND_GLOBAL) &&
428 ctxt != VAR_GLOBAL)
429 {
430 var = Hash_FindEntry(&VAR_GLOBAL->context, name);
431 if (var == NULL && ctxt != VAR_INTERNAL) {
432 /* VAR_INTERNAL is subordinate to VAR_GLOBAL */
433 var = Hash_FindEntry(&VAR_INTERNAL->context, name);
434 }
435 }
436 if (var == NULL && (flags & FIND_ENV)) {
437 char *env;
438
439 if ((env = getenv(name)) != NULL) {
440 int len;
441
442 v = bmake_malloc(sizeof(Var));
443 v->name = bmake_strdup(name);
444
445 len = strlen(env);
446
447 Buf_Init(&v->val, len + 1);
448 Buf_AddBytes(&v->val, len, env);
449
450 v->flags = VAR_FROM_ENV;
451 return v;
452 } else if (checkEnvFirst && (flags & FIND_GLOBAL) &&
453 ctxt != VAR_GLOBAL)
454 {
455 var = Hash_FindEntry(&VAR_GLOBAL->context, name);
456 if (var == NULL && ctxt != VAR_INTERNAL) {
457 var = Hash_FindEntry(&VAR_INTERNAL->context, name);
458 }
459 if (var == NULL) {
460 return NULL;
461 } else {
462 return (Var *)Hash_GetValue(var);
463 }
464 } else {
465 return NULL;
466 }
467 } else if (var == NULL) {
468 return NULL;
469 } else {
470 return (Var *)Hash_GetValue(var);
471 }
472 }
473
474 /*-
475 *-----------------------------------------------------------------------
476 * VarFreeEnv --
477 * If the variable is an environment variable, free it
478 *
479 * Input:
480 * v the variable
481 * destroy true if the value buffer should be destroyed.
482 *
483 * Results:
484 * 1 if it is an environment variable 0 ow.
485 *
486 * Side Effects:
487 * The variable is free'ed if it is an environent variable.
488 *-----------------------------------------------------------------------
489 */
490 static Boolean
491 VarFreeEnv(Var *v, Boolean destroy)
492 {
493 if ((v->flags & VAR_FROM_ENV) == 0)
494 return FALSE;
495 free(v->name);
496 Buf_Destroy(&v->val, destroy);
497 free(v);
498 return TRUE;
499 }
500
501 /*-
502 *-----------------------------------------------------------------------
503 * VarAdd --
504 * Add a new variable of name name and value val to the given context
505 *
506 * Input:
507 * name name of variable to add
508 * val value to set it to
509 * ctxt context in which to set it
510 *
511 * Results:
512 * None
513 *
514 * Side Effects:
515 * The new variable is placed at the front of the given context
516 * The name and val arguments are duplicated so they may
517 * safely be freed.
518 *-----------------------------------------------------------------------
519 */
520 static void
521 VarAdd(const char *name, const char *val, GNode *ctxt)
522 {
523 Var *v;
524 int len;
525 Hash_Entry *h;
526
527 v = bmake_malloc(sizeof(Var));
528
529 len = val ? strlen(val) : 0;
530 Buf_Init(&v->val, len+1);
531 Buf_AddBytes(&v->val, len, val);
532
533 v->flags = 0;
534
535 h = Hash_CreateEntry(&ctxt->context, name, NULL);
536 Hash_SetValue(h, v);
537 v->name = h->name;
538 if (DEBUG(VAR) && (ctxt->flags & INTERNAL) == 0) {
539 fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name, val);
540 }
541 }
542
543 /*-
544 *-----------------------------------------------------------------------
545 * Var_Delete --
546 * Remove a variable from a context.
547 *
548 * Results:
549 * None.
550 *
551 * Side Effects:
552 * The Var structure is removed and freed.
553 *
554 *-----------------------------------------------------------------------
555 */
556 void
557 Var_Delete(const char *name, GNode *ctxt)
558 {
559 Hash_Entry *ln;
560 char *cp;
561
562 if (strchr(name, '$')) {
563 cp = Var_Subst(NULL, name, VAR_GLOBAL, VARF_WANTRES);
564 } else {
565 cp = (char *)name;
566 }
567 ln = Hash_FindEntry(&ctxt->context, cp);
568 if (DEBUG(VAR)) {
569 fprintf(debug_file, "%s:delete %s%s\n",
570 ctxt->name, cp, ln ? "" : " (not found)");
571 }
572 if (cp != name) {
573 free(cp);
574 }
575 if (ln != NULL) {
576 Var *v;
577
578 v = (Var *)Hash_GetValue(ln);
579 if ((v->flags & VAR_EXPORTED)) {
580 unsetenv(v->name);
581 }
582 if (strcmp(MAKE_EXPORTED, v->name) == 0) {
583 var_exportedVars = VAR_EXPORTED_NONE;
584 }
585 if (v->name != ln->name)
586 free(v->name);
587 Hash_DeleteEntry(&ctxt->context, ln);
588 Buf_Destroy(&v->val, TRUE);
589 free(v);
590 }
591 }
592
593
594 /*
595 * Export a var.
596 * We ignore make internal variables (those which start with '.')
597 * Also we jump through some hoops to avoid calling setenv
598 * more than necessary since it can leak.
599 * We only manipulate flags of vars if 'parent' is set.
600 */
601 static int
602 Var_Export1(const char *name, int flags)
603 {
604 char tmp[BUFSIZ];
605 Var *v;
606 char *val = NULL;
607 int n;
608 int parent = (flags & VAR_EXPORT_PARENT);
609
610 if (*name == '.')
611 return 0; /* skip internals */
612 if (!name[1]) {
613 /*
614 * A single char.
615 * If it is one of the vars that should only appear in
616 * local context, skip it, else we can get Var_Subst
617 * into a loop.
618 */
619 switch (name[0]) {
620 case '@':
621 case '%':
622 case '*':
623 case '!':
624 return 0;
625 }
626 }
627 v = VarFind(name, VAR_GLOBAL, 0);
628 if (v == NULL) {
629 return 0;
630 }
631 if (!parent &&
632 (v->flags & (VAR_EXPORTED|VAR_REEXPORT)) == VAR_EXPORTED) {
633 return 0; /* nothing to do */
634 }
635 val = Buf_GetAll(&v->val, NULL);
636 if ((flags & VAR_EXPORT_LITERAL) == 0 && strchr(val, '$')) {
637 if (parent) {
638 /*
639 * Flag this as something we need to re-export.
640 * No point actually exporting it now though,
641 * the child can do it at the last minute.
642 */
643 v->flags |= (VAR_EXPORTED|VAR_REEXPORT);
644 return 1;
645 }
646 if (v->flags & VAR_IN_USE) {
647 /*
648 * We recursed while exporting in a child.
649 * This isn't going to end well, just skip it.
650 */
651 return 0;
652 }
653 n = snprintf(tmp, sizeof(tmp), "${%s}", name);
654 if (n < (int)sizeof(tmp)) {
655 val = Var_Subst(NULL, tmp, VAR_GLOBAL, VARF_WANTRES);
656 setenv(name, val, 1);
657 free(val);
658 }
659 } else {
660 if (parent) {
661 v->flags &= ~VAR_REEXPORT; /* once will do */
662 }
663 if (parent || !(v->flags & VAR_EXPORTED)) {
664 setenv(name, val, 1);
665 }
666 }
667 /*
668 * This is so Var_Set knows to call Var_Export again...
669 */
670 if (parent) {
671 v->flags |= VAR_EXPORTED;
672 }
673 return 1;
674 }
675
676 /*
677 * This gets called from our children.
678 */
679 void
680 Var_ExportVars(void)
681 {
682 char tmp[BUFSIZ];
683 Hash_Entry *var;
684 Hash_Search state;
685 Var *v;
686 char *val;
687 int n;
688
689 /*
690 * Several make's support this sort of mechanism for tracking
691 * recursion - but each uses a different name.
692 * We allow the makefiles to update MAKELEVEL and ensure
693 * children see a correctly incremented value.
694 */
695 snprintf(tmp, sizeof(tmp), "%d", makelevel + 1);
696 setenv(MAKE_LEVEL_ENV, tmp, 1);
697
698 if (VAR_EXPORTED_NONE == var_exportedVars)
699 return;
700
701 if (VAR_EXPORTED_ALL == var_exportedVars) {
702 /*
703 * Ouch! This is crazy...
704 */
705 for (var = Hash_EnumFirst(&VAR_GLOBAL->context, &state);
706 var != NULL;
707 var = Hash_EnumNext(&state)) {
708 v = (Var *)Hash_GetValue(var);
709 Var_Export1(v->name, 0);
710 }
711 return;
712 }
713 /*
714 * We have a number of exported vars,
715 */
716 n = snprintf(tmp, sizeof(tmp), "${" MAKE_EXPORTED ":O:u}");
717 if (n < (int)sizeof(tmp)) {
718 char **av;
719 char *as;
720 int ac;
721 int i;
722
723 val = Var_Subst(NULL, tmp, VAR_GLOBAL, VARF_WANTRES);
724 if (*val) {
725 av = brk_string(val, &ac, FALSE, &as);
726 for (i = 0; i < ac; i++) {
727 Var_Export1(av[i], 0);
728 }
729 free(as);
730 free(av);
731 }
732 free(val);
733 }
734 }
735
736 /*
737 * This is called when .export is seen or
738 * .MAKE.EXPORTED is modified.
739 * It is also called when any exported var is modified.
740 */
741 void
742 Var_Export(char *str, int isExport)
743 {
744 char *name;
745 char *val;
746 char **av;
747 char *as;
748 int flags;
749 int ac;
750 int i;
751
752 if (isExport && (!str || !str[0])) {
753 var_exportedVars = VAR_EXPORTED_ALL; /* use with caution! */
754 return;
755 }
756
757 flags = 0;
758 if (strncmp(str, "-env", 4) == 0) {
759 str += 4;
760 } else if (strncmp(str, "-literal", 8) == 0) {
761 str += 8;
762 flags |= VAR_EXPORT_LITERAL;
763 } else {
764 flags |= VAR_EXPORT_PARENT;
765 }
766 val = Var_Subst(NULL, str, VAR_GLOBAL, VARF_WANTRES);
767 if (*val) {
768 av = brk_string(val, &ac, FALSE, &as);
769 for (i = 0; i < ac; i++) {
770 name = av[i];
771 if (!name[1]) {
772 /*
773 * A single char.
774 * If it is one of the vars that should only appear in
775 * local context, skip it, else we can get Var_Subst
776 * into a loop.
777 */
778 switch (name[0]) {
779 case '@':
780 case '%':
781 case '*':
782 case '!':
783 continue;
784 }
785 }
786 if (Var_Export1(name, flags)) {
787 if (VAR_EXPORTED_ALL != var_exportedVars)
788 var_exportedVars = VAR_EXPORTED_YES;
789 if (isExport && (flags & VAR_EXPORT_PARENT)) {
790 Var_Append(MAKE_EXPORTED, name, VAR_GLOBAL);
791 }
792 }
793 }
794 free(as);
795 free(av);
796 }
797 free(val);
798 }
799
800
801 /*
802 * This is called when .unexport[-env] is seen.
803 */
804 extern char **environ;
805
806 void
807 Var_UnExport(char *str)
808 {
809 char tmp[BUFSIZ];
810 char *vlist;
811 char *cp;
812 Boolean unexport_env;
813 int n;
814
815 if (!str || !str[0]) {
816 return; /* assert? */
817 }
818
819 vlist = NULL;
820
821 str += 8;
822 unexport_env = (strncmp(str, "-env", 4) == 0);
823 if (unexport_env) {
824 char **newenv;
825
826 cp = getenv(MAKE_LEVEL_ENV); /* we should preserve this */
827 if (environ == savedEnv) {
828 /* we have been here before! */
829 newenv = bmake_realloc(environ, 2 * sizeof(char *));
830 } else {
831 if (savedEnv) {
832 free(savedEnv);
833 savedEnv = NULL;
834 }
835 newenv = bmake_malloc(2 * sizeof(char *));
836 }
837 if (!newenv)
838 return;
839 /* Note: we cannot safely free() the original environ. */
840 environ = savedEnv = newenv;
841 newenv[0] = NULL;
842 newenv[1] = NULL;
843 if (cp && *cp)
844 setenv(MAKE_LEVEL_ENV, cp, 1);
845 } else {
846 for (; *str != '\n' && isspace((unsigned char) *str); str++)
847 continue;
848 if (str[0] && str[0] != '\n') {
849 vlist = str;
850 }
851 }
852
853 if (!vlist) {
854 /* Using .MAKE.EXPORTED */
855 n = snprintf(tmp, sizeof(tmp), "${" MAKE_EXPORTED ":O:u}");
856 if (n < (int)sizeof(tmp)) {
857 vlist = Var_Subst(NULL, tmp, VAR_GLOBAL, VARF_WANTRES);
858 }
859 }
860 if (vlist) {
861 Var *v;
862 char **av;
863 char *as;
864 int ac;
865 int i;
866
867 av = brk_string(vlist, &ac, FALSE, &as);
868 for (i = 0; i < ac; i++) {
869 v = VarFind(av[i], VAR_GLOBAL, 0);
870 if (!v)
871 continue;
872 if (!unexport_env &&
873 (v->flags & (VAR_EXPORTED|VAR_REEXPORT)) == VAR_EXPORTED) {
874 unsetenv(v->name);
875 }
876 v->flags &= ~(VAR_EXPORTED|VAR_REEXPORT);
877 /*
878 * If we are unexporting a list,
879 * remove each one from .MAKE.EXPORTED.
880 * If we are removing them all,
881 * just delete .MAKE.EXPORTED below.
882 */
883 if (vlist == str) {
884 n = snprintf(tmp, sizeof(tmp),
885 "${" MAKE_EXPORTED ":N%s}", v->name);
886 if (n < (int)sizeof(tmp)) {
887 cp = Var_Subst(NULL, tmp, VAR_GLOBAL, VARF_WANTRES);
888 Var_Set(MAKE_EXPORTED, cp, VAR_GLOBAL);
889 free(cp);
890 }
891 }
892 }
893 free(as);
894 free(av);
895 if (vlist != str) {
896 Var_Delete(MAKE_EXPORTED, VAR_GLOBAL);
897 free(vlist);
898 }
899 }
900 }
901
902 static void
903 Var_Set_Flags(const char *name, const char *val, GNode *ctxt, VarSet_Flags flags)
904 {
905 Var *v;
906 char *expanded_name = NULL;
907
908 /*
909 * We only look for a variable in the given context since anything set
910 * here will override anything in a lower context, so there's not much
911 * point in searching them all just to save a bit of memory...
912 */
913 if (strchr(name, '$') != NULL) {
914 expanded_name = Var_Subst(NULL, name, ctxt, VARF_WANTRES);
915 if (expanded_name[0] == 0) {
916 if (DEBUG(VAR)) {
917 fprintf(debug_file, "Var_Set(\"%s\", \"%s\", ...) "
918 "name expands to empty string - ignored\n",
919 name, val);
920 }
921 free(expanded_name);
922 return;
923 }
924 name = expanded_name;
925 }
926 if (ctxt == VAR_GLOBAL) {
927 v = VarFind(name, VAR_CMD, 0);
928 if (v != NULL) {
929 if ((v->flags & VAR_FROM_CMD)) {
930 if (DEBUG(VAR)) {
931 fprintf(debug_file, "%s:%s = %s ignored!\n", ctxt->name, name, val);
932 }
933 goto out;
934 }
935 VarFreeEnv(v, TRUE);
936 }
937 }
938 v = VarFind(name, ctxt, 0);
939 if (v == NULL) {
940 if (ctxt == VAR_CMD && (flags & VAR_NO_EXPORT) == 0) {
941 /*
942 * This var would normally prevent the same name being added
943 * to VAR_GLOBAL, so delete it from there if needed.
944 * Otherwise -V name may show the wrong value.
945 */
946 Var_Delete(name, VAR_GLOBAL);
947 }
948 VarAdd(name, val, ctxt);
949 } else {
950 Buf_Empty(&v->val);
951 if (val)
952 Buf_AddBytes(&v->val, strlen(val), val);
953
954 if (DEBUG(VAR)) {
955 fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name, val);
956 }
957 if ((v->flags & VAR_EXPORTED)) {
958 Var_Export1(name, VAR_EXPORT_PARENT);
959 }
960 }
961 /*
962 * Any variables given on the command line are automatically exported
963 * to the environment (as per POSIX standard)
964 */
965 if (ctxt == VAR_CMD && (flags & VAR_NO_EXPORT) == 0) {
966 if (v == NULL) {
967 /* we just added it */
968 v = VarFind(name, ctxt, 0);
969 }
970 if (v != NULL)
971 v->flags |= VAR_FROM_CMD;
972 /*
973 * If requested, don't export these in the environment
974 * individually. We still put them in MAKEOVERRIDES so
975 * that the command-line settings continue to override
976 * Makefile settings.
977 */
978 if (varNoExportEnv != TRUE)
979 setenv(name, val ? val : "", 1);
980
981 Var_Append(MAKEOVERRIDES, name, VAR_GLOBAL);
982 }
983 if (*name == '.') {
984 if (strcmp(name, SAVE_DOLLARS) == 0)
985 save_dollars = s2Boolean(val, save_dollars);
986 }
987
988 out:
989 free(expanded_name);
990 if (v != NULL)
991 VarFreeEnv(v, TRUE);
992 }
993
994 /*-
995 *-----------------------------------------------------------------------
996 * Var_Set --
997 * Set the variable name to the value val in the given context.
998 *
999 * Input:
1000 * name name of variable to set
1001 * val value to give to the variable
1002 * ctxt context in which to set it
1003 *
1004 * Results:
1005 * None.
1006 *
1007 * Side Effects:
1008 * If the variable doesn't yet exist, a new record is created for it.
1009 * Else the old value is freed and the new one stuck in its place
1010 *
1011 * Notes:
1012 * The variable is searched for only in its context before being
1013 * created in that context. I.e. if the context is VAR_GLOBAL,
1014 * only VAR_GLOBAL->context is searched. Likewise if it is VAR_CMD, only
1015 * VAR_CMD->context is searched. This is done to avoid the literally
1016 * thousands of unnecessary strcmp's that used to be done to
1017 * set, say, $(@) or $(<).
1018 * If the context is VAR_GLOBAL though, we check if the variable
1019 * was set in VAR_CMD from the command line and skip it if so.
1020 *-----------------------------------------------------------------------
1021 */
1022 void
1023 Var_Set(const char *name, const char *val, GNode *ctxt)
1024 {
1025 Var_Set_Flags(name, val, ctxt, 0);
1026 }
1027
1028 /*-
1029 *-----------------------------------------------------------------------
1030 * Var_Append --
1031 * The variable of the given name has the given value appended to it in
1032 * the given context.
1033 *
1034 * Input:
1035 * name name of variable to modify
1036 * val String to append to it
1037 * ctxt Context in which this should occur
1038 *
1039 * Results:
1040 * None
1041 *
1042 * Side Effects:
1043 * If the variable doesn't exist, it is created. Else the strings
1044 * are concatenated (with a space in between).
1045 *
1046 * Notes:
1047 * Only if the variable is being sought in the global context is the
1048 * environment searched.
1049 * XXX: Knows its calling circumstances in that if called with ctxt
1050 * an actual target, it will only search that context since only
1051 * a local variable could be being appended to. This is actually
1052 * a big win and must be tolerated.
1053 *-----------------------------------------------------------------------
1054 */
1055 void
1056 Var_Append(const char *name, const char *val, GNode *ctxt)
1057 {
1058 Var *v;
1059 Hash_Entry *h;
1060 char *expanded_name = NULL;
1061
1062 if (strchr(name, '$') != NULL) {
1063 expanded_name = Var_Subst(NULL, name, ctxt, VARF_WANTRES);
1064 if (expanded_name[0] == 0) {
1065 if (DEBUG(VAR)) {
1066 fprintf(debug_file, "Var_Append(\"%s\", \"%s\", ...) "
1067 "name expands to empty string - ignored\n",
1068 name, val);
1069 }
1070 free(expanded_name);
1071 return;
1072 }
1073 name = expanded_name;
1074 }
1075
1076 v = VarFind(name, ctxt, ctxt == VAR_GLOBAL ? (FIND_CMD|FIND_ENV) : 0);
1077
1078 if (v == NULL) {
1079 Var_Set(name, val, ctxt);
1080 } else if (ctxt == VAR_CMD || !(v->flags & VAR_FROM_CMD)) {
1081 Buf_AddByte(&v->val, ' ');
1082 Buf_AddBytes(&v->val, strlen(val), val);
1083
1084 if (DEBUG(VAR)) {
1085 fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name,
1086 Buf_GetAll(&v->val, NULL));
1087 }
1088
1089 if (v->flags & VAR_FROM_ENV) {
1090 /*
1091 * If the original variable came from the environment, we
1092 * have to install it in the global context (we could place
1093 * it in the environment, but then we should provide a way to
1094 * export other variables...)
1095 */
1096 v->flags &= ~VAR_FROM_ENV;
1097 h = Hash_CreateEntry(&ctxt->context, name, NULL);
1098 Hash_SetValue(h, v);
1099 }
1100 }
1101 free(expanded_name);
1102 }
1103
1104 /*-
1105 *-----------------------------------------------------------------------
1106 * Var_Exists --
1107 * See if the given variable exists.
1108 *
1109 * Input:
1110 * name Variable to find
1111 * ctxt Context in which to start search
1112 *
1113 * Results:
1114 * TRUE if it does, FALSE if it doesn't
1115 *
1116 * Side Effects:
1117 * None.
1118 *
1119 *-----------------------------------------------------------------------
1120 */
1121 Boolean
1122 Var_Exists(const char *name, GNode *ctxt)
1123 {
1124 Var *v;
1125 char *cp;
1126
1127 if ((cp = strchr(name, '$')) != NULL) {
1128 cp = Var_Subst(NULL, name, ctxt, VARF_WANTRES);
1129 }
1130 v = VarFind(cp ? cp : name, ctxt, FIND_CMD|FIND_GLOBAL|FIND_ENV);
1131 free(cp);
1132 if (v == NULL) {
1133 return FALSE;
1134 }
1135
1136 (void)VarFreeEnv(v, TRUE);
1137 return TRUE;
1138 }
1139
1140 /*-
1141 *-----------------------------------------------------------------------
1142 * Var_Value --
1143 * Return the value of the named variable in the given context
1144 *
1145 * Input:
1146 * name name to find
1147 * ctxt context in which to search for it
1148 *
1149 * Results:
1150 * The value if the variable exists, NULL if it doesn't
1151 *
1152 * Side Effects:
1153 * None
1154 *-----------------------------------------------------------------------
1155 */
1156 char *
1157 Var_Value(const char *name, GNode *ctxt, char **frp)
1158 {
1159 Var *v;
1160
1161 v = VarFind(name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD);
1162 *frp = NULL;
1163 if (v == NULL)
1164 return NULL;
1165
1166 char *p = (Buf_GetAll(&v->val, NULL));
1167 if (VarFreeEnv(v, FALSE))
1168 *frp = p;
1169 return p;
1170 }
1171
1172 /*-
1173 *-----------------------------------------------------------------------
1174 * VarHead --
1175 * Remove the tail of the given word and place the result in the given
1176 * buffer.
1177 *
1178 * Input:
1179 * word Word to trim
1180 * addSpace True if need to add a space to the buffer
1181 * before sticking in the head
1182 * buf Buffer in which to store it
1183 *
1184 * Results:
1185 * TRUE if characters were added to the buffer (a space needs to be
1186 * added to the buffer before the next word).
1187 *
1188 * Side Effects:
1189 * The trimmed word is added to the buffer.
1190 *
1191 *-----------------------------------------------------------------------
1192 */
1193 static Boolean
1194 VarHead(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
1195 char *word, Boolean addSpace, Buffer *buf,
1196 void *dummy MAKE_ATTR_UNUSED)
1197 {
1198 char *slash;
1199
1200 slash = strrchr(word, '/');
1201 if (slash != NULL) {
1202 if (addSpace && vpstate->varSpace) {
1203 Buf_AddByte(buf, vpstate->varSpace);
1204 }
1205 *slash = '\0';
1206 Buf_AddBytes(buf, strlen(word), word);
1207 *slash = '/';
1208 return TRUE;
1209 } else {
1210 /*
1211 * If no directory part, give . (q.v. the POSIX standard)
1212 */
1213 if (addSpace && vpstate->varSpace)
1214 Buf_AddByte(buf, vpstate->varSpace);
1215 Buf_AddByte(buf, '.');
1216 }
1217 return TRUE;
1218 }
1219
1220 /*-
1221 *-----------------------------------------------------------------------
1222 * VarTail --
1223 * Remove the head of the given word and place the result in the given
1224 * buffer.
1225 *
1226 * Input:
1227 * word Word to trim
1228 * addSpace True if need to add a space to the buffer
1229 * before adding the tail
1230 * buf Buffer in which to store it
1231 *
1232 * Results:
1233 * TRUE if characters were added to the buffer (a space needs to be
1234 * added to the buffer before the next word).
1235 *
1236 * Side Effects:
1237 * The trimmed word is added to the buffer.
1238 *
1239 *-----------------------------------------------------------------------
1240 */
1241 static Boolean
1242 VarTail(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
1243 char *word, Boolean addSpace, Buffer *buf,
1244 void *dummy MAKE_ATTR_UNUSED)
1245 {
1246 char *slash;
1247
1248 if (addSpace && vpstate->varSpace) {
1249 Buf_AddByte(buf, vpstate->varSpace);
1250 }
1251
1252 slash = strrchr(word, '/');
1253 if (slash != NULL) {
1254 *slash++ = '\0';
1255 Buf_AddBytes(buf, strlen(slash), slash);
1256 slash[-1] = '/';
1257 } else {
1258 Buf_AddBytes(buf, strlen(word), word);
1259 }
1260 return TRUE;
1261 }
1262
1263 /*-
1264 *-----------------------------------------------------------------------
1265 * VarSuffix --
1266 * Place the suffix of the given word in the given buffer.
1267 *
1268 * Input:
1269 * word Word to trim
1270 * addSpace TRUE if need to add a space before placing the
1271 * suffix in the buffer
1272 * buf Buffer in which to store it
1273 *
1274 * Results:
1275 * TRUE if characters were added to the buffer (a space needs to be
1276 * added to the buffer before the next word).
1277 *
1278 * Side Effects:
1279 * The suffix from the word is placed in the buffer.
1280 *
1281 *-----------------------------------------------------------------------
1282 */
1283 static Boolean
1284 VarSuffix(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
1285 char *word, Boolean addSpace, Buffer *buf,
1286 void *dummy MAKE_ATTR_UNUSED)
1287 {
1288 char *dot;
1289
1290 dot = strrchr(word, '.');
1291 if (dot != NULL) {
1292 if (addSpace && vpstate->varSpace) {
1293 Buf_AddByte(buf, vpstate->varSpace);
1294 }
1295 *dot++ = '\0';
1296 Buf_AddBytes(buf, strlen(dot), dot);
1297 dot[-1] = '.';
1298 addSpace = TRUE;
1299 }
1300 return addSpace;
1301 }
1302
1303 /*-
1304 *-----------------------------------------------------------------------
1305 * VarRoot --
1306 * Remove the suffix of the given word and place the result in the
1307 * buffer.
1308 *
1309 * Input:
1310 * word Word to trim
1311 * addSpace TRUE if need to add a space to the buffer
1312 * before placing the root in it
1313 * buf Buffer in which to store it
1314 *
1315 * Results:
1316 * TRUE if characters were added to the buffer (a space needs to be
1317 * added to the buffer before the next word).
1318 *
1319 * Side Effects:
1320 * The trimmed word is added to the buffer.
1321 *
1322 *-----------------------------------------------------------------------
1323 */
1324 static Boolean
1325 VarRoot(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
1326 char *word, Boolean addSpace, Buffer *buf,
1327 void *dummy MAKE_ATTR_UNUSED)
1328 {
1329 char *dot;
1330
1331 if (addSpace && vpstate->varSpace) {
1332 Buf_AddByte(buf, vpstate->varSpace);
1333 }
1334
1335 dot = strrchr(word, '.');
1336 if (dot != NULL) {
1337 *dot = '\0';
1338 Buf_AddBytes(buf, strlen(word), word);
1339 *dot = '.';
1340 } else {
1341 Buf_AddBytes(buf, strlen(word), word);
1342 }
1343 return TRUE;
1344 }
1345
1346 /*-
1347 *-----------------------------------------------------------------------
1348 * VarMatch --
1349 * Place the word in the buffer if it matches the given pattern.
1350 * Callback function for VarModify to implement the :M modifier.
1351 *
1352 * Input:
1353 * word Word to examine
1354 * addSpace TRUE if need to add a space to the buffer
1355 * before adding the word, if it matches
1356 * buf Buffer in which to store it
1357 * pattern Pattern the word must match
1358 *
1359 * Results:
1360 * TRUE if a space should be placed in the buffer before the next
1361 * word.
1362 *
1363 * Side Effects:
1364 * The word may be copied to the buffer.
1365 *
1366 *-----------------------------------------------------------------------
1367 */
1368 static Boolean
1369 VarMatch(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
1370 char *word, Boolean addSpace, Buffer *buf,
1371 void *pattern)
1372 {
1373 if (DEBUG(VAR))
1374 fprintf(debug_file, "VarMatch [%s] [%s]\n", word, (char *)pattern);
1375 if (Str_Match(word, (char *)pattern)) {
1376 if (addSpace && vpstate->varSpace) {
1377 Buf_AddByte(buf, vpstate->varSpace);
1378 }
1379 addSpace = TRUE;
1380 Buf_AddBytes(buf, strlen(word), word);
1381 }
1382 return addSpace;
1383 }
1384
1385 #ifdef SYSVVARSUB
1386 /*-
1387 *-----------------------------------------------------------------------
1388 * VarSYSVMatch --
1389 * Place the word in the buffer if it matches the given pattern.
1390 * Callback function for VarModify to implement the System V %
1391 * modifiers.
1392 *
1393 * Input:
1394 * word Word to examine
1395 * addSpace TRUE if need to add a space to the buffer
1396 * before adding the word, if it matches
1397 * buf Buffer in which to store it
1398 * patp Pattern the word must match
1399 *
1400 * Results:
1401 * TRUE if a space should be placed in the buffer before the next
1402 * word.
1403 *
1404 * Side Effects:
1405 * The word may be copied to the buffer.
1406 *
1407 *-----------------------------------------------------------------------
1408 */
1409 static Boolean
1410 VarSYSVMatch(GNode *ctx, Var_Parse_State *vpstate,
1411 char *word, Boolean addSpace, Buffer *buf,
1412 void *patp)
1413 {
1414 size_t len;
1415 char *ptr;
1416 Boolean hasPercent;
1417 VarPattern *pat = (VarPattern *)patp;
1418 char *varexp;
1419
1420 if (addSpace && vpstate->varSpace)
1421 Buf_AddByte(buf, vpstate->varSpace);
1422
1423 addSpace = TRUE;
1424
1425 if ((ptr = Str_SYSVMatch(word, pat->lhs, &len, &hasPercent)) != NULL) {
1426 varexp = Var_Subst(NULL, pat->rhs, ctx, VARF_WANTRES);
1427 Str_SYSVSubst(buf, varexp, ptr, len, hasPercent);
1428 free(varexp);
1429 } else {
1430 Buf_AddBytes(buf, strlen(word), word);
1431 }
1432
1433 return addSpace;
1434 }
1435 #endif
1436
1437
1438 /*-
1439 *-----------------------------------------------------------------------
1440 * VarNoMatch --
1441 * Place the word in the buffer if it doesn't match the given pattern.
1442 * Callback function for VarModify to implement the :N modifier.
1443 *
1444 * Input:
1445 * word Word to examine
1446 * addSpace TRUE if need to add a space to the buffer
1447 * before adding the word, if it matches
1448 * buf Buffer in which to store it
1449 * pattern Pattern the word must match
1450 *
1451 * Results:
1452 * TRUE if a space should be placed in the buffer before the next
1453 * word.
1454 *
1455 * Side Effects:
1456 * The word may be copied to the buffer.
1457 *
1458 *-----------------------------------------------------------------------
1459 */
1460 static Boolean
1461 VarNoMatch(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
1462 char *word, Boolean addSpace, Buffer *buf,
1463 void *pattern)
1464 {
1465 if (!Str_Match(word, (char *)pattern)) {
1466 if (addSpace && vpstate->varSpace) {
1467 Buf_AddByte(buf, vpstate->varSpace);
1468 }
1469 addSpace = TRUE;
1470 Buf_AddBytes(buf, strlen(word), word);
1471 }
1472 return addSpace;
1473 }
1474
1475
1476 /*-
1477 *-----------------------------------------------------------------------
1478 * VarSubstitute --
1479 * Perform a string-substitution on the given word, placing the
1480 * result in the passed buffer.
1481 *
1482 * Input:
1483 * word Word to modify
1484 * addSpace True if space should be added before
1485 * other characters
1486 * buf Buffer for result
1487 * patternp Pattern for substitution
1488 *
1489 * Results:
1490 * TRUE if a space is needed before more characters are added.
1491 *
1492 * Side Effects:
1493 * None.
1494 *
1495 *-----------------------------------------------------------------------
1496 */
1497 static Boolean
1498 VarSubstitute(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
1499 char *word, Boolean addSpace, Buffer *buf,
1500 void *patternp)
1501 {
1502 int wordLen; /* Length of word */
1503 char *cp; /* General pointer */
1504 VarPattern *pattern = (VarPattern *)patternp;
1505
1506 wordLen = strlen(word);
1507 if ((pattern->flags & (VAR_SUB_ONE|VAR_SUB_MATCHED)) !=
1508 (VAR_SUB_ONE|VAR_SUB_MATCHED)) {
1509 /*
1510 * Still substituting -- break it down into simple anchored cases
1511 * and if none of them fits, perform the general substitution case.
1512 */
1513 if ((pattern->flags & VAR_MATCH_START) &&
1514 (strncmp(word, pattern->lhs, pattern->leftLen) == 0)) {
1515 /*
1516 * Anchored at start and beginning of word matches pattern
1517 */
1518 if ((pattern->flags & VAR_MATCH_END) &&
1519 (wordLen == pattern->leftLen)) {
1520 /*
1521 * Also anchored at end and matches to the end (word
1522 * is same length as pattern) add space and rhs only
1523 * if rhs is non-null.
1524 */
1525 if (pattern->rightLen != 0) {
1526 if (addSpace && vpstate->varSpace) {
1527 Buf_AddByte(buf, vpstate->varSpace);
1528 }
1529 addSpace = TRUE;
1530 Buf_AddBytes(buf, pattern->rightLen, pattern->rhs);
1531 }
1532 pattern->flags |= VAR_SUB_MATCHED;
1533 } else if (pattern->flags & VAR_MATCH_END) {
1534 /*
1535 * Doesn't match to end -- copy word wholesale
1536 */
1537 goto nosub;
1538 } else {
1539 /*
1540 * Matches at start but need to copy in trailing characters
1541 */
1542 if ((pattern->rightLen + wordLen - pattern->leftLen) != 0){
1543 if (addSpace && vpstate->varSpace) {
1544 Buf_AddByte(buf, vpstate->varSpace);
1545 }
1546 addSpace = TRUE;
1547 }
1548 Buf_AddBytes(buf, pattern->rightLen, pattern->rhs);
1549 Buf_AddBytes(buf, wordLen - pattern->leftLen,
1550 (word + pattern->leftLen));
1551 pattern->flags |= VAR_SUB_MATCHED;
1552 }
1553 } else if (pattern->flags & VAR_MATCH_START) {
1554 /*
1555 * Had to match at start of word and didn't -- copy whole word.
1556 */
1557 goto nosub;
1558 } else if (pattern->flags & VAR_MATCH_END) {
1559 /*
1560 * Anchored at end, Find only place match could occur (leftLen
1561 * characters from the end of the word) and see if it does. Note
1562 * that because the $ will be left at the end of the lhs, we have
1563 * to use strncmp.
1564 */
1565 cp = word + (wordLen - pattern->leftLen);
1566 if ((cp >= word) &&
1567 (strncmp(cp, pattern->lhs, pattern->leftLen) == 0)) {
1568 /*
1569 * Match found. If we will place characters in the buffer,
1570 * add a space before hand as indicated by addSpace, then
1571 * stuff in the initial, unmatched part of the word followed
1572 * by the right-hand-side.
1573 */
1574 if (((cp - word) + pattern->rightLen) != 0) {
1575 if (addSpace && vpstate->varSpace) {
1576 Buf_AddByte(buf, vpstate->varSpace);
1577 }
1578 addSpace = TRUE;
1579 }
1580 Buf_AddBytes(buf, cp - word, word);
1581 Buf_AddBytes(buf, pattern->rightLen, pattern->rhs);
1582 pattern->flags |= VAR_SUB_MATCHED;
1583 } else {
1584 /*
1585 * Had to match at end and didn't. Copy entire word.
1586 */
1587 goto nosub;
1588 }
1589 } else {
1590 /*
1591 * Pattern is unanchored: search for the pattern in the word using
1592 * String_FindSubstring, copying unmatched portions and the
1593 * right-hand-side for each match found, handling non-global
1594 * substitutions correctly, etc. When the loop is done, any
1595 * remaining part of the word (word and wordLen are adjusted
1596 * accordingly through the loop) is copied straight into the
1597 * buffer.
1598 * addSpace is set FALSE as soon as a space is added to the
1599 * buffer.
1600 */
1601 Boolean done;
1602 int origSize;
1603
1604 done = FALSE;
1605 origSize = Buf_Size(buf);
1606 while (!done) {
1607 cp = Str_FindSubstring(word, pattern->lhs);
1608 if (cp != NULL) {
1609 if (addSpace && (((cp - word) + pattern->rightLen) != 0)){
1610 Buf_AddByte(buf, vpstate->varSpace);
1611 addSpace = FALSE;
1612 }
1613 Buf_AddBytes(buf, cp-word, word);
1614 Buf_AddBytes(buf, pattern->rightLen, pattern->rhs);
1615 wordLen -= (cp - word) + pattern->leftLen;
1616 word = cp + pattern->leftLen;
1617 if (wordLen == 0) {
1618 done = TRUE;
1619 }
1620 if ((pattern->flags & VAR_SUB_GLOBAL) == 0) {
1621 done = TRUE;
1622 }
1623 pattern->flags |= VAR_SUB_MATCHED;
1624 } else {
1625 done = TRUE;
1626 }
1627 }
1628 if (wordLen != 0) {
1629 if (addSpace && vpstate->varSpace) {
1630 Buf_AddByte(buf, vpstate->varSpace);
1631 }
1632 Buf_AddBytes(buf, wordLen, word);
1633 }
1634 /*
1635 * If added characters to the buffer, need to add a space
1636 * before we add any more. If we didn't add any, just return
1637 * the previous value of addSpace.
1638 */
1639 return (Buf_Size(buf) != origSize) || addSpace;
1640 }
1641 return addSpace;
1642 }
1643 nosub:
1644 if (addSpace && vpstate->varSpace) {
1645 Buf_AddByte(buf, vpstate->varSpace);
1646 }
1647 Buf_AddBytes(buf, wordLen, word);
1648 return TRUE;
1649 }
1650
1651 #ifndef NO_REGEX
1652 /*-
1653 *-----------------------------------------------------------------------
1654 * VarREError --
1655 * Print the error caused by a regcomp or regexec call.
1656 *
1657 * Results:
1658 * None.
1659 *
1660 * Side Effects:
1661 * An error gets printed.
1662 *
1663 *-----------------------------------------------------------------------
1664 */
1665 static void
1666 VarREError(int reerr, regex_t *pat, const char *str)
1667 {
1668 char *errbuf;
1669 int errlen;
1670
1671 errlen = regerror(reerr, pat, 0, 0);
1672 errbuf = bmake_malloc(errlen);
1673 regerror(reerr, pat, errbuf, errlen);
1674 Error("%s: %s", str, errbuf);
1675 free(errbuf);
1676 }
1677
1678
1679 /*-
1680 *-----------------------------------------------------------------------
1681 * VarRESubstitute --
1682 * Perform a regex substitution on the given word, placing the
1683 * result in the passed buffer.
1684 *
1685 * Results:
1686 * TRUE if a space is needed before more characters are added.
1687 *
1688 * Side Effects:
1689 * None.
1690 *
1691 *-----------------------------------------------------------------------
1692 */
1693 static Boolean
1694 VarRESubstitute(GNode *ctx MAKE_ATTR_UNUSED,
1695 Var_Parse_State *vpstate MAKE_ATTR_UNUSED,
1696 char *word, Boolean addSpace, Buffer *buf,
1697 void *patternp)
1698 {
1699 VarREPattern *pat;
1700 int xrv;
1701 char *wp;
1702 char *rp;
1703 int added;
1704 int flags = 0;
1705
1706 #define MAYBE_ADD_SPACE() \
1707 if (addSpace && !added) \
1708 Buf_AddByte(buf, ' '); \
1709 added = 1
1710
1711 added = 0;
1712 wp = word;
1713 pat = patternp;
1714
1715 if ((pat->flags & (VAR_SUB_ONE|VAR_SUB_MATCHED)) ==
1716 (VAR_SUB_ONE|VAR_SUB_MATCHED))
1717 xrv = REG_NOMATCH;
1718 else {
1719 tryagain:
1720 xrv = regexec(&pat->re, wp, pat->nsub, pat->matches, flags);
1721 }
1722
1723 switch (xrv) {
1724 case 0:
1725 pat->flags |= VAR_SUB_MATCHED;
1726 if (pat->matches[0].rm_so > 0) {
1727 MAYBE_ADD_SPACE();
1728 Buf_AddBytes(buf, pat->matches[0].rm_so, wp);
1729 }
1730
1731 for (rp = pat->replace; *rp; rp++) {
1732 if ((*rp == '\\') && ((rp[1] == '&') || (rp[1] == '\\'))) {
1733 MAYBE_ADD_SPACE();
1734 Buf_AddByte(buf, rp[1]);
1735 rp++;
1736 }
1737 else if ((*rp == '&') ||
1738 ((*rp == '\\') && isdigit((unsigned char)rp[1]))) {
1739 int n;
1740 const char *subbuf;
1741 int sublen;
1742 char errstr[3];
1743
1744 if (*rp == '&') {
1745 n = 0;
1746 errstr[0] = '&';
1747 errstr[1] = '\0';
1748 } else {
1749 n = rp[1] - '0';
1750 errstr[0] = '\\';
1751 errstr[1] = rp[1];
1752 errstr[2] = '\0';
1753 rp++;
1754 }
1755
1756 if (n > pat->nsub) {
1757 Error("No subexpression %s", &errstr[0]);
1758 subbuf = "";
1759 sublen = 0;
1760 } else if ((pat->matches[n].rm_so == -1) &&
1761 (pat->matches[n].rm_eo == -1)) {
1762 Error("No match for subexpression %s", &errstr[0]);
1763 subbuf = "";
1764 sublen = 0;
1765 } else {
1766 subbuf = wp + pat->matches[n].rm_so;
1767 sublen = pat->matches[n].rm_eo - pat->matches[n].rm_so;
1768 }
1769
1770 if (sublen > 0) {
1771 MAYBE_ADD_SPACE();
1772 Buf_AddBytes(buf, sublen, subbuf);
1773 }
1774 } else {
1775 MAYBE_ADD_SPACE();
1776 Buf_AddByte(buf, *rp);
1777 }
1778 }
1779 wp += pat->matches[0].rm_eo;
1780 if (pat->flags & VAR_SUB_GLOBAL) {
1781 flags |= REG_NOTBOL;
1782 if (pat->matches[0].rm_so == 0 && pat->matches[0].rm_eo == 0) {
1783 MAYBE_ADD_SPACE();
1784 Buf_AddByte(buf, *wp);
1785 wp++;
1786
1787 }
1788 if (*wp)
1789 goto tryagain;
1790 }
1791 if (*wp) {
1792 MAYBE_ADD_SPACE();
1793 Buf_AddBytes(buf, strlen(wp), wp);
1794 }
1795 break;
1796 default:
1797 VarREError(xrv, &pat->re, "Unexpected regex error");
1798 /* fall through */
1799 case REG_NOMATCH:
1800 if (*wp) {
1801 MAYBE_ADD_SPACE();
1802 Buf_AddBytes(buf, strlen(wp), wp);
1803 }
1804 break;
1805 }
1806 return addSpace || added;
1807 }
1808 #endif
1809
1810
1811
1812 /*-
1813 *-----------------------------------------------------------------------
1814 * VarLoopExpand --
1815 * Implements the :@<temp>@<string>@ modifier of ODE make.
1816 * We set the temp variable named in pattern.lhs to word and expand
1817 * pattern.rhs storing the result in the passed buffer.
1818 *
1819 * Input:
1820 * word Word to modify
1821 * addSpace True if space should be added before
1822 * other characters
1823 * buf Buffer for result
1824 * pattern Datafor substitution
1825 *
1826 * Results:
1827 * TRUE if a space is needed before more characters are added.
1828 *
1829 * Side Effects:
1830 * None.
1831 *
1832 *-----------------------------------------------------------------------
1833 */
1834 static Boolean
1835 VarLoopExpand(GNode *ctx MAKE_ATTR_UNUSED,
1836 Var_Parse_State *vpstate MAKE_ATTR_UNUSED,
1837 char *word, Boolean addSpace, Buffer *buf,
1838 void *loopp)
1839 {
1840 VarLoop_t *loop = (VarLoop_t *)loopp;
1841 char *s;
1842 int slen;
1843
1844 if (word && *word) {
1845 Var_Set_Flags(loop->tvar, word, loop->ctxt, VAR_NO_EXPORT);
1846 s = Var_Subst(NULL, loop->str, loop->ctxt, loop->flags);
1847 if (s != NULL && *s != '\0') {
1848 if (addSpace && *s != '\n')
1849 Buf_AddByte(buf, ' ');
1850 Buf_AddBytes(buf, (slen = strlen(s)), s);
1851 addSpace = (slen > 0 && s[slen - 1] != '\n');
1852 }
1853 free(s);
1854 }
1855 return addSpace;
1856 }
1857
1858
1859 /*-
1860 *-----------------------------------------------------------------------
1861 * VarSelectWords --
1862 * Implements the :[start..end] modifier.
1863 * This is a special case of VarModify since we want to be able
1864 * to scan the list backwards if start > end.
1865 *
1866 * Input:
1867 * str String whose words should be trimmed
1868 * seldata words to select
1869 *
1870 * Results:
1871 * A string of all the words selected.
1872 *
1873 * Side Effects:
1874 * None.
1875 *
1876 *-----------------------------------------------------------------------
1877 */
1878 static char *
1879 VarSelectWords(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
1880 const char *str, VarSelectWords_t *seldata)
1881 {
1882 Buffer buf; /* Buffer for the new string */
1883 Boolean addSpace; /* TRUE if need to add a space to the
1884 * buffer before adding the trimmed
1885 * word */
1886 char **av; /* word list */
1887 char *as; /* word list memory */
1888 int ac, i;
1889 int start, end, step;
1890
1891 Buf_Init(&buf, 0);
1892 addSpace = FALSE;
1893
1894 if (vpstate->oneBigWord) {
1895 /* fake what brk_string() would do if there were only one word */
1896 ac = 1;
1897 av = bmake_malloc((ac + 1) * sizeof(char *));
1898 as = bmake_strdup(str);
1899 av[0] = as;
1900 av[1] = NULL;
1901 } else {
1902 av = brk_string(str, &ac, FALSE, &as);
1903 }
1904
1905 /*
1906 * Now sanitize seldata.
1907 * If seldata->start or seldata->end are negative, convert them to
1908 * the positive equivalents (-1 gets converted to argc, -2 gets
1909 * converted to (argc-1), etc.).
1910 */
1911 if (seldata->start < 0)
1912 seldata->start = ac + seldata->start + 1;
1913 if (seldata->end < 0)
1914 seldata->end = ac + seldata->end + 1;
1915
1916 /*
1917 * We avoid scanning more of the list than we need to.
1918 */
1919 if (seldata->start > seldata->end) {
1920 start = MIN(ac, seldata->start) - 1;
1921 end = MAX(0, seldata->end - 1);
1922 step = -1;
1923 } else {
1924 start = MAX(0, seldata->start - 1);
1925 end = MIN(ac, seldata->end);
1926 step = 1;
1927 }
1928
1929 for (i = start;
1930 (step < 0 && i >= end) || (step > 0 && i < end);
1931 i += step) {
1932 if (av[i] && *av[i]) {
1933 if (addSpace && vpstate->varSpace) {
1934 Buf_AddByte(&buf, vpstate->varSpace);
1935 }
1936 Buf_AddBytes(&buf, strlen(av[i]), av[i]);
1937 addSpace = TRUE;
1938 }
1939 }
1940
1941 free(as);
1942 free(av);
1943
1944 return Buf_Destroy(&buf, FALSE);
1945 }
1946
1947
1948 /*-
1949 * VarRealpath --
1950 * Replace each word with the result of realpath()
1951 * if successful.
1952 */
1953 static Boolean
1954 VarRealpath(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate,
1955 char *word, Boolean addSpace, Buffer *buf,
1956 void *patternp MAKE_ATTR_UNUSED)
1957 {
1958 struct stat st;
1959 char rbuf[MAXPATHLEN];
1960 char *rp;
1961
1962 if (addSpace && vpstate->varSpace) {
1963 Buf_AddByte(buf, vpstate->varSpace);
1964 }
1965 addSpace = TRUE;
1966 rp = cached_realpath(word, rbuf);
1967 if (rp && *rp == '/' && stat(rp, &st) == 0)
1968 word = rp;
1969
1970 Buf_AddBytes(buf, strlen(word), word);
1971 return addSpace;
1972 }
1973
1974 /*-
1975 *-----------------------------------------------------------------------
1976 * VarModify --
1977 * Modify each of the words of the passed string using the given
1978 * function. Used to implement all modifiers.
1979 *
1980 * Input:
1981 * str String whose words should be trimmed
1982 * modProc Function to use to modify them
1983 * datum Datum to pass it
1984 *
1985 * Results:
1986 * A string of all the words modified appropriately.
1987 *
1988 * Side Effects:
1989 * None.
1990 *
1991 *-----------------------------------------------------------------------
1992 */
1993 static char *
1994 VarModify(GNode *ctx, Var_Parse_State *vpstate,
1995 const char *str,
1996 Boolean (*modProc)(GNode *, Var_Parse_State *, char *,
1997 Boolean, Buffer *, void *),
1998 void *datum)
1999 {
2000 Buffer buf; /* Buffer for the new string */
2001 Boolean addSpace; /* TRUE if need to add a space to the
2002 * buffer before adding the trimmed
2003 * word */
2004 char **av; /* word list */
2005 char *as; /* word list memory */
2006 int ac, i;
2007
2008 Buf_Init(&buf, 0);
2009 addSpace = FALSE;
2010
2011 if (vpstate->oneBigWord) {
2012 /* fake what brk_string() would do if there were only one word */
2013 ac = 1;
2014 av = bmake_malloc((ac + 1) * sizeof(char *));
2015 as = bmake_strdup(str);
2016 av[0] = as;
2017 av[1] = NULL;
2018 } else {
2019 av = brk_string(str, &ac, FALSE, &as);
2020 }
2021
2022 for (i = 0; i < ac; i++) {
2023 addSpace = (*modProc)(ctx, vpstate, av[i], addSpace, &buf, datum);
2024 }
2025
2026 free(as);
2027 free(av);
2028
2029 return Buf_Destroy(&buf, FALSE);
2030 }
2031
2032
2033 static int
2034 VarWordCompare(const void *a, const void *b)
2035 {
2036 int r = strcmp(*(const char * const *)a, *(const char * const *)b);
2037 return r;
2038 }
2039
2040 static int
2041 VarWordCompareReverse(const void *a, const void *b)
2042 {
2043 int r = strcmp(*(const char * const *)b, *(const char * const *)a);
2044 return r;
2045 }
2046
2047 /*-
2048 *-----------------------------------------------------------------------
2049 * VarOrder --
2050 * Order the words in the string.
2051 *
2052 * Input:
2053 * str String whose words should be sorted.
2054 * otype How to order: s - sort, x - random.
2055 *
2056 * Results:
2057 * A string containing the words ordered.
2058 *
2059 * Side Effects:
2060 * None.
2061 *
2062 *-----------------------------------------------------------------------
2063 */
2064 static char *
2065 VarOrder(const char *str, const char otype)
2066 {
2067 Buffer buf; /* Buffer for the new string */
2068 char **av; /* word list [first word does not count] */
2069 char *as; /* word list memory */
2070 int ac, i;
2071
2072 Buf_Init(&buf, 0);
2073
2074 av = brk_string(str, &ac, FALSE, &as);
2075
2076 if (ac > 0)
2077 switch (otype) {
2078 case 'r': /* reverse sort alphabetically */
2079 qsort(av, ac, sizeof(char *), VarWordCompareReverse);
2080 break;
2081 case 's': /* sort alphabetically */
2082 qsort(av, ac, sizeof(char *), VarWordCompare);
2083 break;
2084 case 'x': /* randomize */
2085 {
2086 int rndidx;
2087 char *t;
2088
2089 /*
2090 * We will use [ac..2] range for mod factors. This will produce
2091 * random numbers in [(ac-1)..0] interval, and minimal
2092 * reasonable value for mod factor is 2 (the mod 1 will produce
2093 * 0 with probability 1).
2094 */
2095 for (i = ac-1; i > 0; i--) {
2096 rndidx = random() % (i + 1);
2097 if (i != rndidx) {
2098 t = av[i];
2099 av[i] = av[rndidx];
2100 av[rndidx] = t;
2101 }
2102 }
2103 }
2104 } /* end of switch */
2105
2106 for (i = 0; i < ac; i++) {
2107 Buf_AddBytes(&buf, strlen(av[i]), av[i]);
2108 if (i != ac - 1)
2109 Buf_AddByte(&buf, ' ');
2110 }
2111
2112 free(as);
2113 free(av);
2114
2115 return Buf_Destroy(&buf, FALSE);
2116 }
2117
2118
2119 /*-
2120 *-----------------------------------------------------------------------
2121 * VarUniq --
2122 * Remove adjacent duplicate words.
2123 *
2124 * Input:
2125 * str String whose words should be sorted
2126 *
2127 * Results:
2128 * A string containing the resulting words.
2129 *
2130 * Side Effects:
2131 * None.
2132 *
2133 *-----------------------------------------------------------------------
2134 */
2135 static char *
2136 VarUniq(const char *str)
2137 {
2138 Buffer buf; /* Buffer for new string */
2139 char **av; /* List of words to affect */
2140 char *as; /* Word list memory */
2141 int ac, i, j;
2142
2143 Buf_Init(&buf, 0);
2144 av = brk_string(str, &ac, FALSE, &as);
2145
2146 if (ac > 1) {
2147 for (j = 0, i = 1; i < ac; i++)
2148 if (strcmp(av[i], av[j]) != 0 && (++j != i))
2149 av[j] = av[i];
2150 ac = j + 1;
2151 }
2152
2153 for (i = 0; i < ac; i++) {
2154 Buf_AddBytes(&buf, strlen(av[i]), av[i]);
2155 if (i != ac - 1)
2156 Buf_AddByte(&buf, ' ');
2157 }
2158
2159 free(as);
2160 free(av);
2161
2162 return Buf_Destroy(&buf, FALSE);
2163 }
2164
2165 /*-
2166 *-----------------------------------------------------------------------
2167 * VarRange --
2168 * Return an integer sequence
2169 *
2170 * Input:
2171 * str String whose words provide default range
2172 * ac range length, if 0 use str words
2173 *
2174 * Side Effects:
2175 * None.
2176 *
2177 *-----------------------------------------------------------------------
2178 */
2179 static char *
2180 VarRange(const char *str, int ac)
2181 {
2182 Buffer buf; /* Buffer for new string */
2183 char tmp[32]; /* each element */
2184 char **av; /* List of words to affect */
2185 char *as; /* Word list memory */
2186 int i, n;
2187
2188 Buf_Init(&buf, 0);
2189 if (ac > 0) {
2190 as = NULL;
2191 av = NULL;
2192 } else {
2193 av = brk_string(str, &ac, FALSE, &as);
2194 }
2195 for (i = 0; i < ac; i++) {
2196 n = snprintf(tmp, sizeof(tmp), "%d", 1 + i);
2197 if (n >= (int)sizeof(tmp))
2198 break;
2199 Buf_AddBytes(&buf, n, tmp);
2200 if (i != ac - 1)
2201 Buf_AddByte(&buf, ' ');
2202 }
2203
2204 free(as);
2205 free(av);
2206
2207 return Buf_Destroy(&buf, FALSE);
2208 }
2209
2210
2211 /*-
2212 *-----------------------------------------------------------------------
2213 * VarGetPattern --
2214 * Pass through the tstr looking for 1) escaped delimiters,
2215 * '$'s and backslashes (place the escaped character in
2216 * uninterpreted) and 2) unescaped $'s that aren't before
2217 * the delimiter (expand the variable substitution unless flags
2218 * has VAR_NOSUBST set).
2219 * Return the expanded string or NULL if the delimiter was missing
2220 * If pattern is specified, handle escaped ampersands, and replace
2221 * unescaped ampersands with the lhs of the pattern.
2222 *
2223 * Results:
2224 * A string of all the words modified appropriately.
2225 * If length is specified, return the string length of the buffer
2226 * If flags is specified and the last character of the pattern is a
2227 * $ set the VAR_MATCH_END bit of flags.
2228 *
2229 * Side Effects:
2230 * None.
2231 *-----------------------------------------------------------------------
2232 */
2233 static char *
2234 VarGetPattern(GNode *ctxt, Var_Parse_State *vpstate MAKE_ATTR_UNUSED,
2235 VarPattern_Flags flags, const char **tstr, int delim,
2236 VarPattern_Flags *vflags, int *length, VarPattern *pattern)
2237 {
2238 const char *cp;
2239 char *rstr;
2240 Buffer buf;
2241 int junk;
2242 int errnum = flags & VARF_UNDEFERR;
2243
2244 Buf_Init(&buf, 0);
2245 if (length == NULL)
2246 length = &junk;
2247
2248 #define IS_A_MATCH(cp, delim) \
2249 ((cp[0] == '\\') && ((cp[1] == delim) || \
2250 (cp[1] == '\\') || (cp[1] == '$') || (pattern && (cp[1] == '&'))))
2251
2252 /*
2253 * Skim through until the matching delimiter is found;
2254 * pick up variable substitutions on the way. Also allow
2255 * backslashes to quote the delimiter, $, and \, but don't
2256 * touch other backslashes.
2257 */
2258 for (cp = *tstr; *cp && (*cp != delim); cp++) {
2259 if (IS_A_MATCH(cp, delim)) {
2260 Buf_AddByte(&buf, cp[1]);
2261 cp++;
2262 } else if (*cp == '$') {
2263 if (cp[1] == delim) {
2264 if (vflags == NULL)
2265 Buf_AddByte(&buf, *cp);
2266 else
2267 /*
2268 * Unescaped $ at end of pattern => anchor
2269 * pattern at end.
2270 */
2271 *vflags |= VAR_MATCH_END;
2272 } else {
2273 if (vflags == NULL || (*vflags & VAR_NOSUBST) == 0) {
2274 char *cp2;
2275 int len;
2276 void *freeIt;
2277
2278 /*
2279 * If unescaped dollar sign not before the
2280 * delimiter, assume it's a variable
2281 * substitution and recurse.
2282 */
2283 cp2 = Var_Parse(cp, ctxt, errnum |
2284 (flags & VARF_WANTRES), &len, &freeIt);
2285 Buf_AddBytes(&buf, strlen(cp2), cp2);
2286 free(freeIt);
2287 cp += len - 1;
2288 } else {
2289 const char *cp2 = &cp[1];
2290
2291 if (*cp2 == PROPEN || *cp2 == BROPEN) {
2292 /*
2293 * Find the end of this variable reference
2294 * and suck it in without further ado.
2295 * It will be interpreted later.
2296 */
2297 int have = *cp2;
2298 int want = (*cp2 == PROPEN) ? PRCLOSE : BRCLOSE;
2299 int depth = 1;
2300
2301 for (++cp2; *cp2 != '\0' && depth > 0; ++cp2) {
2302 if (cp2[-1] != '\\') {
2303 if (*cp2 == have)
2304 ++depth;
2305 if (*cp2 == want)
2306 --depth;
2307 }
2308 }
2309 Buf_AddBytes(&buf, cp2 - cp, cp);
2310 cp = --cp2;
2311 } else
2312 Buf_AddByte(&buf, *cp);
2313 }
2314 }
2315 }
2316 else if (pattern && *cp == '&')
2317 Buf_AddBytes(&buf, pattern->leftLen, pattern->lhs);
2318 else
2319 Buf_AddByte(&buf, *cp);
2320 }
2321
2322 if (*cp != delim) {
2323 *tstr = cp;
2324 *length = 0;
2325 return NULL;
2326 }
2327
2328 *tstr = ++cp;
2329 *length = Buf_Size(&buf);
2330 rstr = Buf_Destroy(&buf, FALSE);
2331 if (DEBUG(VAR))
2332 fprintf(debug_file, "Modifier pattern: \"%s\"\n", rstr);
2333 return rstr;
2334 }
2335
2336 /*-
2337 *-----------------------------------------------------------------------
2338 * VarQuote --
2339 * Quote shell meta-characters and space characters in the string
2340 * if quoteDollar is set, also quote and double any '$' characters.
2341 *
2342 * Results:
2343 * The quoted string
2344 *
2345 * Side Effects:
2346 * None.
2347 *
2348 *-----------------------------------------------------------------------
2349 */
2350 static char *
2351 VarQuote(char *str, Boolean quoteDollar)
2352 {
2353
2354 Buffer buf;
2355 const char *newline;
2356 size_t nlen;
2357
2358 if ((newline = Shell_GetNewline()) == NULL)
2359 newline = "\\\n";
2360 nlen = strlen(newline);
2361
2362 Buf_Init(&buf, 0);
2363
2364 for (; *str != '\0'; str++) {
2365 if (*str == '\n') {
2366 Buf_AddBytes(&buf, nlen, newline);
2367 continue;
2368 }
2369 if (isspace((unsigned char)*str) || ismeta((unsigned char)*str))
2370 Buf_AddByte(&buf, '\\');
2371 Buf_AddByte(&buf, *str);
2372 if (quoteDollar && *str == '$')
2373 Buf_AddBytes(&buf, 2, "\\$");
2374 }
2375
2376 str = Buf_Destroy(&buf, FALSE);
2377 if (DEBUG(VAR))
2378 fprintf(debug_file, "QuoteMeta: [%s]\n", str);
2379 return str;
2380 }
2381
2382 /*-
2383 *-----------------------------------------------------------------------
2384 * VarHash --
2385 * Hash the string using the MurmurHash3 algorithm.
2386 * Output is computed using 32bit Little Endian arithmetic.
2387 *
2388 * Input:
2389 * str String to modify
2390 *
2391 * Results:
2392 * Hash value of str, encoded as 8 hex digits.
2393 *
2394 * Side Effects:
2395 * None.
2396 *
2397 *-----------------------------------------------------------------------
2398 */
2399 static char *
2400 VarHash(char *str)
2401 {
2402 static const char hexdigits[16] = "0123456789abcdef";
2403 Buffer buf;
2404 size_t len, len2;
2405 unsigned char *ustr = (unsigned char *)str;
2406 uint32_t h, k, c1, c2;
2407
2408 h = 0x971e137bU;
2409 c1 = 0x95543787U;
2410 c2 = 0x2ad7eb25U;
2411 len2 = strlen(str);
2412
2413 for (len = len2; len; ) {
2414 k = 0;
2415 switch (len) {
2416 default:
2417 k = (ustr[3] << 24) | (ustr[2] << 16) | (ustr[1] << 8) | ustr[0];
2418 len -= 4;
2419 ustr += 4;
2420 break;
2421 case 3:
2422 k |= (ustr[2] << 16);
2423 /* FALLTHROUGH */
2424 case 2:
2425 k |= (ustr[1] << 8);
2426 /* FALLTHROUGH */
2427 case 1:
2428 k |= ustr[0];
2429 len = 0;
2430 }
2431 c1 = c1 * 5 + 0x7b7d159cU;
2432 c2 = c2 * 5 + 0x6bce6396U;
2433 k *= c1;
2434 k = (k << 11) ^ (k >> 21);
2435 k *= c2;
2436 h = (h << 13) ^ (h >> 19);
2437 h = h * 5 + 0x52dce729U;
2438 h ^= k;
2439 }
2440 h ^= len2;
2441 h *= 0x85ebca6b;
2442 h ^= h >> 13;
2443 h *= 0xc2b2ae35;
2444 h ^= h >> 16;
2445
2446 Buf_Init(&buf, 0);
2447 for (len = 0; len < 8; ++len) {
2448 Buf_AddByte(&buf, hexdigits[h & 15]);
2449 h >>= 4;
2450 }
2451
2452 return Buf_Destroy(&buf, FALSE);
2453 }
2454
2455 static char *
2456 VarStrftime(const char *fmt, int zulu, time_t utc)
2457 {
2458 char buf[BUFSIZ];
2459
2460 if (!utc)
2461 time(&utc);
2462 if (!*fmt)
2463 fmt = "%c";
2464 strftime(buf, sizeof(buf), fmt, zulu ? gmtime(&utc) : localtime(&utc));
2465
2466 buf[sizeof(buf) - 1] = '\0';
2467 return bmake_strdup(buf);
2468 }
2469
2470 typedef struct {
2471 /* const parameters */
2472 int startc;
2473 int endc;
2474 Var * v;
2475 GNode *ctxt;
2476 int flags;
2477 int* lengthPtr;
2478 void ** freePtr;
2479
2480 /* read-write */
2481 char *nstr;
2482 const char *tstr;
2483 const char *start;
2484 const char *cp; /* Secondary pointer into str (place marker
2485 * for tstr) */
2486 char termc; /* Character which terminated scan */
2487 int cnt; /* Used to count brace pairs when variable in
2488 * in parens or braces */
2489 char delim;
2490 int modifier; /* that we are processing */
2491 Var_Parse_State parsestate; /* Flags passed to helper functions */
2492
2493 /* result */
2494 char *newStr; /* New value to return */
2495
2496 } ApplyModifiersState;
2497
2498 /* we now have some modifiers with long names */
2499 #define STRMOD_MATCH(s, want, n) \
2500 (strncmp(s, want, n) == 0 && (s[n] == st->endc || s[n] == ':'))
2501 #define STRMOD_MATCHX(s, want, n) \
2502 (strncmp(s, want, n) == 0 && (s[n] == st->endc || s[n] == ':' || s[n] == '='))
2503 #define CHARMOD_MATCH(c) (c == st->endc || c == ':')
2504
2505 /* :@var (at) ...${var}...@ */
2506 static Boolean
2507 ApplyModifier_At(ApplyModifiersState *st) {
2508 VarLoop_t loop;
2509 VarPattern_Flags vflags = VAR_NOSUBST;
2510
2511 st->cp = ++(st->tstr);
2512 st->delim = '@';
2513 loop.tvar = VarGetPattern(
2514 st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim,
2515 &vflags, &loop.tvarLen, NULL);
2516 if (loop.tvar == NULL)
2517 return FALSE;
2518
2519 loop.str = VarGetPattern(
2520 st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim,
2521 &vflags, &loop.strLen, NULL);
2522 if (loop.str == NULL)
2523 return FALSE;
2524
2525 st->termc = *st->cp;
2526 st->delim = '\0';
2527
2528 loop.flags = st->flags & (VARF_UNDEFERR | VARF_WANTRES);
2529 loop.ctxt = st->ctxt;
2530 st->newStr = VarModify(st->ctxt, &st->parsestate, st->nstr, VarLoopExpand, &loop);
2531 Var_Delete(loop.tvar, st->ctxt);
2532 free(loop.tvar);
2533 free(loop.str);
2534 return TRUE;
2535 }
2536
2537 /* :Ddefined or :Uundefined */
2538 static void
2539 ApplyModifier_Defined(ApplyModifiersState *st)
2540 {
2541 Buffer buf; /* Buffer for patterns */
2542 int nflags;
2543
2544 if (st->flags & VARF_WANTRES) {
2545 int wantres;
2546 if (*st->tstr == 'U')
2547 wantres = ((st->v->flags & VAR_JUNK) != 0);
2548 else
2549 wantres = ((st->v->flags & VAR_JUNK) == 0);
2550 nflags = st->flags & ~VARF_WANTRES;
2551 if (wantres)
2552 nflags |= VARF_WANTRES;
2553 } else
2554 nflags = st->flags;
2555
2556 /*
2557 * Pass through tstr looking for 1) escaped delimiters,
2558 * '$'s and backslashes (place the escaped character in
2559 * uninterpreted) and 2) unescaped $'s that aren't before
2560 * the delimiter (expand the variable substitution).
2561 * The result is left in the Buffer buf.
2562 */
2563 Buf_Init(&buf, 0);
2564 for (st->cp = st->tstr + 1;
2565 *st->cp != st->endc && *st->cp != ':' && *st->cp != '\0';
2566 st->cp++) {
2567 if (*st->cp == '\\' &&
2568 (st->cp[1] == ':' || st->cp[1] == '$' || st->cp[1] == st->endc ||
2569 st->cp[1] == '\\')) {
2570 Buf_AddByte(&buf, st->cp[1]);
2571 st->cp++;
2572 } else if (*st->cp == '$') {
2573 /*
2574 * If unescaped dollar sign, assume it's a
2575 * variable substitution and recurse.
2576 */
2577 char *cp2;
2578 int len;
2579 void *freeIt;
2580
2581 cp2 = Var_Parse(st->cp, st->ctxt, nflags, &len, &freeIt);
2582 Buf_AddBytes(&buf, strlen(cp2), cp2);
2583 free(freeIt);
2584 st->cp += len - 1;
2585 } else {
2586 Buf_AddByte(&buf, *st->cp);
2587 }
2588 }
2589
2590 st->termc = *st->cp;
2591
2592 if ((st->v->flags & VAR_JUNK) != 0)
2593 st->v->flags |= VAR_KEEP;
2594 if (nflags & VARF_WANTRES) {
2595 st->newStr = Buf_Destroy(&buf, FALSE);
2596 } else {
2597 st->newStr = st->nstr;
2598 Buf_Destroy(&buf, TRUE);
2599 }
2600 }
2601
2602 /* :gmtime */
2603 static Boolean
2604 ApplyModifier_Gmtime(ApplyModifiersState *st)
2605 {
2606 time_t utc;
2607 char *ep;
2608
2609 st->cp = st->tstr + 1; /* make sure it is set */
2610 if (!STRMOD_MATCHX(st->tstr, "gmtime", 6))
2611 return FALSE;
2612 if (st->tstr[6] == '=') {
2613 utc = strtoul(&st->tstr[7], &ep, 10);
2614 st->cp = ep;
2615 } else {
2616 utc = 0;
2617 st->cp = st->tstr + 6;
2618 }
2619 st->newStr = VarStrftime(st->nstr, 1, utc);
2620 st->termc = *st->cp;
2621 return TRUE;
2622 }
2623
2624 /* :localtime */
2625 static Boolean
2626 ApplyModifier_Localtime(ApplyModifiersState *st)
2627 {
2628 time_t utc;
2629 char *ep;
2630
2631 st->cp = st->tstr + 1; /* make sure it is set */
2632 if (!STRMOD_MATCHX(st->tstr, "localtime", 9))
2633 return FALSE;
2634
2635 if (st->tstr[9] == '=') {
2636 utc = strtoul(&st->tstr[10], &ep, 10);
2637 st->cp = ep;
2638 } else {
2639 utc = 0;
2640 st->cp = st->tstr + 9;
2641 }
2642 st->newStr = VarStrftime(st->nstr, 0, utc);
2643 st->termc = *st->cp;
2644 return TRUE;
2645 }
2646
2647 /* :hash */
2648 static Boolean
2649 ApplyModifier_Hash(ApplyModifiersState *st)
2650 {
2651 st->cp = st->tstr + 1; /* make sure it is set */
2652 if (!STRMOD_MATCH(st->tstr, "hash", 4))
2653 return FALSE;
2654 st->newStr = VarHash(st->nstr);
2655 st->cp = st->tstr + 4;
2656 st->termc = *st->cp;
2657 return TRUE;
2658 }
2659
2660 /* :P */
2661 static void
2662 ApplyModifier_Path(ApplyModifiersState *st)
2663 {
2664 GNode *gn;
2665
2666 if ((st->v->flags & VAR_JUNK) != 0)
2667 st->v->flags |= VAR_KEEP;
2668 gn = Targ_FindNode(st->v->name, TARG_NOCREATE);
2669 if (gn == NULL || gn->type & OP_NOPATH) {
2670 st->newStr = NULL;
2671 } else if (gn->path) {
2672 st->newStr = bmake_strdup(gn->path);
2673 } else {
2674 st->newStr = Dir_FindFile(st->v->name, Suff_FindPath(gn));
2675 }
2676 if (!st->newStr)
2677 st->newStr = bmake_strdup(st->v->name);
2678 st->cp = ++st->tstr;
2679 st->termc = *st->tstr;
2680 }
2681
2682 /* :!cmd! */
2683 static Boolean
2684 ApplyModifier_Exclam(ApplyModifiersState *st)
2685 {
2686 const char *emsg;
2687 VarPattern pattern;
2688
2689 pattern.flags = 0;
2690
2691 st->delim = '!';
2692 emsg = NULL;
2693 st->cp = ++st->tstr;
2694 pattern.rhs = VarGetPattern(
2695 st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim,
2696 NULL, &pattern.rightLen, NULL);
2697 if (pattern.rhs == NULL)
2698 return FALSE;
2699 if (st->flags & VARF_WANTRES)
2700 st->newStr = Cmd_Exec(pattern.rhs, &emsg);
2701 else
2702 st->newStr = varNoError;
2703 free(UNCONST(pattern.rhs));
2704 if (emsg)
2705 Error(emsg, st->nstr);
2706 st->termc = *st->cp;
2707 st->delim = '\0';
2708 if (st->v->flags & VAR_JUNK)
2709 st->v->flags |= VAR_KEEP;
2710 return TRUE;
2711 }
2712
2713 /* :range */
2714 static Boolean
2715 ApplyModifier_Range(ApplyModifiersState *st)
2716 {
2717 int n;
2718 char *ep;
2719
2720 st->cp = st->tstr + 1; /* make sure it is set */
2721 if (!STRMOD_MATCHX(st->tstr, "range", 5))
2722 return FALSE;
2723
2724 if (st->tstr[5] == '=') {
2725 n = strtoul(&st->tstr[6], &ep, 10);
2726 st->cp = ep;
2727 } else {
2728 n = 0;
2729 st->cp = st->tstr + 5;
2730 }
2731 st->newStr = VarRange(st->nstr, n);
2732 st->termc = *st->cp;
2733 return TRUE;
2734 }
2735
2736 /* :Mpattern or :Npattern */
2737 static void
2738 ApplyModifier_Match(ApplyModifiersState *st)
2739 {
2740 char *pattern;
2741 const char *endpat; /* points just after end of pattern */
2742 char *cp2;
2743 Boolean copy; /* pattern should be, or has been, copied */
2744 Boolean needSubst;
2745 int nest;
2746
2747 copy = FALSE;
2748 needSubst = FALSE;
2749 nest = 1;
2750 /*
2751 * In the loop below, ignore ':' unless we are at
2752 * (or back to) the original brace level.
2753 * XXX This will likely not work right if $() and ${}
2754 * are intermixed.
2755 */
2756 for (st->cp = st->tstr + 1;
2757 *st->cp != '\0' && !(*st->cp == ':' && nest == 1);
2758 st->cp++) {
2759 if (*st->cp == '\\' &&
2760 (st->cp[1] == ':' || st->cp[1] == st->endc ||
2761 st->cp[1] == st->startc)) {
2762 if (!needSubst)
2763 copy = TRUE;
2764 st->cp++;
2765 continue;
2766 }
2767 if (*st->cp == '$')
2768 needSubst = TRUE;
2769 if (*st->cp == '(' || *st->cp == '{')
2770 ++nest;
2771 if (*st->cp == ')' || *st->cp == '}') {
2772 --nest;
2773 if (nest == 0)
2774 break;
2775 }
2776 }
2777 st->termc = *st->cp;
2778 endpat = st->cp;
2779 if (copy) {
2780 /*
2781 * Need to compress the \:'s out of the pattern, so
2782 * allocate enough room to hold the uncompressed
2783 * pattern (note that st->cp started at st->tstr+1, so
2784 * st->cp - st->tstr takes the null byte into account) and
2785 * compress the pattern into the space.
2786 */
2787 pattern = bmake_malloc(st->cp - st->tstr);
2788 for (cp2 = pattern, st->cp = st->tstr + 1;
2789 st->cp < endpat;
2790 st->cp++, cp2++) {
2791 if ((*st->cp == '\\') && (st->cp+1 < endpat) &&
2792 (st->cp[1] == ':' || st->cp[1] == st->endc))
2793 st->cp++;
2794 *cp2 = *st->cp;
2795 }
2796 *cp2 = '\0';
2797 endpat = cp2;
2798 } else {
2799 /*
2800 * Either Var_Subst or VarModify will need a
2801 * nul-terminated string soon, so construct one now.
2802 */
2803 pattern = bmake_strndup(st->tstr+1, endpat - (st->tstr + 1));
2804 }
2805 if (needSubst) {
2806 /* pattern contains embedded '$', so use Var_Subst to expand it. */
2807 cp2 = pattern;
2808 pattern = Var_Subst(NULL, cp2, st->ctxt, st->flags);
2809 free(cp2);
2810 }
2811 if (DEBUG(VAR))
2812 fprintf(debug_file, "Pattern[%s] for [%s] is [%s]\n",
2813 st->v->name, st->nstr, pattern);
2814 if (*st->tstr == 'M') {
2815 st->newStr = VarModify(st->ctxt, &st->parsestate, st->nstr, VarMatch,
2816 pattern);
2817 } else {
2818 st->newStr = VarModify(st->ctxt, &st->parsestate, st->nstr, VarNoMatch,
2819 pattern);
2820 }
2821 free(pattern);
2822 }
2823
2824 /* :S,from,to, */
2825 static Boolean
2826 ApplyModifier_Subst(ApplyModifiersState *st)
2827 {
2828 VarPattern pattern;
2829 Var_Parse_State tmpparsestate;
2830
2831 pattern.flags = 0;
2832 tmpparsestate = st->parsestate;
2833 st->delim = st->tstr[1];
2834 st->tstr += 2;
2835
2836 /*
2837 * If pattern begins with '^', it is anchored to the
2838 * start of the word -- skip over it and flag pattern.
2839 */
2840 if (*st->tstr == '^') {
2841 pattern.flags |= VAR_MATCH_START;
2842 st->tstr += 1;
2843 }
2844
2845 st->cp = st->tstr;
2846 pattern.lhs = VarGetPattern(
2847 st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim,
2848 &pattern.flags, &pattern.leftLen, NULL);
2849 if (pattern.lhs == NULL)
2850 return FALSE;
2851
2852 pattern.rhs = VarGetPattern(
2853 st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim,
2854 NULL, &pattern.rightLen, &pattern);
2855 if (pattern.rhs == NULL)
2856 return FALSE;
2857
2858 /*
2859 * Check for global substitution. If 'g' after the final
2860 * delimiter, substitution is global and is marked that
2861 * way.
2862 */
2863 for (;; st->cp++) {
2864 switch (*st->cp) {
2865 case 'g':
2866 pattern.flags |= VAR_SUB_GLOBAL;
2867 continue;
2868 case '1':
2869 pattern.flags |= VAR_SUB_ONE;
2870 continue;
2871 case 'W':
2872 tmpparsestate.oneBigWord = TRUE;
2873 continue;
2874 }
2875 break;
2876 }
2877
2878 st->termc = *st->cp;
2879 st->newStr = VarModify(
2880 st->ctxt, &tmpparsestate, st->nstr, VarSubstitute, &pattern);
2881
2882 /* Free the two strings. */
2883 free(UNCONST(pattern.lhs));
2884 free(UNCONST(pattern.rhs));
2885 st->delim = '\0';
2886 return TRUE;
2887 }
2888
2889 #ifndef NO_REGEX
2890 /* :C,from,to, */
2891 static Boolean
2892 ApplyModifier_Regex(ApplyModifiersState *st)
2893 {
2894 VarREPattern pattern;
2895 char *re;
2896 int error;
2897 Var_Parse_State tmpparsestate;
2898
2899 pattern.flags = 0;
2900 tmpparsestate = st->parsestate;
2901 st->delim = st->tstr[1];
2902 st->tstr += 2;
2903
2904 st->cp = st->tstr;
2905
2906 re = VarGetPattern(
2907 st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim,
2908 NULL, NULL, NULL);
2909 if (re == NULL)
2910 return FALSE;
2911
2912 pattern.replace = VarGetPattern(
2913 st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim,
2914 NULL, NULL, NULL);
2915 if (pattern.replace == NULL) {
2916 free(re);
2917 return FALSE;
2918 }
2919
2920 for (;; st->cp++) {
2921 switch (*st->cp) {
2922 case 'g':
2923 pattern.flags |= VAR_SUB_GLOBAL;
2924 continue;
2925 case '1':
2926 pattern.flags |= VAR_SUB_ONE;
2927 continue;
2928 case 'W':
2929 tmpparsestate.oneBigWord = TRUE;
2930 continue;
2931 }
2932 break;
2933 }
2934
2935 st->termc = *st->cp;
2936
2937 error = regcomp(&pattern.re, re, REG_EXTENDED);
2938 free(re);
2939 if (error) {
2940 *st->lengthPtr = st->cp - st->start + 1;
2941 VarREError(error, &pattern.re, "RE substitution error");
2942 free(pattern.replace);
2943 return FALSE;
2944 }
2945
2946 pattern.nsub = pattern.re.re_nsub + 1;
2947 if (pattern.nsub < 1)
2948 pattern.nsub = 1;
2949 if (pattern.nsub > 10)
2950 pattern.nsub = 10;
2951 pattern.matches = bmake_malloc(pattern.nsub * sizeof(regmatch_t));
2952 st->newStr = VarModify(
2953 st->ctxt, &tmpparsestate, st->nstr, VarRESubstitute, &pattern);
2954 regfree(&pattern.re);
2955 free(pattern.replace);
2956 free(pattern.matches);
2957 st->delim = '\0';
2958 return TRUE;
2959 }
2960 #endif
2961
2962 /* :tA, :tu, :tl, etc. */
2963 static Boolean
2964 ApplyModifier_To(ApplyModifiersState *st)
2965 {
2966 st->cp = st->tstr + 1; /* make sure it is set */
2967 if (st->tstr[1] != st->endc && st->tstr[1] != ':') {
2968 if (st->tstr[1] == 's') {
2969 /*
2970 * Use the char (if any) at st->tstr[2]
2971 * as the word separator.
2972 */
2973 VarPattern pattern;
2974
2975 if (st->tstr[2] != st->endc &&
2976 (st->tstr[3] == st->endc || st->tstr[3] == ':')) {
2977 /* ":ts<unrecognised><endc>" or
2978 * ":ts<unrecognised>:" */
2979 st->parsestate.varSpace = st->tstr[2];
2980 st->cp = st->tstr + 3;
2981 } else if (st->tstr[2] == st->endc || st->tstr[2] == ':') {
2982 /* ":ts<endc>" or ":ts:" */
2983 st->parsestate.varSpace = 0; /* no separator */
2984 st->cp = st->tstr + 2;
2985 } else if (st->tstr[2] == '\\') {
2986 const char *xp = &st->tstr[3];
2987 int base = 8; /* assume octal */
2988
2989 switch (st->tstr[3]) {
2990 case 'n':
2991 st->parsestate.varSpace = '\n';
2992 st->cp = st->tstr + 4;
2993 break;
2994 case 't':
2995 st->parsestate.varSpace = '\t';
2996 st->cp = st->tstr + 4;
2997 break;
2998 case 'x':
2999 base = 16;
3000 xp++;
3001 goto get_numeric;
3002 case '0':
3003 base = 0;
3004 goto get_numeric;
3005 default:
3006 if (isdigit((unsigned char)st->tstr[3])) {
3007 char *ep;
3008 get_numeric:
3009 st->parsestate.varSpace = strtoul(xp, &ep, base);
3010 if (*ep != ':' && *ep != st->endc)
3011 return FALSE;
3012 st->cp = ep;
3013 } else {
3014 /* ":ts<backslash><unrecognised>". */
3015 return FALSE;
3016 }
3017 break;
3018 }
3019 } else {
3020 /* Found ":ts<unrecognised><unrecognised>". */
3021 return FALSE;
3022 }
3023
3024 st->termc = *st->cp;
3025
3026 /*
3027 * We cannot be certain that VarModify will be used - even if there
3028 * is a subsequent modifier, so do a no-op VarSubstitute now to for
3029 * str to be re-expanded without the spaces.
3030 */
3031 pattern.flags = VAR_SUB_ONE;
3032 pattern.lhs = pattern.rhs = "\032";
3033 pattern.leftLen = pattern.rightLen = 1;
3034
3035 st->newStr = VarModify(
3036 st->ctxt, &st->parsestate, st->nstr, VarSubstitute, &pattern);
3037 } else if (st->tstr[2] == st->endc || st->tstr[2] == ':') {
3038 /* Check for two-character options: ":tu", ":tl" */
3039 if (st->tstr[1] == 'A') { /* absolute path */
3040 st->newStr = VarModify(
3041 st->ctxt, &st->parsestate, st->nstr, VarRealpath, NULL);
3042 st->cp = st->tstr + 2;
3043 st->termc = *st->cp;
3044 } else if (st->tstr[1] == 'u') {
3045 char *dp = bmake_strdup(st->nstr);
3046 for (st->newStr = dp; *dp; dp++)
3047 *dp = toupper((unsigned char)*dp);
3048 st->cp = st->tstr + 2;
3049 st->termc = *st->cp;
3050 } else if (st->tstr[1] == 'l') {
3051 char *dp = bmake_strdup(st->nstr);
3052 for (st->newStr = dp; *dp; dp++)
3053 *dp = tolower((unsigned char)*dp);
3054 st->cp = st->tstr + 2;
3055 st->termc = *st->cp;
3056 } else if (st->tstr[1] == 'W' || st->tstr[1] == 'w') {
3057 st->parsestate.oneBigWord = (st->tstr[1] == 'W');
3058 st->newStr = st->nstr;
3059 st->cp = st->tstr + 2;
3060 st->termc = *st->cp;
3061 } else {
3062 /* Found ":t<unrecognised>:" or ":t<unrecognised><endc>". */
3063 return FALSE;
3064 }
3065 } else {
3066 /* Found ":t<unrecognised><unrecognised>". */
3067 return FALSE;
3068 }
3069 } else {
3070 /* Found ":t<endc>" or ":t:". */
3071 return FALSE;
3072 }
3073 return TRUE;
3074 }
3075
3076 /* :[#], :[1], etc. */
3077 static int
3078 ApplyModifier_Words(ApplyModifiersState *st)
3079 {
3080 /*
3081 * Look for the closing ']', recursively
3082 * expanding any embedded variables.
3083 *
3084 * estr is a pointer to the expanded result,
3085 * which we must free().
3086 */
3087 char *estr;
3088
3089 st->cp = st->tstr+1; /* point to char after '[' */
3090 st->delim = ']'; /* look for closing ']' */
3091 estr = VarGetPattern(
3092 st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim,
3093 NULL, NULL, NULL);
3094 if (estr == NULL)
3095 return 'c'; /* report missing ']' */
3096 /* now st->cp points just after the closing ']' */
3097 st->delim = '\0';
3098 if (st->cp[0] != ':' && st->cp[0] != st->endc) {
3099 /* Found junk after ']' */
3100 free(estr);
3101 return 'b';
3102 }
3103 if (estr[0] == '\0') {
3104 /* Found empty square brackets in ":[]". */
3105 free(estr);
3106 return 'b';
3107 } else if (estr[0] == '#' && estr[1] == '\0') {
3108 /* Found ":[#]" */
3109
3110 /*
3111 * We will need enough space for the decimal
3112 * representation of an int. We calculate the
3113 * space needed for the octal representation,
3114 * and add enough slop to cope with a '-' sign
3115 * (which should never be needed) and a '\0'
3116 * string terminator.
3117 */
3118 int newStrSize = (sizeof(int) * CHAR_BIT + 2) / 3 + 2;
3119
3120 st->newStr = bmake_malloc(newStrSize);
3121 if (st->parsestate.oneBigWord) {
3122 strncpy(st->newStr, "1", newStrSize);
3123 } else {
3124 /* XXX: brk_string() is a rather expensive
3125 * way of counting words. */
3126 char **av;
3127 char *as;
3128 int ac;
3129
3130 av = brk_string(st->nstr, &ac, FALSE, &as);
3131 snprintf(st->newStr, newStrSize, "%d", ac);
3132 free(as);
3133 free(av);
3134 }
3135 st->termc = *st->cp;
3136 free(estr);
3137 return 0;
3138 } else if (estr[0] == '*' && estr[1] == '\0') {
3139 /* Found ":[*]" */
3140 st->parsestate.oneBigWord = TRUE;
3141 st->newStr = st->nstr;
3142 st->termc = *st->cp;
3143 free(estr);
3144 return 0;
3145 } else if (estr[0] == '@' && estr[1] == '\0') {
3146 /* Found ":[@]" */
3147 st->parsestate.oneBigWord = FALSE;
3148 st->newStr = st->nstr;
3149 st->termc = *st->cp;
3150 free(estr);
3151 return 0;
3152 } else {
3153 char *ep;
3154 /*
3155 * We expect estr to contain a single
3156 * integer for :[N], or two integers
3157 * separated by ".." for :[start..end].
3158 */
3159 VarSelectWords_t seldata = { 0, 0 };
3160
3161 seldata.start = strtol(estr, &ep, 0);
3162 if (ep == estr) {
3163 /* Found junk instead of a number */
3164 free(estr);
3165 return 'b';
3166 } else if (ep[0] == '\0') {
3167 /* Found only one integer in :[N] */
3168 seldata.end = seldata.start;
3169 } else if (ep[0] == '.' && ep[1] == '.' && ep[2] != '\0') {
3170 /* Expecting another integer after ".." */
3171 ep += 2;
3172 seldata.end = strtol(ep, &ep, 0);
3173 if (ep[0] != '\0') {
3174 /* Found junk after ".." */
3175 free(estr);
3176 return 'b';
3177 }
3178 } else {
3179 /* Found junk instead of ".." */
3180 free(estr);
3181 return 'b';
3182 }
3183 /*
3184 * Now seldata is properly filled in,
3185 * but we still have to check for 0 as
3186 * a special case.
3187 */
3188 if (seldata.start == 0 && seldata.end == 0) {
3189 /* ":[0]" or perhaps ":[0..0]" */
3190 st->parsestate.oneBigWord = TRUE;
3191 st->newStr = st->nstr;
3192 st->termc = *st->cp;
3193 free(estr);
3194 return 0;
3195 } else if (seldata.start == 0 || seldata.end == 0) {
3196 /* ":[0..N]" or ":[N..0]" */
3197 free(estr);
3198 return 'b';
3199 }
3200 /* Normal case: select the words described by seldata. */
3201 st->newStr = VarSelectWords(
3202 st->ctxt, &st->parsestate, st->nstr, &seldata);
3203
3204 st->termc = *st->cp;
3205 free(estr);
3206 return 0;
3207 }
3208 }
3209
3210 /* :O or :Ox */
3211 static Boolean
3212 ApplyModifier_Order(ApplyModifiersState *st)
3213 {
3214 char otype;
3215
3216 st->cp = st->tstr + 1; /* skip to the rest in any case */
3217 if (st->tstr[1] == st->endc || st->tstr[1] == ':') {
3218 otype = 's';
3219 st->termc = *st->cp;
3220 } else if ((st->tstr[1] == 'r' || st->tstr[1] == 'x') &&
3221 (st->tstr[2] == st->endc || st->tstr[2] == ':')) {
3222 otype = st->tstr[1];
3223 st->cp = st->tstr + 2;
3224 st->termc = *st->cp;
3225 } else {
3226 return FALSE;
3227 }
3228 st->newStr = VarOrder(st->nstr, otype);
3229 return TRUE;
3230 }
3231
3232 /* :? then : else */
3233 static Boolean
3234 ApplyModifier_IfElse(ApplyModifiersState *st)
3235 {
3236 VarPattern pattern;
3237 Boolean value;
3238 int cond_rc;
3239 VarPattern_Flags lhs_flags, rhs_flags;
3240
3241 /* find ':', and then substitute accordingly */
3242 if (st->flags & VARF_WANTRES) {
3243 cond_rc = Cond_EvalExpression(NULL, st->v->name, &value, 0, FALSE);
3244 if (cond_rc == COND_INVALID) {
3245 lhs_flags = rhs_flags = VAR_NOSUBST;
3246 } else if (value) {
3247 lhs_flags = 0;
3248 rhs_flags = VAR_NOSUBST;
3249 } else {
3250 lhs_flags = VAR_NOSUBST;
3251 rhs_flags = 0;
3252 }
3253 } else {
3254 /* we are just consuming and discarding */
3255 cond_rc = value = 0;
3256 lhs_flags = rhs_flags = VAR_NOSUBST;
3257 }
3258 pattern.flags = 0;
3259
3260 st->cp = ++st->tstr;
3261 st->delim = ':';
3262 pattern.lhs = VarGetPattern(
3263 st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim,
3264 &lhs_flags, &pattern.leftLen, NULL);
3265 if (pattern.lhs == NULL)
3266 return FALSE;
3267
3268 /* BROPEN or PROPEN */
3269 st->delim = st->endc;
3270 pattern.rhs = VarGetPattern(
3271 st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim,
3272 &rhs_flags, &pattern.rightLen, NULL);
3273 if (pattern.rhs == NULL)
3274 return FALSE;
3275
3276 st->termc = *--st->cp;
3277 st->delim = '\0';
3278 if (cond_rc == COND_INVALID) {
3279 Error("Bad conditional expression `%s' in %s?%s:%s",
3280 st->v->name, st->v->name, pattern.lhs, pattern.rhs);
3281 return FALSE;
3282 }
3283
3284 if (value) {
3285 st->newStr = UNCONST(pattern.lhs);
3286 free(UNCONST(pattern.rhs));
3287 } else {
3288 st->newStr = UNCONST(pattern.rhs);
3289 free(UNCONST(pattern.lhs));
3290 }
3291 if (st->v->flags & VAR_JUNK)
3292 st->v->flags |= VAR_KEEP;
3293 return TRUE;
3294 }
3295
3296 /* "::=", "::!=", "::+=", or "::?=" */
3297 static int
3298 ApplyModifier_Assign(ApplyModifiersState *st)
3299 {
3300 if (st->tstr[1] == '=' ||
3301 (st->tstr[2] == '=' &&
3302 (st->tstr[1] == '!' || st->tstr[1] == '+' || st->tstr[1] == '?'))) {
3303 GNode *v_ctxt; /* context where v belongs */
3304 const char *emsg;
3305 char *sv_name;
3306 VarPattern pattern;
3307 int how;
3308 VarPattern_Flags vflags;
3309
3310 if (st->v->name[0] == 0)
3311 return 'b';
3312
3313 v_ctxt = st->ctxt;
3314 sv_name = NULL;
3315 ++st->tstr;
3316 if (st->v->flags & VAR_JUNK) {
3317 /*
3318 * We need to bmake_strdup() it incase
3319 * VarGetPattern() recurses.
3320 */
3321 sv_name = st->v->name;
3322 st->v->name = bmake_strdup(st->v->name);
3323 } else if (st->ctxt != VAR_GLOBAL) {
3324 Var *gv = VarFind(st->v->name, st->ctxt, 0);
3325 if (gv == NULL)
3326 v_ctxt = VAR_GLOBAL;
3327 else
3328 VarFreeEnv(gv, TRUE);
3329 }
3330
3331 switch ((how = *st->tstr)) {
3332 case '+':
3333 case '?':
3334 case '!':
3335 st->cp = &st->tstr[2];
3336 break;
3337 default:
3338 st->cp = ++st->tstr;
3339 break;
3340 }
3341 st->delim = st->startc == PROPEN ? PRCLOSE : BRCLOSE;
3342 pattern.flags = 0;
3343
3344 vflags = (st->flags & VARF_WANTRES) ? 0 : VAR_NOSUBST;
3345 pattern.rhs = VarGetPattern(
3346 st->ctxt, &st->parsestate, st->flags, &st->cp, st->delim,
3347 &vflags, &pattern.rightLen, NULL);
3348 if (st->v->flags & VAR_JUNK) {
3349 /* restore original name */
3350 free(st->v->name);
3351 st->v->name = sv_name;
3352 }
3353 if (pattern.rhs == NULL)
3354 return 'c';
3355
3356 st->termc = *--st->cp;
3357 st->delim = '\0';
3358
3359 if (st->flags & VARF_WANTRES) {
3360 switch (how) {
3361 case '+':
3362 Var_Append(st->v->name, pattern.rhs, v_ctxt);
3363 break;
3364 case '!':
3365 st->newStr = Cmd_Exec(pattern.rhs, &emsg);
3366 if (emsg)
3367 Error(emsg, st->nstr);
3368 else
3369 Var_Set(st->v->name, st->newStr, v_ctxt);
3370 free(st->newStr);
3371 break;
3372 case '?':
3373 if ((st->v->flags & VAR_JUNK) == 0)
3374 break;
3375 /* FALLTHROUGH */
3376 default:
3377 Var_Set(st->v->name, pattern.rhs, v_ctxt);
3378 break;
3379 }
3380 }
3381 free(UNCONST(pattern.rhs));
3382 st->newStr = varNoError;
3383 return 0;
3384 }
3385 return 'd'; /* "::<unrecognised>" */
3386 }
3387
3388 /* remember current value */
3389 static Boolean
3390 ApplyModifier_Remember(ApplyModifiersState *st)
3391 {
3392 st->cp = st->tstr + 1; /* make sure it is set */
3393 if (!STRMOD_MATCHX(st->tstr, "_", 1))
3394 return FALSE;
3395
3396 if (st->tstr[1] == '=') {
3397 char *np;
3398 int n;
3399
3400 st->cp++;
3401 n = strcspn(st->cp, ":)}");
3402 np = bmake_strndup(st->cp, n+1);
3403 np[n] = '\0';
3404 st->cp = st->tstr + 2 + n;
3405 Var_Set(np, st->nstr, st->ctxt);
3406 free(np);
3407 } else {
3408 Var_Set("_", st->nstr, st->ctxt);
3409 }
3410 st->newStr = st->nstr;
3411 st->termc = *st->cp;
3412 return TRUE;
3413 }
3414
3415 #ifdef SYSVVARSUB
3416 /* :from=to */
3417 static int
3418 ApplyModifier_SysV(ApplyModifiersState *st)
3419 {
3420 /*
3421 * This can either be a bogus modifier or a System-V
3422 * substitution command.
3423 */
3424 VarPattern pattern;
3425 Boolean eqFound;
3426
3427 pattern.flags = 0;
3428 eqFound = FALSE;
3429 /*
3430 * First we make a pass through the string trying
3431 * to verify it is a SYSV-make-style translation:
3432 * it must be: <string1>=<string2>)
3433 */
3434 st->cp = st->tstr;
3435 st->cnt = 1;
3436 while (*st->cp != '\0' && st->cnt) {
3437 if (*st->cp == '=') {
3438 eqFound = TRUE;
3439 /* continue looking for st->endc */
3440 }
3441 else if (*st->cp == st->endc)
3442 st->cnt--;
3443 else if (*st->cp == st->startc)
3444 st->cnt++;
3445 if (st->cnt)
3446 st->cp++;
3447 }
3448 if (*st->cp == st->endc && eqFound) {
3449
3450 /*
3451 * Now we break this sucker into the lhs and
3452 * rhs. We must null terminate them of course.
3453 */
3454 st->delim='=';
3455 st->cp = st->tstr;
3456 if ((pattern.lhs = VarGetPattern(st->ctxt, &st->parsestate,
3457 st->flags, &st->cp, st->delim, &pattern.flags,
3458 &pattern.leftLen, NULL)) == NULL)
3459 return 'c';
3460 st->delim = st->endc;
3461 if ((pattern.rhs = VarGetPattern(st->ctxt, &st->parsestate,
3462 st->flags, &st->cp, st->delim, NULL, &pattern.rightLen,
3463 &pattern)) == NULL)
3464 return 'c';
3465
3466 /*
3467 * SYSV modifications happen through the whole
3468 * string. Note the pattern is anchored at the end.
3469 */
3470 st->termc = *--st->cp;
3471 st->delim = '\0';
3472 if (pattern.leftLen == 0 && *st->nstr == '\0') {
3473 st->newStr = st->nstr; /* special case */
3474 } else {
3475 st->newStr = VarModify(st->ctxt, &st->parsestate, st->nstr,
3476 VarSYSVMatch,
3477 &pattern);
3478 }
3479 free(UNCONST(pattern.lhs));
3480 free(UNCONST(pattern.rhs));
3481 return '=';
3482 } else
3483 return 0;
3484 }
3485 #endif
3486
3487 /*
3488 * Now we need to apply any modifiers the user wants applied.
3489 * These are:
3490 * :M<pattern> words which match the given <pattern>.
3491 * <pattern> is of the standard file
3492 * wildcarding form.
3493 * :N<pattern> words which do not match the given <pattern>.
3494 * :S<d><pat1><d><pat2><d>[1gW]
3495 * Substitute <pat2> for <pat1> in the value
3496 * :C<d><pat1><d><pat2><d>[1gW]
3497 * Substitute <pat2> for regex <pat1> in the value
3498 * :H Substitute the head of each word
3499 * :T Substitute the tail of each word
3500 * :E Substitute the extension (minus '.') of
3501 * each word
3502 * :R Substitute the root of each word
3503 * (pathname minus the suffix).
3504 * :O ("Order") Alphabeticaly sort words in variable.
3505 * :Ox ("intermiX") Randomize words in variable.
3506 * :u ("uniq") Remove adjacent duplicate words.
3507 * :tu Converts the variable contents to uppercase.
3508 * :tl Converts the variable contents to lowercase.
3509 * :ts[c] Sets varSpace - the char used to
3510 * separate words to 'c'. If 'c' is
3511 * omitted then no separation is used.
3512 * :tW Treat the variable contents as a single
3513 * word, even if it contains spaces.
3514 * (Mnemonic: one big 'W'ord.)
3515 * :tw Treat the variable contents as multiple
3516 * space-separated words.
3517 * (Mnemonic: many small 'w'ords.)
3518 * :[index] Select a single word from the value.
3519 * :[start..end] Select multiple words from the value.
3520 * :[*] or :[0] Select the entire value, as a single
3521 * word. Equivalent to :tW.
3522 * :[@] Select the entire value, as multiple
3523 * words. Undoes the effect of :[*].
3524 * Equivalent to :tw.
3525 * :[#] Returns the number of words in the value.
3526 *
3527 * :?<true-value>:<false-value>
3528 * If the variable evaluates to true, return
3529 * true value, else return the second value.
3530 * :lhs=rhs Like :S, but the rhs goes to the end of
3531 * the invocation.
3532 * :sh Treat the current value as a command
3533 * to be run, new value is its output.
3534 * The following added so we can handle ODE makefiles.
3535 * :@<tmpvar>@<newval>@
3536 * Assign a temporary local variable <tmpvar>
3537 * to the current value of each word in turn
3538 * and replace each word with the result of
3539 * evaluating <newval>
3540 * :D<newval> Use <newval> as value if variable defined
3541 * :U<newval> Use <newval> as value if variable undefined
3542 * :L Use the name of the variable as the value.
3543 * :P Use the path of the node that has the same
3544 * name as the variable as the value. This
3545 * basically includes an implied :L so that
3546 * the common method of refering to the path
3547 * of your dependent 'x' in a rule is to use
3548 * the form '${x:P}'.
3549 * :!<cmd>! Run cmd much the same as :sh run's the
3550 * current value of the variable.
3551 * The ::= modifiers, actually assign a value to the variable.
3552 * Their main purpose is in supporting modifiers of .for loop
3553 * iterators and other obscure uses. They always expand to
3554 * nothing. In a target rule that would otherwise expand to an
3555 * empty line they can be preceded with @: to keep make happy.
3556 * Eg.
3557 *
3558 * foo: .USE
3559 * .for i in ${.TARGET} ${.TARGET:R}.gz
3560 * @: ${t::=$i}
3561 * @echo blah ${t:T}
3562 * .endfor
3563 *
3564 * ::=<str> Assigns <str> as the new value of variable.
3565 * ::?=<str> Assigns <str> as value of variable if
3566 * it was not already set.
3567 * ::+=<str> Appends <str> to variable.
3568 * ::!=<cmd> Assigns output of <cmd> as the new value of
3569 * variable.
3570 */
3571 static char *
3572 ApplyModifiers(char *nstr, const char *tstr,
3573 int const startc, int const endc,
3574 Var * const v, GNode * const ctxt, int const flags,
3575 int * const lengthPtr, void ** const freePtr)
3576 {
3577 ApplyModifiersState st = {
3578 startc, endc, v, ctxt, flags, lengthPtr, freePtr,
3579 nstr, tstr, tstr, tstr,
3580 '\0', 0, '\0', 0, {' ', FALSE}, NULL
3581 };
3582
3583 while (*st.tstr && *st.tstr != st.endc) {
3584
3585 if (*st.tstr == '$') {
3586 /*
3587 * We may have some complex modifiers in a variable.
3588 */
3589 void *freeIt;
3590 char *rval;
3591 int rlen;
3592 int c;
3593
3594 rval = Var_Parse(st.tstr, st.ctxt, st.flags, &rlen, &freeIt);
3595
3596 /*
3597 * If we have not parsed up to st.endc or ':',
3598 * we are not interested.
3599 */
3600 if (rval != NULL && *rval &&
3601 (c = st.tstr[rlen]) != '\0' &&
3602 c != ':' &&
3603 c != st.endc) {
3604 free(freeIt);
3605 goto apply_mods;
3606 }
3607
3608 if (DEBUG(VAR)) {
3609 fprintf(debug_file, "Got '%s' from '%.*s'%.*s\n",
3610 rval, rlen, st.tstr, rlen, st.tstr + rlen);
3611 }
3612
3613 st.tstr += rlen;
3614
3615 if (rval != NULL && *rval) {
3616 int used;
3617
3618 st.nstr = ApplyModifiers(st.nstr, rval, 0, 0, st.v,
3619 st.ctxt, st.flags, &used, st.freePtr);
3620 if (st.nstr == var_Error
3621 || (st.nstr == varNoError && (st.flags & VARF_UNDEFERR) == 0)
3622 || strlen(rval) != (size_t) used) {
3623 free(freeIt);
3624 goto out; /* error already reported */
3625 }
3626 }
3627 free(freeIt);
3628 if (*st.tstr == ':')
3629 st.tstr++;
3630 else if (!*st.tstr && st.endc) {
3631 Error("Unclosed variable specification after complex modifier (expecting '%c') for %s", st.endc, st.v->name);
3632 goto out;
3633 }
3634 continue;
3635 }
3636 apply_mods:
3637 if (DEBUG(VAR)) {
3638 fprintf(debug_file, "Applying[%s] :%c to \"%s\"\n", st.v->name,
3639 *st.tstr, st.nstr);
3640 }
3641 st.newStr = var_Error;
3642 switch ((st.modifier = *st.tstr)) {
3643 case ':':
3644 {
3645 int res = ApplyModifier_Assign(&st);
3646 if (res == 'b')
3647 goto bad_modifier;
3648 if (res == 'c')
3649 goto cleanup;
3650 if (res == 'd')
3651 goto default_case;
3652 break;
3653 }
3654 case '@':
3655 ApplyModifier_At(&st);
3656 break;
3657 case '_':
3658 if (!ApplyModifier_Remember(&st))
3659 goto default_case;
3660 break;
3661 case 'D':
3662 case 'U':
3663 ApplyModifier_Defined(&st);
3664 break;
3665 case 'L':
3666 {
3667 if ((st.v->flags & VAR_JUNK) != 0)
3668 st.v->flags |= VAR_KEEP;
3669 st.newStr = bmake_strdup(st.v->name);
3670 st.cp = ++st.tstr;
3671 st.termc = *st.tstr;
3672 break;
3673 }
3674 case 'P':
3675 ApplyModifier_Path(&st);
3676 break;
3677 case '!':
3678 if (!ApplyModifier_Exclam(&st))
3679 goto cleanup;
3680 break;
3681 case '[':
3682 {
3683 int res = ApplyModifier_Words(&st);
3684 if (res == 'b')
3685 goto bad_modifier;
3686 if (res == 'c')
3687 goto cleanup;
3688 break;
3689 }
3690 case 'g':
3691 if (!ApplyModifier_Gmtime(&st))
3692 goto default_case;
3693 break;
3694 case 'h':
3695 if (!ApplyModifier_Hash(&st))
3696 goto default_case;
3697 break;
3698 case 'l':
3699 if (!ApplyModifier_Localtime(&st))
3700 goto default_case;
3701 break;
3702 case 't':
3703 if (!ApplyModifier_To(&st))
3704 goto bad_modifier;
3705 break;
3706 case 'N':
3707 case 'M':
3708 ApplyModifier_Match(&st);
3709 break;
3710 case 'S':
3711 if (!ApplyModifier_Subst(&st))
3712 goto cleanup;
3713 break;
3714 case '?':
3715 if (!ApplyModifier_IfElse(&st))
3716 goto cleanup;
3717 break;
3718 #ifndef NO_REGEX
3719 case 'C':
3720 if (!ApplyModifier_Regex(&st))
3721 goto cleanup;
3722 break;
3723 #endif
3724 case 'q':
3725 case 'Q':
3726 if (st.tstr[1] == st.endc || st.tstr[1] == ':') {
3727 st.newStr = VarQuote(st.nstr, st.modifier == 'q');
3728 st.cp = st.tstr + 1;
3729 st.termc = *st.cp;
3730 break;
3731 }
3732 goto default_case;
3733 case 'T':
3734 if (st.tstr[1] == st.endc || st.tstr[1] == ':') {
3735 st.newStr = VarModify(st.ctxt, &st.parsestate, st.nstr, VarTail,
3736 NULL);
3737 st.cp = st.tstr + 1;
3738 st.termc = *st.cp;
3739 break;
3740 }
3741 goto default_case;
3742 case 'H':
3743 if (st.tstr[1] == st.endc || st.tstr[1] == ':') {
3744 st.newStr = VarModify(st.ctxt, &st.parsestate, st.nstr, VarHead,
3745 NULL);
3746 st.cp = st.tstr + 1;
3747 st.termc = *st.cp;
3748 break;
3749 }
3750 goto default_case;
3751 case 'E':
3752 if (st.tstr[1] == st.endc || st.tstr[1] == ':') {
3753 st.newStr = VarModify(st.ctxt, &st.parsestate, st.nstr, VarSuffix,
3754 NULL);
3755 st.cp = st.tstr + 1;
3756 st.termc = *st.cp;
3757 break;
3758 }
3759 goto default_case;
3760 case 'R':
3761 if (st.tstr[1] == st.endc || st.tstr[1] == ':') {
3762 st.newStr = VarModify(st.ctxt, &st.parsestate, st.nstr, VarRoot,
3763 NULL);
3764 st.cp = st.tstr + 1;
3765 st.termc = *st.cp;
3766 break;
3767 }
3768 goto default_case;
3769 case 'r':
3770 if (!ApplyModifier_Range(&st))
3771 goto default_case;
3772 break;
3773 case 'O':
3774 if (!ApplyModifier_Order(&st))
3775 goto bad_modifier;
3776 break;
3777 case 'u':
3778 if (st.tstr[1] == st.endc || st.tstr[1] == ':') {
3779 st.newStr = VarUniq(st.nstr);
3780 st.cp = st.tstr + 1;
3781 st.termc = *st.cp;
3782 break;
3783 }
3784 goto default_case;
3785 #ifdef SUNSHCMD
3786 case 's':
3787 if (st.tstr[1] == 'h' && (st.tstr[2] == st.endc || st.tstr[2] == ':')) {
3788 const char *emsg;
3789 if (st.flags & VARF_WANTRES) {
3790 st.newStr = Cmd_Exec(st.nstr, &emsg);
3791 if (emsg)
3792 Error(emsg, st.nstr);
3793 } else
3794 st.newStr = varNoError;
3795 st.cp = st.tstr + 2;
3796 st.termc = *st.cp;
3797 break;
3798 }
3799 goto default_case;
3800 #endif
3801 default:
3802 default_case:
3803 {
3804 #ifdef SYSVVARSUB
3805 int res = ApplyModifier_SysV(&st);
3806 if (res == 'c')
3807 goto cleanup;
3808 if (res != '=')
3809 #endif
3810 {
3811 Error("Unknown modifier '%c'", *st.tstr);
3812 for (st.cp = st.tstr+1;
3813 *st.cp != ':' && *st.cp != st.endc && *st.cp != '\0';
3814 st.cp++)
3815 continue;
3816 st.termc = *st.cp;
3817 st.newStr = var_Error;
3818 }
3819 }
3820 }
3821 if (DEBUG(VAR)) {
3822 fprintf(debug_file, "Result[%s] of :%c is \"%s\"\n",
3823 st.v->name, st.modifier, st.newStr);
3824 }
3825
3826 if (st.newStr != st.nstr) {
3827 if (*st.freePtr) {
3828 free(st.nstr);
3829 *st.freePtr = NULL;
3830 }
3831 st.nstr = st.newStr;
3832 if (st.nstr != var_Error && st.nstr != varNoError) {
3833 *st.freePtr = st.nstr;
3834 }
3835 }
3836 if (st.termc == '\0' && st.endc != '\0') {
3837 Error("Unclosed variable specification (expecting '%c') for \"%s\" (value \"%s\") modifier %c", st.endc, st.v->name, st.nstr, st.modifier);
3838 } else if (st.termc == ':') {
3839 st.cp++;
3840 }
3841 st.tstr = st.cp;
3842 }
3843 out:
3844 *st.lengthPtr = st.tstr - st.start;
3845 return st.nstr;
3846
3847 bad_modifier:
3848 /* "{(" */
3849 Error("Bad modifier `:%.*s' for %s", (int)strcspn(st.tstr, ":)}"), st.tstr,
3850 st.v->name);
3851
3852 cleanup:
3853 *st.lengthPtr = st.cp - st.start;
3854 if (st.delim != '\0')
3855 Error("Unclosed substitution for %s (%c missing)",
3856 st.v->name, st.delim);
3857 free(*st.freePtr);
3858 *st.freePtr = NULL;
3859 return var_Error;
3860 }
3861
3862 /*-
3863 *-----------------------------------------------------------------------
3864 * Var_Parse --
3865 * Given the start of a variable invocation, extract the variable
3866 * name and find its value, then modify it according to the
3867 * specification.
3868 *
3869 * Input:
3870 * str The string to parse
3871 * ctxt The context for the variable
3872 * flags VARF_UNDEFERR if undefineds are an error
3873 * VARF_WANTRES if we actually want the result
3874 * VARF_ASSIGN if we are in a := assignment
3875 * lengthPtr OUT: The length of the specification
3876 * freePtr OUT: Non-NULL if caller should free *freePtr
3877 *
3878 * Results:
3879 * The (possibly-modified) value of the variable or var_Error if the
3880 * specification is invalid. The length of the specification is
3881 * placed in *lengthPtr (for invalid specifications, this is just
3882 * 2...?).
3883 * If *freePtr is non-NULL then it's a pointer that the caller
3884 * should pass to free() to free memory used by the result.
3885 *
3886 * Side Effects:
3887 * None.
3888 *
3889 *-----------------------------------------------------------------------
3890 */
3891 /* coverity[+alloc : arg-*4] */
3892 char *
3893 Var_Parse(const char *str, GNode *ctxt, Varf_Flags flags,
3894 int *lengthPtr, void **freePtr)
3895 {
3896 const char *tstr; /* Pointer into str */
3897 Var *v; /* Variable in invocation */
3898 Boolean haveModifier;/* TRUE if have modifiers for the variable */
3899 char endc; /* Ending character when variable in parens
3900 * or braces */
3901 char startc; /* Starting character when variable in parens
3902 * or braces */
3903 int vlen; /* Length of variable name */
3904 const char *start; /* Points to original start of str */
3905 char *nstr; /* New string, used during expansion */
3906 Boolean dynamic; /* TRUE if the variable is local and we're
3907 * expanding it in a non-local context. This
3908 * is done to support dynamic sources. The
3909 * result is just the invocation, unaltered */
3910 const char *extramodifiers; /* extra modifiers to apply first */
3911 char name[2];
3912
3913 *freePtr = NULL;
3914 extramodifiers = NULL;
3915 dynamic = FALSE;
3916 start = str;
3917
3918 startc = str[1];
3919 if (startc != PROPEN && startc != BROPEN) {
3920 /*
3921 * If it's not bounded by braces of some sort, life is much simpler.
3922 * We just need to check for the first character and return the
3923 * value if it exists.
3924 */
3925
3926 /* Error out some really stupid names */
3927 if (startc == '\0' || strchr(")}:$", startc)) {
3928 *lengthPtr = 1;
3929 return var_Error;
3930 }
3931 name[0] = startc;
3932 name[1] = '\0';
3933
3934 v = VarFind(name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD);
3935 if (v == NULL) {
3936 *lengthPtr = 2;
3937
3938 if ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)) {
3939 /*
3940 * If substituting a local variable in a non-local context,
3941 * assume it's for dynamic source stuff. We have to handle
3942 * this specially and return the longhand for the variable
3943 * with the dollar sign escaped so it makes it back to the
3944 * caller. Only four of the local variables are treated
3945 * specially as they are the only four that will be set
3946 * when dynamic sources are expanded.
3947 */
3948 switch (str[1]) {
3949 case '@':
3950 return UNCONST("$(.TARGET)");
3951 case '%':
3952 return UNCONST("$(.MEMBER)");
3953 case '*':
3954 return UNCONST("$(.PREFIX)");
3955 case '!':
3956 return UNCONST("$(.ARCHIVE)");
3957 }
3958 }
3959 /*
3960 * Error
3961 */
3962 return (flags & VARF_UNDEFERR) ? var_Error : varNoError;
3963 } else {
3964 haveModifier = FALSE;
3965 tstr = &str[1];
3966 endc = str[1];
3967 }
3968 } else {
3969 Buffer buf; /* Holds the variable name */
3970 int depth = 1;
3971
3972 endc = startc == PROPEN ? PRCLOSE : BRCLOSE;
3973 Buf_Init(&buf, 0);
3974
3975 /*
3976 * Skip to the end character or a colon, whichever comes first.
3977 */
3978 for (tstr = str + 2; *tstr != '\0'; tstr++)
3979 {
3980 /*
3981 * Track depth so we can spot parse errors.
3982 */
3983 if (*tstr == startc) {
3984 depth++;
3985 }
3986 if (*tstr == endc) {
3987 if (--depth == 0)
3988 break;
3989 }
3990 if (depth == 1 && *tstr == ':') {
3991 break;
3992 }
3993 /*
3994 * A variable inside a variable, expand.
3995 */
3996 if (*tstr == '$') {
3997 int rlen;
3998 void *freeIt;
3999 char *rval = Var_Parse(tstr, ctxt, flags, &rlen, &freeIt);
4000 if (rval != NULL) {
4001 Buf_AddBytes(&buf, strlen(rval), rval);
4002 }
4003 free(freeIt);
4004 tstr += rlen - 1;
4005 }
4006 else
4007 Buf_AddByte(&buf, *tstr);
4008 }
4009 if (*tstr == ':') {
4010 haveModifier = TRUE;
4011 } else if (*tstr == endc) {
4012 haveModifier = FALSE;
4013 } else {
4014 /*
4015 * If we never did find the end character, return NULL
4016 * right now, setting the length to be the distance to
4017 * the end of the string, since that's what make does.
4018 */
4019 *lengthPtr = tstr - str;
4020 Buf_Destroy(&buf, TRUE);
4021 return var_Error;
4022 }
4023 str = Buf_GetAll(&buf, &vlen);
4024
4025 /*
4026 * At this point, str points into newly allocated memory from
4027 * buf, containing only the name of the variable.
4028 *
4029 * start and tstr point into the const string that was pointed
4030 * to by the original value of the str parameter. start points
4031 * to the '$' at the beginning of the string, while tstr points
4032 * to the char just after the end of the variable name -- this
4033 * will be '\0', ':', PRCLOSE, or BRCLOSE.
4034 */
4035
4036 v = VarFind(str, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD);
4037 /*
4038 * Check also for bogus D and F forms of local variables since we're
4039 * in a local context and the name is the right length.
4040 */
4041 if ((v == NULL) && (ctxt != VAR_CMD) && (ctxt != VAR_GLOBAL) &&
4042 (vlen == 2) && (str[1] == 'F' || str[1] == 'D') &&
4043 strchr("@%?*!<>", str[0]) != NULL) {
4044 /*
4045 * Well, it's local -- go look for it.
4046 */
4047 name[0] = *str;
4048 name[1] = '\0';
4049 v = VarFind(name, ctxt, 0);
4050
4051 if (v != NULL) {
4052 if (str[1] == 'D') {
4053 extramodifiers = "H:";
4054 }
4055 else { /* F */
4056 extramodifiers = "T:";
4057 }
4058 }
4059 }
4060
4061 if (v == NULL) {
4062 if (((vlen == 1) ||
4063 (((vlen == 2) && (str[1] == 'F' || str[1] == 'D')))) &&
4064 ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)))
4065 {
4066 /*
4067 * If substituting a local variable in a non-local context,
4068 * assume it's for dynamic source stuff. We have to handle
4069 * this specially and return the longhand for the variable
4070 * with the dollar sign escaped so it makes it back to the
4071 * caller. Only four of the local variables are treated
4072 * specially as they are the only four that will be set
4073 * when dynamic sources are expanded.
4074 */
4075 switch (*str) {
4076 case '@':
4077 case '%':
4078 case '*':
4079 case '!':
4080 dynamic = TRUE;
4081 break;
4082 }
4083 } else if ((vlen > 2) && (*str == '.') &&
4084 isupper((unsigned char) str[1]) &&
4085 ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)))
4086 {
4087 int len;
4088
4089 len = vlen - 1;
4090 if ((strncmp(str, ".TARGET", len) == 0) ||
4091 (strncmp(str, ".ARCHIVE", len) == 0) ||
4092 (strncmp(str, ".PREFIX", len) == 0) ||
4093 (strncmp(str, ".MEMBER", len) == 0))
4094 {
4095 dynamic = TRUE;
4096 }
4097 }
4098
4099 if (!haveModifier) {
4100 /*
4101 * No modifiers -- have specification length so we can return
4102 * now.
4103 */
4104 *lengthPtr = tstr - start + 1;
4105 if (dynamic) {
4106 char *pstr = bmake_strndup(start, *lengthPtr);
4107 *freePtr = pstr;
4108 Buf_Destroy(&buf, TRUE);
4109 return pstr;
4110 } else {
4111 Buf_Destroy(&buf, TRUE);
4112 return (flags & VARF_UNDEFERR) ? var_Error : varNoError;
4113 }
4114 } else {
4115 /*
4116 * Still need to get to the end of the variable specification,
4117 * so kludge up a Var structure for the modifications
4118 */
4119 v = bmake_malloc(sizeof(Var));
4120 v->name = UNCONST(str);
4121 Buf_Init(&v->val, 1);
4122 v->flags = VAR_JUNK;
4123 Buf_Destroy(&buf, FALSE);
4124 }
4125 } else
4126 Buf_Destroy(&buf, TRUE);
4127 }
4128
4129 if (v->flags & VAR_IN_USE) {
4130 Fatal("Variable %s is recursive.", v->name);
4131 /*NOTREACHED*/
4132 } else {
4133 v->flags |= VAR_IN_USE;
4134 }
4135 /*
4136 * Before doing any modification, we have to make sure the value
4137 * has been fully expanded. If it looks like recursion might be
4138 * necessary (there's a dollar sign somewhere in the variable's value)
4139 * we just call Var_Subst to do any other substitutions that are
4140 * necessary. Note that the value returned by Var_Subst will have
4141 * been dynamically-allocated, so it will need freeing when we
4142 * return.
4143 */
4144 nstr = Buf_GetAll(&v->val, NULL);
4145 if (strchr(nstr, '$') != NULL && (flags & VARF_WANTRES) != 0) {
4146 nstr = Var_Subst(NULL, nstr, ctxt, flags);
4147 *freePtr = nstr;
4148 }
4149
4150 v->flags &= ~VAR_IN_USE;
4151
4152 if ((nstr != NULL) && (haveModifier || extramodifiers != NULL)) {
4153 void *extraFree;
4154 int used;
4155
4156 extraFree = NULL;
4157 if (extramodifiers != NULL) {
4158 nstr = ApplyModifiers(nstr, extramodifiers, '(', ')',
4159 v, ctxt, flags, &used, &extraFree);
4160 }
4161
4162 if (haveModifier) {
4163 /* Skip initial colon. */
4164 tstr++;
4165
4166 nstr = ApplyModifiers(nstr, tstr, startc, endc,
4167 v, ctxt, flags, &used, freePtr);
4168 tstr += used;
4169 free(extraFree);
4170 } else {
4171 *freePtr = extraFree;
4172 }
4173 }
4174 if (*tstr) {
4175 *lengthPtr = tstr - start + 1;
4176 } else {
4177 *lengthPtr = tstr - start;
4178 }
4179
4180 if (v->flags & VAR_FROM_ENV) {
4181 Boolean destroy = FALSE;
4182
4183 if (nstr != Buf_GetAll(&v->val, NULL)) {
4184 destroy = TRUE;
4185 } else {
4186 /*
4187 * Returning the value unmodified, so tell the caller to free
4188 * the thing.
4189 */
4190 *freePtr = nstr;
4191 }
4192 VarFreeEnv(v, destroy);
4193 } else if (v->flags & VAR_JUNK) {
4194 /*
4195 * Perform any free'ing needed and set *freePtr to NULL so the caller
4196 * doesn't try to free a static pointer.
4197 * If VAR_KEEP is also set then we want to keep str as is.
4198 */
4199 if (!(v->flags & VAR_KEEP)) {
4200 if (*freePtr) {
4201 free(nstr);
4202 *freePtr = NULL;
4203 }
4204 if (dynamic) {
4205 nstr = bmake_strndup(start, *lengthPtr);
4206 *freePtr = nstr;
4207 } else {
4208 nstr = (flags & VARF_UNDEFERR) ? var_Error : varNoError;
4209 }
4210 }
4211 if (nstr != Buf_GetAll(&v->val, NULL))
4212 Buf_Destroy(&v->val, TRUE);
4213 free(v->name);
4214 free(v);
4215 }
4216 return nstr;
4217 }
4218
4219 /*-
4220 *-----------------------------------------------------------------------
4221 * Var_Subst --
4222 * Substitute for all variables in the given string in the given context
4223 * If flags & VARF_UNDEFERR, Parse_Error will be called when an undefined
4224 * variable is encountered.
4225 *
4226 * Input:
4227 * var Named variable || NULL for all
4228 * str the string which to substitute
4229 * ctxt the context wherein to find variables
4230 * flags VARF_UNDEFERR if undefineds are an error
4231 * VARF_WANTRES if we actually want the result
4232 * VARF_ASSIGN if we are in a := assignment
4233 *
4234 * Results:
4235 * The resulting string.
4236 *
4237 * Side Effects:
4238 * None. The old string must be freed by the caller
4239 *-----------------------------------------------------------------------
4240 */
4241 char *
4242 Var_Subst(const char *var, const char *str, GNode *ctxt, Varf_Flags flags)
4243 {
4244 Buffer buf; /* Buffer for forming things */
4245 char *val; /* Value to substitute for a variable */
4246 int length; /* Length of the variable invocation */
4247 Boolean trailingBslash; /* variable ends in \ */
4248 void *freeIt = NULL; /* Set if it should be freed */
4249 static Boolean errorReported; /* Set true if an error has already
4250 * been reported to prevent a plethora
4251 * of messages when recursing */
4252
4253 Buf_Init(&buf, 0);
4254 errorReported = FALSE;
4255 trailingBslash = FALSE;
4256
4257 while (*str) {
4258 if (*str == '\n' && trailingBslash)
4259 Buf_AddByte(&buf, ' ');
4260 if (var == NULL && (*str == '$') && (str[1] == '$')) {
4261 /*
4262 * A dollar sign may be escaped either with another dollar sign.
4263 * In such a case, we skip over the escape character and store the
4264 * dollar sign into the buffer directly.
4265 */
4266 if (save_dollars && (flags & VARF_ASSIGN))
4267 Buf_AddByte(&buf, *str);
4268 str++;
4269 Buf_AddByte(&buf, *str);
4270 str++;
4271 } else if (*str != '$') {
4272 /*
4273 * Skip as many characters as possible -- either to the end of
4274 * the string or to the next dollar sign (variable invocation).
4275 */
4276 const char *cp;
4277
4278 for (cp = str++; *str != '$' && *str != '\0'; str++)
4279 continue;
4280 Buf_AddBytes(&buf, str - cp, cp);
4281 } else {
4282 if (var != NULL) {
4283 int expand;
4284 for (;;) {
4285 if (str[1] == '\0') {
4286 /* A trailing $ is kind of a special case */
4287 Buf_AddByte(&buf, str[0]);
4288 str++;
4289 expand = FALSE;
4290 } else if (str[1] != PROPEN && str[1] != BROPEN) {
4291 if (str[1] != *var || strlen(var) > 1) {
4292 Buf_AddBytes(&buf, 2, str);
4293 str += 2;
4294 expand = FALSE;
4295 }
4296 else
4297 expand = TRUE;
4298 break;
4299 }
4300 else {
4301 const char *p;
4302
4303 /*
4304 * Scan up to the end of the variable name.
4305 */
4306 for (p = &str[2]; *p &&
4307 *p != ':' && *p != PRCLOSE && *p != BRCLOSE; p++)
4308 if (*p == '$')
4309 break;
4310 /*
4311 * A variable inside the variable. We cannot expand
4312 * the external variable yet, so we try again with
4313 * the nested one
4314 */
4315 if (*p == '$') {
4316 Buf_AddBytes(&buf, p - str, str);
4317 str = p;
4318 continue;
4319 }
4320
4321 if (strncmp(var, str + 2, p - str - 2) != 0 ||
4322 var[p - str - 2] != '\0') {
4323 /*
4324 * Not the variable we want to expand, scan
4325 * until the next variable
4326 */
4327 for (;*p != '$' && *p != '\0'; p++)
4328 continue;
4329 Buf_AddBytes(&buf, p - str, str);
4330 str = p;
4331 expand = FALSE;
4332 }
4333 else
4334 expand = TRUE;
4335 break;
4336 }
4337 }
4338 if (!expand)
4339 continue;
4340 }
4341
4342 val = Var_Parse(str, ctxt, flags, &length, &freeIt);
4343
4344 /*
4345 * When we come down here, val should either point to the
4346 * value of this variable, suitably modified, or be NULL.
4347 * Length should be the total length of the potential
4348 * variable invocation (from $ to end character...)
4349 */
4350 if (val == var_Error || val == varNoError) {
4351 /*
4352 * If performing old-time variable substitution, skip over
4353 * the variable and continue with the substitution. Otherwise,
4354 * store the dollar sign and advance str so we continue with
4355 * the string...
4356 */
4357 if (oldVars) {
4358 str += length;
4359 } else if ((flags & VARF_UNDEFERR) || val == var_Error) {
4360 /*
4361 * If variable is undefined, complain and skip the
4362 * variable. The complaint will stop us from doing anything
4363 * when the file is parsed.
4364 */
4365 if (!errorReported) {
4366 Parse_Error(PARSE_FATAL, "Undefined variable \"%.*s\"",
4367 length, str);
4368 }
4369 str += length;
4370 errorReported = TRUE;
4371 } else {
4372 Buf_AddByte(&buf, *str);
4373 str += 1;
4374 }
4375 } else {
4376 /*
4377 * We've now got a variable structure to store in. But first,
4378 * advance the string pointer.
4379 */
4380 str += length;
4381
4382 /*
4383 * Copy all the characters from the variable value straight
4384 * into the new string.
4385 */
4386 length = strlen(val);
4387 Buf_AddBytes(&buf, length, val);
4388 trailingBslash = length > 0 && val[length - 1] == '\\';
4389 }
4390 free(freeIt);
4391 freeIt = NULL;
4392 }
4393 }
4394
4395 return Buf_DestroyCompact(&buf);
4396 }
4397
4398 /*-
4399 *-----------------------------------------------------------------------
4400 * Var_Init --
4401 * Initialize the module
4402 *
4403 * Results:
4404 * None
4405 *
4406 * Side Effects:
4407 * The VAR_CMD and VAR_GLOBAL contexts are created
4408 *-----------------------------------------------------------------------
4409 */
4410 void
4411 Var_Init(void)
4412 {
4413 VAR_INTERNAL = Targ_NewGN("Internal");
4414 VAR_GLOBAL = Targ_NewGN("Global");
4415 VAR_CMD = Targ_NewGN("Command");
4416 }
4417
4418
4419 void
4420 Var_End(void)
4421 {
4422 }
4423
4424
4425 /****************** PRINT DEBUGGING INFO *****************/
4426 static void
4427 VarPrintVar(void *vp)
4428 {
4429 Var *v = (Var *)vp;
4430 fprintf(debug_file, "%-16s = %s\n", v->name, Buf_GetAll(&v->val, NULL));
4431 }
4432
4433 /*-
4434 *-----------------------------------------------------------------------
4435 * Var_Dump --
4436 * print all variables in a context
4437 *-----------------------------------------------------------------------
4438 */
4439 void
4440 Var_Dump(GNode *ctxt)
4441 {
4442 Hash_Search search;
4443 Hash_Entry *h;
4444
4445 for (h = Hash_EnumFirst(&ctxt->context, &search);
4446 h != NULL;
4447 h = Hash_EnumNext(&search)) {
4448 VarPrintVar(Hash_GetValue(h));
4449 }
4450 }
4451