Merge from vendor branch BSDTAR:
[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.205 2005/04/29 19:40:49 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         Boolean         err;
114         Boolean         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 Boolean VarModifyProc(const char *, Boolean, struct Buffer *, void *);
150
151 static char *VarParse(VarParser *, Boolean *);
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 Boolean         oldVars;        /* variable substitution style */
188 Boolean         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, Boolean 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 Boolean
246 VarHead(const char *word, Boolean 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, (Byte)' ');
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, (Byte)'.');
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 Boolean
281 VarTail(const char *word, Boolean addSpace, Buffer *buf, void *dummy __unused)
282 {
283         const char *slash;
284
285         if (addSpace) {
286                 Buf_AddByte (buf, (Byte)' ');
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 Boolean
310 VarSuffix(const char *word, Boolean 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, (Byte)' ');
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 Boolean
338 VarRoot(const char *word, Boolean addSpace, Buffer *buf, void *dummy __unused)
339 {
340         char *dot;
341
342         if (addSpace) {
343                 Buf_AddByte(buf, (Byte)' ');
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 Boolean
369 VarMatch(const char *word, Boolean addSpace, Buffer *buf, void *pattern)
370 {
371
372         if (Str_Match(word, pattern)) {
373                 if (addSpace) {
374                         Buf_AddByte(buf, (Byte)' ');
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 Boolean
396 VarSYSVMatch(const char *word, Boolean 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, (Byte)' ');
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 Boolean
429 VarNoMatch(const char *word, Boolean addSpace, Buffer *buf, void *pattern)
430 {
431
432         if (!Str_Match(word, pattern)) {
433                 if (addSpace) {
434                         Buf_AddByte(buf, (Byte)' ');
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 Boolean
450 VarSubstitute(const char *word, Boolean 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, (Byte)' ');
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, (Byte)' ');
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, (Byte)' ');
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                         Boolean 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, (Byte)' ');
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, (Byte)' ');
590                                 }
591                                 Buf_AddBytes(buf, wordLen, (const Byte *)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, (Byte)' ');
610         }
611         Buf_AddBytes(buf, wordLen, (const Byte *)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 Boolean
643 VarRESubstitute(const char *word, Boolean 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, (Byte)' ');    \
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,
675                             (const Byte *)wp);
676                 }
677
678                 for (rp = Buf_Data(pat->rhs); *rp; rp++) {
679                         if ((*rp == '\\') && ((rp[1] == '&') || (rp[1] == '\\'))) {
680                                 MAYBE_ADD_SPACE();
681                                 Buf_AddByte(buf, (Byte)rp[1]);
682                                 rp++;
683
684                         } else if ((*rp == '&') ||
685                             ((*rp == '\\') && isdigit((unsigned char)rp[1]))) {
686                                 int     n;
687                                 const char *subbuf;
688                                 int     sublen;
689                                 char    errstr[3];
690
691                                 if (*rp == '&') {
692                                         n = 0;
693                                         errstr[0] = '&';
694                                         errstr[1] = '\0';
695                                 } else {
696                                         n = rp[1] - '0';
697                                         errstr[0] = '\\';
698                                         errstr[1] = rp[1];
699                                         errstr[2] = '\0';
700                                         rp++;
701                                 }
702
703                                 if (n > pat->nsub) {
704                                         Error("No subexpression %s",
705                                             &errstr[0]);
706                                         subbuf = "";
707                                         sublen = 0;
708
709                                 } else if ((pat->matches[n].rm_so == -1) &&
710                                     (pat->matches[n].rm_eo == -1)) {
711                                         Error("No match for subexpression %s",
712                                             &errstr[0]);
713                                         subbuf = "";
714                                         sublen = 0;
715
716                                 } else {
717                                         subbuf = wp + pat->matches[n].rm_so;
718                                         sublen = pat->matches[n].rm_eo -
719                                             pat->matches[n].rm_so;
720                                 }
721
722                                 if (sublen > 0) {
723                                         MAYBE_ADD_SPACE();
724                                         Buf_AddBytes(buf, sublen,
725                                             (const Byte *)subbuf);
726                                 }
727                         } else {
728                                 MAYBE_ADD_SPACE();
729                                 Buf_AddByte(buf, (Byte)*rp);
730                         }
731                 }
732                 wp += pat->matches[0].rm_eo;
733                 if (pat->flags & VAR_SUB_GLOBAL) {
734                         flags |= REG_NOTBOL;
735                         if (pat->matches[0].rm_so == 0 &&
736                             pat->matches[0].rm_eo == 0) {
737                                 MAYBE_ADD_SPACE();
738                                 Buf_AddByte(buf, (Byte)*wp);
739                                 wp++;
740                         }
741                         if (*wp)
742                                 goto tryagain;
743                 }
744                 if (*wp) {
745                         MAYBE_ADD_SPACE();
746                         Buf_Append(buf, wp);
747                 }
748                 break;
749
750           default:
751                 VarREError(xrv, &pat->re, "Unexpected regex error");
752                 /* fall through */
753
754           case REG_NOMATCH:
755                 if (*wp) {
756                         MAYBE_ADD_SPACE();
757                         Buf_Append(buf, wp);
758                 }
759                 break;
760         }
761         return (addSpace || added);
762 }
763
764 /**
765  * Find a variable in a variable list.
766  */
767 static Var *
768 VarLookup(Lst *vlist, const char *name)
769 {
770         LstNode *ln;
771
772         LST_FOREACH(ln, vlist)
773                 if (strcmp(((const Var *)Lst_Datum(ln))->name, name) == 0)
774                         return (Lst_Datum(ln));
775         return (NULL);
776 }
777
778 /**
779  * Expand a variable name's embedded variables in the given context.
780  *
781  * Results:
782  *      The contents of name, possibly expanded.
783  */
784 static char *
785 VarPossiblyExpand(const char *name, GNode *ctxt)
786 {
787         Buffer  *buf;
788
789         if (strchr(name, '$') != NULL) {
790                 buf = Var_Subst(name, ctxt, 0);
791                 return (Buf_Peel(buf));
792         } else {
793                 return estrdup(name);
794         }
795 }
796
797 /**
798  * If the variable name begins with a '.', it could very well be
799  * one of the local ones.  We check the name against all the local
800  * variables and substitute the short version in for 'name' if it
801  * matches one of them.
802  */
803 static const char *
804 VarLocal(const char name[])
805 {
806         if (name[0] == '.') {
807                 switch (name[1]) {
808                 case 'A':
809                         if (!strcmp(name, ".ALLSRC"))
810                                 return (ALLSRC);
811                         if (!strcmp(name, ".ARCHIVE"))
812                                 return (ARCHIVE);
813                         break;
814                 case 'I':
815                         if (!strcmp(name, ".IMPSRC"))
816                                 return (IMPSRC);
817                         break;
818                 case 'M':
819                         if (!strcmp(name, ".MEMBER"))
820                                 return (MEMBER);
821                         break;
822                 case 'O':
823                         if (!strcmp(name, ".OODATE"))
824                                 return (OODATE);
825                         break;
826                 case 'P':
827                         if (!strcmp(name, ".PREFIX"))
828                                 return (PREFIX);
829                         break;
830                 case 'T':
831                         if (!strcmp(name, ".TARGET"))
832                                 return (TARGET);
833                         break;
834                 default:
835                         break;
836                 }
837         }
838         return (name);
839 }
840
841 /**
842  * Find the given variable in the given context and the enviornment.
843  *
844  * Results:
845  *      A pointer to the structure describing the desired variable or
846  *      NULL if the variable does not exist.
847  */
848 static Var *
849 VarFindEnv(const char name[], GNode *ctxt)
850 {
851         Var     *var;
852
853         name = VarLocal(name);
854
855         if ((var = VarLookup(&ctxt->context, name)) != NULL)
856                 return (var);
857
858         if ((var = VarLookup(&VAR_ENV->context, name)) != NULL)
859                 return (var);
860
861         return (NULL);
862 }
863
864 /**
865  * Look for the variable in the given context.
866  */
867 static Var *
868 VarFindOnly(const char name[], GNode *ctxt)
869 {
870
871         return (VarLookup(&ctxt->context, VarLocal(name)));
872 }
873
874 /**
875  * Look for the variable in all contexts.
876  */
877 static Var *
878 VarFindAny(const char name[], GNode *ctxt)
879 {
880         Boolean localCheckEnvFirst;
881         LstNode *ln;
882         Var     *var;
883
884         name = VarLocal(name);
885
886         /*
887          * Note whether this is one of the specific variables we were told
888          * through the -E flag to use environment-variable-override for.
889          */
890         localCheckEnvFirst = FALSE;
891         LST_FOREACH(ln, &envFirstVars) {
892                 if (strcmp(Lst_Datum(ln), name) == 0) {
893                         localCheckEnvFirst = TRUE;
894                         break;
895                 }
896         }
897
898         /*
899          * First look for the variable in the given context. If it's not there,
900          * look for it in VAR_CMD, VAR_GLOBAL and the environment,
901          * in that order, depending on the FIND_* flags in 'flags'
902          */
903         if ((var = VarLookup(&ctxt->context, name)) != NULL)
904                 return (var);
905
906         /* not there - try command line context */
907         if (ctxt != VAR_CMD) {
908                 if ((var = VarLookup(&VAR_CMD->context, name)) != NULL)
909                         return (var);
910         }
911
912         /* not there - try global context, but only if not -e/-E */
913         if (ctxt != VAR_GLOBAL && (!checkEnvFirst && !localCheckEnvFirst)) {
914                 if ((var = VarLookup(&VAR_GLOBAL->context, name)) != NULL)
915                         return (var);
916         }
917
918         if ((var = VarLookup(&VAR_ENV->context, name)) != NULL)
919                 return (var);
920
921         /* deferred check for the environment (in case of -e/-E) */
922         if ((ctxt != VAR_GLOBAL) && (checkEnvFirst || localCheckEnvFirst)) {
923                 if ((var = VarLookup(&VAR_GLOBAL->context, name)) != NULL)
924                         return (var);
925         }
926
927         return (NULL);
928 }
929
930 /**
931  * Add a new variable of name name and value val to the given context.
932  *
933  * Side Effects:
934  *      The new variable is placed at the front of the given context
935  *      The name and val arguments are duplicated so they may
936  *      safely be freed.
937  */
938 static void
939 VarAdd(const char *name, const char *val, GNode *ctxt)
940 {
941
942         Lst_AtFront(&ctxt->context, VarCreate(name, val, 0));
943         DEBUGF(VAR, ("%s:%s = %s\n", ctxt->name, name, val));
944 }
945
946 /**
947  * Remove a variable from a context.
948  *
949  * Side Effects:
950  *      The Var structure is removed and freed.
951  */
952 void
953 Var_Delete(const char *name, GNode *ctxt)
954 {
955         LstNode *ln;
956
957         DEBUGF(VAR, ("%s:delete %s\n", ctxt->name, name));
958         LST_FOREACH(ln, &ctxt->context) {
959                 if (strcmp(((const Var *)Lst_Datum(ln))->name, name) == 0) {
960                         VarDestroy(Lst_Datum(ln), TRUE);
961                         Lst_Remove(&ctxt->context, ln);
962                         break;
963                 }
964         }
965 }
966
967 /**
968  * Set the variable name to the value val in the given context.
969  *
970  * Side Effects:
971  *      If the variable doesn't yet exist, a new record is created for it.
972  *      Else the old value is freed and the new one stuck in its place
973  *
974  * Notes:
975  *      The variable is searched for only in its context before being
976  *      created in that context. I.e. if the context is VAR_GLOBAL,
977  *      only VAR_GLOBAL->context is searched. Likewise if it is VAR_CMD, only
978  *      VAR_CMD->context is searched. This is done to avoid the literally
979  *      thousands of unnecessary strcmp's that used to be done to
980  *      set, say, $(@) or $(<).
981  */
982 void
983 Var_Set(const char *name, const char *val, GNode *ctxt)
984 {
985         Var    *v;
986         char   *n;
987
988         /*
989          * We only look for a variable in the given context since anything
990          * set here will override anything in a lower context, so there's not
991          * much point in searching them all just to save a bit of memory...
992          */
993         n = VarPossiblyExpand(name, ctxt);
994         v = VarFindOnly(n, ctxt);
995         if (v == NULL) {
996                 VarAdd(n, val, ctxt);
997                 if (ctxt == VAR_CMD) {
998                         /*
999                          * Any variables given on the command line
1000                          * are automatically exported to the
1001                          * environment (as per POSIX standard)
1002                          */
1003                         setenv(n, val, 1);
1004                 }
1005         } else {
1006                 Buf_Clear(v->val);
1007                 Buf_Append(v->val, val);
1008
1009                 if (ctxt == VAR_CMD || (v->flags & VAR_TO_ENV)) {
1010                         /*
1011                          * Any variables given on the command line
1012                          * are automatically exported to the
1013                          * environment (as per POSIX standard)
1014                          */
1015                         setenv(n, val, 1);
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         Var_Set(name, value, VAR_GLOBAL);
1031 }
1032
1033
1034 /**
1035  * Set the VAR_TO_ENV flag on a variable
1036  */
1037 void
1038 Var_SetEnv(const char *name, GNode *ctxt)
1039 {
1040         Var    *v;
1041
1042         v = VarFindOnly(name, VAR_CMD);
1043         if (v != NULL) {
1044                 /*
1045                  * Do not allow .EXPORT: to be set on variables
1046                  * from the comand line or MAKEFLAGS.
1047                  */
1048                 Error(
1049                     "Warning: Did not set .EXPORTVAR: on %s because it "
1050                     "is from the comand line or MAKEFLAGS", name);
1051                 return;
1052         }
1053
1054         v = VarFindAny(name, ctxt);
1055         if (v == NULL) {
1056                 Lst_AtFront(&VAR_ENV->context,
1057                     VarCreate(name, NULL, VAR_TO_ENV));
1058                 setenv(name, "", 1);
1059                 Error("Warning: .EXPORTVAR: set on undefined variable %s", name);
1060         } else {
1061                 if ((v->flags & VAR_TO_ENV) == 0) {
1062                         v->flags |= VAR_TO_ENV;
1063                         setenv(v->name, Buf_Data(v->val), 1);
1064                 }
1065         }
1066 }
1067
1068 /**
1069  * The variable of the given name has the given value appended to it in
1070  * the given context.
1071  *
1072  * Side Effects:
1073  *      If the variable doesn't exist, it is created. Else the strings
1074  *      are concatenated (with a space in between).
1075  *
1076  * Notes:
1077  *      Only if the variable is being sought in the global context is the
1078  *      environment searched.
1079  *      XXX: Knows its calling circumstances in that if called with ctxt
1080  *      an actual target, it will only search that context since only
1081  *      a local variable could be being appended to. This is actually
1082  *      a big win and must be tolerated.
1083  */
1084 void
1085 Var_Append(const char *name, const char *val, GNode *ctxt)
1086 {
1087         Var     *v;
1088         char    *n;
1089
1090         n = VarPossiblyExpand(name, ctxt);
1091         if (ctxt == VAR_GLOBAL) {
1092                 v = VarFindEnv(n, ctxt);
1093         } else {
1094                 v = VarFindOnly(n, ctxt);
1095         }
1096         if (v == NULL) {
1097                 VarAdd(n, val, ctxt);
1098         } else {
1099                 Buf_AddByte(v->val, (Byte)' ');
1100                 Buf_Append(v->val, val);
1101                 DEBUGF(VAR, ("%s:%s = %s\n", ctxt->name, n, Buf_Data(v->val)));
1102         }
1103         free(n);
1104 }
1105
1106 /**
1107  * See if the given variable exists.
1108  *
1109  * Results:
1110  *      TRUE if it does, FALSE if it doesn't
1111  */
1112 Boolean
1113 Var_Exists(const char *name, GNode *ctxt)
1114 {
1115         Var     *v;
1116         char    *n;
1117
1118         n = VarPossiblyExpand(name, ctxt);
1119         v = VarFindAny(n, ctxt);
1120         if (v == NULL) {
1121                 free(n);
1122                 return (FALSE);
1123         } else {
1124                 free(n);
1125                 return (TRUE);
1126         }
1127 }
1128
1129 /**
1130  * Return the value of the named variable in the given context
1131  *
1132  * Results:
1133  *      The value if the variable exists, NULL if it doesn't
1134  */
1135 char *
1136 Var_Value(const char *name, GNode *ctxt, char **frp)
1137 {
1138         Var     *v;
1139         char    *n;
1140         char    *p;
1141
1142         n = VarPossiblyExpand(name, ctxt);
1143         v = VarFindAny(n, ctxt);
1144         if (v == NULL) {
1145                 p = NULL;
1146                 *frp = NULL;
1147         } else {
1148                 p = Buf_Data(v->val);
1149                 *frp = NULL;
1150         }
1151         free(n);
1152         return (p);
1153 }
1154
1155 /**
1156  * Modify each of the words of the passed string using the given
1157  * function. Used to implement all modifiers.
1158  *
1159  * Results:
1160  *      A string of all the words modified appropriately.
1161  *
1162  * Side Effects:
1163  *      Uses brk_string() so it invalidates any previous call to
1164  *      brk_string().
1165  */
1166 static char *
1167 VarModify(const char *str, VarModifyProc *modProc, void *datum)
1168 {
1169         char    **av;           /* word list [first word does not count] */
1170         int     ac;
1171         Buffer  *buf;           /* Buffer for the new string */
1172         Boolean addSpace;       /* TRUE if need to add a space to the buffer
1173                                  * before adding the trimmed word */
1174         int     i;
1175
1176         av = brk_string(str, &ac, FALSE);
1177
1178         buf = Buf_Init(0);
1179
1180         addSpace = FALSE;
1181         for (i = 1; i < ac; i++)
1182                 addSpace = (*modProc)(av[i], addSpace, buf, datum);
1183
1184         return (Buf_Peel(buf));
1185 }
1186
1187 /**
1188  * Sort the words in the string.
1189  *
1190  * Input:
1191  *      str             String whose words should be sorted
1192  *      cmp             A comparison function to control the ordering
1193  *
1194  * Results:
1195  *      A string containing the words sorted
1196  *
1197  * Side Effects:
1198  *      Uses brk_string() so it invalidates any previous call to
1199  *      brk_string().
1200  */
1201 static char *
1202 VarSortWords(const char *str, int (*cmp)(const void *, const void *))
1203 {
1204         char    **av;
1205         int     ac;
1206         Buffer  *buf;
1207         int     i;
1208
1209         av = brk_string(str, &ac, FALSE);
1210         qsort(av + 1, ac - 1, sizeof(char *), cmp);
1211
1212         buf = Buf_Init(0);
1213         for (i = 1; i < ac; i++) {
1214                 Buf_Append(buf, av[i]);
1215                 Buf_AddByte(buf, (Byte)((i < ac - 1) ? ' ' : '\0'));
1216         }
1217
1218         return (Buf_Peel(buf));
1219 }
1220
1221 static int
1222 SortIncreasing(const void *l, const void *r)
1223 {
1224
1225         return (strcmp(*(const char* const*)l, *(const char* const*)r));
1226 }
1227
1228 /**
1229  * Pass through the tstr looking for 1) escaped delimiters,
1230  * '$'s and backslashes (place the escaped character in
1231  * uninterpreted) and 2) unescaped $'s that aren't before
1232  * the delimiter (expand the variable substitution).
1233  * Return the expanded string or NULL if the delimiter was missing
1234  * If pattern is specified, handle escaped ampersands, and replace
1235  * unescaped ampersands with the lhs of the pattern.
1236  *
1237  * Results:
1238  *      A string of all the words modified appropriately.
1239  *      If length is specified, return the string length of the buffer
1240  *      If flags is specified and the last character of the pattern is a
1241  *      $ set the VAR_MATCH_END bit of flags.
1242  */
1243 static Buffer *
1244 VarGetPattern(VarParser *vp, int delim, int *flags, VarPattern *patt)
1245 {
1246         Buffer          *buf;
1247
1248         buf = Buf_Init(0);
1249
1250         /*
1251          * Skim through until the matching delimiter is found; pick up
1252          * variable substitutions on the way. Also allow backslashes to quote
1253          * the delimiter, $, and \, but don't touch other backslashes.
1254          */
1255         while (*vp->ptr != '\0') {
1256                 if (*vp->ptr == delim) {
1257                         return (buf);
1258
1259                 } else if ((vp->ptr[0] == '\\') &&
1260                     ((vp->ptr[1] == delim) ||
1261                      (vp->ptr[1] == '\\') ||
1262                      (vp->ptr[1] == '$') ||
1263                      (vp->ptr[1] == '&' && patt != NULL))) {
1264                         vp->ptr++;              /* consume backslash */
1265                         Buf_AddByte(buf, (Byte)vp->ptr[0]);
1266                         vp->ptr++;
1267
1268                 } else if (vp->ptr[0] == '$') {
1269                         if (vp->ptr[1] == delim) {
1270                                 if (flags == NULL) {
1271                                         Buf_AddByte(buf, (Byte)vp->ptr[0]);
1272                                         vp->ptr++;
1273                                 } else {
1274                                         /*
1275                                          * Unescaped $ at end of patt =>
1276                                          * anchor patt at end.
1277                                          */
1278                                         *flags |= VAR_MATCH_END;
1279                                         vp->ptr++;
1280                                 }
1281                         } else {
1282                                 VarParser       subvp = {
1283                                         vp->ptr,
1284                                         vp->ptr,
1285                                         vp->ctxt,
1286                                         vp->err,
1287                                         vp->execute
1288                                 };
1289                                 char   *rval;
1290                                 Boolean rfree;
1291
1292                                 /*
1293                                  * If unescaped dollar sign not
1294                                  * before the delimiter, assume it's
1295                                  * a variable substitution and
1296                                  * recurse.
1297                                  */
1298                                 rval = VarParse(&subvp, &rfree);
1299                                 Buf_Append(buf, rval);
1300                                 if (rfree)
1301                                         free(rval);
1302                                 vp->ptr = subvp.ptr;
1303                         }
1304                 } else if (vp->ptr[0] == '&' && patt != NULL) {
1305                         Buf_AppendBuf(buf, patt->lhs);
1306                         vp->ptr++;
1307                 } else {
1308                         Buf_AddByte(buf, (Byte)vp->ptr[0]);
1309                         vp->ptr++;
1310                 }
1311         }
1312
1313         Buf_Destroy(buf, TRUE);
1314         return (NULL);
1315 }
1316
1317 /**
1318  * Make sure this variable is fully expanded.
1319  */
1320 static char *
1321 VarExpand(Var *v, VarParser *vp)
1322 {
1323         char    *value;
1324         char    *result;
1325
1326         if (v->flags & VAR_IN_USE) {
1327                 Fatal("Variable %s is recursive.", v->name);
1328                 /* NOTREACHED */
1329         }
1330
1331         v->flags |= VAR_IN_USE;
1332
1333         /*
1334          * Before doing any modification, we have to make sure the
1335          * value has been fully expanded. If it looks like recursion
1336          * might be necessary (there's a dollar sign somewhere in the
1337          * variable's value) we just call Var_Subst to do any other
1338          * substitutions that are necessary. Note that the value
1339          * returned by Var_Subst will have been
1340          * dynamically-allocated, so it will need freeing when we
1341          * return.
1342          */
1343         value = Buf_Data(v->val);
1344         if (strchr(value, '$') == NULL) {
1345                 result = strdup(value);
1346         } else {
1347                 Buffer  *buf;
1348
1349                 buf = Var_Subst(value, vp->ctxt, vp->err);
1350                 result = Buf_Peel(buf);
1351         }
1352
1353         v->flags &= ~VAR_IN_USE;
1354
1355         return (result);
1356 }
1357
1358 /**
1359  * Select only those words in value that match the modifier.
1360  */
1361 static char *
1362 modifier_M(VarParser *vp, const char value[], char endc)
1363 {
1364         char    *patt;
1365         char    *ptr;
1366         char    *newValue;
1367         char    modifier;
1368
1369         modifier = vp->ptr[0];
1370         vp->ptr++;      /* consume 'M' or 'N' */
1371
1372         /*
1373          * Compress the \:'s out of the pattern, so allocate enough
1374          * room to hold the uncompressed pattern and compress the
1375          * pattern into that space.
1376          */
1377         patt = estrdup(vp->ptr);
1378         ptr = patt;
1379         while (vp->ptr[0] != '\0') {
1380                 if (vp->ptr[0] == endc || vp->ptr[0] == ':') {
1381                         break;
1382                 }
1383                 if (vp->ptr[0] == '\\' &&
1384                     (vp->ptr[1] == endc || vp->ptr[1] == ':')) {
1385                         vp->ptr++;      /* consume backslash */
1386                 }
1387                 *ptr = vp->ptr[0];
1388                 ptr++;
1389                 vp->ptr++;
1390         }
1391         *ptr = '\0';
1392
1393         if (modifier == 'M') {
1394                 newValue = VarModify(value, VarMatch, patt);
1395         } else {
1396                 newValue = VarModify(value, VarNoMatch, patt);
1397         }
1398         free(patt);
1399
1400         return (newValue);
1401 }
1402
1403 /**
1404  * Substitute the replacement string for the pattern.  The substitution
1405  * is applied to each word in value.
1406  */
1407 static char *
1408 modifier_S(VarParser *vp, const char value[], Var *v)
1409 {
1410         VarPattern      patt;
1411         char            delim;
1412         char            *newValue;
1413
1414         patt.flags = 0;
1415
1416         vp->ptr++;              /* consume 'S' */
1417
1418         delim = *vp->ptr;       /* used to find end of pattern */
1419         vp->ptr++;              /* consume 1st delim */
1420
1421         /*
1422          * If pattern begins with '^', it is anchored to the start of the
1423          * word -- skip over it and flag pattern.
1424          */
1425         if (*vp->ptr == '^') {
1426                 patt.flags |= VAR_MATCH_START;
1427                 vp->ptr++;
1428         }
1429
1430         patt.lhs = VarGetPattern(vp, delim, &patt.flags, NULL);
1431         if (patt.lhs == NULL) {
1432                 /*
1433                  * LHS didn't end with the delim, complain and exit.
1434                  */
1435                 Fatal("Unclosed substitution for %s (%c missing)",
1436                     v->name, delim);
1437         }
1438
1439         vp->ptr++;      /* consume 2nd delim */
1440
1441         patt.rhs = VarGetPattern(vp, delim, NULL, &patt);
1442         if (patt.rhs == NULL) {
1443                 /*
1444                  * RHS didn't end with the delim, complain and exit.
1445                  */
1446                 Fatal("Unclosed substitution for %s (%c missing)",
1447                     v->name, delim);
1448         }
1449
1450         vp->ptr++;      /* consume last delim */
1451
1452         /*
1453          * Check for global substitution. If 'g' after the final delimiter,
1454          * substitution is global and is marked that way.
1455          */
1456         if (vp->ptr[0] == 'g') {
1457                 patt.flags |= VAR_SUB_GLOBAL;
1458                 vp->ptr++;
1459         }
1460
1461         /*
1462          * Global substitution of the empty string causes an infinite number
1463          * of matches, unless anchored by '^' (start of string) or '$' (end
1464          * of string). Catch the infinite substitution here. Note that flags
1465          * can only contain the 3 bits we're interested in so we don't have
1466          * to mask unrelated bits. We can test for equality.
1467          */
1468         if (Buf_Size(patt.lhs) == 0 && patt.flags == VAR_SUB_GLOBAL)
1469                 Fatal("Global substitution of the empty string");
1470
1471         newValue = VarModify(value, VarSubstitute, &patt);
1472
1473         /*
1474          * Free the two strings.
1475          */
1476         free(patt.lhs);
1477         free(patt.rhs);
1478
1479         return (newValue);
1480 }
1481
1482 static char *
1483 modifier_C(VarParser *vp, char value[], Var *v)
1484 {
1485         VarPattern      patt;
1486         char            delim;
1487         int             error;
1488         char            *newValue;
1489
1490         patt.flags = 0;
1491
1492         vp->ptr++;              /* consume 'C' */
1493
1494         delim = *vp->ptr;       /* delimiter between sections */
1495
1496         vp->ptr++;              /* consume 1st delim */
1497
1498         patt.lhs = VarGetPattern(vp, delim, NULL, NULL);
1499         if (patt.lhs == NULL) {
1500                 Fatal("Unclosed substitution for %s (%c missing)",
1501                      v->name, delim);
1502         }
1503
1504         vp->ptr++;              /* consume 2st delim */
1505
1506         patt.rhs = VarGetPattern(vp, delim, NULL, NULL);
1507         if (patt.rhs == NULL) {
1508                 Fatal("Unclosed substitution for %s (%c missing)",
1509                      v->name, delim);
1510         }
1511
1512         vp->ptr++;              /* consume last delim */
1513
1514         switch (*vp->ptr) {
1515         case 'g':
1516                 patt.flags |= VAR_SUB_GLOBAL;
1517                 vp->ptr++;              /* consume 'g' */
1518                 break;
1519         case '1':
1520                 patt.flags |= VAR_SUB_ONE;
1521                 vp->ptr++;              /* consume '1' */
1522                 break;
1523         default:
1524                 break;
1525         }
1526
1527         error = regcomp(&patt.re, Buf_Data(patt.lhs), REG_EXTENDED);
1528         if (error) {
1529                 VarREError(error, &patt.re, "RE substitution error");
1530                 free(patt.rhs);
1531                 free(patt.lhs);
1532                 return (var_Error);
1533         }
1534
1535         patt.nsub = patt.re.re_nsub + 1;
1536         if (patt.nsub < 1)
1537                 patt.nsub = 1;
1538         if (patt.nsub > 10)
1539                 patt.nsub = 10;
1540         patt.matches = emalloc(patt.nsub * sizeof(regmatch_t));
1541
1542         newValue = VarModify(value, VarRESubstitute, &patt);
1543
1544         regfree(&patt.re);
1545         free(patt.matches);
1546         free(patt.rhs);
1547         free(patt.lhs);
1548
1549         return (newValue);
1550 }
1551
1552 static char *
1553 sysVvarsub(VarParser *vp, char startc, Var *v, const char value[])
1554 {
1555 #ifdef SYSVVARSUB
1556         /*
1557          * This can either be a bogus modifier or a System-V substitution
1558          * command.
1559          */
1560         char            endc;
1561         VarPattern      patt;
1562         Boolean         eqFound;
1563         int             cnt;
1564         char            *newStr;
1565         const char      *cp;
1566
1567         endc = (startc == OPEN_PAREN) ? CLOSE_PAREN : CLOSE_BRACE;
1568
1569         patt.flags = 0;
1570
1571         /*
1572          * First we make a pass through the string trying to verify it is a
1573          * SYSV-make-style translation: it must be: <string1>=<string2>)
1574          */
1575         eqFound = FALSE;
1576         cp = vp->ptr;
1577         cnt = 1;
1578         while (*cp != '\0' && cnt) {
1579                 if (*cp == '=') {
1580                         eqFound = TRUE;
1581                         /* continue looking for endc */
1582                 } else if (*cp == endc)
1583                         cnt--;
1584                 else if (*cp == startc)
1585                         cnt++;
1586                 if (cnt)
1587                         cp++;
1588         }
1589
1590         if (*cp == endc && eqFound) {
1591                 /*
1592                  * Now we break this sucker into the lhs and rhs.
1593                  */
1594                 patt.lhs = VarGetPattern(vp, '=', &patt.flags, NULL);
1595                 if (patt.lhs == NULL) {
1596                         Fatal("Unclosed substitution for %s (%c missing)",
1597                               v->name, '=');
1598                 }
1599                 vp->ptr++;      /* consume '=' */
1600
1601                 patt.rhs = VarGetPattern(vp, endc, NULL, &patt);
1602                 if (patt.rhs == NULL) {
1603                         Fatal("Unclosed substitution for %s (%c missing)",
1604                               v->name, endc);
1605                 }
1606
1607                 /*
1608                  * SYSV modifications happen through the whole string. Note
1609                  * the pattern is anchored at the end.
1610                  */
1611                 newStr = VarModify(value, VarSYSVMatch, &patt);
1612
1613                 free(patt.lhs);
1614                 free(patt.rhs);
1615         } else
1616 #endif
1617         {
1618                 Error("Unknown modifier '%c'\n", *vp->ptr);
1619                 vp->ptr++;
1620                 while (*vp->ptr != '\0') {
1621                         if (*vp->ptr == endc && *vp->ptr == ':') {
1622                                 break;
1623                         }
1624                         vp->ptr++;
1625                 }
1626                 newStr = var_Error;
1627         }
1628
1629         return (newStr);
1630 }
1631
1632 /**
1633  * Quote shell meta-characters in the string
1634  *
1635  * Results:
1636  *      The quoted string
1637  */
1638 static char *
1639 Var_Quote(const char *str)
1640 {
1641         Buffer *buf;
1642         /* This should cover most shells :-( */
1643         static char meta[] = "\n \t'`\";&<>()|*?{}[]\\$!#^~";
1644
1645         buf = Buf_Init(MAKE_BSIZE);
1646         for (; *str; str++) {
1647                 if (strchr(meta, *str) != NULL)
1648                         Buf_AddByte(buf, (Byte)'\\');
1649                 Buf_AddByte(buf, (Byte)*str);
1650         }
1651
1652         return (Buf_Peel(buf));
1653 }
1654
1655
1656 /*
1657  * Now we need to apply any modifiers the user wants applied.
1658  * These are:
1659  *      :M<pattern>
1660  *              words which match the given <pattern>.
1661  *              <pattern> is of the standard file
1662  *              wildcarding form.
1663  *      :S<d><pat1><d><pat2><d>[g]
1664  *              Substitute <pat2> for <pat1> in the value
1665  *      :C<d><pat1><d><pat2><d>[g]
1666  *              Substitute <pat2> for regex <pat1> in the value
1667  *      :H      Substitute the head of each word
1668  *      :T      Substitute the tail of each word
1669  *      :E      Substitute the extension (minus '.') of
1670  *              each word
1671  *      :R      Substitute the root of each word
1672  *              (pathname minus the suffix).
1673  *      :lhs=rhs
1674  *              Like :S, but the rhs goes to the end of
1675  *              the invocation.
1676  *      :U      Converts variable to upper-case.
1677  *      :L      Converts variable to lower-case.
1678  *
1679  * XXXHB update this comment or remove it and point to the man page.
1680  */
1681 static char *
1682 ParseModifier(VarParser *vp, char startc, Var *v, Boolean *freeResult)
1683 {
1684         char    *value;
1685         char    endc;
1686
1687         value = VarExpand(v, vp);
1688         *freeResult = TRUE;
1689
1690         endc = (startc == OPEN_PAREN) ? CLOSE_PAREN : CLOSE_BRACE;
1691
1692         vp->ptr++;      /* consume first colon */
1693
1694         while (*vp->ptr != '\0') {
1695                 char    *newStr;        /* New value to return */
1696
1697                 if (*vp->ptr == endc) {
1698                         return (value);
1699                 }
1700
1701                 DEBUGF(VAR, ("Applying :%c to \"%s\"\n", *vp->ptr, value));
1702                 switch (*vp->ptr) {
1703                 case 'N':
1704                 case 'M':
1705                         newStr = modifier_M(vp, value, endc);
1706                         break;
1707                 case 'S':
1708                         newStr = modifier_S(vp, value, v);
1709                         break;
1710                 case 'C':
1711                         newStr = modifier_C(vp, value, v);
1712                         break;
1713                 default:
1714                         if (vp->ptr[1] != endc && vp->ptr[1] != ':') {
1715 #ifdef SUNSHCMD
1716                                 if ((vp->ptr[0] == 's') &&
1717                                     (vp->ptr[1] == 'h') &&
1718                                     (vp->ptr[2] == endc || vp->ptr[2] == ':')) {
1719                                         const char      *error;
1720
1721                                         if (vp->execute) {
1722                                                 newStr = Buf_Peel(
1723                                                     Cmd_Exec(value, &error));
1724                                         } else {
1725                                                 newStr = estrdup("");
1726                                         }
1727
1728                                         if (error)
1729                                                 Error(error, value);
1730                                         vp->ptr += 2;
1731                                 } else
1732 #endif
1733                                 {
1734                                         newStr = sysVvarsub(vp, startc, v, value);
1735                                 }
1736                                 break;
1737                         }
1738
1739                         switch (vp->ptr[0]) {
1740                         case 'L':
1741                                 {
1742                                 const char      *cp;
1743                                 Buffer          *buf;
1744                                 buf = Buf_Init(MAKE_BSIZE);
1745                                 for (cp = value; *cp; cp++)
1746                                         Buf_AddByte(buf, (Byte)tolower(*cp));
1747
1748                                 newStr = Buf_Peel(buf);
1749
1750                                 vp->ptr++;
1751                                 break;
1752                                 }
1753                         case 'O':
1754                                 newStr = VarSortWords(value, SortIncreasing);
1755                                 vp->ptr++;
1756                                 break;
1757                         case 'Q':
1758                                 newStr = Var_Quote(value);
1759                                 vp->ptr++;
1760                                 break;
1761                         case 'T':
1762                                 newStr = VarModify(value, VarTail, NULL);
1763                                 vp->ptr++;
1764                                 break;
1765                         case 'U':
1766                                 {
1767                                 const char      *cp;
1768                                 Buffer          *buf;
1769                                 buf = Buf_Init(MAKE_BSIZE);
1770                                 for (cp = value; *cp; cp++)
1771                                         Buf_AddByte(buf, (Byte)toupper(*cp));
1772
1773                                 newStr = Buf_Peel(buf);
1774
1775                                 vp->ptr++;
1776                                 break;
1777                                 }
1778                         case 'H':
1779                                 newStr = VarModify(value, VarHead, NULL);
1780                                 vp->ptr++;
1781                                 break;
1782                         case 'E':
1783                                 newStr = VarModify(value, VarSuffix, NULL);
1784                                 vp->ptr++;
1785                                 break;
1786                         case 'R':
1787                                 newStr = VarModify(value, VarRoot, NULL);
1788                                 vp->ptr++;
1789                                 break;
1790                         default:
1791                                 newStr = sysVvarsub(vp, startc, v, value);
1792                                 break;
1793                         }
1794                         break;
1795                 }
1796
1797                 DEBUGF(VAR, ("Result is \"%s\"\n", newStr));
1798                 if (*freeResult) {
1799                         free(value);
1800                 }
1801
1802                 value = newStr;
1803                 *freeResult = (value == var_Error) ? FALSE : TRUE;
1804
1805                 if (vp->ptr[0] == ':') {
1806                         vp->ptr++;      /* consume colon */
1807                 }
1808         }
1809
1810         return (value);
1811 }
1812
1813 static char *
1814 ParseRestModifier(VarParser *vp, char startc, Buffer *buf, Boolean *freeResult)
1815 {
1816         const char      *vname;
1817         size_t          vlen;
1818         Var             *v;
1819         char            *value;
1820
1821         vname = Buf_GetAll(buf, &vlen);
1822
1823         v = VarFindAny(vname, vp->ctxt);
1824         if (v != NULL) {
1825                 value = ParseModifier(vp, startc, v, freeResult);
1826                 return (value);
1827         }
1828
1829         if ((vp->ctxt == VAR_CMD) || (vp->ctxt == VAR_GLOBAL)) {
1830                 size_t  consumed;
1831                 /*
1832                  * Still need to get to the end of the variable
1833                  * specification, so kludge up a Var structure for the
1834                  * modifications
1835                  */
1836                 v = VarCreate(vname, NULL, VAR_JUNK);
1837                 value = ParseModifier(vp, startc, v, freeResult);
1838                 if (*freeResult) {
1839                         free(value);
1840                 }
1841                 VarDestroy(v, TRUE);
1842
1843                 consumed = vp->ptr - vp->input + 1;
1844                 /*
1845                  * If substituting a local variable in a non-local context,
1846                  * assume it's for dynamic source stuff. We have to handle
1847                  * this specially and return the longhand for the variable
1848                  * with the dollar sign escaped so it makes it back to the
1849                  * caller. Only four of the local variables are treated
1850                  * specially as they are the only four that will be set when
1851                  * dynamic sources are expanded.
1852                  */
1853                 if (vlen == 1 ||
1854                     (vlen == 2 && (vname[1] == 'F' || vname[1] == 'D'))) {
1855                         if (strchr("!%*@", vname[0]) != NULL) {
1856                                 value = emalloc(consumed + 1);
1857                                 strncpy(value, vp->input, consumed);
1858                                 value[consumed] = '\0';
1859
1860                                 *freeResult = TRUE;
1861                                 return (value);
1862                         }
1863                 }
1864                 if (vlen > 2 &&
1865                     vname[0] == '.' &&
1866                     isupper((unsigned char)vname[1])) {
1867                         if ((strncmp(vname, ".TARGET", vlen - 1) == 0) ||
1868                             (strncmp(vname, ".ARCHIVE", vlen - 1) == 0) ||
1869                             (strncmp(vname, ".PREFIX", vlen - 1) == 0) ||
1870                             (strncmp(vname, ".MEMBER", vlen - 1) == 0)) {
1871                                 value = emalloc(consumed + 1);
1872                                 strncpy(value, vp->input, consumed);
1873                                 value[consumed] = '\0';
1874
1875                                 *freeResult = TRUE;
1876                                 return (value);
1877                         }
1878                 }
1879
1880                 *freeResult = FALSE;
1881                 return (vp->err ? var_Error : varNoError);
1882         } else {
1883                 /*
1884                  * Check for D and F forms of local variables since we're in
1885                  * a local context and the name is the right length.
1886                  */
1887                 if (vlen == 2 &&
1888                     (vname[1] == 'F' || vname[1] == 'D') &&
1889                     (strchr("!%*<>@", vname[0]) != NULL)) {
1890                         char    name[2];
1891
1892                         name[0] = vname[0];
1893                         name[1] = '\0';
1894
1895                         v = VarFindOnly(name, vp->ctxt);
1896                         if (v != NULL) {
1897                                 value = ParseModifier(vp, startc, v, freeResult);
1898                                 return (value);
1899                         }
1900                 }
1901
1902                 /*
1903                  * Still need to get to the end of the variable
1904                  * specification, so kludge up a Var structure for the
1905                  * modifications
1906                  */
1907                 v = VarCreate(vname, NULL, VAR_JUNK);
1908                 value = ParseModifier(vp, startc, v, freeResult);
1909                 if (*freeResult) {
1910                         free(value);
1911                 }
1912                 VarDestroy(v, TRUE);
1913
1914                 *freeResult = FALSE;
1915                 return (vp->err ? var_Error : varNoError);
1916         }
1917 }
1918
1919 static char *
1920 ParseRestEnd(VarParser *vp, Buffer *buf, Boolean *freeResult)
1921 {
1922         const char      *vname;
1923         size_t          vlen;
1924         Var             *v;
1925         char            *value;
1926
1927         vname = Buf_GetAll(buf, &vlen);
1928
1929         v = VarFindAny(vname, vp->ctxt);
1930         if (v != NULL) {
1931                 value = VarExpand(v, vp);
1932                 *freeResult = TRUE;
1933                 return (value);
1934         }
1935
1936         if ((vp->ctxt == VAR_CMD) || (vp->ctxt == VAR_GLOBAL)) {
1937                 size_t  consumed = vp->ptr - vp->input + 1;
1938
1939                 /*
1940                  * If substituting a local variable in a non-local context,
1941                  * assume it's for dynamic source stuff. We have to handle
1942                  * this specially and return the longhand for the variable
1943                  * with the dollar sign escaped so it makes it back to the
1944                  * caller. Only four of the local variables are treated
1945                  * specially as they are the only four that will be set when
1946                  * dynamic sources are expanded.
1947                  */
1948                 if (vlen == 1 ||
1949                     (vlen == 2 && (vname[1] == 'F' || vname[1] == 'D'))) {
1950                         if (strchr("!%*@", vname[0]) != NULL) {
1951                                 value = emalloc(consumed + 1);
1952                                 strncpy(value, vp->input, consumed);
1953                                 value[consumed] = '\0';
1954
1955                                 *freeResult = TRUE;
1956                                 return (value);
1957                         }
1958                 }
1959                 if (vlen > 2 &&
1960                     vname[0] == '.' &&
1961                     isupper((unsigned char)vname[1])) {
1962                         if ((strncmp(vname, ".TARGET", vlen - 1) == 0) ||
1963                             (strncmp(vname, ".ARCHIVE", vlen - 1) == 0) ||
1964                             (strncmp(vname, ".PREFIX", vlen - 1) == 0) ||
1965                             (strncmp(vname, ".MEMBER", vlen - 1) == 0)) {
1966                                 value = emalloc(consumed + 1);
1967                                 strncpy(value, vp->input, consumed);
1968                                 value[consumed] = '\0';
1969
1970                                 *freeResult = TRUE;
1971                                 return (value);
1972                         }
1973                 }
1974         } else {
1975                 /*
1976                  * Check for D and F forms of local variables since we're in
1977                  * a local context and the name is the right length.
1978                  */
1979                 if (vlen == 2 &&
1980                     (vname[1] == 'F' || vname[1] == 'D') &&
1981                     (strchr("!%*<>@", vname[0]) != NULL)) {
1982                         char    name[2];
1983
1984                         name[0] = vname[0];
1985                         name[1] = '\0';
1986
1987                         v = VarFindOnly(name, vp->ctxt);
1988                         if (v != NULL) {
1989                                 char    *val;
1990                                 /*
1991                                  * No need for nested expansion or anything,
1992                                  * as we're the only one who sets these
1993                                  * things and we sure don't put nested
1994                                  * invocations in them...
1995                                  */
1996                                 val = Buf_Data(v->val);
1997
1998                                 if (vname[1] == 'D') {
1999                                         val = VarModify(val, VarHead, NULL);
2000                                 } else {
2001                                         val = VarModify(val, VarTail, NULL);
2002                                 }
2003
2004                                 *freeResult = TRUE;
2005                                 return (val);
2006                         }
2007                 }
2008         }
2009
2010         *freeResult = FALSE;
2011         return (vp->err ? var_Error : varNoError);
2012 }
2013
2014 /**
2015  * Parse a multi letter variable name, and return it's value.
2016  */
2017 static char *
2018 VarParseLong(VarParser *vp, Boolean *freeResult)
2019 {
2020         Buffer          *buf;
2021         char            startc;
2022         char            endc;
2023         char            *value;
2024
2025         buf = Buf_Init(MAKE_BSIZE);
2026
2027         startc = vp->ptr[0];
2028         vp->ptr++;              /* consume opening paren or brace */
2029
2030         endc = (startc == OPEN_PAREN) ? CLOSE_PAREN : CLOSE_BRACE;
2031
2032         /*
2033          * Process characters until we reach an end character or a colon,
2034          * replacing embedded variables as we go.
2035          */
2036         while (*vp->ptr != '\0') {
2037                 if (*vp->ptr == endc) {
2038                         value = ParseRestEnd(vp, buf, freeResult);
2039                         vp->ptr++;      /* consume closing paren or brace */
2040                         Buf_Destroy(buf, TRUE);
2041                         return (value);
2042
2043                 } else if (*vp->ptr == ':') {
2044                         value = ParseRestModifier(vp, startc, buf, freeResult);
2045                         vp->ptr++;      /* consume closing paren or brace */
2046                         Buf_Destroy(buf, TRUE);
2047                         return (value);
2048
2049                 } else if (*vp->ptr == '$') {
2050                         VarParser       subvp = {
2051                                 vp->ptr,
2052                                 vp->ptr,
2053                                 vp->ctxt,
2054                                 vp->err,
2055                                 vp->execute
2056                         };
2057                         char    *rval;
2058                         Boolean rfree;
2059
2060                         rval = VarParse(&subvp, &rfree);
2061                         if (rval == var_Error) {
2062                                 Fatal("Error expanding embedded variable.");
2063                         }
2064                         Buf_Append(buf, rval);
2065                         if (rfree)
2066                                 free(rval);
2067                         vp->ptr = subvp.ptr;
2068                 } else {
2069                         Buf_AddByte(buf, (Byte)*vp->ptr);
2070                         vp->ptr++;
2071                 }
2072         }
2073
2074         /* If we did not find the end character, return var_Error */
2075         Buf_Destroy(buf, TRUE);
2076         *freeResult = FALSE;
2077         return (var_Error);
2078 }
2079
2080 /**
2081  * Parse a single letter variable name, and return it's value.
2082  */
2083 static char *
2084 VarParseShort(VarParser *vp, Boolean *freeResult)
2085 {
2086         char    vname[2];
2087         Var     *v;
2088         char    *value;
2089
2090         vname[0] = vp->ptr[0];
2091         vname[1] = '\0';
2092
2093         vp->ptr++;      /* consume single letter */
2094
2095         v = VarFindAny(vname, vp->ctxt);
2096         if (v != NULL) {
2097                 value = VarExpand(v, vp);
2098                 *freeResult = TRUE;
2099                 return (value);
2100         }
2101
2102         /*
2103          * If substituting a local variable in a non-local context, assume
2104          * it's for dynamic source stuff. We have to handle this specially
2105          * and return the longhand for the variable with the dollar sign
2106          * escaped so it makes it back to the caller. Only four of the local
2107          * variables are treated specially as they are the only four that
2108          * will be set when dynamic sources are expanded.
2109          */
2110         if ((vp->ctxt == VAR_CMD) || (vp->ctxt == VAR_GLOBAL)) {
2111
2112                 /* XXX: It looks like $% and $! are reversed here */
2113                 switch (vname[0]) {
2114                 case '@':
2115                         *freeResult = TRUE;
2116                         return (estrdup("$(.TARGET)"));
2117                 case '%':
2118                         *freeResult = TRUE;
2119                         return (estrdup("$(.ARCHIVE)"));
2120                 case '*':
2121                         *freeResult = TRUE;
2122                         return (estrdup("$(.PREFIX)"));
2123                 case '!':
2124                         *freeResult = TRUE;
2125                         return (estrdup("$(.MEMBER)"));
2126                 default:
2127                         *freeResult = FALSE;
2128                         return (vp->err ? var_Error : varNoError);
2129                 }
2130         }
2131
2132         /* Variable name was not found. */
2133         *freeResult = FALSE;
2134         return (vp->err ? var_Error : varNoError);
2135 }
2136
2137 static char *
2138 VarParse(VarParser *vp, Boolean *freeResult)
2139 {
2140
2141         vp->ptr++;      /* consume '$' or last letter of conditional */
2142
2143         if (vp->ptr[0] == '\0') {
2144                 /* Error, there is only a dollar sign in the input string. */
2145                 *freeResult = FALSE;
2146                 return (vp->err ? var_Error : varNoError);
2147
2148         } else if (vp->ptr[0] == OPEN_PAREN || vp->ptr[0] == OPEN_BRACE) {
2149                 /* multi letter variable name */
2150                 return (VarParseLong(vp, freeResult));
2151
2152         } else {
2153                 /* single letter variable name */
2154                 return (VarParseShort(vp, freeResult));
2155         }
2156 }
2157
2158 /**
2159  * Given the start of a variable invocation, extract the variable
2160  * name and find its value, then modify it according to the
2161  * specification.
2162  *
2163  * Results:
2164  *      The value of the variable or var_Error if the specification
2165  *      is invalid.  The number of characters in the specification
2166  *      is placed in the variable pointed to by consumed.  (for
2167  *      invalid specifications, this is just 2 to skip the '$' and
2168  *      the following letter, or 1 if '$' was the last character
2169  *      in the string).  A Boolean in *freeResult telling whether the
2170  *      returned string should be freed by the caller.
2171  */
2172 char *
2173 Var_Parse(const char input[], GNode *ctxt, Boolean err,
2174         size_t *consumed, Boolean *freeResult)
2175 {
2176         VarParser       vp = {
2177                 input,
2178                 input,
2179                 ctxt,
2180                 err,
2181                 TRUE
2182         };
2183         char            *value;
2184
2185         value = VarParse(&vp, freeResult);
2186         *consumed += vp.ptr - vp.input;
2187         return (value);
2188 }
2189
2190 /*
2191  * Given the start of a variable invocation, determine the length
2192  * of the specification.
2193  *
2194  * Results:
2195  *      The number of characters in the specification.  For invalid
2196  *      specifications, this is just 2 to skip the '$' and the
2197  *      following letter, or 1 if '$' was the last character in the
2198  *      string.
2199  */
2200 size_t
2201 Var_Match(const char input[], GNode *ctxt)
2202 {
2203         VarParser       vp = {
2204                 input,
2205                 input,
2206                 ctxt,
2207                 FALSE,
2208                 FALSE
2209         };
2210         char            *value;
2211         Boolean         freeResult;
2212
2213         value = VarParse(&vp, &freeResult);
2214         if (freeResult) {
2215                 free(value);
2216         }
2217         return (vp.ptr - vp.input);
2218 }
2219
2220 static int
2221 match_var(const char str[], const char var[])
2222 {
2223         const char      *start = str;
2224         size_t          len;
2225
2226         str++;                  /* consume '$' */
2227
2228         if (str[0] == OPEN_PAREN || str[0] == OPEN_BRACE) {
2229                 str++;          /* consume opening paren or brace */
2230
2231                 while (str[0] != '\0') {
2232                         if (str[0] == '$') {
2233                                 /*
2234                                  * A variable inside the variable. We cannot
2235                                  * expand the external variable yet.
2236                                  */
2237                                 return (str - start);
2238                         } else if (str[0] == ':' ||
2239                                    str[0] == CLOSE_PAREN ||
2240                                    str[0] == CLOSE_BRACE) {
2241                                 len = str - (start + 2);
2242
2243                                 if (var[len] == '\0' && strncmp(var, start + 2, len) == 0) {
2244                                         return (0);     /* match */
2245                                 } else {
2246                                         /*
2247                                          * Not the variable we want to
2248                                          * expand.
2249                                          */
2250                                         return (str - start);
2251                                 }
2252                         } else {
2253                                 ++str;
2254                         }
2255                 }
2256                 return (str - start);
2257         } else {
2258                 /* Single letter variable name */
2259                 if (var[1] == '\0' && var[0] == str[0]) {
2260                         return (0);     /* match */
2261                 } else {
2262                         str++;  /* consume variable name */
2263                         return (str - start);
2264                 }
2265         }
2266 }
2267
2268 /**
2269  * Substitute for all variables in the given string in the given
2270  * context If err is TRUE, Parse_Error will be called when an
2271  * undefined variable is encountered.
2272  *
2273  * Results:
2274  *      The resulting string.
2275  *
2276  * Side Effects:
2277  *      None. The old string must be freed by the caller
2278  */
2279 Buffer *
2280 Var_Subst(const char *str, GNode *ctxt, Boolean err)
2281 {
2282         Boolean errorReported;
2283         Buffer *buf;            /* Buffer for forming things */
2284
2285         /*
2286          * Set TRUE if an error has already been reported to prevent a
2287          * plethora of messages when recursing. XXXHB this comment sounds
2288          * wrong.
2289          */
2290         errorReported = FALSE;
2291
2292         buf = Buf_Init(0);
2293         while (str[0] != '\0') {
2294                 if ((str[0] == '$') && (str[1] == '$')) {
2295                         /*
2296                          * A dollar sign may be escaped with another dollar
2297                          * sign.  In such a case, we skip over the escape
2298                          * character and store the dollar sign into the
2299                          * buffer directly.
2300                          */
2301                         str++;
2302                         Buf_AddByte(buf, (Byte)str[0]);
2303                         str++;
2304
2305                 } else if (str[0] == '$') {
2306                         /* Variable invocation. */
2307                         VarParser subvp = {
2308                                 str,
2309                                 str,
2310                                 ctxt,
2311                                 err,
2312                                 TRUE
2313                         };
2314                         char    *rval;
2315                         Boolean rfree;
2316
2317                         rval = VarParse(&subvp, &rfree);
2318
2319                         /*
2320                          * When we come down here, val should either point to
2321                          * the value of this variable, suitably modified, or
2322                          * be NULL. Length should be the total length of the
2323                          * potential variable invocation (from $ to end
2324                          * character...)
2325                          */
2326                         if (rval == var_Error || rval == varNoError) {
2327                                 /*
2328                                  * If performing old-time variable
2329                                  * substitution, skip over the variable and
2330                                  * continue with the substitution. Otherwise,
2331                                  * store the dollar sign and advance str so
2332                                  * we continue with the string...
2333                                  */
2334                                 if (oldVars) {
2335                                         str = subvp.ptr;
2336                                 } else if (err) {
2337                                         /*
2338                                          * If variable is undefined, complain
2339                                          * and skip the variable. The
2340                                          * complaint will stop us from doing
2341                                          * anything when the file is parsed.
2342                                          */
2343                                         if (!errorReported) {
2344                                                 Parse_Error(PARSE_FATAL,
2345                                                             "Undefined variable \"%.*s\"", subvp.ptr - subvp.input, str);
2346                                         }
2347                                         errorReported = TRUE;
2348                                         str = subvp.ptr;
2349                                 } else {
2350                                         Buf_AddByte(buf, (Byte)str[0]);
2351                                         str++;
2352                                 }
2353                         } else {
2354                                 /*
2355                                  * Copy all the characters from the variable
2356                                  * value straight into the new string.
2357                                  */
2358                                 Buf_Append(buf, rval);
2359                                 if (rfree) {
2360                                         free(rval);
2361                                 }
2362                                 str = subvp.ptr;
2363                         }
2364                 } else {
2365                         Buf_AddByte(buf, (Byte)str[0]);
2366                         str++;
2367                 }
2368         }
2369
2370         return (buf);
2371 }
2372
2373 /**
2374  * Substitute for all variables except if it is the same as 'var',
2375  * in the given string in the given context.  If err is TRUE,
2376  * Parse_Error will be called when an undefined variable is
2377  * encountered.
2378  *
2379  * Results:
2380  *      The resulting string.
2381  *
2382  * Side Effects:
2383  *      None. The old string must be freed by the caller
2384  */
2385 Buffer *
2386 Var_SubstOnly(const char *var, const char *str, Boolean err)
2387 {
2388         GNode *ctxt = VAR_GLOBAL;
2389         Boolean errorReported;
2390         Buffer  *buf;           /* Buffer for forming things */
2391
2392         /*
2393          * Set TRUE if an error has already been reported to prevent a
2394          * plethora of messages when recursing. XXXHB this comment sounds
2395          * wrong.
2396          */
2397         errorReported = FALSE;
2398
2399         buf = Buf_Init(0);
2400         while (str[0] != '\0') {
2401                 if (str[0] == '$') {
2402                         int     skip;
2403
2404                         skip = match_var(str, var);
2405                         if (skip > 0) {
2406                                 Buf_AddBytes(buf, skip, str);
2407                                 str += skip;
2408                         } else {
2409                                 /* Variable invocation. */
2410                                 VarParser       subvp = {
2411                                         str,
2412                                         str,
2413                                         ctxt,
2414                                         err,
2415                                         TRUE
2416                                 };
2417                                 char    *rval;
2418                                 Boolean rfree;
2419
2420                                 rval = VarParse(&subvp, &rfree);
2421
2422                                 /*
2423                                  * When we get down here, rval should either
2424                                  * point to the value of this variable, or be
2425                                  * NULL.
2426                                  */
2427                                 if (rval == var_Error || rval == varNoError) {
2428                                         /*
2429                                          * If performing old-time variable
2430                                          * substitution, skip over the
2431                                          * variable and continue with the
2432                                          * substitution. Otherwise, store the
2433                                          * dollar sign and advance str so we
2434                                          * continue with the string...
2435                                          */
2436                                         if (oldVars) {
2437                                                 str = subvp.ptr;
2438                                         } else if (err) {
2439                                                 /*
2440                                                  * If variable is undefined,
2441                                                  * complain and skip the
2442                                                  * variable. The complaint
2443                                                  * will stop us from doing
2444                                                  * anything when the file is
2445                                                  * parsed.
2446                                                  */
2447                                                 if (!errorReported) {
2448                                                         Parse_Error(PARSE_FATAL,
2449                                                                     "Undefined variable \"%.*s\"", subvp.ptr - subvp.input, str);
2450                                                 }
2451                                                 errorReported = TRUE;
2452                                                 str = subvp.ptr;
2453                                         } else {
2454                                                 Buf_AddByte(buf, (Byte)str[0]);
2455                                                 str++;
2456                                         }
2457                                 } else {
2458                                         /*
2459                                          * Copy all the characters from the
2460                                          * variable value straight into the
2461                                          * new string.
2462                                          */
2463                                         Buf_Append(buf, rval);
2464                                         if (rfree) {
2465                                                 free(rval);
2466                                         }
2467                                         str = subvp.ptr;
2468                                 }
2469                         }
2470                 } else {
2471                         Buf_AddByte(buf, (Byte)str[0]);
2472                         str++;
2473                 }
2474         }
2475
2476         return (buf);
2477 }
2478
2479 /**
2480  * Initialize the module
2481  *
2482  * Side Effects:
2483  *      The VAR_CMD and VAR_GLOBAL contexts are created
2484  */
2485 void
2486 Var_Init(char **env)
2487 {
2488         char    **ptr;
2489
2490         VAR_CMD = Targ_NewGN("Command");
2491         VAR_ENV = Targ_NewGN("Environment");
2492         VAR_GLOBAL = Targ_NewGN("Global");
2493
2494         /*
2495          * Copy user environment variables into ENV context.
2496          */
2497         for (ptr = env; *ptr != NULL; ++ptr) {
2498                 char            *tmp = estrdup(*ptr);
2499                 const char      *name = tmp;
2500                 char            *sep = strchr(name, '=');
2501                 const char      *value = sep + 1;
2502
2503                 if (sep != NULL) {
2504                         *sep = '\0';
2505                         VarAdd(name, value, VAR_ENV);
2506                 }
2507                 free(tmp);
2508         }
2509 }
2510
2511 /**
2512  * Print all variables in global and command line contexts.
2513  */
2514 void
2515 Var_Dump(void)
2516 {
2517         const LstNode   *ln;
2518         const Var       *v;
2519
2520         printf("#*** Global Variables:\n");
2521         LST_FOREACH(ln, &VAR_GLOBAL->context) {
2522                 v = Lst_Datum(ln);
2523                 printf("%-16s = %s\n", v->name, Buf_Data(v->val));
2524         }
2525
2526         printf("#*** Command-line Variables:\n");
2527         LST_FOREACH(ln, &VAR_CMD->context) {
2528                 v = Lst_Datum(ln);
2529                 printf("%-16s = %s\n", v->name, Buf_Data(v->val));
2530         }
2531 }
2532
2533 /**
2534  * Print the values of any variables requested by
2535  * the user.
2536  */
2537 void
2538 Var_Print(Lst *vlist, Boolean expandVars)
2539 {
2540         LstNode         *n;
2541         const char      *name;
2542
2543         LST_FOREACH(n, vlist) {
2544                 name = Lst_Datum(n);
2545                 if (expandVars) {
2546                         char            *v;
2547                         char            *value;
2548
2549                         v = emalloc(strlen(name) + 1 + 3);
2550                         sprintf(v, "${%s}", name);
2551
2552                         value = Buf_Peel(Var_Subst(v,
2553                             VAR_GLOBAL, FALSE));
2554                         printf("%s\n", value);
2555
2556                         free(v);
2557                         free(value);
2558                 } else {
2559                         char    *value;
2560                         char    *v;
2561                         value = Var_Value(name, VAR_GLOBAL, &v);
2562                         printf("%s\n", value != NULL ? value : "");
2563                         if (v != NULL)
2564                                 free(v);
2565                 }
2566         }
2567 }
2568