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