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