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