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