]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/make/var.c
BSD 4.4 Lite Usr.bin Sources
[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
39 #ifndef lint
40 static char sccsid[] = "@(#)var.c       8.3 (Berkeley) 3/19/94";
41 #endif /* not lint */
42
43 /*-
44  * var.c --
45  *      Variable-handling functions
46  *
47  * Interface:
48  *      Var_Set             Set the value of a variable in the given
49  *                          context. The variable is created if it doesn't
50  *                          yet exist. The value and variable name need not
51  *                          be preserved.
52  *
53  *      Var_Append          Append more characters to an existing variable
54  *                          in the given context. The variable needn't
55  *                          exist already -- it will be created if it doesn't.
56  *                          A space is placed between the old value and the
57  *                          new one.
58  *
59  *      Var_Exists          See if a variable exists.
60  *
61  *      Var_Value           Return the value of a variable in a context or
62  *                          NULL if the variable is undefined.
63  *
64  *      Var_Subst           Substitute named variable, or all variables if
65  *                          NULL in a string using
66  *                          the given context as the top-most one. If the
67  *                          third argument is non-zero, Parse_Error is
68  *                          called if any variables are undefined.
69  *
70  *      Var_Parse           Parse a variable expansion from a string and
71  *                          return the result and the number of characters
72  *                          consumed.
73  *
74  *      Var_Delete          Delete a variable in a context.
75  *
76  *      Var_Init            Initialize this module.
77  *
78  * Debugging:
79  *      Var_Dump            Print out all variables defined in the given
80  *                          context.
81  *
82  * XXX: There's a lot of duplication in these functions.
83  */
84
85 #include    <ctype.h>
86 #include    "make.h"
87 #include    "buf.h"
88
89 /*
90  * This is a harmless return value for Var_Parse that can be used by Var_Subst
91  * to determine if there was an error in parsing -- easier than returning
92  * a flag, as things outside this module don't give a hoot.
93  */
94 char    var_Error[] = "";
95
96 /*
97  * Similar to var_Error, but returned when the 'err' flag for Var_Parse is
98  * set false. Why not just use a constant? Well, gcc likes to condense
99  * identical string instances...
100  */
101 static char     varNoError[] = "";
102
103 /*
104  * Internally, variables are contained in four different contexts.
105  *      1) the environment. They may not be changed. If an environment
106  *          variable is appended-to, the result is placed in the global
107  *          context.
108  *      2) the global context. Variables set in the Makefile are located in
109  *          the global context. It is the penultimate context searched when
110  *          substituting.
111  *      3) the command-line context. All variables set on the command line
112  *         are placed in this context. They are UNALTERABLE once placed here.
113  *      4) the local context. Each target has associated with it a context
114  *         list. On this list are located the structures describing such
115  *         local variables as $(@) and $(*)
116  * The four contexts are searched in the reverse order from which they are
117  * listed.
118  */
119 GNode          *VAR_GLOBAL;   /* variables from the makefile */
120 GNode          *VAR_CMD;      /* variables defined on the command-line */
121
122 #define FIND_CMD        0x1   /* look in VAR_CMD when searching */
123 #define FIND_GLOBAL     0x2   /* look in VAR_GLOBAL as well */
124 #define FIND_ENV        0x4   /* look in the environment also */
125
126 typedef struct Var {
127     char          *name;        /* the variable's name */
128     Buffer        val;          /* its value */
129     int           flags;        /* miscellaneous status flags */
130 #define VAR_IN_USE      1           /* Variable's value currently being used.
131                                      * Used to avoid recursion */
132 #define VAR_FROM_ENV    2           /* Variable comes from the environment */
133 #define VAR_JUNK        4           /* Variable is a junk variable that
134                                      * should be destroyed when done with
135                                      * it. Used by Var_Parse for undefined,
136                                      * modified variables */
137 }  Var;
138
139 typedef struct {
140     char          *lhs;     /* String to match */
141     int           leftLen;  /* Length of string */
142     char          *rhs;     /* Replacement string (w/ &'s removed) */
143     int           rightLen; /* Length of replacement */
144     int           flags;
145 #define VAR_SUB_GLOBAL  1   /* Apply substitution globally */
146 #define VAR_MATCH_START 2   /* Match at start of word */
147 #define VAR_MATCH_END   4   /* Match at end of word */
148 #define VAR_NO_SUB      8   /* Substitution is non-global and already done */
149 } VarPattern;
150
151 static int VarCmp __P((Var *, char *));
152 static Var *VarFind __P((char *, GNode *, int));
153 static void VarAdd __P((char *, char *, GNode *));
154 static Boolean VarHead __P((char *, Boolean, Buffer));
155 static Boolean VarTail __P((char *, Boolean, Buffer));
156 static Boolean VarSuffix __P((char *, Boolean, Buffer));
157 static Boolean VarRoot __P((char *, Boolean, Buffer));
158 static Boolean VarMatch __P((char *, Boolean, Buffer, char *));
159 static Boolean VarSYSVMatch __P((char *, Boolean, Buffer, VarPattern *));
160 static Boolean VarNoMatch __P((char *, Boolean, Buffer, char *));
161 static Boolean VarSubstitute __P((char *, Boolean, Buffer, VarPattern *));
162 static char *VarModify __P((char *, Boolean (*modProc )(), ClientData));
163 static int VarPrintVar __P((Var *));
164
165 /*-
166  *-----------------------------------------------------------------------
167  * VarCmp  --
168  *      See if the given variable matches the named one. Called from
169  *      Lst_Find when searching for a variable of a given name.
170  *
171  * Results:
172  *      0 if they match. non-zero otherwise.
173  *
174  * Side Effects:
175  *      none
176  *-----------------------------------------------------------------------
177  */
178 static int
179 VarCmp (v, name)
180     Var            *v;          /* VAR structure to compare */
181     char           *name;       /* name to look for */
182 {
183     return (strcmp (name, v->name));
184 }
185
186 /*-
187  *-----------------------------------------------------------------------
188  * VarFind --
189  *      Find the given variable in the given context and any other contexts
190  *      indicated.
191  *
192  * Results:
193  *      A pointer to the structure describing the desired variable or
194  *      NIL if the variable does not exist.
195  *
196  * Side Effects:
197  *      None
198  *-----------------------------------------------------------------------
199  */
200 static Var *
201 VarFind (name, ctxt, flags)
202     char                *name;  /* name to find */
203     GNode               *ctxt;  /* context in which to find it */
204     int                 flags;  /* FIND_GLOBAL set means to look in the
205                                  * VAR_GLOBAL context as well.
206                                  * FIND_CMD set means to look in the VAR_CMD
207                                  * context also.
208                                  * FIND_ENV set means to look in the
209                                  * environment */
210 {
211     LstNode             var;
212     Var                 *v;
213
214         /*
215          * If the variable name begins with a '.', it could very well be one of
216          * the local ones.  We check the name against all the local variables
217          * and substitute the short version in for 'name' if it matches one of
218          * them.
219          */
220         if (*name == '.' && isupper(name[1]))
221                 switch (name[1]) {
222                 case 'A':
223                         if (!strcmp(name, ".ALLSRC"))
224                                 name = ALLSRC;
225                         if (!strcmp(name, ".ARCHIVE"))
226                                 name = ARCHIVE;
227                         break;
228                 case 'I':
229                         if (!strcmp(name, ".IMPSRC"))
230                                 name = IMPSRC;
231                         break;
232                 case 'M':
233                         if (!strcmp(name, ".MEMBER"))
234                                 name = MEMBER;
235                         break;
236                 case 'O':
237                         if (!strcmp(name, ".OODATE"))
238                                 name = OODATE;
239                         break;
240                 case 'P':
241                         if (!strcmp(name, ".PREFIX"))
242                                 name = PREFIX;
243                         break;
244                 case 'T':
245                         if (!strcmp(name, ".TARGET"))
246                                 name = TARGET;
247                         break;
248                 }
249     /*
250      * First look for the variable in the given context. If it's not there,
251      * look for it in VAR_CMD, VAR_GLOBAL and the environment, in that order,
252      * depending on the FIND_* flags in 'flags'
253      */
254     var = Lst_Find (ctxt->context, (ClientData)name, VarCmp);
255
256     if ((var == NILLNODE) && (flags & FIND_CMD) && (ctxt != VAR_CMD)) {
257         var = Lst_Find (VAR_CMD->context, (ClientData)name, VarCmp);
258     }
259     if (!checkEnvFirst && (var == NILLNODE) && (flags & FIND_GLOBAL) &&
260         (ctxt != VAR_GLOBAL))
261     {
262         var = Lst_Find (VAR_GLOBAL->context, (ClientData)name, VarCmp);
263     }
264     if ((var == NILLNODE) && (flags & FIND_ENV)) {
265         char *env;
266
267         if ((env = getenv (name)) != NULL) {
268             /*
269              * If the variable is found in the environment, we only duplicate
270              * its value (since eVarVal was allocated on the stack). The name
271              * doesn't need duplication since it's always in the environment
272              */
273             int         len;
274             
275             v = (Var *) emalloc(sizeof(Var));
276             v->name = name;
277
278             len = strlen(env);
279             
280             v->val = Buf_Init(len);
281             Buf_AddBytes(v->val, len, (Byte *)env);
282             
283             v->flags = VAR_FROM_ENV;
284             return (v);
285         } else if (checkEnvFirst && (flags & FIND_GLOBAL) &&
286                    (ctxt != VAR_GLOBAL))
287         {
288             var = Lst_Find (VAR_GLOBAL->context, (ClientData)name, VarCmp);
289             if (var == NILLNODE) {
290                 return ((Var *) NIL);
291             } else {
292                 return ((Var *)Lst_Datum(var));
293             }
294         } else {
295             return((Var *)NIL);
296         }
297     } else if (var == NILLNODE) {
298         return ((Var *) NIL);
299     } else {
300         return ((Var *) Lst_Datum (var));
301     }
302 }
303
304 /*-
305  *-----------------------------------------------------------------------
306  * VarAdd  --
307  *      Add a new variable of name name and value val to the given context
308  *
309  * Results:
310  *      None
311  *
312  * Side Effects:
313  *      The new variable is placed at the front of the given context
314  *      The name and val arguments are duplicated so they may
315  *      safely be freed.
316  *-----------------------------------------------------------------------
317  */
318 static void
319 VarAdd (name, val, ctxt)
320     char           *name;       /* name of variable to add */
321     char           *val;        /* value to set it to */
322     GNode          *ctxt;       /* context in which to set it */
323 {
324     register Var   *v;
325     int           len;
326
327     v = (Var *) emalloc (sizeof (Var));
328
329     v->name = strdup (name);
330
331     len = val ? strlen(val) : 0;
332     v->val = Buf_Init(len+1);
333     Buf_AddBytes(v->val, len, (Byte *)val);
334
335     v->flags = 0;
336
337     (void) Lst_AtFront (ctxt->context, (ClientData)v);
338     if (DEBUG(VAR)) {
339         printf("%s:%s = %s\n", ctxt->name, name, val);
340     }
341 }
342
343 /*-
344  *-----------------------------------------------------------------------
345  * Var_Delete --
346  *      Remove a variable from a context.
347  *
348  * Results:
349  *      None.
350  *
351  * Side Effects:
352  *      The Var structure is removed and freed.
353  *
354  *-----------------------------------------------------------------------
355  */
356 void
357 Var_Delete(name, ctxt)
358     char          *name;
359     GNode         *ctxt;
360 {
361     LstNode       ln;
362
363     if (DEBUG(VAR)) {
364         printf("%s:delete %s\n", ctxt->name, name);
365     }
366     ln = Lst_Find(ctxt->context, (ClientData)name, VarCmp);
367     if (ln != NILLNODE) {
368         register Var      *v;
369
370         v = (Var *)Lst_Datum(ln);
371         Lst_Remove(ctxt->context, ln);
372         Buf_Destroy(v->val, TRUE);
373         free(v->name);
374         free((char *)v);
375     }
376 }
377
378 /*-
379  *-----------------------------------------------------------------------
380  * Var_Set --
381  *      Set the variable name to the value val in the given context.
382  *
383  * Results:
384  *      None.
385  *
386  * Side Effects:
387  *      If the variable doesn't yet exist, a new record is created for it.
388  *      Else the old value is freed and the new one stuck in its place
389  *
390  * Notes:
391  *      The variable is searched for only in its context before being
392  *      created in that context. I.e. if the context is VAR_GLOBAL,
393  *      only VAR_GLOBAL->context is searched. Likewise if it is VAR_CMD, only
394  *      VAR_CMD->context is searched. This is done to avoid the literally
395  *      thousands of unnecessary strcmp's that used to be done to
396  *      set, say, $(@) or $(<).
397  *-----------------------------------------------------------------------
398  */
399 void
400 Var_Set (name, val, ctxt)
401     char           *name;       /* name of variable to set */
402     char           *val;        /* value to give to the variable */
403     GNode          *ctxt;       /* context in which to set it */
404 {
405     register Var   *v;
406
407     /*
408      * We only look for a variable in the given context since anything set
409      * here will override anything in a lower context, so there's not much
410      * point in searching them all just to save a bit of memory...
411      */
412     v = VarFind (name, ctxt, 0);
413     if (v == (Var *) NIL) {
414         VarAdd (name, val, ctxt);
415     } else {
416         Buf_Discard(v->val, Buf_Size(v->val));
417         Buf_AddBytes(v->val, strlen(val), (Byte *)val);
418
419         if (DEBUG(VAR)) {
420             printf("%s:%s = %s\n", ctxt->name, name, val);
421         }
422     }
423     /*
424      * Any variables given on the command line are automatically exported
425      * to the environment (as per POSIX standard)
426      */
427     if (ctxt == VAR_CMD) {
428         setenv(name, val, 1);
429     }
430 }
431
432 /*-
433  *-----------------------------------------------------------------------
434  * Var_Append --
435  *      The variable of the given name has the given value appended to it in
436  *      the given context.
437  *
438  * Results:
439  *      None
440  *
441  * Side Effects:
442  *      If the variable doesn't exist, it is created. Else the strings
443  *      are concatenated (with a space in between).
444  *
445  * Notes:
446  *      Only if the variable is being sought in the global context is the
447  *      environment searched.
448  *      XXX: Knows its calling circumstances in that if called with ctxt
449  *      an actual target, it will only search that context since only
450  *      a local variable could be being appended to. This is actually
451  *      a big win and must be tolerated.
452  *-----------------------------------------------------------------------
453  */
454 void
455 Var_Append (name, val, ctxt)
456     char           *name;       /* Name of variable to modify */
457     char           *val;        /* String to append to it */
458     GNode          *ctxt;       /* Context in which this should occur */
459 {
460     register Var   *v;
461
462     v = VarFind (name, ctxt, (ctxt == VAR_GLOBAL) ? FIND_ENV : 0);
463
464     if (v == (Var *) NIL) {
465         VarAdd (name, val, ctxt);
466     } else {
467         Buf_AddByte(v->val, (Byte)' ');
468         Buf_AddBytes(v->val, strlen(val), (Byte *)val);
469
470         if (DEBUG(VAR)) {
471             printf("%s:%s = %s\n", ctxt->name, name,
472                    (char *) Buf_GetAll(v->val, (int *)NULL));
473         }
474
475         if (v->flags & VAR_FROM_ENV) {
476             /*
477              * If the original variable came from the environment, we
478              * have to install it in the global context (we could place
479              * it in the environment, but then we should provide a way to
480              * export other variables...)
481              */
482             v->flags &= ~VAR_FROM_ENV;
483             Lst_AtFront(ctxt->context, (ClientData)v);
484         }
485     }
486 }
487
488 /*-
489  *-----------------------------------------------------------------------
490  * Var_Exists --
491  *      See if the given variable exists.
492  *
493  * Results:
494  *      TRUE if it does, FALSE if it doesn't
495  *
496  * Side Effects:
497  *      None.
498  *
499  *-----------------------------------------------------------------------
500  */
501 Boolean
502 Var_Exists(name, ctxt)
503     char          *name;        /* Variable to find */
504     GNode         *ctxt;        /* Context in which to start search */
505 {
506     Var           *v;
507
508     v = VarFind(name, ctxt, FIND_CMD|FIND_GLOBAL|FIND_ENV);
509
510     if (v == (Var *)NIL) {
511         return(FALSE);
512     } else if (v->flags & VAR_FROM_ENV) {
513         Buf_Destroy(v->val, TRUE);
514         free((char *)v);
515     }
516     return(TRUE);
517 }
518
519 /*-
520  *-----------------------------------------------------------------------
521  * Var_Value --
522  *      Return the value of the named variable in the given context
523  *
524  * Results:
525  *      The value if the variable exists, NULL if it doesn't
526  *
527  * Side Effects:
528  *      None
529  *-----------------------------------------------------------------------
530  */
531 char *
532 Var_Value (name, ctxt)
533     char           *name;       /* name to find */
534     GNode          *ctxt;       /* context in which to search for it */
535 {
536     Var            *v;
537
538     v = VarFind (name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD);
539     if (v != (Var *) NIL) {
540         return ((char *)Buf_GetAll(v->val, (int *)NULL));
541     } else {
542         return ((char *) NULL);
543     }
544 }
545
546 /*-
547  *-----------------------------------------------------------------------
548  * VarHead --
549  *      Remove the tail of the given word and place the result in the given
550  *      buffer.
551  *
552  * Results:
553  *      TRUE if characters were added to the buffer (a space needs to be
554  *      added to the buffer before the next word).
555  *
556  * Side Effects:
557  *      The trimmed word is added to the buffer.
558  *
559  *-----------------------------------------------------------------------
560  */
561 static Boolean
562 VarHead (word, addSpace, buf)
563     char          *word;        /* Word to trim */
564     Boolean       addSpace;     /* True if need to add a space to the buffer
565                                  * before sticking in the head */
566     Buffer        buf;          /* Buffer in which to store it */
567 {
568     register char *slash;
569
570     slash = strrchr (word, '/');
571     if (slash != (char *)NULL) {
572         if (addSpace) {
573             Buf_AddByte (buf, (Byte)' ');
574         }
575         *slash = '\0';
576         Buf_AddBytes (buf, strlen (word), (Byte *)word);
577         *slash = '/';
578         return (TRUE);
579     } else {
580         /*
581          * If no directory part, give . (q.v. the POSIX standard)
582          */
583         if (addSpace) {
584             Buf_AddBytes(buf, 2, (Byte *)" .");
585         } else {
586             Buf_AddByte(buf, (Byte)'.');
587         }
588         return(TRUE);
589     }
590 }
591
592 /*-
593  *-----------------------------------------------------------------------
594  * VarTail --
595  *      Remove the head of the given word and place the result in the given
596  *      buffer.
597  *
598  * Results:
599  *      TRUE if characters were added to the buffer (a space needs to be
600  *      added to the buffer before the next word).
601  *
602  * Side Effects:
603  *      The trimmed word is added to the buffer.
604  *
605  *-----------------------------------------------------------------------
606  */
607 static Boolean
608 VarTail (word, addSpace, buf)
609     char          *word;        /* Word to trim */
610     Boolean       addSpace;     /* TRUE if need to stick a space in the
611                                  * buffer before adding the tail */
612     Buffer        buf;          /* Buffer in which to store it */
613 {
614     register char *slash;
615
616     if (addSpace) {
617         Buf_AddByte (buf, (Byte)' ');
618     }
619
620     slash = strrchr (word, '/');
621     if (slash != (char *)NULL) {
622         *slash++ = '\0';
623         Buf_AddBytes (buf, strlen(slash), (Byte *)slash);
624         slash[-1] = '/';
625     } else {
626         Buf_AddBytes (buf, strlen(word), (Byte *)word);
627     }
628     return (TRUE);
629 }
630
631 /*-
632  *-----------------------------------------------------------------------
633  * VarSuffix --
634  *      Place the suffix of the given word in the given buffer.
635  *
636  * Results:
637  *      TRUE if characters were added to the buffer (a space needs to be
638  *      added to the buffer before the next word).
639  *
640  * Side Effects:
641  *      The suffix from the word is placed in the buffer.
642  *
643  *-----------------------------------------------------------------------
644  */
645 static Boolean
646 VarSuffix (word, addSpace, buf)
647     char          *word;        /* Word to trim */
648     Boolean       addSpace;     /* TRUE if need to add a space before placing
649                                  * the suffix in the buffer */
650     Buffer        buf;          /* Buffer in which to store it */
651 {
652     register char *dot;
653
654     dot = strrchr (word, '.');
655     if (dot != (char *)NULL) {
656         if (addSpace) {
657             Buf_AddByte (buf, (Byte)' ');
658         }
659         *dot++ = '\0';
660         Buf_AddBytes (buf, strlen (dot), (Byte *)dot);
661         dot[-1] = '.';
662         return (TRUE);
663     } else {
664         return (addSpace);
665     }
666 }
667
668 /*-
669  *-----------------------------------------------------------------------
670  * VarRoot --
671  *      Remove the suffix of the given word and place the result in the
672  *      buffer.
673  *
674  * Results:
675  *      TRUE if characters were added to the buffer (a space needs to be
676  *      added to the buffer before the next word).
677  *
678  * Side Effects:
679  *      The trimmed word is added to the buffer.
680  *
681  *-----------------------------------------------------------------------
682  */
683 static Boolean
684 VarRoot (word, addSpace, buf)
685     char          *word;        /* Word to trim */
686     Boolean       addSpace;     /* TRUE if need to add a space to the buffer
687                                  * before placing the root in it */
688     Buffer        buf;          /* Buffer in which to store it */
689 {
690     register char *dot;
691
692     if (addSpace) {
693         Buf_AddByte (buf, (Byte)' ');
694     }
695
696     dot = strrchr (word, '.');
697     if (dot != (char *)NULL) {
698         *dot = '\0';
699         Buf_AddBytes (buf, strlen (word), (Byte *)word);
700         *dot = '.';
701     } else {
702         Buf_AddBytes (buf, strlen(word), (Byte *)word);
703     }
704     return (TRUE);
705 }
706
707 /*-
708  *-----------------------------------------------------------------------
709  * VarMatch --
710  *      Place the word in the buffer if it matches the given pattern.
711  *      Callback function for VarModify to implement the :M modifier.
712  *      
713  * Results:
714  *      TRUE if a space should be placed in the buffer before the next
715  *      word.
716  *
717  * Side Effects:
718  *      The word may be copied to the buffer.
719  *
720  *-----------------------------------------------------------------------
721  */
722 static Boolean
723 VarMatch (word, addSpace, buf, pattern)
724     char          *word;        /* Word to examine */
725     Boolean       addSpace;     /* TRUE if need to add a space to the
726                                  * buffer before adding the word, if it
727                                  * matches */
728     Buffer        buf;          /* Buffer in which to store it */
729     char          *pattern;     /* Pattern the word must match */
730 {
731     if (Str_Match(word, pattern)) {
732         if (addSpace) {
733             Buf_AddByte(buf, (Byte)' ');
734         }
735         addSpace = TRUE;
736         Buf_AddBytes(buf, strlen(word), (Byte *)word);
737     }
738     return(addSpace);
739 }
740
741
742
743 /*-
744  *-----------------------------------------------------------------------
745  * VarSYSVMatch --
746  *      Place the word in the buffer if it matches the given pattern.
747  *      Callback function for VarModify to implement the System V %
748  *      modifiers.
749  *      
750  * Results:
751  *      TRUE if a space should be placed in the buffer before the next
752  *      word.
753  *
754  * Side Effects:
755  *      The word may be copied to the buffer.
756  *
757  *-----------------------------------------------------------------------
758  */
759 static Boolean
760 VarSYSVMatch (word, addSpace, buf, pat)
761     char          *word;        /* Word to examine */
762     Boolean       addSpace;     /* TRUE if need to add a space to the
763                                  * buffer before adding the word, if it
764                                  * matches */
765     Buffer        buf;          /* Buffer in which to store it */
766     VarPattern    *pat;         /* Pattern the word must match */
767 {
768     int len;
769     char *ptr;
770
771     if (addSpace)
772         Buf_AddByte(buf, (Byte)' ');
773
774     addSpace = TRUE;
775
776     if ((ptr = Str_SYSVMatch(word, pat->lhs, &len)) != NULL)
777         Str_SYSVSubst(buf, pat->rhs, ptr, len);
778     else
779         Buf_AddBytes(buf, strlen(word), (Byte *) word);
780
781     return(addSpace);
782 }
783
784
785 /*-
786  *-----------------------------------------------------------------------
787  * VarNoMatch --
788  *      Place the word in the buffer if it doesn't match the given pattern.
789  *      Callback function for VarModify to implement the :N modifier.
790  *      
791  * Results:
792  *      TRUE if a space should be placed in the buffer before the next
793  *      word.
794  *
795  * Side Effects:
796  *      The word may be copied to the buffer.
797  *
798  *-----------------------------------------------------------------------
799  */
800 static Boolean
801 VarNoMatch (word, addSpace, buf, pattern)
802     char          *word;        /* Word to examine */
803     Boolean       addSpace;     /* TRUE if need to add a space to the
804                                  * buffer before adding the word, if it
805                                  * matches */
806     Buffer        buf;          /* Buffer in which to store it */
807     char          *pattern;     /* Pattern the word must match */
808 {
809     if (!Str_Match(word, pattern)) {
810         if (addSpace) {
811             Buf_AddByte(buf, (Byte)' ');
812         }
813         addSpace = TRUE;
814         Buf_AddBytes(buf, strlen(word), (Byte *)word);
815     }
816     return(addSpace);
817 }
818
819
820 /*-
821  *-----------------------------------------------------------------------
822  * VarSubstitute --
823  *      Perform a string-substitution on the given word, placing the
824  *      result in the passed buffer.
825  *
826  * Results:
827  *      TRUE if a space is needed before more characters are added.
828  *
829  * Side Effects:
830  *      None.
831  *
832  *-----------------------------------------------------------------------
833  */
834 static Boolean
835 VarSubstitute (word, addSpace, buf, pattern)
836     char                *word;      /* Word to modify */
837     Boolean             addSpace;   /* True if space should be added before
838                                      * other characters */
839     Buffer              buf;        /* Buffer for result */
840     register VarPattern *pattern;   /* Pattern for substitution */
841 {
842     register int        wordLen;    /* Length of word */
843     register char       *cp;        /* General pointer */
844
845     wordLen = strlen(word);
846     if ((pattern->flags & VAR_NO_SUB) == 0) {
847         /*
848          * Still substituting -- break it down into simple anchored cases
849          * and if none of them fits, perform the general substitution case.
850          */
851         if ((pattern->flags & VAR_MATCH_START) &&
852             (strncmp(word, pattern->lhs, pattern->leftLen) == 0)) {
853                 /*
854                  * Anchored at start and beginning of word matches pattern
855                  */
856                 if ((pattern->flags & VAR_MATCH_END) &&
857                     (wordLen == pattern->leftLen)) {
858                         /*
859                          * Also anchored at end and matches to the end (word
860                          * is same length as pattern) add space and rhs only
861                          * if rhs is non-null.
862                          */
863                         if (pattern->rightLen != 0) {
864                             if (addSpace) {
865                                 Buf_AddByte(buf, (Byte)' ');
866                             }
867                             addSpace = TRUE;
868                             Buf_AddBytes(buf, pattern->rightLen,
869                                          (Byte *)pattern->rhs);
870                         }
871                 } else if (pattern->flags & VAR_MATCH_END) {
872                     /*
873                      * Doesn't match to end -- copy word wholesale
874                      */
875                     goto nosub;
876                 } else {
877                     /*
878                      * Matches at start but need to copy in trailing characters
879                      */
880                     if ((pattern->rightLen + wordLen - pattern->leftLen) != 0){
881                         if (addSpace) {
882                             Buf_AddByte(buf, (Byte)' ');
883                         }
884                         addSpace = TRUE;
885                     }
886                     Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs);
887                     Buf_AddBytes(buf, wordLen - pattern->leftLen,
888                                  (Byte *)(word + pattern->leftLen));
889                 }
890         } else if (pattern->flags & VAR_MATCH_START) {
891             /*
892              * Had to match at start of word and didn't -- copy whole word.
893              */
894             goto nosub;
895         } else if (pattern->flags & VAR_MATCH_END) {
896             /*
897              * Anchored at end, Find only place match could occur (leftLen
898              * characters from the end of the word) and see if it does. Note
899              * that because the $ will be left at the end of the lhs, we have
900              * to use strncmp.
901              */
902             cp = word + (wordLen - pattern->leftLen);
903             if ((cp >= word) &&
904                 (strncmp(cp, pattern->lhs, pattern->leftLen) == 0)) {
905                 /*
906                  * Match found. If we will place characters in the buffer,
907                  * add a space before hand as indicated by addSpace, then
908                  * stuff in the initial, unmatched part of the word followed
909                  * by the right-hand-side.
910                  */
911                 if (((cp - word) + pattern->rightLen) != 0) {
912                     if (addSpace) {
913                         Buf_AddByte(buf, (Byte)' ');
914                     }
915                     addSpace = TRUE;
916                 }
917                 Buf_AddBytes(buf, cp - word, (Byte *)word);
918                 Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs);
919             } else {
920                 /*
921                  * Had to match at end and didn't. Copy entire word.
922                  */
923                 goto nosub;
924             }
925         } else {
926             /*
927              * Pattern is unanchored: search for the pattern in the word using
928              * String_FindSubstring, copying unmatched portions and the
929              * right-hand-side for each match found, handling non-global
930              * subsititutions correctly, etc. When the loop is done, any
931              * remaining part of the word (word and wordLen are adjusted
932              * accordingly through the loop) is copied straight into the
933              * buffer.
934              * addSpace is set FALSE as soon as a space is added to the
935              * buffer.
936              */
937             register Boolean done;
938             int origSize;
939
940             done = FALSE;
941             origSize = Buf_Size(buf);
942             while (!done) {
943                 cp = Str_FindSubstring(word, pattern->lhs);
944                 if (cp != (char *)NULL) {
945                     if (addSpace && (((cp - word) + pattern->rightLen) != 0)){
946                         Buf_AddByte(buf, (Byte)' ');
947                         addSpace = FALSE;
948                     }
949                     Buf_AddBytes(buf, cp-word, (Byte *)word);
950                     Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs);
951                     wordLen -= (cp - word) + pattern->leftLen;
952                     word = cp + pattern->leftLen;
953                     if (wordLen == 0) {
954                         done = TRUE;
955                     }
956                     if ((pattern->flags & VAR_SUB_GLOBAL) == 0) {
957                         done = TRUE;
958                         pattern->flags |= VAR_NO_SUB;
959                     }
960                 } else {
961                     done = TRUE;
962                 }
963             }
964             if (wordLen != 0) {
965                 if (addSpace) {
966                     Buf_AddByte(buf, (Byte)' ');
967                 }
968                 Buf_AddBytes(buf, wordLen, (Byte *)word);
969             }
970             /*
971              * If added characters to the buffer, need to add a space
972              * before we add any more. If we didn't add any, just return
973              * the previous value of addSpace.
974              */
975             return ((Buf_Size(buf) != origSize) || addSpace);
976         }
977         /*
978          * Common code for anchored substitutions: if performed a substitution
979          * and it's not supposed to be global, mark the pattern as requiring
980          * no more substitutions. addSpace was set TRUE if characters were
981          * added to the buffer.
982          */
983         if ((pattern->flags & VAR_SUB_GLOBAL) == 0) {
984             pattern->flags |= VAR_NO_SUB;
985         }
986         return (addSpace);
987     }
988  nosub:
989     if (addSpace) {
990         Buf_AddByte(buf, (Byte)' ');
991     }
992     Buf_AddBytes(buf, wordLen, (Byte *)word);
993     return(TRUE);
994 }
995
996 /*-
997  *-----------------------------------------------------------------------
998  * VarModify --
999  *      Modify each of the words of the passed string using the given
1000  *      function. Used to implement all modifiers.
1001  *
1002  * Results:
1003  *      A string of all the words modified appropriately.
1004  *
1005  * Side Effects:
1006  *      None.
1007  *
1008  *-----------------------------------------------------------------------
1009  */
1010 static char *
1011 VarModify (str, modProc, datum)
1012     char          *str;             /* String whose words should be trimmed */
1013     Boolean       (*modProc)();     /* Function to use to modify them */
1014     ClientData    datum;            /* Datum to pass it */
1015 {
1016     Buffer        buf;              /* Buffer for the new string */
1017     register char *cp;              /* Pointer to end of current word */
1018     char          endc;             /* Character that ended the word */
1019     Boolean       addSpace;         /* TRUE if need to add a space to the
1020                                      * buffer before adding the trimmed
1021                                      * word */
1022     
1023     buf = Buf_Init (0);
1024     cp = str;
1025     addSpace = FALSE;
1026     
1027     for (;;) {
1028         /*
1029          * Skip to next word and place cp at its end.
1030          */
1031         while (isspace (*str)) {
1032             str++;
1033         }
1034         for (cp = str; *cp != '\0' && !isspace (*cp); cp++) 
1035             continue;
1036         if (cp == str) {
1037             /*
1038              * If we didn't go anywhere, we must be done!
1039              */
1040             Buf_AddByte (buf, '\0');
1041             str = (char *)Buf_GetAll (buf, (int *)NULL);
1042             Buf_Destroy (buf, FALSE);
1043             return (str);
1044         }
1045         /*
1046          * Nuke terminating character, but save it in endc b/c if str was
1047          * some variable's value, it would not be good to screw it
1048          * over...
1049          */
1050         endc = *cp;
1051         *cp = '\0';
1052
1053         addSpace = (* modProc) (str, addSpace, buf, datum);
1054
1055         if (endc) {
1056             *cp++ = endc;
1057         }
1058         str = cp;
1059     }
1060 }
1061
1062 /*-
1063  *-----------------------------------------------------------------------
1064  * Var_Parse --
1065  *      Given the start of a variable invocation, extract the variable
1066  *      name and find its value, then modify it according to the
1067  *      specification.
1068  *
1069  * Results:
1070  *      The (possibly-modified) value of the variable or var_Error if the
1071  *      specification is invalid. The length of the specification is
1072  *      placed in *lengthPtr (for invalid specifications, this is just
1073  *      2...?).
1074  *      A Boolean in *freePtr telling whether the returned string should
1075  *      be freed by the caller.
1076  *
1077  * Side Effects:
1078  *      None.
1079  *
1080  *-----------------------------------------------------------------------
1081  */
1082 char *
1083 Var_Parse (str, ctxt, err, lengthPtr, freePtr)
1084     char          *str;         /* The string to parse */
1085     GNode         *ctxt;        /* The context for the variable */
1086     Boolean         err;        /* TRUE if undefined variables are an error */
1087     int             *lengthPtr; /* OUT: The length of the specification */
1088     Boolean         *freePtr;   /* OUT: TRUE if caller should free result */
1089 {
1090     register char   *tstr;      /* Pointer into str */
1091     Var             *v;         /* Variable in invocation */
1092     register char   *cp;        /* Secondary pointer into str (place marker
1093                                  * for tstr) */
1094     Boolean         haveModifier;/* TRUE if have modifiers for the variable */
1095     register char   endc;       /* Ending character when variable in parens
1096                                  * or braces */
1097     char            *start;
1098     Boolean         dynamic;    /* TRUE if the variable is local and we're
1099                                  * expanding it in a non-local context. This
1100                                  * is done to support dynamic sources. The
1101                                  * result is just the invocation, unaltered */
1102     
1103     *freePtr = FALSE;
1104     dynamic = FALSE;
1105     start = str;
1106     
1107     if (str[1] != '(' && str[1] != '{') {
1108         /*
1109          * If it's not bounded by braces of some sort, life is much simpler.
1110          * We just need to check for the first character and return the
1111          * value if it exists.
1112          */
1113         char      name[2];
1114
1115         name[0] = str[1];
1116         name[1] = '\0';
1117
1118         v = VarFind (name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD);
1119         if (v == (Var *)NIL) {
1120             *lengthPtr = 2;
1121             
1122             if ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)) {
1123                 /*
1124                  * If substituting a local variable in a non-local context,
1125                  * assume it's for dynamic source stuff. We have to handle
1126                  * this specially and return the longhand for the variable
1127                  * with the dollar sign escaped so it makes it back to the
1128                  * caller. Only four of the local variables are treated
1129                  * specially as they are the only four that will be set
1130                  * when dynamic sources are expanded.
1131                  */
1132                 switch (str[1]) {
1133                     case '@':
1134                         return("$(.TARGET)");
1135                     case '%':
1136                         return("$(.ARCHIVE)");
1137                     case '*':
1138                         return("$(.PREFIX)");
1139                     case '!':
1140                         return("$(.MEMBER)");
1141                 }
1142             }
1143             /*
1144              * Error
1145              */
1146             return (err ? var_Error : varNoError);
1147         } else {
1148             haveModifier = FALSE;
1149             tstr = &str[1];
1150             endc = str[1];
1151         }
1152     } else {
1153         endc = str[1] == '(' ? ')' : '}';
1154
1155         /*
1156          * Skip to the end character or a colon, whichever comes first.
1157          */
1158         for (tstr = str + 2;
1159              *tstr != '\0' && *tstr != endc && *tstr != ':';
1160              tstr++)
1161         {
1162             continue;
1163         }
1164         if (*tstr == ':') {
1165             haveModifier = TRUE;
1166         } else if (*tstr != '\0') {
1167             haveModifier = FALSE;
1168         } else {
1169             /*
1170              * If we never did find the end character, return NULL
1171              * right now, setting the length to be the distance to
1172              * the end of the string, since that's what make does.
1173              */
1174             *lengthPtr = tstr - str;
1175             return (var_Error);
1176         }
1177         *tstr = '\0';
1178         
1179         v = VarFind (str + 2, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD);
1180         if ((v == (Var *)NIL) && (ctxt != VAR_CMD) && (ctxt != VAR_GLOBAL) &&
1181             ((tstr-str) == 4) && (str[3] == 'F' || str[3] == 'D'))
1182         {
1183             /*
1184              * Check for bogus D and F forms of local variables since we're
1185              * in a local context and the name is the right length.
1186              */
1187             switch(str[2]) {
1188                 case '@':
1189                 case '%':
1190                 case '*':
1191                 case '!':
1192                 case '>':
1193                 case '<':
1194                 {
1195                     char    vname[2];
1196                     char    *val;
1197
1198                     /*
1199                      * Well, it's local -- go look for it.
1200                      */
1201                     vname[0] = str[2];
1202                     vname[1] = '\0';
1203                     v = VarFind(vname, ctxt, 0);
1204                     
1205                     if (v != (Var *)NIL) {
1206                         /*
1207                          * No need for nested expansion or anything, as we're
1208                          * the only one who sets these things and we sure don't
1209                          * but nested invocations in them...
1210                          */
1211                         val = (char *)Buf_GetAll(v->val, (int *)NULL);
1212                         
1213                         if (str[3] == 'D') {
1214                             val = VarModify(val, VarHead, (ClientData)0);
1215                         } else {
1216                             val = VarModify(val, VarTail, (ClientData)0);
1217                         }
1218                         /*
1219                          * Resulting string is dynamically allocated, so
1220                          * tell caller to free it.
1221                          */
1222                         *freePtr = TRUE;
1223                         *lengthPtr = tstr-start+1;
1224                         *tstr = endc;
1225                         return(val);
1226                     }
1227                     break;
1228                 }
1229             }
1230         }
1231                             
1232         if (v == (Var *)NIL) {
1233             if ((((tstr-str) == 3) ||
1234                  ((((tstr-str) == 4) && (str[3] == 'F' ||
1235                                          str[3] == 'D')))) &&
1236                 ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)))
1237             {
1238                 /*
1239                  * If substituting a local variable in a non-local context,
1240                  * assume it's for dynamic source stuff. We have to handle
1241                  * this specially and return the longhand for the variable
1242                  * with the dollar sign escaped so it makes it back to the
1243                  * caller. Only four of the local variables are treated
1244                  * specially as they are the only four that will be set
1245                  * when dynamic sources are expanded.
1246                  */
1247                 switch (str[2]) {
1248                     case '@':
1249                     case '%':
1250                     case '*':
1251                     case '!':
1252                         dynamic = TRUE;
1253                         break;
1254                 }
1255             } else if (((tstr-str) > 4) && (str[2] == '.') &&
1256                        isupper(str[3]) &&
1257                        ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)))
1258             {
1259                 int     len;
1260                 
1261                 len = (tstr-str) - 3;
1262                 if ((strncmp(str+2, ".TARGET", len) == 0) ||
1263                     (strncmp(str+2, ".ARCHIVE", len) == 0) ||
1264                     (strncmp(str+2, ".PREFIX", len) == 0) ||
1265                     (strncmp(str+2, ".MEMBER", len) == 0))
1266                 {
1267                     dynamic = TRUE;
1268                 }
1269             }
1270             
1271             if (!haveModifier) {
1272                 /*
1273                  * No modifiers -- have specification length so we can return
1274                  * now.
1275                  */
1276                 *lengthPtr = tstr - start + 1;
1277                 *tstr = endc;
1278                 if (dynamic) {
1279                     str = emalloc(*lengthPtr + 1);
1280                     strncpy(str, start, *lengthPtr);
1281                     str[*lengthPtr] = '\0';
1282                     *freePtr = TRUE;
1283                     return(str);
1284                 } else {
1285                     return (err ? var_Error : varNoError);
1286                 }
1287             } else {
1288                 /*
1289                  * Still need to get to the end of the variable specification,
1290                  * so kludge up a Var structure for the modifications
1291                  */
1292                 v = (Var *) emalloc(sizeof(Var));
1293                 v->name = &str[1];
1294                 v->val = Buf_Init(1);
1295                 v->flags = VAR_JUNK;
1296             }
1297         }
1298     }
1299
1300     if (v->flags & VAR_IN_USE) {
1301         Fatal("Variable %s is recursive.", v->name);
1302         /*NOTREACHED*/
1303     } else {
1304         v->flags |= VAR_IN_USE;
1305     }
1306     /*
1307      * Before doing any modification, we have to make sure the value
1308      * has been fully expanded. If it looks like recursion might be
1309      * necessary (there's a dollar sign somewhere in the variable's value)
1310      * we just call Var_Subst to do any other substitutions that are
1311      * necessary. Note that the value returned by Var_Subst will have
1312      * been dynamically-allocated, so it will need freeing when we
1313      * return.
1314      */
1315     str = (char *)Buf_GetAll(v->val, (int *)NULL);
1316     if (strchr (str, '$') != (char *)NULL) {
1317         str = Var_Subst(NULL, str, ctxt, err);
1318         *freePtr = TRUE;
1319     }
1320     
1321     v->flags &= ~VAR_IN_USE;
1322     
1323     /*
1324      * Now we need to apply any modifiers the user wants applied.
1325      * These are:
1326      *            :M<pattern>   words which match the given <pattern>.
1327      *                          <pattern> is of the standard file
1328      *                          wildcarding form.
1329      *            :S<d><pat1><d><pat2><d>[g]
1330      *                          Substitute <pat2> for <pat1> in the value
1331      *            :H            Substitute the head of each word
1332      *            :T            Substitute the tail of each word
1333      *            :E            Substitute the extension (minus '.') of
1334      *                          each word
1335      *            :R            Substitute the root of each word
1336      *                          (pathname minus the suffix).
1337      *            :lhs=rhs      Like :S, but the rhs goes to the end of
1338      *                          the invocation.
1339      */
1340     if ((str != (char *)NULL) && haveModifier) {
1341         /*
1342          * Skip initial colon while putting it back.
1343          */
1344         *tstr++ = ':';
1345         while (*tstr != endc) {
1346             char        *newStr;    /* New value to return */
1347             char        termc;      /* Character which terminated scan */
1348             
1349             if (DEBUG(VAR)) {
1350                 printf("Applying :%c to \"%s\"\n", *tstr, str);
1351             }
1352             switch (*tstr) {
1353                 case 'N':
1354                 case 'M':
1355                 {
1356                     char    *pattern;
1357                     char    *cp2;
1358                     Boolean copy;
1359
1360                     copy = FALSE;
1361                     for (cp = tstr + 1;
1362                          *cp != '\0' && *cp != ':' && *cp != endc;
1363                          cp++)
1364                     {
1365                         if (*cp == '\\' && (cp[1] == ':' || cp[1] == endc)){
1366                             copy = TRUE;
1367                             cp++;
1368                         }
1369                     }
1370                     termc = *cp;
1371                     *cp = '\0';
1372                     if (copy) {
1373                         /*
1374                          * Need to compress the \:'s out of the pattern, so
1375                          * allocate enough room to hold the uncompressed
1376                          * pattern (note that cp started at tstr+1, so
1377                          * cp - tstr takes the null byte into account) and
1378                          * compress the pattern into the space.
1379                          */
1380                         pattern = emalloc(cp - tstr);
1381                         for (cp2 = pattern, cp = tstr + 1;
1382                              *cp != '\0';
1383                              cp++, cp2++)
1384                         {
1385                             if ((*cp == '\\') &&
1386                                 (cp[1] == ':' || cp[1] == endc)) {
1387                                     cp++;
1388                             }
1389                             *cp2 = *cp;
1390                         }
1391                         *cp2 = '\0';
1392                     } else {
1393                         pattern = &tstr[1];
1394                     }
1395                     if (*tstr == 'M' || *tstr == 'm') {
1396                         newStr = VarModify(str, VarMatch, (ClientData)pattern);
1397                     } else {
1398                         newStr = VarModify(str, VarNoMatch,
1399                                            (ClientData)pattern);
1400                     }
1401                     if (copy) {
1402                         free(pattern);
1403                     }
1404                     break;
1405                 }
1406                 case 'S':
1407                 {
1408                     VarPattern      pattern;
1409                     register char   delim;
1410                     Buffer          buf;        /* Buffer for patterns */
1411
1412                     pattern.flags = 0;
1413                     delim = tstr[1];
1414                     tstr += 2;
1415                     /*
1416                      * If pattern begins with '^', it is anchored to the
1417                      * start of the word -- skip over it and flag pattern.
1418                      */
1419                     if (*tstr == '^') {
1420                         pattern.flags |= VAR_MATCH_START;
1421                         tstr += 1;
1422                     }
1423
1424                     buf = Buf_Init(0);
1425                     
1426                     /*
1427                      * Pass through the lhs looking for 1) escaped delimiters,
1428                      * '$'s and backslashes (place the escaped character in
1429                      * uninterpreted) and 2) unescaped $'s that aren't before
1430                      * the delimiter (expand the variable substitution).
1431                      * The result is left in the Buffer buf.
1432                      */
1433                     for (cp = tstr; *cp != '\0' && *cp != delim; cp++) {
1434                         if ((*cp == '\\') &&
1435                             ((cp[1] == delim) ||
1436                              (cp[1] == '$') ||
1437                              (cp[1] == '\\')))
1438                         {
1439                             Buf_AddByte(buf, (Byte)cp[1]);
1440                             cp++;
1441                         } else if (*cp == '$') {
1442                             if (cp[1] != delim) {
1443                                 /*
1444                                  * If unescaped dollar sign not before the
1445                                  * delimiter, assume it's a variable
1446                                  * substitution and recurse.
1447                                  */
1448                                 char        *cp2;
1449                                 int         len;
1450                                 Boolean     freeIt;
1451                                 
1452                                 cp2 = Var_Parse(cp, ctxt, err, &len, &freeIt);
1453                                 Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2);
1454                                 if (freeIt) {
1455                                     free(cp2);
1456                                 }
1457                                 cp += len - 1;
1458                             } else {
1459                                 /*
1460                                  * Unescaped $ at end of pattern => anchor
1461                                  * pattern at end.
1462                                  */
1463                                 pattern.flags |= VAR_MATCH_END;
1464                             }
1465                         } else {
1466                             Buf_AddByte(buf, (Byte)*cp);
1467                         }
1468                     }
1469
1470                     Buf_AddByte(buf, (Byte)'\0');
1471                     
1472                     /*
1473                      * If lhs didn't end with the delimiter, complain and
1474                      * return NULL
1475                      */
1476                     if (*cp != delim) {
1477                         *lengthPtr = cp - start + 1;
1478                         if (*freePtr) {
1479                             free(str);
1480                         }
1481                         Buf_Destroy(buf, TRUE);
1482                         Error("Unclosed substitution for %s (%c missing)",
1483                               v->name, delim);
1484                         return (var_Error);
1485                     }
1486
1487                     /*
1488                      * Fetch pattern and destroy buffer, but preserve the data
1489                      * in it, since that's our lhs. Note that Buf_GetAll
1490                      * will return the actual number of bytes, which includes
1491                      * the null byte, so we have to decrement the length by
1492                      * one.
1493                      */
1494                     pattern.lhs = (char *)Buf_GetAll(buf, &pattern.leftLen);
1495                     pattern.leftLen--;
1496                     Buf_Destroy(buf, FALSE);
1497
1498                     /*
1499                      * Now comes the replacement string. Three things need to
1500                      * be done here: 1) need to compress escaped delimiters and
1501                      * ampersands and 2) need to replace unescaped ampersands
1502                      * with the l.h.s. (since this isn't regexp, we can do
1503                      * it right here) and 3) expand any variable substitutions.
1504                      */
1505                     buf = Buf_Init(0);
1506                     
1507                     tstr = cp + 1;
1508                     for (cp = tstr; *cp != '\0' && *cp != delim; cp++) {
1509                         if ((*cp == '\\') &&
1510                             ((cp[1] == delim) ||
1511                              (cp[1] == '&') ||
1512                              (cp[1] == '\\') ||
1513                              (cp[1] == '$')))
1514                         {
1515                             Buf_AddByte(buf, (Byte)cp[1]);
1516                             cp++;
1517                         } else if ((*cp == '$') && (cp[1] != delim)) {
1518                             char    *cp2;
1519                             int     len;
1520                             Boolean freeIt;
1521
1522                             cp2 = Var_Parse(cp, ctxt, err, &len, &freeIt);
1523                             Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2);
1524                             cp += len - 1;
1525                             if (freeIt) {
1526                                 free(cp2);
1527                             }
1528                         } else if (*cp == '&') {
1529                             Buf_AddBytes(buf, pattern.leftLen,
1530                                          (Byte *)pattern.lhs);
1531                         } else {
1532                             Buf_AddByte(buf, (Byte)*cp);
1533                         }
1534                     }
1535
1536                     Buf_AddByte(buf, (Byte)'\0');
1537                     
1538                     /*
1539                      * If didn't end in delimiter character, complain
1540                      */
1541                     if (*cp != delim) {
1542                         *lengthPtr = cp - start + 1;
1543                         if (*freePtr) {
1544                             free(str);
1545                         }
1546                         Buf_Destroy(buf, TRUE);
1547                         Error("Unclosed substitution for %s (%c missing)",
1548                               v->name, delim);
1549                         return (var_Error);
1550                     }
1551
1552                     pattern.rhs = (char *)Buf_GetAll(buf, &pattern.rightLen);
1553                     pattern.rightLen--;
1554                     Buf_Destroy(buf, FALSE);
1555
1556                     /*
1557                      * Check for global substitution. If 'g' after the final
1558                      * delimiter, substitution is global and is marked that
1559                      * way.
1560                      */
1561                     cp++;
1562                     if (*cp == 'g') {
1563                         pattern.flags |= VAR_SUB_GLOBAL;
1564                         cp++;
1565                     }
1566
1567                     termc = *cp;
1568                     newStr = VarModify(str, VarSubstitute,
1569                                        (ClientData)&pattern);
1570                     /*
1571                      * Free the two strings.
1572                      */
1573                     free(pattern.lhs);
1574                     free(pattern.rhs);
1575                     break;
1576                 }
1577                 case 'T':
1578                     if (tstr[1] == endc || tstr[1] == ':') {
1579                         newStr = VarModify (str, VarTail, (ClientData)0);
1580                         cp = tstr + 1;
1581                         termc = *cp;
1582                         break;
1583                     }
1584                     /*FALLTHRU*/
1585                 case 'H':
1586                     if (tstr[1] == endc || tstr[1] == ':') {
1587                         newStr = VarModify (str, VarHead, (ClientData)0);
1588                         cp = tstr + 1;
1589                         termc = *cp;
1590                         break;
1591                     }
1592                     /*FALLTHRU*/
1593                 case 'E':
1594                     if (tstr[1] == endc || tstr[1] == ':') {
1595                         newStr = VarModify (str, VarSuffix, (ClientData)0);
1596                         cp = tstr + 1;
1597                         termc = *cp;
1598                         break;
1599                     }
1600                     /*FALLTHRU*/
1601                 case 'R':
1602                     if (tstr[1] == endc || tstr[1] == ':') {
1603                         newStr = VarModify (str, VarRoot, (ClientData)0);
1604                         cp = tstr + 1;
1605                         termc = *cp;
1606                         break;
1607                     }
1608                     /*FALLTHRU*/
1609                 default: {
1610                     /*
1611                      * This can either be a bogus modifier or a System-V
1612                      * substitution command.
1613                      */
1614                     VarPattern      pattern;
1615                     Boolean         eqFound;
1616                     
1617                     pattern.flags = 0;
1618                     eqFound = FALSE;
1619                     /*
1620                      * First we make a pass through the string trying
1621                      * to verify it is a SYSV-make-style translation:
1622                      * it must be: <string1>=<string2>)
1623                      */
1624                     for (cp = tstr; *cp != '\0' && *cp != endc; cp++) {
1625                         if (*cp == '=') {
1626                             eqFound = TRUE;
1627                             /* continue looking for endc */
1628                         }
1629                     }
1630                     if (*cp == endc && eqFound) {
1631                         
1632                         /*
1633                          * Now we break this sucker into the lhs and
1634                          * rhs. We must null terminate them of course.
1635                          */
1636                         for (cp = tstr; *cp != '='; cp++)
1637                             continue;
1638                         pattern.lhs = tstr;
1639                         pattern.leftLen = cp - tstr;
1640                         *cp++ = '\0';
1641                         
1642                         pattern.rhs = cp;
1643                         while (*cp != endc) {
1644                             cp++;
1645                         }
1646                         pattern.rightLen = cp - pattern.rhs;
1647                         *cp = '\0';
1648                         
1649                         /*
1650                          * SYSV modifications happen through the whole
1651                          * string. Note the pattern is anchored at the end.
1652                          */
1653                         newStr = VarModify(str, VarSYSVMatch,
1654                                            (ClientData)&pattern);
1655
1656                         /*
1657                          * Restore the nulled characters
1658                          */
1659                         pattern.lhs[pattern.leftLen] = '=';
1660                         pattern.rhs[pattern.rightLen] = endc;
1661                         termc = endc;
1662                     } else {
1663                         Error ("Unknown modifier '%c'\n", *tstr);
1664                         for (cp = tstr+1;
1665                              *cp != ':' && *cp != endc && *cp != '\0';
1666                              cp++) 
1667                                  continue;
1668                         termc = *cp;
1669                         newStr = var_Error;
1670                     }
1671                 }
1672             }
1673             if (DEBUG(VAR)) {
1674                 printf("Result is \"%s\"\n", newStr);
1675             }
1676             
1677             if (*freePtr) {
1678                 free (str);
1679             }
1680             str = newStr;
1681             if (str != var_Error) {
1682                 *freePtr = TRUE;
1683             } else {
1684                 *freePtr = FALSE;
1685             }
1686             if (termc == '\0') {
1687                 Error("Unclosed variable specification for %s", v->name);
1688             } else if (termc == ':') {
1689                 *cp++ = termc;
1690             } else {
1691                 *cp = termc;
1692             }
1693             tstr = cp;
1694         }
1695         *lengthPtr = tstr - start + 1;
1696     } else {
1697         *lengthPtr = tstr - start + 1;
1698         *tstr = endc;
1699     }
1700     
1701     if (v->flags & VAR_FROM_ENV) {
1702         Boolean   destroy = FALSE;
1703         
1704         if (str != (char *)Buf_GetAll(v->val, (int *)NULL)) {
1705             destroy = TRUE;
1706         } else {
1707             /*
1708              * Returning the value unmodified, so tell the caller to free
1709              * the thing.
1710              */
1711             *freePtr = TRUE;
1712         }
1713         Buf_Destroy(v->val, destroy);
1714         free((Address)v);
1715     } else if (v->flags & VAR_JUNK) {
1716         /*
1717          * Perform any free'ing needed and set *freePtr to FALSE so the caller
1718          * doesn't try to free a static pointer.
1719          */
1720         if (*freePtr) {
1721             free(str);
1722         }
1723         *freePtr = FALSE;
1724         free((Address)v);
1725         if (dynamic) {
1726             str = emalloc(*lengthPtr + 1);
1727             strncpy(str, start, *lengthPtr);
1728             str[*lengthPtr] = '\0';
1729             *freePtr = TRUE;
1730         } else {
1731             str = var_Error;
1732         }
1733     }
1734     return (str);
1735 }
1736
1737 /*-
1738  *-----------------------------------------------------------------------
1739  * Var_Subst  --
1740  *      Substitute for all variables in the given string in the given context
1741  *      If undefErr is TRUE, Parse_Error will be called when an undefined
1742  *      variable is encountered.
1743  *
1744  * Results:
1745  *      The resulting string.
1746  *
1747  * Side Effects:
1748  *      None. The old string must be freed by the caller
1749  *-----------------------------------------------------------------------
1750  */
1751 char *
1752 Var_Subst (var, str, ctxt, undefErr)
1753     char          *var;             /* Named variable || NULL for all */
1754     char          *str;             /* the string in which to substitute */
1755     GNode         *ctxt;            /* the context wherein to find variables */
1756     Boolean       undefErr;         /* TRUE if undefineds are an error */
1757 {
1758     Buffer        buf;              /* Buffer for forming things */
1759     char          *val;             /* Value to substitute for a variable */
1760     int           length;           /* Length of the variable invocation */
1761     Boolean       doFree;           /* Set true if val should be freed */
1762     static Boolean errorReported;   /* Set true if an error has already
1763                                      * been reported to prevent a plethora
1764                                      * of messages when recursing */
1765
1766     buf = Buf_Init (MAKE_BSIZE);
1767     errorReported = FALSE;
1768
1769     while (*str) {
1770         if (var == NULL && (*str == '$') && (str[1] == '$')) {
1771             /*
1772              * A dollar sign may be escaped either with another dollar sign.
1773              * In such a case, we skip over the escape character and store the
1774              * dollar sign into the buffer directly.
1775              */
1776             str++;
1777             Buf_AddByte(buf, (Byte)*str);
1778             str++;
1779         } else if (*str != '$') {
1780             /*
1781              * Skip as many characters as possible -- either to the end of
1782              * the string or to the next dollar sign (variable invocation).
1783              */
1784             char  *cp;
1785
1786             for (cp = str++; *str != '$' && *str != '\0'; str++)
1787                 continue;
1788             Buf_AddBytes(buf, str - cp, (Byte *)cp);
1789         } else {
1790             if (var != NULL) {
1791                 int expand;
1792                 for (;;) {
1793                     if (str[1] != '(' && str[1] != '{') {
1794                         if (str[1] != *var) {
1795                             Buf_AddBytes(buf, 2, (Byte *) str);
1796                             str += 2;
1797                             expand = FALSE;
1798                         }
1799                         else
1800                             expand = TRUE;
1801                         break;
1802                     }
1803                     else {
1804                         char *p;
1805
1806                         /*
1807                          * Scan up to the end of the variable name.
1808                          */
1809                         for (p = &str[2]; *p && 
1810                              *p != ':' && *p != ')' && *p != '}'; p++)
1811                             if (*p == '$') 
1812                                 break;
1813                         /*
1814                          * A variable inside the variable. We cannot expand
1815                          * the external variable yet, so we try again with
1816                          * the nested one
1817                          */
1818                         if (*p == '$') {
1819                             Buf_AddBytes(buf, p - str, (Byte *) str);
1820                             str = p;
1821                             continue;
1822                         }
1823                                 
1824                         if (strncmp(var, str + 2, p - str - 2) != 0 || 
1825                             var[p - str - 2] != '\0') {
1826                             /*
1827                              * Not the variable we want to expand, scan
1828                              * until the next variable
1829                              */
1830                             for (;*p != '$' && *p != '\0'; p++) 
1831                                 continue;
1832                             Buf_AddBytes(buf, p - str, (Byte *) str);
1833                             str = p;
1834                             expand = FALSE;
1835                         }
1836                         else
1837                             expand = TRUE;
1838                         break;
1839                     }
1840                 }
1841                 if (!expand)
1842                     continue;
1843             }
1844                         
1845             val = Var_Parse (str, ctxt, undefErr, &length, &doFree);
1846
1847             /*
1848              * When we come down here, val should either point to the
1849              * value of this variable, suitably modified, or be NULL.
1850              * Length should be the total length of the potential
1851              * variable invocation (from $ to end character...)
1852              */
1853             if (val == var_Error || val == varNoError) {
1854                 /*
1855                  * If performing old-time variable substitution, skip over
1856                  * the variable and continue with the substitution. Otherwise,
1857                  * store the dollar sign and advance str so we continue with
1858                  * the string...
1859                  */
1860                 if (oldVars) {
1861                     str += length;
1862                 } else if (undefErr) {
1863                     /*
1864                      * If variable is undefined, complain and skip the
1865                      * variable. The complaint will stop us from doing anything
1866                      * when the file is parsed.
1867                      */
1868                     if (!errorReported) {
1869                         Parse_Error (PARSE_FATAL,
1870                                      "Undefined variable \"%.*s\"",length,str);
1871                     }
1872                     str += length;
1873                     errorReported = TRUE;
1874                 } else {
1875                     Buf_AddByte (buf, (Byte)*str);
1876                     str += 1;
1877                 }
1878             } else {
1879                 /*
1880                  * We've now got a variable structure to store in. But first,
1881                  * advance the string pointer.
1882                  */
1883                 str += length;
1884                 
1885                 /*
1886                  * Copy all the characters from the variable value straight
1887                  * into the new string.
1888                  */
1889                 Buf_AddBytes (buf, strlen (val), (Byte *)val);
1890                 if (doFree) {
1891                     free ((Address)val);
1892                 }
1893             }
1894         }
1895     }
1896         
1897     Buf_AddByte (buf, '\0');
1898     str = (char *)Buf_GetAll (buf, (int *)NULL);
1899     Buf_Destroy (buf, FALSE);
1900     return (str);
1901 }
1902
1903 /*-
1904  *-----------------------------------------------------------------------
1905  * Var_GetTail --
1906  *      Return the tail from each of a list of words. Used to set the
1907  *      System V local variables.
1908  *
1909  * Results:
1910  *      The resulting string.
1911  *
1912  * Side Effects:
1913  *      None.
1914  *
1915  *-----------------------------------------------------------------------
1916  */
1917 char *
1918 Var_GetTail(file)
1919     char        *file;      /* Filename to modify */
1920 {
1921     return(VarModify(file, VarTail, (ClientData)0));
1922 }
1923
1924 /*-
1925  *-----------------------------------------------------------------------
1926  * Var_GetHead --
1927  *      Find the leading components of a (list of) filename(s).
1928  *      XXX: VarHead does not replace foo by ., as (sun) System V make
1929  *      does.
1930  *
1931  * Results:
1932  *      The leading components.
1933  *
1934  * Side Effects:
1935  *      None.
1936  *
1937  *-----------------------------------------------------------------------
1938  */
1939 char *
1940 Var_GetHead(file)
1941     char        *file;      /* Filename to manipulate */
1942 {
1943     return(VarModify(file, VarHead, (ClientData)0));
1944 }
1945
1946 /*-
1947  *-----------------------------------------------------------------------
1948  * Var_Init --
1949  *      Initialize the module
1950  *
1951  * Results:
1952  *      None
1953  *
1954  * Side Effects:
1955  *      The VAR_CMD and VAR_GLOBAL contexts are created 
1956  *-----------------------------------------------------------------------
1957  */
1958 void
1959 Var_Init ()
1960 {
1961     VAR_GLOBAL = Targ_NewGN ("Global");
1962     VAR_CMD = Targ_NewGN ("Command");
1963
1964 }
1965
1966 /****************** PRINT DEBUGGING INFO *****************/
1967 static int
1968 VarPrintVar (v)
1969     Var            *v;
1970 {
1971     printf ("%-16s = %s\n", v->name, (char *) Buf_GetAll(v->val, (int *)NULL));
1972     return (0);
1973 }
1974
1975 /*-
1976  *-----------------------------------------------------------------------
1977  * Var_Dump --
1978  *      print all variables in a context
1979  *-----------------------------------------------------------------------
1980  */
1981 void
1982 Var_Dump (ctxt)
1983     GNode          *ctxt;
1984 {
1985     Lst_ForEach (ctxt->context, VarPrintVar);
1986 }