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