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