f408a99f629df408423fc48da8a5b40642311cdf
[games.git] / usr.bin / make / var.c
1 /*-
2  * Copyright (c) 2002 Juli Mallett.
3  * Copyright (c) 1988, 1989, 1990, 1993
4  *      The Regents of the University of California.  All rights reserved.
5  * Copyright (c) 1989 by Berkeley Softworks
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to Berkeley by
9  * Adam de Boor.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *      This product includes software developed by the University of
22  *      California, Berkeley and its contributors.
23  * 4. Neither the name of the University nor the names of its contributors
24  *    may be used to endorse or promote products derived from this software
25  *    without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37  * SUCH DAMAGE.
38  *
39  * @(#)var.c    8.3 (Berkeley) 3/19/94
40  * $FreeBSD: src/usr.bin/make/var.c,v 1.83 2005/02/11 10:49:01 harti Exp $
41  * $DragonFly: src/usr.bin/make/var.c,v 1.224 2005/09/24 07:37:38 okumoto Exp $
42  */
43
44 /**
45  * var.c --
46  *      Variable-handling functions
47  *
48  * Interface:
49  *      Var_Set         Set the value of a variable in the given
50  *                      context. The variable is created if it doesn't
51  *                      yet exist. The value and variable name need not
52  *                      be preserved.
53  *
54  *      Var_Append      Append more characters to an existing variable
55  *                      in the given context. The variable needn't
56  *                      exist already -- it will be created if it doesn't.
57  *                      A space is placed between the old value and the
58  *                      new one.
59  *
60  *      Var_Value       Return the value of a variable in a context or
61  *                      NULL if the variable is undefined.
62  *
63  *      Var_Subst       Substitute named variable, or all variables if
64  *                      NULL in a string using
65  *                      the given context as the top-most one. If the
66  *                      third argument is non-zero, Parse_Error is
67  *                      called if any variables are undefined.
68  *
69  *      Var_Parse       Parse a variable expansion from a string and
70  *                      return the result and the number of characters
71  *                      consumed.
72  *
73  *      Var_Delete      Delete a variable in a context.
74  *
75  *      Var_Init        Initialize this module.
76  *
77  * Debugging:
78  *      Var_Dump        Print out all variables defined in the given
79  *                      context.
80  *
81  * XXX: There's a lot of duplication in these functions.
82  */
83
84 #include <assert.h>
85 #include <ctype.h>
86 #include <stdlib.h>
87 #include <string.h>
88 #include <sys/types.h>
89 #include <regex.h>
90
91 #include "buf.h"
92 #include "config.h"
93 #include "globals.h"
94 #include "GNode.h"
95 #include "job.h"
96 #include "lst.h"
97 #include "make.h"
98 #include "parse.h"
99 #include "str.h"
100 #include "targ.h"
101 #include "util.h"
102 #include "var.h"
103
104 /**
105  *
106  */
107 typedef struct VarParser {
108         const char      *const input;   /* pointer to input string */
109         const char      *ptr;           /* current parser pos in input str */
110         GNode           *ctxt;
111         bool            err;
112         bool            execute;
113 } VarParser;
114
115 typedef struct Var {
116         char            *name;  /* the variable's name */
117         struct Buffer   *val;   /* its value */
118         int             flags;  /* miscellaneous status flags */
119
120 #define VAR_IN_USE      1       /* Variable's value currently being used.
121                                  * Used to avoid recursion */
122
123 #define VAR_JUNK        4       /* Variable is a junk variable that
124                                  * should be destroyed when done with
125                                  * it. Used by Var_Parse for undefined,
126                                  * modified variables */
127
128 #define VAR_TO_ENV      8       /* Place variable in environment */
129 } Var;
130
131 typedef struct {
132         struct Buffer   *lhs;   /* String to match */
133         struct Buffer   *rhs;   /* Replacement string (w/ &'s removed) */
134
135         regex_t                 re;
136         int                     nsub;
137         regmatch_t              *matches;
138
139         int     flags;
140 #define VAR_SUB_GLOBAL  0x01    /* Apply substitution globally */
141 #define VAR_SUB_ONE     0x02    /* Apply substitution to one word */
142 #define VAR_SUB_MATCHED 0x04    /* There was a match */
143 #define VAR_MATCH_START 0x08    /* Match at start of word */
144 #define VAR_MATCH_END   0x10    /* Match at end of word */
145 } VarPattern;
146
147 typedef bool VarModifyProc(const char [], bool, struct Buffer *, void *);
148
149 static char *VarParse(VarParser *, bool *);
150
151 /*
152  * This is a harmless return value for Var_Parse that can be used by Var_Subst
153  * to determine if there was an error in parsing -- easier than returning
154  * a flag, as things outside this module don't give a hoot.
155  */
156 char    var_Error[] = "";
157
158 /*
159  * Similar to var_Error, but returned when the 'err' flag for Var_Parse is
160  * set false. Why not just use a constant? Well, gcc likes to condense
161  * identical string instances...
162  */
163 static char     varNoError[] = "";
164
165 /*
166  * Internally, variables are contained in four different contexts.
167  *      1) the environment. They may not be changed. If an environment
168  *         variable is appended-to, the result is placed in the global
169  *         context.
170  *      2) the global context. Variables set in the Makefile are located in
171  *         the global context. It is the penultimate context searched when
172  *         substituting.
173  *      3) the command-line context. All variables set on the command line
174  *         are placed in this context. They are UNALTERABLE once placed here.
175  *      4) the local context. Each target has associated with it a context
176  *         list. On this list are located the structures describing such
177  *         local variables as $(@) and $(*)
178  * The four contexts are searched in the reverse order from which they are
179  * listed.
180  */
181 static GNode    *VAR_ENV;       /* variables from the environment */
182 GNode           *VAR_GLOBAL;    /* variables from the makefile */
183 GNode           *VAR_CMD;       /* variables defined on the command-line */
184
185 bool            oldVars;        /* variable substitution style */
186 bool            checkEnvFirst;  /* -e flag */
187
188 /**
189  * Create a Var object.
190  *
191  * @param name          Name of variable.
192  * @param value         Value of variable.
193  * @param flags         Flags set on variable.
194  */
195 static Var *
196 VarCreate(const char name[], const char value[], int flags)
197 {
198         Var *v;
199
200         v = emalloc(sizeof(Var));
201         v->name = estrdup(name);
202         v->val  = Buf_Init(0);
203         v->flags        = flags;
204
205         if (value != NULL) {
206                 Buf_Append(v->val, value);
207         }
208         return (v);
209 }
210
211 /**
212  * Destroy a Var object.
213  *
214  * @param v     Object to destroy.
215  * @param f     true if internal buffer in Buffer object is to be
216  *              removed.
217  */
218 static void
219 VarDestroy(Var *v, bool f)
220 {
221
222         Buf_Destroy(v->val, f);
223         free(v->name);
224         free(v);
225 }
226
227 /**
228  * Remove the tail of the given word and place the result in the given
229  * buffer.
230  *
231  * Results:
232  *      true if characters were added to the buffer (a space needs to be
233  *      added to the buffer before the next word).
234  *
235  * Side Effects:
236  *      The trimmed word is added to the buffer.
237  */
238 static bool
239 VarHead(const char word[], bool addSpace, Buffer *buf, void *dummy __unused)
240 {
241         char *slash;
242
243         slash = strrchr(word, '/');
244         if (slash != NULL) {
245                 if (addSpace) {
246                         Buf_AddByte(buf, ' ');
247                 }
248                 Buf_AppendRange(buf, word, slash);
249         } else {
250                 /*
251                  * If no directory part, give . (q.v. the POSIX standard)
252                  */
253                 if (addSpace) {
254                         Buf_Append(buf, " .");
255                 } else {
256                         Buf_AddByte(buf, '.');
257                 }
258         }
259         return (true);
260 }
261
262 /**
263  * Remove the head of the given word and place the result in the given
264  * buffer.
265  *
266  * Results:
267  *      true if characters were added to the buffer (a space needs to be
268  *      added to the buffer before the next word).
269  *
270  * Side Effects:
271  *      The trimmed word is added to the buffer.
272  */
273 static bool
274 VarTail(const char word[], bool addSpace, Buffer *buf, void *dummy __unused)
275 {
276         const char *slash;
277
278         if (addSpace) {
279                 Buf_AddByte(buf, ' ');
280         }
281
282         slash = strrchr(word, '/');
283         if (slash != NULL) {
284                 slash++;
285                 Buf_Append(buf, slash);
286         } else {
287                 Buf_Append(buf, word);
288         }
289         return (true);
290 }
291
292 /**
293  * Place the suffix of the given word in the given buffer.
294  *
295  * Results:
296  *      true if characters were added to the buffer (a space needs to be
297  *      added to the buffer before the next word).
298  *
299  * Side Effects:
300  *      The suffix from the word is placed in the buffer.
301  */
302 static bool
303 VarSuffix(const char word[], bool addSpace, Buffer *buf, void *dummy __unused)
304 {
305         const char *dot;
306
307         dot = strrchr(word, '.');
308         if (dot != NULL) {
309                 if (addSpace) {
310                         Buf_AddByte(buf, ' ');
311                 }
312                 dot++;
313                 Buf_Append(buf, dot);
314                 addSpace = true;
315         }
316         return (addSpace);
317 }
318
319 /**
320  * Remove the suffix of the given word and place the result in the
321  * buffer.
322  *
323  * Results:
324  *      true if characters were added to the buffer (a space needs to be
325  *      added to the buffer before the next word).
326  *
327  * Side Effects:
328  *      The trimmed word is added to the buffer.
329  */
330 static bool
331 VarRoot(const char word[], bool addSpace, Buffer *buf, void *dummy __unused)
332 {
333         char *dot;
334
335         if (addSpace) {
336                 Buf_AddByte(buf, ' ');
337         }
338
339         dot = strrchr(word, '.');
340         if (dot != NULL) {
341                 Buf_AppendRange(buf, word, dot);
342         } else {
343                 Buf_Append(buf, word);
344         }
345         return (true);
346 }
347
348 /**
349  * Place the word in the buffer if it matches the given pattern.
350  * Callback function for VarModify to implement the :M modifier.
351  * A space will be added if requested.  A pattern is supplied
352  * which the word must match.
353  *
354  * Results:
355  *      true if a space should be placed in the buffer before the next
356  *      word.
357  *
358  * Side Effects:
359  *      The word may be copied to the buffer.
360  */
361 static bool
362 VarMatch(const char word[], bool addSpace, Buffer *buf, void *pattern)
363 {
364
365         if (Str_Match(word, pattern)) {
366                 if (addSpace) {
367                         Buf_AddByte(buf, ' ');
368                 }
369                 addSpace = true;
370                 Buf_Append(buf, word);
371         }
372         return (addSpace);
373 }
374
375 /**
376  * Place the word in the buffer if it matches the given pattern.
377  * Callback function for VarModify to implement the System V %
378  * modifiers.  A space is added if requested.
379  *
380  * Results:
381  *      true if a space should be placed in the buffer before the next
382  *      word.
383  *
384  * Side Effects:
385  *      The word may be copied to the buffer.
386  */
387 static bool
388 VarSYSVMatch(const char word[], bool addSpace, Buffer *buf, void *patp)
389 {
390         int             len;
391         const char      *ptr;
392         VarPattern      *pat = (VarPattern *)patp;
393
394         if (addSpace)
395                 Buf_AddByte(buf, ' ');
396
397         addSpace = true;
398
399         if ((ptr = Str_SYSVMatch(word, Buf_Data(pat->lhs), &len)) != NULL)
400                 Str_SYSVSubst(buf, Buf_Data(pat->rhs), ptr, len);
401         else
402                 Buf_Append(buf, word);
403
404         return (addSpace);
405 }
406
407 /**
408  * Place the word in the buffer if it doesn't match the given pattern.
409  * Callback function for VarModify to implement the :N modifier.  A
410  * space is added if requested.
411  *
412  * Results:
413  *      true if a space should be placed in the buffer before the next
414  *      word.
415  *
416  * Side Effects:
417  *      The word may be copied to the buffer.
418  */
419 static bool
420 VarNoMatch(const char word[], bool addSpace, Buffer *buf, void *pattern)
421 {
422
423         if (!Str_Match(word, pattern)) {
424                 if (addSpace) {
425                         Buf_AddByte(buf, ' ');
426                 }
427                 addSpace = true;
428                 Buf_Append(buf, word);
429         }
430         return (addSpace);
431 }
432
433 /**
434  * Perform a string-substitution on the given word, placing the
435  * result in the passed buffer.  A space is added if requested.
436  *
437  * Results:
438  *      true if a space is needed before more characters are added.
439  */
440 static bool
441 VarSubstitute(const char word[], bool addSpace, Buffer *buf, void *patternp)
442 {
443         size_t          wordLen;        /* Length of word */
444         const char      *cp;            /* General pointer */
445         VarPattern      *pattern = patternp;
446
447         wordLen = strlen(word);
448         if (1) { /* substitute in each word of the variable */
449                 /*
450                  * Break substitution down into simple anchored cases
451                  * and if none of them fits, perform the general substitution
452                  * case.
453                  */
454                 if ((pattern->flags & VAR_MATCH_START) &&
455                    (strncmp(word, Buf_Data(pattern->lhs),
456                     Buf_Size(pattern->lhs)) == 0)) {
457                         /*
458                          * Anchored at start and beginning of word matches
459                          * pattern.
460                          */
461                         if ((pattern->flags & VAR_MATCH_END) &&
462                             (wordLen == Buf_Size(pattern->lhs))) {
463                                 /*
464                                  * Also anchored at end and matches to the end
465                                  * (word is same length as pattern) add space
466                                  * and rhs only if rhs is non-null.
467                                  */
468                                 if (Buf_Size(pattern->rhs) != 0) {
469                                         if (addSpace) {
470                                                 Buf_AddByte(buf, ' ');
471                                         }
472                                         addSpace = true;
473                                         Buf_AppendBuf(buf, pattern->rhs);
474                                 }
475
476                         } else if (pattern->flags & VAR_MATCH_END) {
477                                 /*
478                                  * Doesn't match to end -- copy word wholesale
479                                  */
480                                 goto nosub;
481
482                         } else {
483                                 /*
484                                  * Matches at start but need to copy in
485                                  * trailing characters.
486                                  */
487                                 if ((Buf_Size(pattern->rhs) + wordLen -
488                                     Buf_Size(pattern->lhs)) != 0) {
489                                         if (addSpace) {
490                                                 Buf_AddByte(buf, ' ');
491                                         }
492                                         addSpace = true;
493                                 }
494                                 Buf_AppendBuf(buf, pattern->rhs);
495                                 Buf_AddBytes(buf, wordLen -
496                                     Buf_Size(pattern->lhs),
497                                     (word + Buf_Size(pattern->lhs)));
498                         }
499
500                 } else if (pattern->flags & VAR_MATCH_START) {
501                         /*
502                          * Had to match at start of word and didn't -- copy
503                          * whole word.
504                          */
505                         goto nosub;
506
507                 } else if (pattern->flags & VAR_MATCH_END) {
508                         /*
509                          * Anchored at end, Find only place match could occur
510                          * (leftLen characters from the end of the word) and
511                          * see if it does. Note that because the $ will be
512                          * left at the end of the lhs, we have to use strncmp.
513                          */
514                         cp = word + (wordLen - Buf_Size(pattern->lhs));
515                         if ((cp >= word) && (strncmp(cp, Buf_Data(pattern->lhs),
516                             Buf_Size(pattern->lhs)) == 0)) {
517                                 /*
518                                  * Match found. If we will place characters in
519                                  * the buffer, add a space before hand as
520                                  * indicated by addSpace, then stuff in the
521                                  * initial, unmatched part of the word followed
522                                  * by the right-hand-side.
523                                  */
524                                 if ((cp - word) + Buf_Size(pattern->rhs) != 0) {
525                                         if (addSpace) {
526                                                 Buf_AddByte(buf, ' ');
527                                         }
528                                         addSpace = true;
529                                 }
530                                 Buf_AppendRange(buf, word, cp);
531                                 Buf_AppendBuf(buf, pattern->rhs);
532
533                         } else {
534                                 /*
535                                  * Had to match at end and didn't. Copy entire
536                                  * word.
537                                  */
538                                 goto nosub;
539                         }
540                 } else {
541                         /*
542                          * Pattern is unanchored: search for the pattern in the
543                          * word using strstr(3), copying unmatched portions and
544                          * the right-hand-side for each match found, handling
545                          * non-global substitutions correctly, etc. When the
546                          * loop is done, any remaining part of the word (word
547                          * and wordLen are adjusted accordingly through the
548                          * loop) is copied straight into the buffer.
549                          * addSpace is set false as soon as a space is added
550                          * to the buffer.
551                          */
552                         bool done;
553                         size_t origSize;
554
555                         done = false;
556                         origSize = Buf_Size(buf);
557                         while (!done) {
558                                 cp = strstr(word, Buf_Data(pattern->lhs));
559                                 if (cp != NULL) {
560                                         if (addSpace && (((cp - word) +
561                                             Buf_Size(pattern->rhs)) != 0)) {
562                                                 Buf_AddByte(buf, ' ');
563                                                 addSpace = false;
564                                         }
565                                         Buf_AppendRange(buf, word, cp);
566                                         Buf_AppendBuf(buf, pattern->rhs);
567                                         wordLen -= (cp - word) +
568                                             Buf_Size(pattern->lhs);
569                                         word = cp + Buf_Size(pattern->lhs);
570                                         if (wordLen == 0 || (pattern->flags &
571                                             VAR_SUB_GLOBAL) == 0) {
572                                                 done = true;
573                                         }
574                                 } else {
575                                         done = true;
576                                 }
577                         }
578                         if (wordLen != 0) {
579                                 if (addSpace) {
580                                         Buf_AddByte(buf, ' ');
581                                 }
582                                 Buf_AddBytes(buf, wordLen, word);
583                         }
584
585                         /*
586                          * If added characters to the buffer, need to add a
587                          * space before we add any more. If we didn't add any,
588                          * just return the previous value of addSpace.
589                          */
590                         return ((Buf_Size(buf) != origSize) || addSpace);
591                 }
592                 /*
593                  * Common code for anchored substitutions:
594                  * addSpace was set true if characters were added to the buffer.
595                  */
596                 return (addSpace);
597         }
598   nosub:
599         if (addSpace) {
600                 Buf_AddByte(buf, ' ');
601         }
602         Buf_AddBytes(buf, wordLen, word);
603         return (true);
604 }
605
606 /**
607  * Print the error caused by a regcomp or regexec call.
608  *
609  * Side Effects:
610  *      An error gets printed.
611  */
612 static void
613 VarREError(int err, regex_t *pat, const char str[])
614 {
615         char   *errbuf;
616         int     errlen;
617
618         errlen = regerror(err, pat, 0, 0);
619         errbuf = emalloc(errlen);
620         regerror(err, pat, errbuf, errlen);
621         Error("%s: %s", str, errbuf);
622         free(errbuf);
623 }
624
625
626 /**
627  * Perform a regex substitution on the given word, placing the
628  * result in the passed buffer.  A space is added if requested.
629  *
630  * Results:
631  *      true if a space is needed before more characters are added.
632  */
633 static bool
634 VarRESubstitute(const char word[], bool addSpace, Buffer *buf, void *patternp)
635 {
636         VarPattern      *pat;
637         int             xrv;
638         const char      *wp;
639         char            *rp;
640         int             added;
641         int             flags = 0;
642
643 #define MAYBE_ADD_SPACE()                       \
644         if (addSpace && !added)                 \
645                 Buf_AddByte(buf, ' ');  \
646         added = 1
647
648         added = 0;
649         wp = word;
650         pat = patternp;
651
652         if ((pat->flags & (VAR_SUB_ONE | VAR_SUB_MATCHED)) ==
653             (VAR_SUB_ONE | VAR_SUB_MATCHED)) {
654                 xrv = REG_NOMATCH;
655         } else {
656   tryagain:
657                 xrv = regexec(&pat->re, wp, pat->nsub, pat->matches, flags);
658         }
659
660         switch (xrv) {
661           case 0:
662                 pat->flags |= VAR_SUB_MATCHED;
663                 if (pat->matches[0].rm_so > 0) {
664                         MAYBE_ADD_SPACE();
665                         Buf_AddBytes(buf, pat->matches[0].rm_so, wp);
666                 }
667
668                 for (rp = Buf_Data(pat->rhs); *rp; rp++) {
669                         if ((*rp == '\\') && ((rp[1] == '&') || (rp[1] == '\\'))) {
670                                 MAYBE_ADD_SPACE();
671                                 Buf_AddByte(buf, rp[1]);
672                                 rp++;
673
674                         } else if ((*rp == '&') ||
675                             ((*rp == '\\') && isdigit((unsigned char)rp[1]))) {
676                                 int     n;
677                                 const char *subbuf;
678                                 int     sublen;
679                                 char    errstr[3];
680
681                                 if (*rp == '&') {
682                                         n = 0;
683                                         errstr[0] = '&';
684                                         errstr[1] = '\0';
685                                 } else {
686                                         n = rp[1] - '0';
687                                         errstr[0] = '\\';
688                                         errstr[1] = rp[1];
689                                         errstr[2] = '\0';
690                                         rp++;
691                                 }
692
693                                 if (n > pat->nsub) {
694                                         Error("No subexpression %s",
695                                             &errstr[0]);
696                                         subbuf = "";
697                                         sublen = 0;
698
699                                 } else if ((pat->matches[n].rm_so == -1) &&
700                                     (pat->matches[n].rm_eo == -1)) {
701                                         Error("No match for subexpression %s",
702                                             &errstr[0]);
703                                         subbuf = "";
704                                         sublen = 0;
705
706                                 } else {
707                                         subbuf = wp + pat->matches[n].rm_so;
708                                         sublen = pat->matches[n].rm_eo -
709                                             pat->matches[n].rm_so;
710                                 }
711
712                                 if (sublen > 0) {
713                                         MAYBE_ADD_SPACE();
714                                         Buf_AddBytes(buf, sublen, subbuf);
715                                 }
716                         } else {
717                                 MAYBE_ADD_SPACE();
718                                 Buf_AddByte(buf, *rp);
719                         }
720                 }
721                 wp += pat->matches[0].rm_eo;
722                 if (pat->flags & VAR_SUB_GLOBAL) {
723                         flags |= REG_NOTBOL;
724                         if (pat->matches[0].rm_so == 0 &&
725                             pat->matches[0].rm_eo == 0) {
726                                 MAYBE_ADD_SPACE();
727                                 Buf_AddByte(buf, *wp);
728                                 wp++;
729                         }
730                         if (*wp)
731                                 goto tryagain;
732                 }
733                 if (*wp) {
734                         MAYBE_ADD_SPACE();
735                         Buf_Append(buf, wp);
736                 }
737                 break;
738
739           default:
740                 VarREError(xrv, &pat->re, "Unexpected regex error");
741                 /* fall through */
742
743           case REG_NOMATCH:
744                 if (*wp) {
745                         MAYBE_ADD_SPACE();
746                         Buf_Append(buf, wp);
747                 }
748                 break;
749         }
750         return (addSpace || added);
751 }
752
753 /**
754  * Find a variable in a variable list.
755  */
756 static Var *
757 VarLookup(Lst *vlist, const char name[])
758 {
759         LstNode *ln;
760
761         LST_FOREACH(ln, vlist)
762                 if (strcmp(((const Var *)Lst_Datum(ln))->name, name) == 0)
763                         return (Lst_Datum(ln));
764         return (NULL);
765 }
766
767 /**
768  * Expand a variable name's embedded variables in the given context.
769  *
770  * Results:
771  *      The contents of name, possibly expanded.
772  */
773 static char *
774 VarPossiblyExpand(const char name[], GNode *ctxt)
775 {
776         Buffer  *buf;
777
778         if (strchr(name, '$') != NULL) {
779                 buf = Var_Subst(name, ctxt, 0);
780                 return (Buf_Peel(buf));
781         } else {
782                 return estrdup(name);
783         }
784 }
785
786 /**
787  * If the variable name begins with a '.', it could very well be
788  * one of the local ones.  We check the name against all the local
789  * variables and substitute the short version in for 'name' if it
790  * matches one of them.
791  */
792 static const char *
793 VarLocal(const char name[])
794 {
795         if (name[0] == '.') {
796                 switch (name[1]) {
797                 case 'A':
798                         if (!strcmp(name, ".ALLSRC"))
799                                 return (ALLSRC);
800                         if (!strcmp(name, ".ARCHIVE"))
801                                 return (ARCHIVE);
802                         break;
803                 case 'I':
804                         if (!strcmp(name, ".IMPSRC"))
805                                 return (IMPSRC);
806                         break;
807                 case 'M':
808                         if (!strcmp(name, ".MEMBER"))
809                                 return (MEMBER);
810                         break;
811                 case 'O':
812                         if (!strcmp(name, ".OODATE"))
813                                 return (OODATE);
814                         break;
815                 case 'P':
816                         if (!strcmp(name, ".PREFIX"))
817                                 return (PREFIX);
818                         break;
819                 case 'T':
820                         if (!strcmp(name, ".TARGET"))
821                                 return (TARGET);
822                         break;
823                 default:
824                         break;
825                 }
826         }
827         return (name);
828 }
829
830 /**
831  * Find the given variable in the given context and the environment.
832  *
833  * Results:
834  *      A pointer to the structure describing the desired variable or
835  *      NULL if the variable does not exist.
836  */
837 static Var *
838 VarFindEnv(const char name[], GNode *ctxt)
839 {
840         Var     *var;
841
842         name = VarLocal(name);
843
844         if ((var = VarLookup(&ctxt->context, name)) != NULL)
845                 return (var);
846
847         if ((var = VarLookup(&VAR_ENV->context, name)) != NULL)
848                 return (var);
849
850         return (NULL);
851 }
852
853 /**
854  * Look for the variable in the given context.
855  */
856 static Var *
857 VarFindOnly(const char name[], GNode *ctxt)
858 {
859
860         return (VarLookup(&ctxt->context, VarLocal(name)));
861 }
862
863 /**
864  * Look for the variable in all contexts.
865  */
866 static Var *
867 VarFindAny(const char name[], GNode *ctxt)
868 {
869         bool    localCheckEnvFirst;
870         LstNode *ln;
871         Var     *var;
872
873         name = VarLocal(name);
874
875         /*
876          * Note whether this is one of the specific variables we were told
877          * through the -E flag to use environment-variable-override for.
878          */
879         localCheckEnvFirst = false;
880         LST_FOREACH(ln, &envFirstVars) {
881                 if (strcmp(Lst_Datum(ln), name) == 0) {
882                         localCheckEnvFirst = true;
883                         break;
884                 }
885         }
886
887         /*
888          * First look for the variable in the given context. If it's not there,
889          * look for it in VAR_CMD, VAR_GLOBAL and the environment,
890          * in that order, depending on the FIND_* flags in 'flags'
891          */
892         if ((var = VarLookup(&ctxt->context, name)) != NULL)
893                 return (var);
894
895         /* not there - try command line context */
896         if (ctxt != VAR_CMD) {
897                 if ((var = VarLookup(&VAR_CMD->context, name)) != NULL)
898                         return (var);
899         }
900
901         /* not there - try global context, but only if not -e/-E */
902         if (ctxt != VAR_GLOBAL && (!checkEnvFirst && !localCheckEnvFirst)) {
903                 if ((var = VarLookup(&VAR_GLOBAL->context, name)) != NULL)
904                         return (var);
905         }
906
907         if ((var = VarLookup(&VAR_ENV->context, name)) != NULL)
908                 return (var);
909
910         /* deferred check for the environment (in case of -e/-E) */
911         if ((ctxt != VAR_GLOBAL) && (checkEnvFirst || localCheckEnvFirst)) {
912                 if ((var = VarLookup(&VAR_GLOBAL->context, name)) != NULL)
913                         return (var);
914         }
915
916         return (NULL);
917 }
918
919 /**
920  * Add a new variable of name name and value val to the given context.
921  *
922  * Side Effects:
923  *      The new variable is placed at the front of the given context
924  *      The name and val arguments are duplicated so they may
925  *      safely be freed.
926  */
927 static void
928 VarAdd(const char name[], const char val[], GNode *ctxt)
929 {
930
931         Lst_AtFront(&ctxt->context, VarCreate(name, val, 0));
932         DEBUGF(VAR, ("%s:%s = %s\n", ctxt->name, name, val));
933 }
934
935 /**
936  * Remove a variable from a context.
937  *
938  * Side Effects:
939  *      The Var structure is removed and freed.
940  */
941 void
942 Var_Delete(const char name[], GNode *ctxt)
943 {
944         LstNode *ln;
945
946         DEBUGF(VAR, ("%s:delete %s\n", ctxt->name, name));
947         LST_FOREACH(ln, &ctxt->context) {
948                 if (strcmp(((const Var *)Lst_Datum(ln))->name, name) == 0) {
949                         VarDestroy(Lst_Datum(ln), true);
950                         Lst_Remove(&ctxt->context, ln);
951                         break;
952                 }
953         }
954 }
955
956 /**
957  * Set the variable name to the value val in the given context.
958  *
959  * Side Effects:
960  *      If the variable doesn't yet exist, a new record is created for it.
961  *      Else the old value is freed and the new one stuck in its place
962  *
963  * Notes:
964  *      The variable is searched for only in its context before being
965  *      created in that context. I.e. if the context is VAR_GLOBAL,
966  *      only VAR_GLOBAL->context is searched. Likewise if it is VAR_CMD, only
967  *      VAR_CMD->context is searched. This is done to avoid the literally
968  *      thousands of unnecessary strcmp's that used to be done to
969  *      set, say, $(@) or $(<).
970  */
971 void
972 Var_Set(const char name[], const char val[], GNode *ctxt)
973 {
974         Var    *v;
975         char   *n;
976
977         /*
978          * We only look for a variable in the given context since anything
979          * set here will override anything in a lower context, so there's not
980          * much point in searching them all just to save a bit of memory...
981          */
982         n = VarPossiblyExpand(name, ctxt);
983         v = VarFindOnly(n, ctxt);
984         if (v == NULL) {
985                 VarAdd(n, val, ctxt);
986                 if (ctxt == VAR_CMD) {
987                         /*
988                          * Any variables given on the command line
989                          * are automatically exported to the
990                          * environment (as per POSIX standard)
991                          */
992                         if (setenv(n, val, 1) == -1)
993                                 Punt( "setenv: %s: can't allocate memory", n);
994                 }
995         } else {
996                 Buf_Clear(v->val);
997                 Buf_Append(v->val, val);
998
999                 if (ctxt == VAR_CMD || (v->flags & VAR_TO_ENV)) {
1000                         /*
1001                          * Any variables given on the command line
1002                          * are automatically exported to the
1003                          * environment (as per POSIX standard)
1004                          */
1005                         char *exp_value;
1006
1007                         exp_value = Buf_Peel(Var_Subst(val, ctxt, false));
1008                         if (setenv(n, exp_value, 1) == -1)
1009                                 Punt( "setenv: %s: can't allocate memory", n);
1010                         free(exp_value);
1011                 }
1012
1013         }
1014
1015         DEBUGF(VAR, ("%s:%s = %s\n", ctxt->name, n, val));
1016         free(n);
1017 }
1018
1019 /**
1020  * Set the a global name variable to the value.
1021  */
1022 void
1023 Var_SetGlobal(const char name[], const char value[])
1024 {
1025
1026         Var_Set(name, value, VAR_GLOBAL);
1027 }
1028
1029
1030 /**
1031  * Set the VAR_TO_ENV flag on a variable
1032  */
1033 void
1034 Var_SetEnv(const char name[], GNode *ctxt)
1035 {
1036         Var    *v;
1037
1038         v = VarFindOnly(name, VAR_CMD);
1039         if (v != NULL) {
1040                 /*
1041                  * Do not allow .EXPORT: to be set on variables
1042                  * from the command line or MAKEFLAGS.
1043                  */
1044                 Error(
1045                     "Warning: Did not set .EXPORTVAR: on %s because it "
1046                     "is from the command line or MAKEFLAGS", name);
1047                 return;
1048         }
1049
1050         v = VarFindAny(name, ctxt);
1051         if (v == NULL) {
1052                 Lst_AtFront(&VAR_ENV->context,
1053                     VarCreate(name, NULL, VAR_TO_ENV));
1054                 if (setenv(name, "", 1) == -1)
1055                         Punt( "setenv: %s: can't allocate memory", name);
1056                 Error("Warning: .EXPORTVAR: set on undefined variable %s", name);
1057         } else {
1058                 if ((v->flags & VAR_TO_ENV) == 0) {
1059                         char *value;
1060
1061                         value = Buf_Peel(Var_Subst(Buf_Data(v->val), ctxt, false));
1062                         v->flags |= VAR_TO_ENV;
1063                         if (setenv(v->name, value, 1) == -1)
1064                                 Punt( "setenv: %s: can't allocate memory", v->name);    
1065                         free(value);
1066                 }
1067         }
1068 }
1069
1070 /**
1071  * The variable of the given name has the given value appended to it in
1072  * the given context.
1073  *
1074  * Side Effects:
1075  *      If the variable doesn't exist, it is created. Else the strings
1076  *      are concatenated (with a space in between).
1077  *
1078  * Notes:
1079  *      Only if the variable is being sought in the global context is the
1080  *      environment searched.
1081  *      XXX: Knows its calling circumstances in that if called with ctxt
1082  *      an actual target, it will only search that context since only
1083  *      a local variable could be being appended to. This is actually
1084  *      a big win and must be tolerated.
1085  */
1086 void
1087 Var_Append(const char name[], const char val[], GNode *ctxt)
1088 {
1089         Var     *v;
1090         char    *n;
1091
1092         n = VarPossiblyExpand(name, ctxt);
1093         if (ctxt == VAR_GLOBAL) {
1094                 v = VarFindEnv(n, ctxt);
1095         } else {
1096                 v = VarFindOnly(n, ctxt);
1097         }
1098         if (v == NULL) {
1099                 VarAdd(n, val, ctxt);
1100         } else {
1101                 Buf_AddByte(v->val, ' ');
1102                 Buf_Append(v->val, val);
1103                 DEBUGF(VAR, ("%s:%s = %s\n", ctxt->name, n, Buf_Data(v->val)));
1104         }
1105         free(n);
1106 }
1107
1108 /**
1109  * Return the value of the named variable in the given context
1110  *
1111  * Results:
1112  *      The value if the variable exists, NULL if it doesn't.
1113  */
1114 const char *
1115 Var_Value(const char name[], GNode *ctxt)
1116 {
1117         Var     *v;
1118         char    *n;
1119
1120         n = VarPossiblyExpand(name, ctxt);
1121         v = VarFindAny(n, ctxt);
1122         free(n);
1123         if (v == NULL) {
1124                 return (NULL);
1125         } else {
1126                 return (Buf_Data(v->val));
1127         }
1128 }
1129
1130 /**
1131  * Modify each of the words of the passed string using the given
1132  * function. Used to implement all modifiers.
1133  *
1134  * Results:
1135  *      A string of all the words modified appropriately.
1136  */
1137 static char *
1138 VarModify(const char str[], VarModifyProc *modProc, void *datum)
1139 {
1140         ArgArray        aa;
1141         Buffer          *buf;           /* Buffer for the new string */
1142         int             i;
1143         bool            addSpace;       /*
1144                                          * true if need to add a space to
1145                                          * the buffer before adding the
1146                                          * trimmed word
1147                                          */
1148
1149         brk_string(&aa, str, false);
1150
1151         addSpace = false;
1152         buf = Buf_Init(0);
1153         for (i = 1; i < aa.argc; i++)
1154                 addSpace = (*modProc)(aa.argv[i], addSpace, buf, datum);
1155
1156         ArgArray_Done(&aa);
1157         return (Buf_Peel(buf));
1158 }
1159
1160 /**
1161  * Sort the words in the string.
1162  *
1163  * Input:
1164  *      str             String whose words should be sorted
1165  *      cmp             A comparison function to control the ordering
1166  *
1167  * Results:
1168  *      A string containing the words sorted
1169  */
1170 static char *
1171 VarSortWords(const char str[], int (*cmp)(const void *, const void *))
1172 {
1173         ArgArray        aa;
1174         Buffer          *buf;
1175         int             i;
1176
1177         brk_string(&aa, str, false);
1178         qsort(aa.argv + 1, aa.argc - 1, sizeof(char *), cmp);
1179
1180         buf = Buf_Init(0);
1181         for (i = 1; i < aa.argc; i++) {
1182                 Buf_Append(buf, aa.argv[i]);
1183                 Buf_AddByte(buf, ((i < aa.argc - 1) ? ' ' : '\0'));
1184         }
1185
1186         ArgArray_Done(&aa);
1187         return (Buf_Peel(buf));
1188 }
1189
1190 static int
1191 SortIncreasing(const void *l, const void *r)
1192 {
1193
1194         return (strcmp(*(const char* const*)l, *(const char* const*)r));
1195 }
1196
1197 /**
1198  * Pass through the tstr looking for 1) escaped delimiters,
1199  * '$'s and backslashes (place the escaped character in
1200  * uninterpreted) and 2) unescaped $'s that aren't before
1201  * the delimiter (expand the variable substitution).
1202  * Return the expanded string or NULL if the delimiter was missing
1203  * If pattern is specified, handle escaped ampersands, and replace
1204  * unescaped ampersands with the lhs of the pattern.
1205  *
1206  * Results:
1207  *      A string of all the words modified appropriately.
1208  *      If length is specified, return the string length of the buffer
1209  *      If flags is specified and the last character of the pattern is a
1210  *      $ set the VAR_MATCH_END bit of flags.
1211  */
1212 static Buffer *
1213 VarGetPattern(VarParser *vp, int delim, int *flags, VarPattern *patt)
1214 {
1215         Buffer          *buf;
1216
1217         buf = Buf_Init(0);
1218
1219         /*
1220          * Skim through until the matching delimiter is found; pick up
1221          * variable substitutions on the way. Also allow backslashes to quote
1222          * the delimiter, $, and \, but don't touch other backslashes.
1223          */
1224         while (*vp->ptr != '\0') {
1225                 if (*vp->ptr == delim) {
1226                         return (buf);
1227
1228                 } else if ((vp->ptr[0] == '\\') &&
1229                     ((vp->ptr[1] == delim) ||
1230                      (vp->ptr[1] == '\\') ||
1231                      (vp->ptr[1] == '$') ||
1232                      (vp->ptr[1] == '&' && patt != NULL))) {
1233                         vp->ptr++;              /* consume backslash */
1234                         Buf_AddByte(buf, vp->ptr[0]);
1235                         vp->ptr++;
1236
1237                 } else if (vp->ptr[0] == '$') {
1238                         if (vp->ptr[1] == delim) {
1239                                 if (flags == NULL) {
1240                                         Buf_AddByte(buf, vp->ptr[0]);
1241                                         vp->ptr++;
1242                                 } else {
1243                                         /*
1244                                          * Unescaped $ at end of patt =>
1245                                          * anchor patt at end.
1246                                          */
1247                                         *flags |= VAR_MATCH_END;
1248                                         vp->ptr++;
1249                                 }
1250                         } else {
1251                                 VarParser       subvp = {
1252                                         vp->ptr,
1253                                         vp->ptr,
1254                                         vp->ctxt,
1255                                         vp->err,
1256                                         vp->execute
1257                                 };
1258                                 char   *rval;
1259                                 bool rfree;
1260
1261                                 /*
1262                                  * If unescaped dollar sign not
1263                                  * before the delimiter, assume it's
1264                                  * a variable substitution and
1265                                  * recurse.
1266                                  */
1267                                 rval = VarParse(&subvp, &rfree);
1268                                 Buf_Append(buf, rval);
1269                                 if (rfree)
1270                                         free(rval);
1271                                 vp->ptr = subvp.ptr;
1272                         }
1273                 } else if (vp->ptr[0] == '&' && patt != NULL) {
1274                         Buf_AppendBuf(buf, patt->lhs);
1275                         vp->ptr++;
1276                 } else {
1277                         Buf_AddByte(buf, vp->ptr[0]);
1278                         vp->ptr++;
1279                 }
1280         }
1281
1282         Buf_Destroy(buf, true);
1283         return (NULL);
1284 }
1285
1286 /**
1287  * Make sure this variable is fully expanded.
1288  */
1289 static char *
1290 VarExpand(Var *v, VarParser *vp)
1291 {
1292         char    *value;
1293         char    *result;
1294
1295         if (v->flags & VAR_IN_USE) {
1296                 Fatal("Variable %s is recursive.", v->name);
1297                 /* NOTREACHED */
1298         }
1299
1300         v->flags |= VAR_IN_USE;
1301
1302         /*
1303          * Before doing any modification, we have to make sure the
1304          * value has been fully expanded. If it looks like recursion
1305          * might be necessary (there's a dollar sign somewhere in the
1306          * variable's value) we just call Var_Subst to do any other
1307          * substitutions that are necessary. Note that the value
1308          * returned by Var_Subst will have been
1309          * dynamically-allocated, so it will need freeing when we
1310          * return.
1311          */
1312         value = Buf_Data(v->val);
1313         if (strchr(value, '$') == NULL) {
1314                 result = strdup(value);
1315         } else {
1316                 Buffer  *buf;
1317
1318                 buf = Var_Subst(value, vp->ctxt, vp->err);
1319                 result = Buf_Peel(buf);
1320         }
1321
1322         v->flags &= ~VAR_IN_USE;
1323
1324         return (result);
1325 }
1326
1327 /**
1328  * Select only those words in value that match the modifier.
1329  */
1330 static char *
1331 modifier_M(VarParser *vp, const char value[], char endc)
1332 {
1333         char    *patt;
1334         char    *ptr;
1335         char    *newValue;
1336         char    modifier;
1337
1338         modifier = vp->ptr[0];
1339         vp->ptr++;      /* consume 'M' or 'N' */
1340
1341         /*
1342          * Compress the \:'s out of the pattern, so allocate enough
1343          * room to hold the uncompressed pattern and compress the
1344          * pattern into that space.
1345          */
1346         patt = estrdup(vp->ptr);
1347         ptr = patt;
1348         while (vp->ptr[0] != '\0') {
1349                 if (vp->ptr[0] == endc || vp->ptr[0] == ':') {
1350                         break;
1351                 }
1352                 if (vp->ptr[0] == '\\' &&
1353                     (vp->ptr[1] == endc || vp->ptr[1] == ':')) {
1354                         vp->ptr++;      /* consume backslash */
1355                 }
1356                 *ptr = vp->ptr[0];
1357                 ptr++;
1358                 vp->ptr++;
1359         }
1360         *ptr = '\0';
1361
1362         if (modifier == 'M') {
1363                 newValue = VarModify(value, VarMatch, patt);
1364         } else {
1365                 newValue = VarModify(value, VarNoMatch, patt);
1366         }
1367         free(patt);
1368
1369         return (newValue);
1370 }
1371
1372 /**
1373  * Substitute the replacement string for the pattern.  The substitution
1374  * is applied to each word in value.
1375  */
1376 static char *
1377 modifier_S(VarParser *vp, const char value[], Var *v)
1378 {
1379         VarPattern      patt;
1380         char            delim;
1381         char            *newValue;
1382
1383         patt.flags = 0;
1384
1385         vp->ptr++;              /* consume 'S' */
1386
1387         delim = *vp->ptr;       /* used to find end of pattern */
1388         vp->ptr++;              /* consume 1st delim */
1389
1390         /*
1391          * If pattern begins with '^', it is anchored to the start of the
1392          * word -- skip over it and flag pattern.
1393          */
1394         if (*vp->ptr == '^') {
1395                 patt.flags |= VAR_MATCH_START;
1396                 vp->ptr++;
1397         }
1398
1399         patt.lhs = VarGetPattern(vp, delim, &patt.flags, NULL);
1400         if (patt.lhs == NULL) {
1401                 /*
1402                  * LHS didn't end with the delim, complain and exit.
1403                  */
1404                 Fatal("Unclosed substitution for %s (%c missing)",
1405                     v->name, delim);
1406         }
1407
1408         vp->ptr++;      /* consume 2nd delim */
1409
1410         patt.rhs = VarGetPattern(vp, delim, NULL, &patt);
1411         if (patt.rhs == NULL) {
1412                 /*
1413                  * RHS didn't end with the delim, complain and exit.
1414                  */
1415                 Fatal("Unclosed substitution for %s (%c missing)",
1416                     v->name, delim);
1417         }
1418
1419         vp->ptr++;      /* consume last delim */
1420
1421         /*
1422          * Check for global substitution. If 'g' after the final delimiter,
1423          * substitution is global and is marked that way.
1424          */
1425         if (vp->ptr[0] == 'g') {
1426                 patt.flags |= VAR_SUB_GLOBAL;
1427                 vp->ptr++;
1428         }
1429
1430         /*
1431          * Global substitution of the empty string causes an infinite number
1432          * of matches, unless anchored by '^' (start of string) or '$' (end
1433          * of string). Catch the infinite substitution here. Note that flags
1434          * can only contain the 3 bits we're interested in so we don't have
1435          * to mask unrelated bits. We can test for equality.
1436          */
1437         if (Buf_Size(patt.lhs) == 0 && patt.flags == VAR_SUB_GLOBAL)
1438                 Fatal("Global substitution of the empty string");
1439
1440         newValue = VarModify(value, VarSubstitute, &patt);
1441
1442         /*
1443          * Free the two strings.
1444          */
1445         free(patt.lhs);
1446         free(patt.rhs);
1447
1448         return (newValue);
1449 }
1450
1451 static char *
1452 modifier_C(VarParser *vp, char value[], Var *v)
1453 {
1454         VarPattern      patt;
1455         char            delim;
1456         int             error;
1457         char            *newValue;
1458
1459         patt.flags = 0;
1460
1461         vp->ptr++;              /* consume 'C' */
1462
1463         delim = *vp->ptr;       /* delimiter between sections */
1464
1465         vp->ptr++;              /* consume 1st delim */
1466
1467         patt.lhs = VarGetPattern(vp, delim, NULL, NULL);
1468         if (patt.lhs == NULL) {
1469                 Fatal("Unclosed substitution for %s (%c missing)",
1470                      v->name, delim);
1471         }
1472
1473         vp->ptr++;              /* consume 2st delim */
1474
1475         patt.rhs = VarGetPattern(vp, delim, NULL, NULL);
1476         if (patt.rhs == NULL) {
1477                 Fatal("Unclosed substitution for %s (%c missing)",
1478                      v->name, delim);
1479         }
1480
1481         vp->ptr++;              /* consume last delim */
1482
1483         switch (*vp->ptr) {
1484         case 'g':
1485                 patt.flags |= VAR_SUB_GLOBAL;
1486                 vp->ptr++;              /* consume 'g' */
1487                 break;
1488         case '1':
1489                 patt.flags |= VAR_SUB_ONE;
1490                 vp->ptr++;              /* consume '1' */
1491                 break;
1492         default:
1493                 break;
1494         }
1495
1496         error = regcomp(&patt.re, Buf_Data(patt.lhs), REG_EXTENDED);
1497         if (error) {
1498                 VarREError(error, &patt.re, "RE substitution error");
1499                 free(patt.rhs);
1500                 free(patt.lhs);
1501                 return (var_Error);
1502         }
1503
1504         patt.nsub = patt.re.re_nsub + 1;
1505         if (patt.nsub < 1)
1506                 patt.nsub = 1;
1507         if (patt.nsub > 10)
1508                 patt.nsub = 10;
1509         patt.matches = emalloc(patt.nsub * sizeof(regmatch_t));
1510
1511         newValue = VarModify(value, VarRESubstitute, &patt);
1512
1513         regfree(&patt.re);
1514         free(patt.matches);
1515         free(patt.rhs);
1516         free(patt.lhs);
1517
1518         return (newValue);
1519 }
1520
1521 static char *
1522 sysVvarsub(VarParser *vp, char startc, Var *v, const char value[])
1523 {
1524         /*
1525          * This can either be a bogus modifier or a System-V substitution
1526          * command.
1527          */
1528         char            endc;
1529         VarPattern      patt;
1530         bool            eqFound;
1531         int             cnt;
1532         char            *newStr;
1533         const char      *cp;
1534
1535         endc = (startc == OPEN_PAREN) ? CLOSE_PAREN : CLOSE_BRACE;
1536
1537         patt.flags = 0;
1538
1539         /*
1540          * First we make a pass through the string trying to verify it is a
1541          * SYSV-make-style translation: it must be: <string1>=<string2>)
1542          */
1543         eqFound = false;
1544         cp = vp->ptr;
1545         cnt = 1;
1546         while (*cp != '\0' && cnt) {
1547                 if (*cp == '=') {
1548                         eqFound = true;
1549                         /* continue looking for endc */
1550                 } else if (*cp == endc)
1551                         cnt--;
1552                 else if (*cp == startc)
1553                         cnt++;
1554                 if (cnt)
1555                         cp++;
1556         }
1557
1558         if (*cp == endc && eqFound) {
1559                 /*
1560                  * Now we break this sucker into the lhs and rhs.
1561                  */
1562                 patt.lhs = VarGetPattern(vp, '=', &patt.flags, NULL);
1563                 if (patt.lhs == NULL) {
1564                         Fatal("Unclosed substitution for %s (%c missing)",
1565                               v->name, '=');
1566                 }
1567                 vp->ptr++;      /* consume '=' */
1568
1569                 patt.rhs = VarGetPattern(vp, endc, NULL, &patt);
1570                 if (patt.rhs == NULL) {
1571                         Fatal("Unclosed substitution for %s (%c missing)",
1572                               v->name, endc);
1573                 }
1574
1575                 /*
1576                  * SYSV modifications happen through the whole string. Note
1577                  * the pattern is anchored at the end.
1578                  */
1579                 newStr = VarModify(value, VarSYSVMatch, &patt);
1580
1581                 free(patt.lhs);
1582                 free(patt.rhs);
1583         } else {
1584                 Error("Unknown modifier '%c'\n", *vp->ptr);
1585                 vp->ptr++;
1586                 while (*vp->ptr != '\0') {
1587                         if (*vp->ptr == endc && *vp->ptr == ':') {
1588                                 break;
1589                         }
1590                         vp->ptr++;
1591                 }
1592                 newStr = var_Error;
1593         }
1594
1595         return (newStr);
1596 }
1597
1598 /**
1599  * Quote shell meta-characters in the string
1600  *
1601  * Results:
1602  *      The quoted string
1603  */
1604 static char *
1605 Var_Quote(const char str[])
1606 {
1607         Buffer *buf;
1608         /* This should cover most shells :-( */
1609         static char meta[] = "\n \t'`\";&<>()|*?{}[]\\$!#^~";
1610
1611         buf = Buf_Init(MAKE_BSIZE);
1612         for (; *str; str++) {
1613                 if (strchr(meta, *str) != NULL)
1614                         Buf_AddByte(buf, '\\');
1615                 Buf_AddByte(buf, *str);
1616         }
1617
1618         return (Buf_Peel(buf));
1619 }
1620
1621
1622 /*
1623  * Now we need to apply any modifiers the user wants applied.
1624  * These are:
1625  *      :M<pattern>
1626  *              words which match the given <pattern>.
1627  *              <pattern> is of the standard file
1628  *              wildcarding form.
1629  *      :S<d><pat1><d><pat2><d>[g]
1630  *              Substitute <pat2> for <pat1> in the value
1631  *      :C<d><pat1><d><pat2><d>[g]
1632  *              Substitute <pat2> for regex <pat1> in the value
1633  *      :H      Substitute the head of each word
1634  *      :T      Substitute the tail of each word
1635  *      :E      Substitute the extension (minus '.') of
1636  *              each word
1637  *      :R      Substitute the root of each word
1638  *              (pathname minus the suffix).
1639  *      :lhs=rhs
1640  *              Like :S, but the rhs goes to the end of
1641  *              the invocation.
1642  *      :U      Converts variable to upper-case.
1643  *      :L      Converts variable to lower-case.
1644  *
1645  * XXXHB update this comment or remove it and point to the man page.
1646  */
1647 static char *
1648 ParseModifier(VarParser *vp, char startc, Var *v, bool *freeResult)
1649 {
1650         char    *value;
1651         char    endc;
1652
1653         value = VarExpand(v, vp);
1654         *freeResult = true;
1655
1656         endc = (startc == OPEN_PAREN) ? CLOSE_PAREN : CLOSE_BRACE;
1657
1658         vp->ptr++;      /* consume first colon */
1659
1660         while (*vp->ptr != '\0') {
1661                 char    *newStr;        /* New value to return */
1662
1663                 if (*vp->ptr == endc) {
1664                         return (value);
1665                 }
1666
1667                 DEBUGF(VAR, ("Applying :%c to \"%s\"\n", *vp->ptr, value));
1668                 switch (*vp->ptr) {
1669                 case 'N':
1670                 case 'M':
1671                         newStr = modifier_M(vp, value, endc);
1672                         break;
1673                 case 'S':
1674                         newStr = modifier_S(vp, value, v);
1675                         break;
1676                 case 'C':
1677                         newStr = modifier_C(vp, value, v);
1678                         break;
1679                 default:
1680                         if (vp->ptr[1] != endc && vp->ptr[1] != ':') {
1681 #ifdef SUNSHCMD
1682                                 if ((vp->ptr[0] == 's') &&
1683                                     (vp->ptr[1] == 'h') &&
1684                                     (vp->ptr[2] == endc || vp->ptr[2] == ':')) {
1685                                         const char      *error;
1686
1687                                         if (vp->execute) {
1688                                                 newStr = Buf_Peel(
1689                                                     Cmd_Exec(value, &error));
1690                                         } else {
1691                                                 newStr = estrdup("");
1692                                         }
1693
1694                                         if (error)
1695                                                 Error(error, value);
1696                                         vp->ptr += 2;
1697                                 } else
1698 #endif
1699                                 {
1700                                         newStr = sysVvarsub(vp, startc, v, value);
1701                                 }
1702                                 break;
1703                         }
1704
1705                         switch (vp->ptr[0]) {
1706                         case 'L':
1707                                 {
1708                                 const char      *cp;
1709                                 Buffer          *buf;
1710                                 buf = Buf_Init(MAKE_BSIZE);
1711                                 for (cp = value; *cp; cp++)
1712                                         Buf_AddByte(buf, tolower((unsigned char)*cp));
1713
1714                                 newStr = Buf_Peel(buf);
1715
1716                                 vp->ptr++;
1717                                 break;
1718                                 }
1719                         case 'O':
1720                                 newStr = VarSortWords(value, SortIncreasing);
1721                                 vp->ptr++;
1722                                 break;
1723                         case 'Q':
1724                                 newStr = Var_Quote(value);
1725                                 vp->ptr++;
1726                                 break;
1727                         case 'T':
1728                                 newStr = VarModify(value, VarTail, NULL);
1729                                 vp->ptr++;
1730                                 break;
1731                         case 'U':
1732                                 {
1733                                 const char      *cp;
1734                                 Buffer          *buf;
1735                                 buf = Buf_Init(MAKE_BSIZE);
1736                                 for (cp = value; *cp; cp++)
1737                                         Buf_AddByte(buf, toupper((unsigned char)*cp));
1738
1739                                 newStr = Buf_Peel(buf);
1740
1741                                 vp->ptr++;
1742                                 break;
1743                                 }
1744                         case 'H':
1745                                 newStr = VarModify(value, VarHead, NULL);
1746                                 vp->ptr++;
1747                                 break;
1748                         case 'E':
1749                                 newStr = VarModify(value, VarSuffix, NULL);
1750                                 vp->ptr++;
1751                                 break;
1752                         case 'R':
1753                                 newStr = VarModify(value, VarRoot, NULL);
1754                                 vp->ptr++;
1755                                 break;
1756                         default:
1757                                 newStr = sysVvarsub(vp, startc, v, value);
1758                                 break;
1759                         }
1760                         break;
1761                 }
1762
1763                 DEBUGF(VAR, ("Result is \"%s\"\n", newStr));
1764                 if (*freeResult) {
1765                         free(value);
1766                 }
1767
1768                 value = newStr;
1769                 *freeResult = (value == var_Error) ? false : true;
1770
1771                 if (vp->ptr[0] == ':') {
1772                         vp->ptr++;      /* consume colon */
1773                 }
1774         }
1775
1776         return (value);
1777 }
1778
1779 static char *
1780 ParseRestModifier(VarParser *vp, char startc, Buffer *buf, bool *freeResult)
1781 {
1782         const char      *vname;
1783         size_t          vlen;
1784         Var             *v;
1785         char            *value;
1786
1787         vname = Buf_Data(buf);
1788         vlen = Buf_Size(buf);
1789
1790         v = VarFindAny(vname, vp->ctxt);
1791         if (v != NULL) {
1792                 value = ParseModifier(vp, startc, v, freeResult);
1793                 return (value);
1794         }
1795
1796         if ((vp->ctxt == VAR_CMD) || (vp->ctxt == VAR_GLOBAL)) {
1797                 size_t  consumed;
1798                 /*
1799                  * Still need to get to the end of the variable
1800                  * specification, so kludge up a Var structure for the
1801                  * modifications
1802                  */
1803                 v = VarCreate(vname, NULL, VAR_JUNK);
1804                 value = ParseModifier(vp, startc, v, freeResult);
1805                 if (*freeResult) {
1806                         free(value);
1807                 }
1808                 VarDestroy(v, true);
1809
1810                 consumed = vp->ptr - vp->input + 1;
1811                 /*
1812                  * If substituting a local variable in a non-local context,
1813                  * assume it's for dynamic source stuff. We have to handle
1814                  * this specially and return the longhand for the variable
1815                  * with the dollar sign escaped so it makes it back to the
1816                  * caller. Only four of the local variables are treated
1817                  * specially as they are the only four that will be set when
1818                  * dynamic sources are expanded.
1819                  */
1820                 if (vlen == 1 ||
1821                     (vlen == 2 && (vname[1] == 'F' || vname[1] == 'D'))) {
1822                         if (strchr("!%*@", vname[0]) != NULL) {
1823                                 value = emalloc(consumed + 1);
1824                                 strncpy(value, vp->input, consumed);
1825                                 value[consumed] = '\0';
1826
1827                                 *freeResult = true;
1828                                 return (value);
1829                         }
1830                 }
1831                 if (vlen > 2 &&
1832                     vname[0] == '.' &&
1833                     isupper((unsigned char)vname[1])) {
1834                         if ((strncmp(vname, ".TARGET", vlen - 1) == 0) ||
1835                             (strncmp(vname, ".ARCHIVE", vlen - 1) == 0) ||
1836                             (strncmp(vname, ".PREFIX", vlen - 1) == 0) ||
1837                             (strncmp(vname, ".MEMBER", vlen - 1) == 0)) {
1838                                 value = emalloc(consumed + 1);
1839                                 strncpy(value, vp->input, consumed);
1840                                 value[consumed] = '\0';
1841
1842                                 *freeResult = true;
1843                                 return (value);
1844                         }
1845                 }
1846
1847                 *freeResult = false;
1848                 return (vp->err ? var_Error : varNoError);
1849         } else {
1850                 /*
1851                  * Check for D and F forms of local variables since we're in
1852                  * a local context and the name is the right length.
1853                  */
1854                 if (vlen == 2 &&
1855                     (vname[1] == 'F' || vname[1] == 'D') &&
1856                     (strchr("!%*<>@", vname[0]) != NULL)) {
1857                         char    name[2];
1858
1859                         name[0] = vname[0];
1860                         name[1] = '\0';
1861
1862                         v = VarFindOnly(name, vp->ctxt);
1863                         if (v != NULL) {
1864                                 value = ParseModifier(vp, startc, v, freeResult);
1865                                 return (value);
1866                         }
1867                 }
1868
1869                 /*
1870                  * Still need to get to the end of the variable
1871                  * specification, so kludge up a Var structure for the
1872                  * modifications
1873                  */
1874                 v = VarCreate(vname, NULL, VAR_JUNK);
1875                 value = ParseModifier(vp, startc, v, freeResult);
1876                 if (*freeResult) {
1877                         free(value);
1878                 }
1879                 VarDestroy(v, true);
1880
1881                 *freeResult = false;
1882                 return (vp->err ? var_Error : varNoError);
1883         }
1884 }
1885
1886 static char *
1887 ParseRestEnd(VarParser *vp, Buffer *buf, bool *freeResult)
1888 {
1889         const char      *vname;
1890         size_t          vlen;
1891         Var             *v;
1892         char            *value;
1893
1894         vname = Buf_Data(buf);
1895         vlen = Buf_Size(buf);
1896
1897         v = VarFindAny(vname, vp->ctxt);
1898         if (v != NULL) {
1899                 value = VarExpand(v, vp);
1900                 *freeResult = true;
1901                 return (value);
1902         }
1903
1904         if ((vp->ctxt == VAR_CMD) || (vp->ctxt == VAR_GLOBAL)) {
1905                 size_t  consumed = vp->ptr - vp->input + 1;
1906
1907                 /*
1908                  * If substituting a local variable in a non-local context,
1909                  * assume it's for dynamic source stuff. We have to handle
1910                  * this specially and return the longhand for the variable
1911                  * with the dollar sign escaped so it makes it back to the
1912                  * caller. Only four of the local variables are treated
1913                  * specially as they are the only four that will be set when
1914                  * dynamic sources are expanded.
1915                  */
1916                 if (vlen == 1 ||
1917                     (vlen == 2 && (vname[1] == 'F' || vname[1] == 'D'))) {
1918                         if (strchr("!%*@", vname[0]) != NULL) {
1919                                 value = emalloc(consumed + 1);
1920                                 strncpy(value, vp->input, consumed);
1921                                 value[consumed] = '\0';
1922
1923                                 *freeResult = true;
1924                                 return (value);
1925                         }
1926                 }
1927                 if (vlen > 2 &&
1928                     vname[0] == '.' &&
1929                     isupper((unsigned char)vname[1])) {
1930                         if ((strncmp(vname, ".TARGET", vlen - 1) == 0) ||
1931                             (strncmp(vname, ".ARCHIVE", vlen - 1) == 0) ||
1932                             (strncmp(vname, ".PREFIX", vlen - 1) == 0) ||
1933                             (strncmp(vname, ".MEMBER", vlen - 1) == 0)) {
1934                                 value = emalloc(consumed + 1);
1935                                 strncpy(value, vp->input, consumed);
1936                                 value[consumed] = '\0';
1937
1938                                 *freeResult = true;
1939                                 return (value);
1940                         }
1941                 }
1942         } else {
1943                 /*
1944                  * Check for D and F forms of local variables since we're in
1945                  * a local context and the name is the right length.
1946                  */
1947                 if (vlen == 2 &&
1948                     (vname[1] == 'F' || vname[1] == 'D') &&
1949                     (strchr("!%*<>@", vname[0]) != NULL)) {
1950                         char    name[2];
1951
1952                         name[0] = vname[0];
1953                         name[1] = '\0';
1954
1955                         v = VarFindOnly(name, vp->ctxt);
1956                         if (v != NULL) {
1957                                 char    *val;
1958                                 /*
1959                                  * No need for nested expansion or anything,
1960                                  * as we're the only one who sets these
1961                                  * things and we sure don't put nested
1962                                  * invocations in them...
1963                                  */
1964                                 val = Buf_Data(v->val);
1965
1966                                 if (vname[1] == 'D') {
1967                                         val = VarModify(val, VarHead, NULL);
1968                                 } else {
1969                                         val = VarModify(val, VarTail, NULL);
1970                                 }
1971
1972                                 *freeResult = true;
1973                                 return (val);
1974                         }
1975                 }
1976         }
1977
1978         *freeResult = false;
1979         return (vp->err ? var_Error : varNoError);
1980 }
1981
1982 /**
1983  * Parse a multi letter variable name, and return it's value.
1984  */
1985 static char *
1986 VarParseLong(VarParser *vp, bool *freeResult)
1987 {
1988         Buffer          *buf;
1989         char            startc;
1990         char            endc;
1991         char            *value;
1992
1993         buf = Buf_Init(MAKE_BSIZE);
1994
1995         startc = vp->ptr[0];
1996         vp->ptr++;              /* consume opening paren or brace */
1997
1998         endc = (startc == OPEN_PAREN) ? CLOSE_PAREN : CLOSE_BRACE;
1999
2000         /*
2001          * Process characters until we reach an end character or a colon,
2002          * replacing embedded variables as we go.
2003          */
2004         while (*vp->ptr != '\0') {
2005                 if (*vp->ptr == endc) {
2006                         value = ParseRestEnd(vp, buf, freeResult);
2007                         vp->ptr++;      /* consume closing paren or brace */
2008                         Buf_Destroy(buf, true);
2009                         return (value);
2010
2011                 } else if (*vp->ptr == ':') {
2012                         value = ParseRestModifier(vp, startc, buf, freeResult);
2013                         vp->ptr++;      /* consume closing paren or brace */
2014                         Buf_Destroy(buf, true);
2015                         return (value);
2016
2017                 } else if (*vp->ptr == '$') {
2018                         VarParser       subvp = {
2019                                 vp->ptr,
2020                                 vp->ptr,
2021                                 vp->ctxt,
2022                                 vp->err,
2023                                 vp->execute
2024                         };
2025                         char    *rval;
2026                         bool    rfree;
2027
2028                         rval = VarParse(&subvp, &rfree);
2029                         if (rval == var_Error) {
2030                                 Fatal("Error expanding embedded variable.");
2031                         }
2032                         Buf_Append(buf, rval);
2033                         if (rfree)
2034                                 free(rval);
2035                         vp->ptr = subvp.ptr;
2036                 } else {
2037                         Buf_AddByte(buf, *vp->ptr);
2038                         vp->ptr++;
2039                 }
2040         }
2041
2042         /* If we did not find the end character, return var_Error */
2043         Buf_Destroy(buf, true);
2044         *freeResult = false;
2045         return (var_Error);
2046 }
2047
2048 /**
2049  * Parse a single letter variable name, and return it's value.
2050  */
2051 static char *
2052 VarParseShort(VarParser *vp, bool *freeResult)
2053 {
2054         char    vname[2];
2055         Var     *v;
2056         char    *value;
2057
2058         vname[0] = vp->ptr[0];
2059         vname[1] = '\0';
2060
2061         vp->ptr++;      /* consume single letter */
2062
2063         v = VarFindAny(vname, vp->ctxt);
2064         if (v != NULL) {
2065                 value = VarExpand(v, vp);
2066                 *freeResult = true;
2067                 return (value);
2068         }
2069
2070         /*
2071          * If substituting a local variable in a non-local context, assume
2072          * it's for dynamic source stuff. We have to handle this specially
2073          * and return the longhand for the variable with the dollar sign
2074          * escaped so it makes it back to the caller. Only four of the local
2075          * variables are treated specially as they are the only four that
2076          * will be set when dynamic sources are expanded.
2077          */
2078         if ((vp->ctxt == VAR_CMD) || (vp->ctxt == VAR_GLOBAL)) {
2079
2080                 /* XXX: It looks like $% and $! are reversed here */
2081                 switch (vname[0]) {
2082                 case '@':
2083                         *freeResult = true;
2084                         return (estrdup("$(.TARGET)"));
2085                 case '%':
2086                         *freeResult = true;
2087                         return (estrdup("$(.ARCHIVE)"));
2088                 case '*':
2089                         *freeResult = true;
2090                         return (estrdup("$(.PREFIX)"));
2091                 case '!':
2092                         *freeResult = true;
2093                         return (estrdup("$(.MEMBER)"));
2094                 default:
2095                         *freeResult = false;
2096                         return (vp->err ? var_Error : varNoError);
2097                 }
2098         }
2099
2100         /* Variable name was not found. */
2101         *freeResult = false;
2102         return (vp->err ? var_Error : varNoError);
2103 }
2104
2105 static char *
2106 VarParse(VarParser *vp, bool *freeResult)
2107 {
2108
2109         vp->ptr++;      /* consume '$' or last letter of conditional */
2110
2111         if (vp->ptr[0] == '\0') {
2112                 /* Error, there is only a dollar sign in the input string. */
2113                 *freeResult = false;
2114                 return (vp->err ? var_Error : varNoError);
2115
2116         } else if (vp->ptr[0] == OPEN_PAREN || vp->ptr[0] == OPEN_BRACE) {
2117                 /* multi letter variable name */
2118                 return (VarParseLong(vp, freeResult));
2119
2120         } else {
2121                 /* single letter variable name */
2122                 return (VarParseShort(vp, freeResult));
2123         }
2124 }
2125
2126 /**
2127  * Given the start of a variable invocation, extract the variable
2128  * name and find its value, then modify it according to the
2129  * specification.
2130  *
2131  * Results:
2132  *      The value of the variable or var_Error if the specification
2133  *      is invalid.  The number of characters in the specification
2134  *      is placed in the variable pointed to by consumed.  (for
2135  *      invalid specifications, this is just 2 to skip the '$' and
2136  *      the following letter, or 1 if '$' was the last character
2137  *      in the string).  A bool in *freeResult telling whether the
2138  *      returned string should be freed by the caller.
2139  */
2140 char *
2141 Var_Parse(const char input[], GNode *ctxt, bool err,
2142         size_t *consumed, bool *freeResult)
2143 {
2144         VarParser       vp = {
2145                 input,
2146                 input,
2147                 ctxt,
2148                 err,
2149                 true
2150         };
2151         char            *value;
2152
2153         value = VarParse(&vp, freeResult);
2154         *consumed += vp.ptr - vp.input;
2155         return (value);
2156 }
2157
2158 /*
2159  * Given the start of a variable invocation, determine the length
2160  * of the specification.
2161  *
2162  * Results:
2163  *      The number of characters in the specification.  For invalid
2164  *      specifications, this is just 2 to skip the '$' and the
2165  *      following letter, or 1 if '$' was the last character in the
2166  *      string.
2167  */
2168 size_t
2169 Var_Match(const char input[], GNode *ctxt)
2170 {
2171         VarParser       vp = {
2172                 input,
2173                 input,
2174                 ctxt,
2175                 false,
2176                 false
2177         };
2178         char            *value;
2179         bool            freeResult;
2180
2181         value = VarParse(&vp, &freeResult);
2182         if (freeResult) {
2183                 free(value);
2184         }
2185         return (vp.ptr - vp.input);
2186 }
2187
2188 static int
2189 match_var(const char str[], const char var[])
2190 {
2191         const char      *start = str;
2192         size_t          len;
2193
2194         str++;                  /* consume '$' */
2195
2196         if (str[0] == OPEN_PAREN || str[0] == OPEN_BRACE) {
2197                 str++;          /* consume opening paren or brace */
2198
2199                 while (str[0] != '\0') {
2200                         if (str[0] == '$') {
2201                                 /*
2202                                  * A variable inside the variable. We cannot
2203                                  * expand the external variable yet.
2204                                  */
2205                                 return (str - start);
2206                         } else if (str[0] == ':' ||
2207                                    str[0] == CLOSE_PAREN ||
2208                                    str[0] == CLOSE_BRACE) {
2209                                 len = str - (start + 2);
2210
2211                                 if (var[len] == '\0' && strncmp(var, start + 2, len) == 0) {
2212                                         return (0);     /* match */
2213                                 } else {
2214                                         /*
2215                                          * Not the variable we want to
2216                                          * expand.
2217                                          */
2218                                         return (str - start);
2219                                 }
2220                         } else {
2221                                 ++str;
2222                         }
2223                 }
2224                 return (str - start);
2225         } else {
2226                 /* Single letter variable name */
2227                 if (var[1] == '\0' && var[0] == str[0]) {
2228                         return (0);     /* match */
2229                 } else {
2230                         str++;  /* consume variable name */
2231                         return (str - start);
2232                 }
2233         }
2234 }
2235
2236 /**
2237  * Substitute for all variables in the given string in the given
2238  * context If err is true, Parse_Error will be called when an
2239  * undefined variable is encountered.
2240  *
2241  * Results:
2242  *      The resulting string.
2243  *
2244  * Side Effects:
2245  *      None. The old string must be freed by the caller
2246  */
2247 Buffer *
2248 Var_Subst(const char str[], GNode *ctxt, bool err)
2249 {
2250         bool    errorReported;
2251         Buffer *buf;            /* Buffer for forming things */
2252
2253         /*
2254          * Set true if an error has already been reported to prevent a
2255          * plethora of messages when recursing. XXXHB this comment sounds
2256          * wrong.
2257          */
2258         errorReported = false;
2259
2260         buf = Buf_Init(0);
2261         while (str[0] != '\0') {
2262                 if ((str[0] == '$') && (str[1] == '$')) {
2263                         /*
2264                          * A dollar sign may be escaped with another dollar
2265                          * sign.  In such a case, we skip over the escape
2266                          * character and store the dollar sign into the
2267                          * buffer directly.
2268                          */
2269                         str++;
2270                         Buf_AddByte(buf, str[0]);
2271                         str++;
2272
2273                 } else if (str[0] == '$') {
2274                         /* Variable invocation. */
2275                         VarParser subvp = {
2276                                 str,
2277                                 str,
2278                                 ctxt,
2279                                 err,
2280                                 true
2281                         };
2282                         char    *rval;
2283                         bool    rfree;
2284
2285                         rval = VarParse(&subvp, &rfree);
2286
2287                         /*
2288                          * When we come down here, val should either point to
2289                          * the value of this variable, suitably modified, or
2290                          * be NULL. Length should be the total length of the
2291                          * potential variable invocation (from $ to end
2292                          * character...)
2293                          */
2294                         if (rval == var_Error || rval == varNoError) {
2295                                 /*
2296                                  * If performing old-time variable
2297                                  * substitution, skip over the variable and
2298                                  * continue with the substitution. Otherwise,
2299                                  * store the dollar sign and advance str so
2300                                  * we continue with the string...
2301                                  */
2302                                 if (oldVars) {
2303                                         str = subvp.ptr;
2304                                 } else if (err) {
2305                                         /*
2306                                          * If variable is undefined, complain
2307                                          * and skip the variable. The
2308                                          * complaint will stop us from doing
2309                                          * anything when the file is parsed.
2310                                          */
2311                                         if (!errorReported) {
2312                                                 Parse_Error(PARSE_FATAL,
2313                                                             "Undefined variable \"%.*s\"", subvp.ptr - subvp.input, str);
2314                                         }
2315                                         errorReported = true;
2316                                         str = subvp.ptr;
2317                                 } else {
2318                                         Buf_AddByte(buf, str[0]);
2319                                         str++;
2320                                 }
2321                         } else {
2322                                 /*
2323                                  * Copy all the characters from the variable
2324                                  * value straight into the new string.
2325                                  */
2326                                 Buf_Append(buf, rval);
2327                                 if (rfree) {
2328                                         free(rval);
2329                                 }
2330                                 str = subvp.ptr;
2331                         }
2332                 } else {
2333                         Buf_AddByte(buf, str[0]);
2334                         str++;
2335                 }
2336         }
2337
2338         return (buf);
2339 }
2340
2341 /**
2342  * Substitute for all variables except if it is the same as 'var',
2343  * in the given string in the given context.  If err is true,
2344  * Parse_Error will be called when an undefined variable is
2345  * encountered.
2346  *
2347  * Results:
2348  *      The resulting string.
2349  *
2350  * Side Effects:
2351  *      None. The old string must be freed by the caller
2352  */
2353 Buffer *
2354 Var_SubstOnly(const char var[], const char str[], bool err)
2355 {
2356         GNode *ctxt = VAR_GLOBAL;
2357         bool    errorReported;
2358         Buffer  *buf;           /* Buffer for forming things */
2359
2360         /*
2361          * Set true if an error has already been reported to prevent a
2362          * plethora of messages when recursing. XXXHB this comment sounds
2363          * wrong.
2364          */
2365         errorReported = false;
2366
2367         buf = Buf_Init(0);
2368         while (str[0] != '\0') {
2369                 if (str[0] == '$') {
2370                         int     skip;
2371
2372                         skip = match_var(str, var);
2373                         if (skip > 0) {
2374                                 Buf_AddBytes(buf, skip, str);
2375                                 str += skip;
2376                         } else {
2377                                 /* Variable invocation. */
2378                                 VarParser       subvp = {
2379                                         str,
2380                                         str,
2381                                         ctxt,
2382                                         err,
2383                                         true
2384                                 };
2385                                 char    *rval;
2386                                 bool    rfree;
2387
2388                                 rval = VarParse(&subvp, &rfree);
2389
2390                                 /*
2391                                  * When we get down here, rval should either
2392                                  * point to the value of this variable, or be
2393                                  * NULL.
2394                                  */
2395                                 if (rval == var_Error || rval == varNoError) {
2396                                         /*
2397                                          * If performing old-time variable
2398                                          * substitution, skip over the
2399                                          * variable and continue with the
2400                                          * substitution. Otherwise, store the
2401                                          * dollar sign and advance str so we
2402                                          * continue with the string...
2403                                          */
2404                                         if (oldVars) {
2405                                                 str = subvp.ptr;
2406                                         } else if (err) {
2407                                                 /*
2408                                                  * If variable is undefined,
2409                                                  * complain and skip the
2410                                                  * variable. The complaint
2411                                                  * will stop us from doing
2412                                                  * anything when the file is
2413                                                  * parsed.
2414                                                  */
2415                                                 if (!errorReported) {
2416                                                         Parse_Error(PARSE_FATAL,
2417                                                                     "Undefined variable \"%.*s\"", subvp.ptr - subvp.input, str);
2418                                                 }
2419                                                 errorReported = true;
2420                                                 str = subvp.ptr;
2421                                         } else {
2422                                                 Buf_AddByte(buf, str[0]);
2423                                                 str++;
2424                                         }
2425                                 } else {
2426                                         /*
2427                                          * Copy all the characters from the
2428                                          * variable value straight into the
2429                                          * new string.
2430                                          */
2431                                         Buf_Append(buf, rval);
2432                                         if (rfree) {
2433                                                 free(rval);
2434                                         }
2435                                         str = subvp.ptr;
2436                                 }
2437                         }
2438                 } else {
2439                         Buf_AddByte(buf, str[0]);
2440                         str++;
2441                 }
2442         }
2443
2444         return (buf);
2445 }
2446
2447 /**
2448  * Initialize the module
2449  *
2450  * Side Effects:
2451  *      The VAR_CMD and VAR_GLOBAL contexts are created
2452  */
2453 void
2454 Var_Init(char **env)
2455 {
2456         char    **ptr;
2457
2458         VAR_CMD = Targ_NewGN("Command");
2459         VAR_ENV = Targ_NewGN("Environment");
2460         VAR_GLOBAL = Targ_NewGN("Global");
2461
2462         /*
2463          * Copy user environment variables into ENV context.
2464          */
2465         for (ptr = env; *ptr != NULL; ++ptr) {
2466                 char            *tmp = estrdup(*ptr);
2467                 const char      *name = tmp;
2468                 char            *sep = strchr(name, '=');
2469
2470                 if (sep != NULL) {
2471                         const char      *value = sep + 1;
2472
2473                         *sep = '\0';
2474                         VarAdd(name, value, VAR_ENV);
2475                 }
2476                 free(tmp);
2477         }
2478 }
2479
2480 /**
2481  * Print all variables in global and command line contexts.
2482  */
2483 void
2484 Var_Dump(void)
2485 {
2486         const LstNode   *ln;
2487         const Var       *v;
2488
2489         printf("#*** Global Variables:\n");
2490         LST_FOREACH(ln, &VAR_GLOBAL->context) {
2491                 v = Lst_Datum(ln);
2492                 printf("%-16s = %s\n", v->name, Buf_Data(v->val));
2493         }
2494
2495         printf("#*** Command-line Variables:\n");
2496         LST_FOREACH(ln, &VAR_CMD->context) {
2497                 v = Lst_Datum(ln);
2498                 printf("%-16s = %s\n", v->name, Buf_Data(v->val));
2499         }
2500 }
2501
2502 /**
2503  * Print the values of any variables requested by
2504  * the user.
2505  */
2506 void
2507 Var_Print(Lst *vlist, bool expandVars)
2508 {
2509         LstNode         *n;
2510
2511         LST_FOREACH(n, vlist) {
2512                 const char *name = Lst_Datum(n);
2513
2514                 if (expandVars) {
2515                         char            *v;
2516                         char            *value;
2517
2518                         v = emalloc(strlen(name) + 1 + 3);
2519                         sprintf(v, "${%s}", name);
2520
2521                         value = Buf_Peel(Var_Subst(v, VAR_GLOBAL, false));
2522                         printf("%s\n", value);
2523
2524                         free(v);
2525                         free(value);
2526                 } else {
2527                         const char *value = Var_Value(name, VAR_GLOBAL);
2528                         printf("%s\n", value != NULL ? value : "");
2529                 }
2530         }
2531 }
2532