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