p_tracep -> p_tracenode, tracking changes made in recent commits.
[dragonfly.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                         if (setenv(n, val, 1) == -1)
1006                                 Punt( "setenv: %s: can't allocate memory", n);
1007                 }
1008
1009         }
1010
1011         DEBUGF(VAR, ("%s:%s = %s\n", ctxt->name, n, val));
1012         free(n);
1013 }
1014
1015 /**
1016  * Set the a global name variable to the value.
1017  */
1018 void
1019 Var_SetGlobal(const char name[], const char value[])
1020 {
1021
1022         Var_Set(name, value, VAR_GLOBAL);
1023 }
1024
1025
1026 /**
1027  * Set the VAR_TO_ENV flag on a variable
1028  */
1029 void
1030 Var_SetEnv(const char name[], GNode *ctxt)
1031 {
1032         Var    *v;
1033
1034         v = VarFindOnly(name, VAR_CMD);
1035         if (v != NULL) {
1036                 /*
1037                  * Do not allow .EXPORT: to be set on variables
1038                  * from the command line or MAKEFLAGS.
1039                  */
1040                 Error(
1041                     "Warning: Did not set .EXPORTVAR: on %s because it "
1042                     "is from the command line or MAKEFLAGS", name);
1043                 return;
1044         }
1045
1046         v = VarFindAny(name, ctxt);
1047         if (v == NULL) {
1048                 Lst_AtFront(&VAR_ENV->context,
1049                     VarCreate(name, NULL, VAR_TO_ENV));
1050                 if (setenv(name, "", 1) == -1)
1051                         Punt( "setenv: %s: can't allocate memory", name);
1052                 Error("Warning: .EXPORTVAR: set on undefined variable %s", name);
1053         } else {
1054                 if ((v->flags & VAR_TO_ENV) == 0) {
1055                         v->flags |= VAR_TO_ENV;
1056                         if (setenv(v->name, Buf_Data(v->val), 1) == -1)
1057                                 Punt( "setenv: %s: can't allocate memory", v->name);    
1058                 }
1059         }
1060 }
1061
1062 /**
1063  * The variable of the given name has the given value appended to it in
1064  * the given context.
1065  *
1066  * Side Effects:
1067  *      If the variable doesn't exist, it is created. Else the strings
1068  *      are concatenated (with a space in between).
1069  *
1070  * Notes:
1071  *      Only if the variable is being sought in the global context is the
1072  *      environment searched.
1073  *      XXX: Knows its calling circumstances in that if called with ctxt
1074  *      an actual target, it will only search that context since only
1075  *      a local variable could be being appended to. This is actually
1076  *      a big win and must be tolerated.
1077  */
1078 void
1079 Var_Append(const char name[], const char val[], GNode *ctxt)
1080 {
1081         Var     *v;
1082         char    *n;
1083
1084         n = VarPossiblyExpand(name, ctxt);
1085         if (ctxt == VAR_GLOBAL) {
1086                 v = VarFindEnv(n, ctxt);
1087         } else {
1088                 v = VarFindOnly(n, ctxt);
1089         }
1090         if (v == NULL) {
1091                 VarAdd(n, val, ctxt);
1092         } else {
1093                 Buf_AddByte(v->val, ' ');
1094                 Buf_Append(v->val, val);
1095                 DEBUGF(VAR, ("%s:%s = %s\n", ctxt->name, n, Buf_Data(v->val)));
1096         }
1097         free(n);
1098 }
1099
1100 /**
1101  * Return the value of the named variable in the given context
1102  *
1103  * Results:
1104  *      The value if the variable exists, NULL if it doesn't.
1105  */
1106 const char *
1107 Var_Value(const char name[], GNode *ctxt)
1108 {
1109         Var     *v;
1110         char    *n;
1111
1112         n = VarPossiblyExpand(name, ctxt);
1113         v = VarFindAny(n, ctxt);
1114         free(n);
1115         if (v == NULL) {
1116                 return (NULL);
1117         } else {
1118                 return (Buf_Data(v->val));
1119         }
1120 }
1121
1122 /**
1123  * Modify each of the words of the passed string using the given
1124  * function. Used to implement all modifiers.
1125  *
1126  * Results:
1127  *      A string of all the words modified appropriately.
1128  */
1129 static char *
1130 VarModify(const char str[], VarModifyProc *modProc, void *datum)
1131 {
1132         ArgArray        aa;
1133         Buffer          *buf;           /* Buffer for the new string */
1134         int             i;
1135         bool            addSpace;       /*
1136                                          * true if need to add a space to
1137                                          * the buffer before adding the
1138                                          * trimmed word
1139                                          */
1140
1141         brk_string(&aa, str, false);
1142
1143         addSpace = false;
1144         buf = Buf_Init(0);
1145         for (i = 1; i < aa.argc; i++)
1146                 addSpace = (*modProc)(aa.argv[i], addSpace, buf, datum);
1147
1148         ArgArray_Done(&aa);
1149         return (Buf_Peel(buf));
1150 }
1151
1152 /**
1153  * Sort the words in the string.
1154  *
1155  * Input:
1156  *      str             String whose words should be sorted
1157  *      cmp             A comparison function to control the ordering
1158  *
1159  * Results:
1160  *      A string containing the words sorted
1161  */
1162 static char *
1163 VarSortWords(const char str[], int (*cmp)(const void *, const void *))
1164 {
1165         ArgArray        aa;
1166         Buffer          *buf;
1167         int             i;
1168
1169         brk_string(&aa, str, false);
1170         qsort(aa.argv + 1, aa.argc - 1, sizeof(char *), cmp);
1171
1172         buf = Buf_Init(0);
1173         for (i = 1; i < aa.argc; i++) {
1174                 Buf_Append(buf, aa.argv[i]);
1175                 Buf_AddByte(buf, ((i < aa.argc - 1) ? ' ' : '\0'));
1176         }
1177
1178         ArgArray_Done(&aa);
1179         return (Buf_Peel(buf));
1180 }
1181
1182 static int
1183 SortIncreasing(const void *l, const void *r)
1184 {
1185
1186         return (strcmp(*(const char* const*)l, *(const char* const*)r));
1187 }
1188
1189 /**
1190  * Pass through the tstr looking for 1) escaped delimiters,
1191  * '$'s and backslashes (place the escaped character in
1192  * uninterpreted) and 2) unescaped $'s that aren't before
1193  * the delimiter (expand the variable substitution).
1194  * Return the expanded string or NULL if the delimiter was missing
1195  * If pattern is specified, handle escaped ampersands, and replace
1196  * unescaped ampersands with the lhs of the pattern.
1197  *
1198  * Results:
1199  *      A string of all the words modified appropriately.
1200  *      If length is specified, return the string length of the buffer
1201  *      If flags is specified and the last character of the pattern is a
1202  *      $ set the VAR_MATCH_END bit of flags.
1203  */
1204 static Buffer *
1205 VarGetPattern(VarParser *vp, int delim, int *flags, VarPattern *patt)
1206 {
1207         Buffer          *buf;
1208
1209         buf = Buf_Init(0);
1210
1211         /*
1212          * Skim through until the matching delimiter is found; pick up
1213          * variable substitutions on the way. Also allow backslashes to quote
1214          * the delimiter, $, and \, but don't touch other backslashes.
1215          */
1216         while (*vp->ptr != '\0') {
1217                 if (*vp->ptr == delim) {
1218                         return (buf);
1219
1220                 } else if ((vp->ptr[0] == '\\') &&
1221                     ((vp->ptr[1] == delim) ||
1222                      (vp->ptr[1] == '\\') ||
1223                      (vp->ptr[1] == '$') ||
1224                      (vp->ptr[1] == '&' && patt != NULL))) {
1225                         vp->ptr++;              /* consume backslash */
1226                         Buf_AddByte(buf, vp->ptr[0]);
1227                         vp->ptr++;
1228
1229                 } else if (vp->ptr[0] == '$') {
1230                         if (vp->ptr[1] == delim) {
1231                                 if (flags == NULL) {
1232                                         Buf_AddByte(buf, vp->ptr[0]);
1233                                         vp->ptr++;
1234                                 } else {
1235                                         /*
1236                                          * Unescaped $ at end of patt =>
1237                                          * anchor patt at end.
1238                                          */
1239                                         *flags |= VAR_MATCH_END;
1240                                         vp->ptr++;
1241                                 }
1242                         } else {
1243                                 VarParser       subvp = {
1244                                         vp->ptr,
1245                                         vp->ptr,
1246                                         vp->ctxt,
1247                                         vp->err,
1248                                         vp->execute
1249                                 };
1250                                 char   *rval;
1251                                 bool rfree;
1252
1253                                 /*
1254                                  * If unescaped dollar sign not
1255                                  * before the delimiter, assume it's
1256                                  * a variable substitution and
1257                                  * recurse.
1258                                  */
1259                                 rval = VarParse(&subvp, &rfree);
1260                                 Buf_Append(buf, rval);
1261                                 if (rfree)
1262                                         free(rval);
1263                                 vp->ptr = subvp.ptr;
1264                         }
1265                 } else if (vp->ptr[0] == '&' && patt != NULL) {
1266                         Buf_AppendBuf(buf, patt->lhs);
1267                         vp->ptr++;
1268                 } else {
1269                         Buf_AddByte(buf, vp->ptr[0]);
1270                         vp->ptr++;
1271                 }
1272         }
1273
1274         Buf_Destroy(buf, true);
1275         return (NULL);
1276 }
1277
1278 /**
1279  * Make sure this variable is fully expanded.
1280  */
1281 static char *
1282 VarExpand(Var *v, VarParser *vp)
1283 {
1284         char    *value;
1285         char    *result;
1286
1287         if (v->flags & VAR_IN_USE) {
1288                 Fatal("Variable %s is recursive.", v->name);
1289                 /* NOTREACHED */
1290         }
1291
1292         v->flags |= VAR_IN_USE;
1293
1294         /*
1295          * Before doing any modification, we have to make sure the
1296          * value has been fully expanded. If it looks like recursion
1297          * might be necessary (there's a dollar sign somewhere in the
1298          * variable's value) we just call Var_Subst to do any other
1299          * substitutions that are necessary. Note that the value
1300          * returned by Var_Subst will have been
1301          * dynamically-allocated, so it will need freeing when we
1302          * return.
1303          */
1304         value = Buf_Data(v->val);
1305         if (strchr(value, '$') == NULL) {
1306                 result = strdup(value);
1307         } else {
1308                 Buffer  *buf;
1309
1310                 buf = Var_Subst(value, vp->ctxt, vp->err);
1311                 result = Buf_Peel(buf);
1312         }
1313
1314         v->flags &= ~VAR_IN_USE;
1315
1316         return (result);
1317 }
1318
1319 /**
1320  * Select only those words in value that match the modifier.
1321  */
1322 static char *
1323 modifier_M(VarParser *vp, const char value[], char endc)
1324 {
1325         char    *patt;
1326         char    *ptr;
1327         char    *newValue;
1328         char    modifier;
1329
1330         modifier = vp->ptr[0];
1331         vp->ptr++;      /* consume 'M' or 'N' */
1332
1333         /*
1334          * Compress the \:'s out of the pattern, so allocate enough
1335          * room to hold the uncompressed pattern and compress the
1336          * pattern into that space.
1337          */
1338         patt = estrdup(vp->ptr);
1339         ptr = patt;
1340         while (vp->ptr[0] != '\0') {
1341                 if (vp->ptr[0] == endc || vp->ptr[0] == ':') {
1342                         break;
1343                 }
1344                 if (vp->ptr[0] == '\\' &&
1345                     (vp->ptr[1] == endc || vp->ptr[1] == ':')) {
1346                         vp->ptr++;      /* consume backslash */
1347                 }
1348                 *ptr = vp->ptr[0];
1349                 ptr++;
1350                 vp->ptr++;
1351         }
1352         *ptr = '\0';
1353
1354         if (modifier == 'M') {
1355                 newValue = VarModify(value, VarMatch, patt);
1356         } else {
1357                 newValue = VarModify(value, VarNoMatch, patt);
1358         }
1359         free(patt);
1360
1361         return (newValue);
1362 }
1363
1364 /**
1365  * Substitute the replacement string for the pattern.  The substitution
1366  * is applied to each word in value.
1367  */
1368 static char *
1369 modifier_S(VarParser *vp, const char value[], Var *v)
1370 {
1371         VarPattern      patt;
1372         char            delim;
1373         char            *newValue;
1374
1375         patt.flags = 0;
1376
1377         vp->ptr++;              /* consume 'S' */
1378
1379         delim = *vp->ptr;       /* used to find end of pattern */
1380         vp->ptr++;              /* consume 1st delim */
1381
1382         /*
1383          * If pattern begins with '^', it is anchored to the start of the
1384          * word -- skip over it and flag pattern.
1385          */
1386         if (*vp->ptr == '^') {
1387                 patt.flags |= VAR_MATCH_START;
1388                 vp->ptr++;
1389         }
1390
1391         patt.lhs = VarGetPattern(vp, delim, &patt.flags, NULL);
1392         if (patt.lhs == NULL) {
1393                 /*
1394                  * LHS didn't end with the delim, complain and exit.
1395                  */
1396                 Fatal("Unclosed substitution for %s (%c missing)",
1397                     v->name, delim);
1398         }
1399
1400         vp->ptr++;      /* consume 2nd delim */
1401
1402         patt.rhs = VarGetPattern(vp, delim, NULL, &patt);
1403         if (patt.rhs == NULL) {
1404                 /*
1405                  * RHS didn't end with the delim, complain and exit.
1406                  */
1407                 Fatal("Unclosed substitution for %s (%c missing)",
1408                     v->name, delim);
1409         }
1410
1411         vp->ptr++;      /* consume last delim */
1412
1413         /*
1414          * Check for global substitution. If 'g' after the final delimiter,
1415          * substitution is global and is marked that way.
1416          */
1417         if (vp->ptr[0] == 'g') {
1418                 patt.flags |= VAR_SUB_GLOBAL;
1419                 vp->ptr++;
1420         }
1421
1422         /*
1423          * Global substitution of the empty string causes an infinite number
1424          * of matches, unless anchored by '^' (start of string) or '$' (end
1425          * of string). Catch the infinite substitution here. Note that flags
1426          * can only contain the 3 bits we're interested in so we don't have
1427          * to mask unrelated bits. We can test for equality.
1428          */
1429         if (Buf_Size(patt.lhs) == 0 && patt.flags == VAR_SUB_GLOBAL)
1430                 Fatal("Global substitution of the empty string");
1431
1432         newValue = VarModify(value, VarSubstitute, &patt);
1433
1434         /*
1435          * Free the two strings.
1436          */
1437         free(patt.lhs);
1438         free(patt.rhs);
1439
1440         return (newValue);
1441 }
1442
1443 static char *
1444 modifier_C(VarParser *vp, char value[], Var *v)
1445 {
1446         VarPattern      patt;
1447         char            delim;
1448         int             error;
1449         char            *newValue;
1450
1451         patt.flags = 0;
1452
1453         vp->ptr++;              /* consume 'C' */
1454
1455         delim = *vp->ptr;       /* delimiter between sections */
1456
1457         vp->ptr++;              /* consume 1st delim */
1458
1459         patt.lhs = VarGetPattern(vp, delim, NULL, NULL);
1460         if (patt.lhs == NULL) {
1461                 Fatal("Unclosed substitution for %s (%c missing)",
1462                      v->name, delim);
1463         }
1464
1465         vp->ptr++;              /* consume 2st delim */
1466
1467         patt.rhs = VarGetPattern(vp, delim, NULL, NULL);
1468         if (patt.rhs == NULL) {
1469                 Fatal("Unclosed substitution for %s (%c missing)",
1470                      v->name, delim);
1471         }
1472
1473         vp->ptr++;              /* consume last delim */
1474
1475         switch (*vp->ptr) {
1476         case 'g':
1477                 patt.flags |= VAR_SUB_GLOBAL;
1478                 vp->ptr++;              /* consume 'g' */
1479                 break;
1480         case '1':
1481                 patt.flags |= VAR_SUB_ONE;
1482                 vp->ptr++;              /* consume '1' */
1483                 break;
1484         default:
1485                 break;
1486         }
1487
1488         error = regcomp(&patt.re, Buf_Data(patt.lhs), REG_EXTENDED);
1489         if (error) {
1490                 VarREError(error, &patt.re, "RE substitution error");
1491                 free(patt.rhs);
1492                 free(patt.lhs);
1493                 return (var_Error);
1494         }
1495
1496         patt.nsub = patt.re.re_nsub + 1;
1497         if (patt.nsub < 1)
1498                 patt.nsub = 1;
1499         if (patt.nsub > 10)
1500                 patt.nsub = 10;
1501         patt.matches = emalloc(patt.nsub * sizeof(regmatch_t));
1502
1503         newValue = VarModify(value, VarRESubstitute, &patt);
1504
1505         regfree(&patt.re);
1506         free(patt.matches);
1507         free(patt.rhs);
1508         free(patt.lhs);
1509
1510         return (newValue);
1511 }
1512
1513 static char *
1514 sysVvarsub(VarParser *vp, char startc, Var *v, const char value[])
1515 {
1516         /*
1517          * This can either be a bogus modifier or a System-V substitution
1518          * command.
1519          */
1520         char            endc;
1521         VarPattern      patt;
1522         bool            eqFound;
1523         int             cnt;
1524         char            *newStr;
1525         const char      *cp;
1526
1527         endc = (startc == OPEN_PAREN) ? CLOSE_PAREN : CLOSE_BRACE;
1528
1529         patt.flags = 0;
1530
1531         /*
1532          * First we make a pass through the string trying to verify it is a
1533          * SYSV-make-style translation: it must be: <string1>=<string2>)
1534          */
1535         eqFound = false;
1536         cp = vp->ptr;
1537         cnt = 1;
1538         while (*cp != '\0' && cnt) {
1539                 if (*cp == '=') {
1540                         eqFound = true;
1541                         /* continue looking for endc */
1542                 } else if (*cp == endc)
1543                         cnt--;
1544                 else if (*cp == startc)
1545                         cnt++;
1546                 if (cnt)
1547                         cp++;
1548         }
1549
1550         if (*cp == endc && eqFound) {
1551                 /*
1552                  * Now we break this sucker into the lhs and rhs.
1553                  */
1554                 patt.lhs = VarGetPattern(vp, '=', &patt.flags, NULL);
1555                 if (patt.lhs == NULL) {
1556                         Fatal("Unclosed substitution for %s (%c missing)",
1557                               v->name, '=');
1558                 }
1559                 vp->ptr++;      /* consume '=' */
1560
1561                 patt.rhs = VarGetPattern(vp, endc, NULL, &patt);
1562                 if (patt.rhs == NULL) {
1563                         Fatal("Unclosed substitution for %s (%c missing)",
1564                               v->name, endc);
1565                 }
1566
1567                 /*
1568                  * SYSV modifications happen through the whole string. Note
1569                  * the pattern is anchored at the end.
1570                  */
1571                 newStr = VarModify(value, VarSYSVMatch, &patt);
1572
1573                 free(patt.lhs);
1574                 free(patt.rhs);
1575         } else {
1576                 Error("Unknown modifier '%c'\n", *vp->ptr);
1577                 vp->ptr++;
1578                 while (*vp->ptr != '\0') {
1579                         if (*vp->ptr == endc && *vp->ptr == ':') {
1580                                 break;
1581                         }
1582                         vp->ptr++;
1583                 }
1584                 newStr = var_Error;
1585         }
1586
1587         return (newStr);
1588 }
1589
1590 /**
1591  * Quote shell meta-characters in the string
1592  *
1593  * Results:
1594  *      The quoted string
1595  */
1596 static char *
1597 Var_Quote(const char str[])
1598 {
1599         Buffer *buf;
1600         /* This should cover most shells :-( */
1601         static char meta[] = "\n \t'`\";&<>()|*?{}[]\\$!#^~";
1602
1603         buf = Buf_Init(MAKE_BSIZE);
1604         for (; *str; str++) {
1605                 if (strchr(meta, *str) != NULL)
1606                         Buf_AddByte(buf, '\\');
1607                 Buf_AddByte(buf, *str);
1608         }
1609
1610         return (Buf_Peel(buf));
1611 }
1612
1613
1614 /*
1615  * Now we need to apply any modifiers the user wants applied.
1616  * These are:
1617  *      :M<pattern>
1618  *              words which match the given <pattern>.
1619  *              <pattern> is of the standard file
1620  *              wildcarding form.
1621  *      :S<d><pat1><d><pat2><d>[g]
1622  *              Substitute <pat2> for <pat1> in the value
1623  *      :C<d><pat1><d><pat2><d>[g]
1624  *              Substitute <pat2> for regex <pat1> in the value
1625  *      :H      Substitute the head of each word
1626  *      :T      Substitute the tail of each word
1627  *      :E      Substitute the extension (minus '.') of
1628  *              each word
1629  *      :R      Substitute the root of each word
1630  *              (pathname minus the suffix).
1631  *      :lhs=rhs
1632  *              Like :S, but the rhs goes to the end of
1633  *              the invocation.
1634  *      :U      Converts variable to upper-case.
1635  *      :L      Converts variable to lower-case.
1636  *
1637  * XXXHB update this comment or remove it and point to the man page.
1638  */
1639 static char *
1640 ParseModifier(VarParser *vp, char startc, Var *v, bool *freeResult)
1641 {
1642         char    *value;
1643         char    endc;
1644
1645         value = VarExpand(v, vp);
1646         *freeResult = true;
1647
1648         endc = (startc == OPEN_PAREN) ? CLOSE_PAREN : CLOSE_BRACE;
1649
1650         vp->ptr++;      /* consume first colon */
1651
1652         while (*vp->ptr != '\0') {
1653                 char    *newStr;        /* New value to return */
1654
1655                 if (*vp->ptr == endc) {
1656                         return (value);
1657                 }
1658
1659                 DEBUGF(VAR, ("Applying :%c to \"%s\"\n", *vp->ptr, value));
1660                 switch (*vp->ptr) {
1661                 case 'N':
1662                 case 'M':
1663                         newStr = modifier_M(vp, value, endc);
1664                         break;
1665                 case 'S':
1666                         newStr = modifier_S(vp, value, v);
1667                         break;
1668                 case 'C':
1669                         newStr = modifier_C(vp, value, v);
1670                         break;
1671                 default:
1672                         if (vp->ptr[1] != endc && vp->ptr[1] != ':') {
1673 #ifdef SUNSHCMD
1674                                 if ((vp->ptr[0] == 's') &&
1675                                     (vp->ptr[1] == 'h') &&
1676                                     (vp->ptr[2] == endc || vp->ptr[2] == ':')) {
1677                                         const char      *error;
1678
1679                                         if (vp->execute) {
1680                                                 newStr = Buf_Peel(
1681                                                     Cmd_Exec(value, &error));
1682                                         } else {
1683                                                 newStr = estrdup("");
1684                                         }
1685
1686                                         if (error)
1687                                                 Error(error, value);
1688                                         vp->ptr += 2;
1689                                 } else
1690 #endif
1691                                 {
1692                                         newStr = sysVvarsub(vp, startc, v, value);
1693                                 }
1694                                 break;
1695                         }
1696
1697                         switch (vp->ptr[0]) {
1698                         case 'L':
1699                                 {
1700                                 const char      *cp;
1701                                 Buffer          *buf;
1702                                 buf = Buf_Init(MAKE_BSIZE);
1703                                 for (cp = value; *cp; cp++)
1704                                         Buf_AddByte(buf, tolower((unsigned char)*cp));
1705
1706                                 newStr = Buf_Peel(buf);
1707
1708                                 vp->ptr++;
1709                                 break;
1710                                 }
1711                         case 'O':
1712                                 newStr = VarSortWords(value, SortIncreasing);
1713                                 vp->ptr++;
1714                                 break;
1715                         case 'Q':
1716                                 newStr = Var_Quote(value);
1717                                 vp->ptr++;
1718                                 break;
1719                         case 'T':
1720                                 newStr = VarModify(value, VarTail, NULL);
1721                                 vp->ptr++;
1722                                 break;
1723                         case 'U':
1724                                 {
1725                                 const char      *cp;
1726                                 Buffer          *buf;
1727                                 buf = Buf_Init(MAKE_BSIZE);
1728                                 for (cp = value; *cp; cp++)
1729                                         Buf_AddByte(buf, toupper((unsigned char)*cp));
1730
1731                                 newStr = Buf_Peel(buf);
1732
1733                                 vp->ptr++;
1734                                 break;
1735                                 }
1736                         case 'H':
1737                                 newStr = VarModify(value, VarHead, NULL);
1738                                 vp->ptr++;
1739                                 break;
1740                         case 'E':
1741                                 newStr = VarModify(value, VarSuffix, NULL);
1742                                 vp->ptr++;
1743                                 break;
1744                         case 'R':
1745                                 newStr = VarModify(value, VarRoot, NULL);
1746                                 vp->ptr++;
1747                                 break;
1748                         default:
1749                                 newStr = sysVvarsub(vp, startc, v, value);
1750                                 break;
1751                         }
1752                         break;
1753                 }
1754
1755                 DEBUGF(VAR, ("Result is \"%s\"\n", newStr));
1756                 if (*freeResult) {
1757                         free(value);
1758                 }
1759
1760                 value = newStr;
1761                 *freeResult = (value == var_Error) ? false : true;
1762
1763                 if (vp->ptr[0] == ':') {
1764                         vp->ptr++;      /* consume colon */
1765                 }
1766         }
1767
1768         return (value);
1769 }
1770
1771 static char *
1772 ParseRestModifier(VarParser *vp, char startc, Buffer *buf, bool *freeResult)
1773 {
1774         const char      *vname;
1775         size_t          vlen;
1776         Var             *v;
1777         char            *value;
1778
1779         vname = Buf_Data(buf);
1780         vlen = Buf_Size(buf);
1781
1782         v = VarFindAny(vname, vp->ctxt);
1783         if (v != NULL) {
1784                 value = ParseModifier(vp, startc, v, freeResult);
1785                 return (value);
1786         }
1787
1788         if ((vp->ctxt == VAR_CMD) || (vp->ctxt == VAR_GLOBAL)) {
1789                 size_t  consumed;
1790                 /*
1791                  * Still need to get to the end of the variable
1792                  * specification, so kludge up a Var structure for the
1793                  * modifications
1794                  */
1795                 v = VarCreate(vname, NULL, VAR_JUNK);
1796                 value = ParseModifier(vp, startc, v, freeResult);
1797                 if (*freeResult) {
1798                         free(value);
1799                 }
1800                 VarDestroy(v, true);
1801
1802                 consumed = vp->ptr - vp->input + 1;
1803                 /*
1804                  * If substituting a local variable in a non-local context,
1805                  * assume it's for dynamic source stuff. We have to handle
1806                  * this specially and return the longhand for the variable
1807                  * with the dollar sign escaped so it makes it back to the
1808                  * caller. Only four of the local variables are treated
1809                  * specially as they are the only four that will be set when
1810                  * dynamic sources are expanded.
1811                  */
1812                 if (vlen == 1 ||
1813                     (vlen == 2 && (vname[1] == 'F' || vname[1] == 'D'))) {
1814                         if (strchr("!%*@", vname[0]) != NULL) {
1815                                 value = emalloc(consumed + 1);
1816                                 strncpy(value, vp->input, consumed);
1817                                 value[consumed] = '\0';
1818
1819                                 *freeResult = true;
1820                                 return (value);
1821                         }
1822                 }
1823                 if (vlen > 2 &&
1824                     vname[0] == '.' &&
1825                     isupper((unsigned char)vname[1])) {
1826                         if ((strncmp(vname, ".TARGET", vlen - 1) == 0) ||
1827                             (strncmp(vname, ".ARCHIVE", vlen - 1) == 0) ||
1828                             (strncmp(vname, ".PREFIX", vlen - 1) == 0) ||
1829                             (strncmp(vname, ".MEMBER", vlen - 1) == 0)) {
1830                                 value = emalloc(consumed + 1);
1831                                 strncpy(value, vp->input, consumed);
1832                                 value[consumed] = '\0';
1833
1834                                 *freeResult = true;
1835                                 return (value);
1836                         }
1837                 }
1838
1839                 *freeResult = false;
1840                 return (vp->err ? var_Error : varNoError);
1841         } else {
1842                 /*
1843                  * Check for D and F forms of local variables since we're in
1844                  * a local context and the name is the right length.
1845                  */
1846                 if (vlen == 2 &&
1847                     (vname[1] == 'F' || vname[1] == 'D') &&
1848                     (strchr("!%*<>@", vname[0]) != NULL)) {
1849                         char    name[2];
1850
1851                         name[0] = vname[0];
1852                         name[1] = '\0';
1853
1854                         v = VarFindOnly(name, vp->ctxt);
1855                         if (v != NULL) {
1856                                 value = ParseModifier(vp, startc, v, freeResult);
1857                                 return (value);
1858                         }
1859                 }
1860
1861                 /*
1862                  * Still need to get to the end of the variable
1863                  * specification, so kludge up a Var structure for the
1864                  * modifications
1865                  */
1866                 v = VarCreate(vname, NULL, VAR_JUNK);
1867                 value = ParseModifier(vp, startc, v, freeResult);
1868                 if (*freeResult) {
1869                         free(value);
1870                 }
1871                 VarDestroy(v, true);
1872
1873                 *freeResult = false;
1874                 return (vp->err ? var_Error : varNoError);
1875         }
1876 }
1877
1878 static char *
1879 ParseRestEnd(VarParser *vp, Buffer *buf, bool *freeResult)
1880 {
1881         const char      *vname;
1882         size_t          vlen;
1883         Var             *v;
1884         char            *value;
1885
1886         vname = Buf_Data(buf);
1887         vlen = Buf_Size(buf);
1888
1889         v = VarFindAny(vname, vp->ctxt);
1890         if (v != NULL) {
1891                 value = VarExpand(v, vp);
1892                 *freeResult = true;
1893                 return (value);
1894         }
1895
1896         if ((vp->ctxt == VAR_CMD) || (vp->ctxt == VAR_GLOBAL)) {
1897                 size_t  consumed = vp->ptr - vp->input + 1;
1898
1899                 /*
1900                  * If substituting a local variable in a non-local context,
1901                  * assume it's for dynamic source stuff. We have to handle
1902                  * this specially and return the longhand for the variable
1903                  * with the dollar sign escaped so it makes it back to the
1904                  * caller. Only four of the local variables are treated
1905                  * specially as they are the only four that will be set when
1906                  * dynamic sources are expanded.
1907                  */
1908                 if (vlen == 1 ||
1909                     (vlen == 2 && (vname[1] == 'F' || vname[1] == 'D'))) {
1910                         if (strchr("!%*@", vname[0]) != NULL) {
1911                                 value = emalloc(consumed + 1);
1912                                 strncpy(value, vp->input, consumed);
1913                                 value[consumed] = '\0';
1914
1915                                 *freeResult = true;
1916                                 return (value);
1917                         }
1918                 }
1919                 if (vlen > 2 &&
1920                     vname[0] == '.' &&
1921                     isupper((unsigned char)vname[1])) {
1922                         if ((strncmp(vname, ".TARGET", vlen - 1) == 0) ||
1923                             (strncmp(vname, ".ARCHIVE", vlen - 1) == 0) ||
1924                             (strncmp(vname, ".PREFIX", vlen - 1) == 0) ||
1925                             (strncmp(vname, ".MEMBER", vlen - 1) == 0)) {
1926                                 value = emalloc(consumed + 1);
1927                                 strncpy(value, vp->input, consumed);
1928                                 value[consumed] = '\0';
1929
1930                                 *freeResult = true;
1931                                 return (value);
1932                         }
1933                 }
1934         } else {
1935                 /*
1936                  * Check for D and F forms of local variables since we're in
1937                  * a local context and the name is the right length.
1938                  */
1939                 if (vlen == 2 &&
1940                     (vname[1] == 'F' || vname[1] == 'D') &&
1941                     (strchr("!%*<>@", vname[0]) != NULL)) {
1942                         char    name[2];
1943
1944                         name[0] = vname[0];
1945                         name[1] = '\0';
1946
1947                         v = VarFindOnly(name, vp->ctxt);
1948                         if (v != NULL) {
1949                                 char    *val;
1950                                 /*
1951                                  * No need for nested expansion or anything,
1952                                  * as we're the only one who sets these
1953                                  * things and we sure don't put nested
1954                                  * invocations in them...
1955                                  */
1956                                 val = Buf_Data(v->val);
1957
1958                                 if (vname[1] == 'D') {
1959                                         val = VarModify(val, VarHead, NULL);
1960                                 } else {
1961                                         val = VarModify(val, VarTail, NULL);
1962                                 }
1963
1964                                 *freeResult = true;
1965                                 return (val);
1966                         }
1967                 }
1968         }
1969
1970         *freeResult = false;
1971         return (vp->err ? var_Error : varNoError);
1972 }
1973
1974 /**
1975  * Parse a multi letter variable name, and return it's value.
1976  */
1977 static char *
1978 VarParseLong(VarParser *vp, bool *freeResult)
1979 {
1980         Buffer          *buf;
1981         char            startc;
1982         char            endc;
1983         char            *value;
1984
1985         buf = Buf_Init(MAKE_BSIZE);
1986
1987         startc = vp->ptr[0];
1988         vp->ptr++;              /* consume opening paren or brace */
1989
1990         endc = (startc == OPEN_PAREN) ? CLOSE_PAREN : CLOSE_BRACE;
1991
1992         /*
1993          * Process characters until we reach an end character or a colon,
1994          * replacing embedded variables as we go.
1995          */
1996         while (*vp->ptr != '\0') {
1997                 if (*vp->ptr == endc) {
1998                         value = ParseRestEnd(vp, buf, freeResult);
1999                         vp->ptr++;      /* consume closing paren or brace */
2000                         Buf_Destroy(buf, true);
2001                         return (value);
2002
2003                 } else if (*vp->ptr == ':') {
2004                         value = ParseRestModifier(vp, startc, buf, freeResult);
2005                         vp->ptr++;      /* consume closing paren or brace */
2006                         Buf_Destroy(buf, true);
2007                         return (value);
2008
2009                 } else if (*vp->ptr == '$') {
2010                         VarParser       subvp = {
2011                                 vp->ptr,
2012                                 vp->ptr,
2013                                 vp->ctxt,
2014                                 vp->err,
2015                                 vp->execute
2016                         };
2017                         char    *rval;
2018                         bool    rfree;
2019
2020                         rval = VarParse(&subvp, &rfree);
2021                         if (rval == var_Error) {
2022                                 Fatal("Error expanding embedded variable.");
2023                         }
2024                         Buf_Append(buf, rval);
2025                         if (rfree)
2026                                 free(rval);
2027                         vp->ptr = subvp.ptr;
2028                 } else {
2029                         Buf_AddByte(buf, *vp->ptr);
2030                         vp->ptr++;
2031                 }
2032         }
2033
2034         /* If we did not find the end character, return var_Error */
2035         Buf_Destroy(buf, true);
2036         *freeResult = false;
2037         return (var_Error);
2038 }
2039
2040 /**
2041  * Parse a single letter variable name, and return it's value.
2042  */
2043 static char *
2044 VarParseShort(VarParser *vp, bool *freeResult)
2045 {
2046         char    vname[2];
2047         Var     *v;
2048         char    *value;
2049
2050         vname[0] = vp->ptr[0];
2051         vname[1] = '\0';
2052
2053         vp->ptr++;      /* consume single letter */
2054
2055         v = VarFindAny(vname, vp->ctxt);
2056         if (v != NULL) {
2057                 value = VarExpand(v, vp);
2058                 *freeResult = true;
2059                 return (value);
2060         }
2061
2062         /*
2063          * If substituting a local variable in a non-local context, assume
2064          * it's for dynamic source stuff. We have to handle this specially
2065          * and return the longhand for the variable with the dollar sign
2066          * escaped so it makes it back to the caller. Only four of the local
2067          * variables are treated specially as they are the only four that
2068          * will be set when dynamic sources are expanded.
2069          */
2070         if ((vp->ctxt == VAR_CMD) || (vp->ctxt == VAR_GLOBAL)) {
2071
2072                 /* XXX: It looks like $% and $! are reversed here */
2073                 switch (vname[0]) {
2074                 case '@':
2075                         *freeResult = true;
2076                         return (estrdup("$(.TARGET)"));
2077                 case '%':
2078                         *freeResult = true;
2079                         return (estrdup("$(.ARCHIVE)"));
2080                 case '*':
2081                         *freeResult = true;
2082                         return (estrdup("$(.PREFIX)"));
2083                 case '!':
2084                         *freeResult = true;
2085                         return (estrdup("$(.MEMBER)"));
2086                 default:
2087                         *freeResult = false;
2088                         return (vp->err ? var_Error : varNoError);
2089                 }
2090         }
2091
2092         /* Variable name was not found. */
2093         *freeResult = false;
2094         return (vp->err ? var_Error : varNoError);
2095 }
2096
2097 static char *
2098 VarParse(VarParser *vp, bool *freeResult)
2099 {
2100
2101         vp->ptr++;      /* consume '$' or last letter of conditional */
2102
2103         if (vp->ptr[0] == '\0') {
2104                 /* Error, there is only a dollar sign in the input string. */
2105                 *freeResult = false;
2106                 return (vp->err ? var_Error : varNoError);
2107
2108         } else if (vp->ptr[0] == OPEN_PAREN || vp->ptr[0] == OPEN_BRACE) {
2109                 /* multi letter variable name */
2110                 return (VarParseLong(vp, freeResult));
2111
2112         } else {
2113                 /* single letter variable name */
2114                 return (VarParseShort(vp, freeResult));
2115         }
2116 }
2117
2118 /**
2119  * Given the start of a variable invocation, extract the variable
2120  * name and find its value, then modify it according to the
2121  * specification.
2122  *
2123  * Results:
2124  *      The value of the variable or var_Error if the specification
2125  *      is invalid.  The number of characters in the specification
2126  *      is placed in the variable pointed to by consumed.  (for
2127  *      invalid specifications, this is just 2 to skip the '$' and
2128  *      the following letter, or 1 if '$' was the last character
2129  *      in the string).  A bool in *freeResult telling whether the
2130  *      returned string should be freed by the caller.
2131  */
2132 char *
2133 Var_Parse(const char input[], GNode *ctxt, bool err,
2134         size_t *consumed, bool *freeResult)
2135 {
2136         VarParser       vp = {
2137                 input,
2138                 input,
2139                 ctxt,
2140                 err,
2141                 true
2142         };
2143         char            *value;
2144
2145         value = VarParse(&vp, freeResult);
2146         *consumed += vp.ptr - vp.input;
2147         return (value);
2148 }
2149
2150 /*
2151  * Given the start of a variable invocation, determine the length
2152  * of the specification.
2153  *
2154  * Results:
2155  *      The number of characters in the specification.  For invalid
2156  *      specifications, this is just 2 to skip the '$' and the
2157  *      following letter, or 1 if '$' was the last character in the
2158  *      string.
2159  */
2160 size_t
2161 Var_Match(const char input[], GNode *ctxt)
2162 {
2163         VarParser       vp = {
2164                 input,
2165                 input,
2166                 ctxt,
2167                 false,
2168                 false
2169         };
2170         char            *value;
2171         bool            freeResult;
2172
2173         value = VarParse(&vp, &freeResult);
2174         if (freeResult) {
2175                 free(value);
2176         }
2177         return (vp.ptr - vp.input);
2178 }
2179
2180 static int
2181 match_var(const char str[], const char var[])
2182 {
2183         const char      *start = str;
2184         size_t          len;
2185
2186         str++;                  /* consume '$' */
2187
2188         if (str[0] == OPEN_PAREN || str[0] == OPEN_BRACE) {
2189                 str++;          /* consume opening paren or brace */
2190
2191                 while (str[0] != '\0') {
2192                         if (str[0] == '$') {
2193                                 /*
2194                                  * A variable inside the variable. We cannot
2195                                  * expand the external variable yet.
2196                                  */
2197                                 return (str - start);
2198                         } else if (str[0] == ':' ||
2199                                    str[0] == CLOSE_PAREN ||
2200                                    str[0] == CLOSE_BRACE) {
2201                                 len = str - (start + 2);
2202
2203                                 if (var[len] == '\0' && strncmp(var, start + 2, len) == 0) {
2204                                         return (0);     /* match */
2205                                 } else {
2206                                         /*
2207                                          * Not the variable we want to
2208                                          * expand.
2209                                          */
2210                                         return (str - start);
2211                                 }
2212                         } else {
2213                                 ++str;
2214                         }
2215                 }
2216                 return (str - start);
2217         } else {
2218                 /* Single letter variable name */
2219                 if (var[1] == '\0' && var[0] == str[0]) {
2220                         return (0);     /* match */
2221                 } else {
2222                         str++;  /* consume variable name */
2223                         return (str - start);
2224                 }
2225         }
2226 }
2227
2228 /**
2229  * Substitute for all variables in the given string in the given
2230  * context If err is true, Parse_Error will be called when an
2231  * undefined variable is encountered.
2232  *
2233  * Results:
2234  *      The resulting string.
2235  *
2236  * Side Effects:
2237  *      None. The old string must be freed by the caller
2238  */
2239 Buffer *
2240 Var_Subst(const char str[], GNode *ctxt, bool err)
2241 {
2242         bool    errorReported;
2243         Buffer *buf;            /* Buffer for forming things */
2244
2245         /*
2246          * Set true if an error has already been reported to prevent a
2247          * plethora of messages when recursing. XXXHB this comment sounds
2248          * wrong.
2249          */
2250         errorReported = false;
2251
2252         buf = Buf_Init(0);
2253         while (str[0] != '\0') {
2254                 if ((str[0] == '$') && (str[1] == '$')) {
2255                         /*
2256                          * A dollar sign may be escaped with another dollar
2257                          * sign.  In such a case, we skip over the escape
2258                          * character and store the dollar sign into the
2259                          * buffer directly.
2260                          */
2261                         str++;
2262                         Buf_AddByte(buf, str[0]);
2263                         str++;
2264
2265                 } else if (str[0] == '$') {
2266                         /* Variable invocation. */
2267                         VarParser subvp = {
2268                                 str,
2269                                 str,
2270                                 ctxt,
2271                                 err,
2272                                 true
2273                         };
2274                         char    *rval;
2275                         bool    rfree;
2276
2277                         rval = VarParse(&subvp, &rfree);
2278
2279                         /*
2280                          * When we come down here, val should either point to
2281                          * the value of this variable, suitably modified, or
2282                          * be NULL. Length should be the total length of the
2283                          * potential variable invocation (from $ to end
2284                          * character...)
2285                          */
2286                         if (rval == var_Error || rval == varNoError) {
2287                                 /*
2288                                  * If performing old-time variable
2289                                  * substitution, skip over the variable and
2290                                  * continue with the substitution. Otherwise,
2291                                  * store the dollar sign and advance str so
2292                                  * we continue with the string...
2293                                  */
2294                                 if (oldVars) {
2295                                         str = subvp.ptr;
2296                                 } else if (err) {
2297                                         /*
2298                                          * If variable is undefined, complain
2299                                          * and skip the variable. The
2300                                          * complaint will stop us from doing
2301                                          * anything when the file is parsed.
2302                                          */
2303                                         if (!errorReported) {
2304                                                 Parse_Error(PARSE_FATAL,
2305                                                             "Undefined variable \"%.*s\"", subvp.ptr - subvp.input, str);
2306                                         }
2307                                         errorReported = true;
2308                                         str = subvp.ptr;
2309                                 } else {
2310                                         Buf_AddByte(buf, str[0]);
2311                                         str++;
2312                                 }
2313                         } else {
2314                                 /*
2315                                  * Copy all the characters from the variable
2316                                  * value straight into the new string.
2317                                  */
2318                                 Buf_Append(buf, rval);
2319                                 if (rfree) {
2320                                         free(rval);
2321                                 }
2322                                 str = subvp.ptr;
2323                         }
2324                 } else {
2325                         Buf_AddByte(buf, str[0]);
2326                         str++;
2327                 }
2328         }
2329
2330         return (buf);
2331 }
2332
2333 /**
2334  * Substitute for all variables except if it is the same as 'var',
2335  * in the given string in the given context.  If err is true,
2336  * Parse_Error will be called when an undefined variable is
2337  * encountered.
2338  *
2339  * Results:
2340  *      The resulting string.
2341  *
2342  * Side Effects:
2343  *      None. The old string must be freed by the caller
2344  */
2345 Buffer *
2346 Var_SubstOnly(const char var[], const char str[], bool err)
2347 {
2348         GNode *ctxt = VAR_GLOBAL;
2349         bool    errorReported;
2350         Buffer  *buf;           /* Buffer for forming things */
2351
2352         /*
2353          * Set true if an error has already been reported to prevent a
2354          * plethora of messages when recursing. XXXHB this comment sounds
2355          * wrong.
2356          */
2357         errorReported = false;
2358
2359         buf = Buf_Init(0);
2360         while (str[0] != '\0') {
2361                 if (str[0] == '$') {
2362                         int     skip;
2363
2364                         skip = match_var(str, var);
2365                         if (skip > 0) {
2366                                 Buf_AddBytes(buf, skip, str);
2367                                 str += skip;
2368                         } else {
2369                                 /* Variable invocation. */
2370                                 VarParser       subvp = {
2371                                         str,
2372                                         str,
2373                                         ctxt,
2374                                         err,
2375                                         true
2376                                 };
2377                                 char    *rval;
2378                                 bool    rfree;
2379
2380                                 rval = VarParse(&subvp, &rfree);
2381
2382                                 /*
2383                                  * When we get down here, rval should either
2384                                  * point to the value of this variable, or be
2385                                  * NULL.
2386                                  */
2387                                 if (rval == var_Error || rval == varNoError) {
2388                                         /*
2389                                          * If performing old-time variable
2390                                          * substitution, skip over the
2391                                          * variable and continue with the
2392                                          * substitution. Otherwise, store the
2393                                          * dollar sign and advance str so we
2394                                          * continue with the string...
2395                                          */
2396                                         if (oldVars) {
2397                                                 str = subvp.ptr;
2398                                         } else if (err) {
2399                                                 /*
2400                                                  * If variable is undefined,
2401                                                  * complain and skip the
2402                                                  * variable. The complaint
2403                                                  * will stop us from doing
2404                                                  * anything when the file is
2405                                                  * parsed.
2406                                                  */
2407                                                 if (!errorReported) {
2408                                                         Parse_Error(PARSE_FATAL,
2409                                                                     "Undefined variable \"%.*s\"", subvp.ptr - subvp.input, str);
2410                                                 }
2411                                                 errorReported = true;
2412                                                 str = subvp.ptr;
2413                                         } else {
2414                                                 Buf_AddByte(buf, str[0]);
2415                                                 str++;
2416                                         }
2417                                 } else {
2418                                         /*
2419                                          * Copy all the characters from the
2420                                          * variable value straight into the
2421                                          * new string.
2422                                          */
2423                                         Buf_Append(buf, rval);
2424                                         if (rfree) {
2425                                                 free(rval);
2426                                         }
2427                                         str = subvp.ptr;
2428                                 }
2429                         }
2430                 } else {
2431                         Buf_AddByte(buf, str[0]);
2432                         str++;
2433                 }
2434         }
2435
2436         return (buf);
2437 }
2438
2439 /**
2440  * Initialize the module
2441  *
2442  * Side Effects:
2443  *      The VAR_CMD and VAR_GLOBAL contexts are created
2444  */
2445 void
2446 Var_Init(char **env)
2447 {
2448         char    **ptr;
2449
2450         VAR_CMD = Targ_NewGN("Command");
2451         VAR_ENV = Targ_NewGN("Environment");
2452         VAR_GLOBAL = Targ_NewGN("Global");
2453
2454         /*
2455          * Copy user environment variables into ENV context.
2456          */
2457         for (ptr = env; *ptr != NULL; ++ptr) {
2458                 char            *tmp = estrdup(*ptr);
2459                 const char      *name = tmp;
2460                 char            *sep = strchr(name, '=');
2461
2462                 if (sep != NULL) {
2463                         const char      *value = sep + 1;
2464
2465                         *sep = '\0';
2466                         VarAdd(name, value, VAR_ENV);
2467                 }
2468                 free(tmp);
2469         }
2470 }
2471
2472 /**
2473  * Print all variables in global and command line contexts.
2474  */
2475 void
2476 Var_Dump(void)
2477 {
2478         const LstNode   *ln;
2479         const Var       *v;
2480
2481         printf("#*** Global Variables:\n");
2482         LST_FOREACH(ln, &VAR_GLOBAL->context) {
2483                 v = Lst_Datum(ln);
2484                 printf("%-16s = %s\n", v->name, Buf_Data(v->val));
2485         }
2486
2487         printf("#*** Command-line Variables:\n");
2488         LST_FOREACH(ln, &VAR_CMD->context) {
2489                 v = Lst_Datum(ln);
2490                 printf("%-16s = %s\n", v->name, Buf_Data(v->val));
2491         }
2492 }
2493
2494 /**
2495  * Print the values of any variables requested by
2496  * the user.
2497  */
2498 void
2499 Var_Print(Lst *vlist, bool expandVars)
2500 {
2501         LstNode         *n;
2502
2503         LST_FOREACH(n, vlist) {
2504                 const char *name = Lst_Datum(n);
2505
2506                 if (expandVars) {
2507                         char            *v;
2508                         char            *value;
2509
2510                         v = emalloc(strlen(name) + 1 + 3);
2511                         sprintf(v, "${%s}", name);
2512
2513                         value = Buf_Peel(Var_Subst(v, VAR_GLOBAL, false));
2514                         printf("%s\n", value);
2515
2516                         free(v);
2517                         free(value);
2518                 } else {
2519                         const char *value = Var_Value(name, VAR_GLOBAL);
2520                         printf("%s\n", value != NULL ? value : "");
2521                 }
2522         }
2523 }
2524