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