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