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