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