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