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