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