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