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