Changeset 51 for trunk/src/kmk/var.c


Ignore:
Timestamp:
Apr 7, 2003, 3:30:32 AM (22 years ago)
Author:
bird
Message:

kMk and porting to kLib.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/kmk/var.c

    r46 r51  
    11/*
    22 * Copyright (c) 1988, 1989, 1990, 1993
    3  *      The Regents of the University of California.  All rights reserved.
     3 *      The Regents of the University of California.  All rights reserved.
    44 * Copyright (c) 1989 by Berkeley Softworks
    55 * All rights reserved.
     
    1818 * 3. All advertising materials mentioning features or use of this software
    1919 *    must display the following acknowledgement:
    20  *      This product includes software developed by the University of
    21  *      California, Berkeley and its contributors.
     20 *      This product includes software developed by the University of
     21 *      California, Berkeley and its contributors.
    2222 * 4. Neither the name of the University nor the names of its contributors
    2323 *    may be used to endorse or promote products derived from this software
     
    3939#ifndef lint
    4040#if 0
    41 static char sccsid[] = "@(#)var.c       8.3 (Berkeley) 3/19/94";
     41static char sccsid[] = "@(#)var.c       8.3 (Berkeley) 3/19/94";
    4242#else
    4343static const char rcsid[] =
    4444  "$FreeBSD: src/usr.bin/make/var.c,v 1.16.2.3 2002/02/27 14:18:57 cjc Exp $";
    4545#endif
     46#define KLIBFILEDEF rcsid
    4647#endif /* not lint */
    4748
    4849/*-
    4950 * var.c --
    50  *      Variable-handling functions
     51 *      Variable-handling functions
    5152 *
    5253 * Interface:
    53  *      Var_Set             Set the value of a variable in the given
    54  *                          context. The variable is created if it doesn't
    55  *                          yet exist. The value and variable name need not
    56  *                          be preserved.
    57  *
    58  *      Var_Append          Append more characters to an existing variable
    59  *                          in the given context. The variable needn't
    60  *                          exist already -- it will be created if it doesn't.
    61  *                          A space is placed between the old value and the
    62  *                          new one.
    63  *
    64  *      Var_Exists          See if a variable exists.
    65  *
    66  *      Var_Value           Return the value of a variable in a context or
    67  *                          NULL if the variable is undefined.
    68  *
    69  *      Var_Subst           Substitute named variable, or all variables if
    70  *                          NULL in a string using
    71  *                          the given context as the top-most one. If the
    72  *                          third argument is non-zero, Parse_Error is
    73  *                          called if any variables are undefined.
    74  *
    75  *      Var_Parse           Parse a variable expansion from a string and
    76  *                          return the result and the number of characters
    77  *                          consumed.
    78  *
    79  *      Var_Delete          Delete a variable in a context.
    80  *
    81  *      Var_Init            Initialize this module.
     54 *      Var_Set             Set the value of a variable in the given
     55 *                          context. The variable is created if it doesn't
     56 *                          yet exist. The value and variable name need not
     57 *                          be preserved.
     58 *
     59 *      Var_Append          Append more characters to an existing variable
     60 *                          in the given context. The variable needn't
     61 *                          exist already -- it will be created if it doesn't.
     62 *                          A space is placed between the old value and the
     63 *                          new one.
     64 *
     65 *      Var_Exists          See if a variable exists.
     66 *
     67 *      Var_Value           Return the value of a variable in a context or
     68 *                          NULL if the variable is undefined.
     69 *
     70 *      Var_Subst           Substitute named variable, or all variables if
     71 *                          NULL in a string using
     72 *                          the given context as the top-most one. If the
     73 *                          third argument is non-zero, Parse_Error is
     74 *                          called if any variables are undefined.
     75 *
     76 *      Var_Parse           Parse a variable expansion from a string and
     77 *                          return the result and the number of characters
     78 *                          consumed.
     79 *
     80 *      Var_Delete          Delete a variable in a context.
     81 *
     82 *      Var_Init            Initialize this module.
    8283 *
    8384 * Debugging:
    84  *      Var_Dump            Print out all variables defined in the given
    85  *                          context.
     85 *      Var_Dump            Print out all variables defined in the given
     86 *                          context.
    8687 *
    8788 * XXX: There's a lot of duplication in these functions.
     
    106107 * a flag, as things outside this module don't give a hoot.
    107108 */
    108 char    var_Error[] = "";
     109char    var_Error[] = "";
    109110
    110111/*
     
    113114 * identical string instances...
    114115 */
    115 static char     varNoError[] = "";
     116static char     varNoError[] = "";
    116117
    117118/*
    118119 * Internally, variables are contained in four different contexts.
    119  *      1) the environment. They may not be changed. If an environment
    120  *          variable is appended-to, the result is placed in the global
    121  *          context.
    122  *      2) the global context. Variables set in the Makefile are located in
    123  *          the global context. It is the penultimate context searched when
    124  *          substituting.
    125  *      3) the command-line context. All variables set on the command line
    126  *         are placed in this context. They are UNALTERABLE once placed here.
    127  *      4) the local context. Each target has associated with it a context
    128  *         list. On this list are located the structures describing such
    129  *         local variables as $(@) and $(*)
     120 *      1) the environment. They may not be changed. If an environment
     121 *          variable is appended-to, the result is placed in the global
     122 *          context.
     123 *      2) the global context. Variables set in the Makefile are located in
     124 *          the global context. It is the penultimate context searched when
     125 *          substituting.
     126 *      3) the command-line context. All variables set on the command line
     127 *         are placed in this context. They are UNALTERABLE once placed here.
     128 *      4) the local context. Each target has associated with it a context
     129 *         list. On this list are located the structures describing such
     130 *         local variables as $(@) and $(*)
    130131 * The four contexts are searched in the reverse order from which they are
    131132 * listed.
     
    134135GNode          *VAR_CMD;      /* variables defined on the command-line */
    135136
    136 static Lst      allVars;      /* List of all variables */
    137 
    138 #define FIND_CMD        0x1   /* look in VAR_CMD when searching */
    139 #define FIND_GLOBAL     0x2   /* look in VAR_GLOBAL as well */
    140 #define FIND_ENV        0x4   /* look in the environment also */
     137static Lst      allVars;      /* List of all variables */
     138
     139#define FIND_CMD        0x1   /* look in VAR_CMD when searching */
     140#define FIND_GLOBAL     0x2   /* look in VAR_GLOBAL as well */
     141#define FIND_ENV        0x4   /* look in the environment also */
    141142
    142143typedef struct Var {
    143     char          *name;        /* the variable's name */
    144     Buffer        val;          /* its value */
    145     int           flags;        /* miscellaneous status flags */
    146 #define VAR_IN_USE      1           /* Variable's value currently being used.
    147                                      * Used to avoid recursion */
    148 #define VAR_FROM_ENV    2           /* Variable comes from the environment */
    149 #define VAR_JUNK        4           /* Variable is a junk variable that
    150                                      * should be destroyed when done with
    151                                      * it. Used by Var_Parse for undefined,
    152                                      * modified variables */
     144    char          *name;        /* the variable's name */
     145    Buffer        val;          /* its value */
     146    int           flags;        /* miscellaneous status flags */
     147#define VAR_IN_USE      1           /* Variable's value currently being used.
     148                                     * Used to avoid recursion */
     149#define VAR_FROM_ENV    2           /* Variable comes from the environment */
     150#define VAR_JUNK        4           /* Variable is a junk variable that
     151                                     * should be destroyed when done with
     152                                     * it. Used by Var_Parse for undefined,
     153                                     * modified variables */
    153154}  Var;
    154155
    155156/* Var*Pattern flags */
    156 #define VAR_SUB_GLOBAL  0x01    /* Apply substitution globally */
    157 #define VAR_SUB_ONE     0x02    /* Apply substitution to one word */
    158 #define VAR_SUB_MATCHED 0x04    /* There was a match */
    159 #define VAR_MATCH_START 0x08    /* Match at start of word */
    160 #define VAR_MATCH_END   0x10    /* Match at end of word */
    161 #define VAR_NOSUBST     0x20    /* don't expand vars in VarGetPattern */
     157#define VAR_SUB_GLOBAL  0x01    /* Apply substitution globally */
     158#define VAR_SUB_ONE     0x02    /* Apply substitution to one word */
     159#define VAR_SUB_MATCHED 0x04    /* There was a match */
     160#define VAR_MATCH_START 0x08    /* Match at start of word */
     161#define VAR_MATCH_END   0x10    /* Match at end of word */
     162#define VAR_NOSUBST     0x20    /* don't expand vars in VarGetPattern */
    162163
    163164typedef struct {
    164     char          *lhs;     /* String to match */
    165     int           leftLen;  /* Length of string */
    166     char          *rhs;     /* Replacement string (w/ &'s removed) */
    167     int           rightLen; /* Length of replacement */
    168     int           flags;
     165    char          *lhs;     /* String to match */
     166    int           leftLen;  /* Length of string */
     167    char          *rhs;     /* Replacement string (w/ &'s removed) */
     168    int           rightLen; /* Length of replacement */
     169    int           flags;
    169170} VarPattern;
    170171
    171172typedef struct {
    172     regex_t        re;
    173     int            nsub;
    174     regmatch_t    *matches;
    175     char          *replace;
    176     int            flags;
     173    regex_t        re;
     174    int            nsub;
     175    regmatch_t    *matches;
     176    char          *replace;
     177    int            flags;
    177178} VarREPattern;
    178179
     
    185186static Boolean VarSuffix __P((char *, Boolean, Buffer, ClientData));
    186187static Boolean VarRoot __P((char *, Boolean, Buffer, ClientData));
    187 #if defined(NMAKE) || defined(KMK)
     188#ifdef USE_BASEANDROOT_MODIFIERS
    188189static Boolean VarBase __P((char *, Boolean, Buffer, ClientData));
    189190#endif
     
    197198static Boolean VarSubstitute __P((char *, Boolean, Buffer, ClientData));
    198199static char *VarGetPattern __P((GNode *, int, char **, int, int *, int *,
    199                                 VarPattern *));
     200                                VarPattern *));
    200201static char *VarQuote __P((char *));
    201202static char *VarModify __P((char *, Boolean (*)(char *, Boolean, Buffer,
    202                                                 ClientData),
    203                             ClientData));
     203                                                ClientData),
     204                            ClientData));
    204205static int VarPrintVar __P((ClientData, ClientData));
    205206
     
    207208 *-----------------------------------------------------------------------
    208209 * VarCmp  --
    209  *      See if the given variable matches the named one. Called from
    210  *      Lst_Find when searching for a variable of a given name.
    211  *
    212  * Results:
    213  *      0 if they match. non-zero otherwise.
    214  *
    215  * Side Effects:
    216  *      none
     210 *      See if the given variable matches the named one. Called from
     211 *      Lst_Find when searching for a variable of a given name.
     212 *
     213 * Results:
     214 *      0 if they match. non-zero otherwise.
     215 *
     216 * Side Effects:
     217 *      none
    217218 *-----------------------------------------------------------------------
    218219 */
    219220static int
    220221VarCmp (v, name)
    221     ClientData     v;           /* VAR structure to compare */
    222     ClientData     name;        /* name to look for */
     222    ClientData     v;           /* VAR structure to compare */
     223    ClientData     name;        /* name to look for */
    223224{
    224225    return (strcmp ((char *) name, ((Var *) v)->name));
     
    228229 *-----------------------------------------------------------------------
    229230 * StrCmp  --
    230  *      See if the given strings matches. Called from
    231  *      Lst_Find when searching for a environment-variable-overrided var.
    232  *
    233  * Results:
    234  *      0 if they match. non-zero otherwise.
    235  *
    236  * Side Effects:
    237  *      none
     231 *      See if the given strings matches. Called from
     232 *      Lst_Find when searching for a environment-variable-overrided var.
     233 *
     234 * Results:
     235 *      0 if they match. non-zero otherwise.
     236 *
     237 * Side Effects:
     238 *      none
    238239 *-----------------------------------------------------------------------
    239240 */
     
    251252 *-----------------------------------------------------------------------
    252253 * VarFind --
    253  *      Find the given variable in the given context and any other contexts
    254  *      indicated.
    255  *
    256  * Results:
    257  *      A pointer to the structure describing the desired variable or
    258  *      NIL if the variable does not exist.
    259  *
    260  * Side Effects:
    261  *      None
     254 *      Find the given variable in the given context and any other contexts
     255 *      indicated.
     256 *
     257 * Results:
     258 *      A pointer to the structure describing the desired variable or
     259 *      NIL if the variable does not exist.
     260 *
     261 * Side Effects:
     262 *      None
    262263 *-----------------------------------------------------------------------
    263264 */
    264265static Var *
    265266VarFind (name, ctxt, flags)
    266     char                *name;  /* name to find */
    267     GNode               *ctxt;  /* context in which to find it */
    268     int                 flags;  /* FIND_GLOBAL set means to look in the
    269                                 * VAR_GLOBAL context as well.
    270                                 * FIND_CMD set means to look in the VAR_CMD
    271                                 * context also.
    272                                 * FIND_ENV set means to look in the
    273                                 * environment */
    274 {
    275     Boolean             localCheckEnvFirst;
    276     LstNode             var;
    277     Var                 *v;
    278 
    279         /*
    280         * If the variable name begins with a '.', it could very well be one of
    281         * the local ones.  We check the name against all the local variables
    282         * and substitute the short version in for 'name' if it matches one of
    283         * them.
    284         */
    285         if (*name == '.' && isupper((unsigned char) name[1]))
    286                 switch (name[1]) {
    287                 case 'A':
    288                         if (!strcmp(name, ".ALLSRC"))
    289                                 name = ALLSRC;
     267    char                *name;  /* name to find */
     268    GNode               *ctxt;  /* context in which to find it */
     269    int                 flags;  /* FIND_GLOBAL set means to look in the
     270                                * VAR_GLOBAL context as well.
     271                                * FIND_CMD set means to look in the VAR_CMD
     272                                * context also.
     273                                * FIND_ENV set means to look in the
     274                                * environment */
     275{
     276    Boolean             localCheckEnvFirst;
     277    LstNode             var;
     278    Var                 *v;
     279
     280        /*
     281        * If the variable name begins with a '.', it could very well be one of
     282        * the local ones.  We check the name against all the local variables
     283        * and substitute the short version in for 'name' if it matches one of
     284        * them.
     285        */
     286        if (*name == '.' && isupper((unsigned char) name[1]))
     287                switch (name[1]) {
     288                case 'A':
     289                        if (!strcmp(name, ".ALLSRC"))
     290                                name = ALLSRC;
    290291#ifdef USE_ARCHIVES
    291                         if (!strcmp(name, ".ARCHIVE"))
    292                                 name = ARCHIVE;
     292                        if (!strcmp(name, ".ARCHIVE"))
     293                                name = ARCHIVE;
    293294#endif
    294                         break;
    295                 case 'I':
    296                         if (!strcmp(name, ".IMPSRC"))
    297                                 name = IMPSRC;
    298                         break;
     295                        break;
     296                case 'I':
     297                        if (!strcmp(name, ".IMPSRC"))
     298                                name = IMPSRC;
     299                        break;
    299300#ifdef USE_ARCHIVES
    300                 case 'M':
    301                         if (!strcmp(name, ".MEMBER"))
    302                                 name = MEMBER;
    303                         break;
     301                case 'M':
     302                        if (!strcmp(name, ".MEMBER"))
     303                                name = MEMBER;
     304                        break;
    304305#endif
    305                 case 'O':
    306                         if (!strcmp(name, ".OODATE"))
    307                                 name = OODATE;
    308                         break;
    309                 case 'P':
    310                         if (!strcmp(name, ".PREFIX"))
    311                                 name = PREFIX;
     306                case 'O':
     307                        if (!strcmp(name, ".OODATE"))
     308                                name = OODATE;
     309                        break;
     310                case 'P':
     311                        if (!strcmp(name, ".PREFIX"))
     312                                name = PREFIX;
    312313                        #ifdef USE_PARENTS
    313314                        else if (!strcmp(name, ".PARENTS"))
    314315                                name = PARENTS;
    315316                        #endif
    316                         break;
    317                 case 'T':
    318                         if (!strcmp(name, ".TARGET"))
    319                                 name = TARGET;
    320                         break;
    321                 }
     317                        break;
     318                case 'T':
     319                        if (!strcmp(name, ".TARGET"))
     320                                name = TARGET;
     321                        break;
     322                }
    322323
    323324    /*
     
    326327     */
    327328    if (Lst_Find (envFirstVars, (ClientData)name,
    328                   (int (*)(ClientData, ClientData)) VarStrCmp) != NILLNODE)
     329                  (int (*)(ClientData, ClientData)) VarStrCmp) != NILLNODE)
    329330    {
    330         localCheckEnvFirst = TRUE;
     331        localCheckEnvFirst = TRUE;
    331332    } else {
    332         localCheckEnvFirst = FALSE;
     333        localCheckEnvFirst = FALSE;
    333334    }
    334335
     
    341342
    342343    if ((var == NILLNODE) && (flags & FIND_CMD) && (ctxt != VAR_CMD)) {
    343         var = Lst_Find (VAR_CMD->context, (ClientData)name, VarCmp);
     344        var = Lst_Find (VAR_CMD->context, (ClientData)name, VarCmp);
    344345    }
    345346    if ((var == NILLNODE) && (flags & FIND_GLOBAL) && (ctxt != VAR_GLOBAL) &&
    346         !checkEnvFirst && !localCheckEnvFirst)
     347        !checkEnvFirst && !localCheckEnvFirst)
    347348    {
    348         var = Lst_Find (VAR_GLOBAL->context, (ClientData)name, VarCmp);
     349        var = Lst_Find (VAR_GLOBAL->context, (ClientData)name, VarCmp);
    349350    }
    350351    if ((var == NILLNODE) && (flags & FIND_ENV)) {
    351352        #ifdef USE_KLIB
    352         const char *env;
    353         if ((env = kEnvGet (name)) != NULL) {
     353        const char *env;
     354        if ((env = kEnvGet (name)) != NULL) {
    354355        #else
    355356        char *env;
    356         if ((env = getenv (name)) != NULL) {
     357        if ((env = getenv (name)) != NULL) {
    357358        #endif
    358             int         len;
    359 
    360             v = (Var *) emalloc(sizeof(Var));
    361             v->name = estrdup(name);
    362 
    363             len = strlen(env);
    364 
    365             v->val = Buf_Init(len);
    366             Buf_AddBytes(v->val, len, (Byte *)env);
    367 
    368             v->flags = VAR_FROM_ENV;
    369             return (v);
    370         } else if ((checkEnvFirst || localCheckEnvFirst) &&
    371                    (flags & FIND_GLOBAL) && (ctxt != VAR_GLOBAL))
    372         {
    373             var = Lst_Find (VAR_GLOBAL->context, (ClientData)name, VarCmp);
    374             if (var == NILLNODE) {
    375                 return ((Var *) NIL);
    376             } else {
    377                 return ((Var *)Lst_Datum(var));
    378             }
    379         } else {
    380             return((Var *)NIL);
    381         }
     359            int         len;
     360
     361            v = (Var *) emalloc(sizeof(Var));
     362            v->name = estrdup(name);
     363
     364            len = strlen(env);
     365
     366            v->val = Buf_Init(len);
     367            Buf_AddBytes(v->val, len, (Byte *)env);
     368
     369            v->flags = VAR_FROM_ENV;
     370            return (v);
     371        } else if ((checkEnvFirst || localCheckEnvFirst) &&
     372                   (flags & FIND_GLOBAL) && (ctxt != VAR_GLOBAL))
     373        {
     374            var = Lst_Find (VAR_GLOBAL->context, (ClientData)name, VarCmp);
     375            if (var == NILLNODE) {
     376                return ((Var *) NIL);
     377            } else {
     378                return ((Var *)Lst_Datum(var));
     379            }
     380        } else {
     381            return((Var *)NIL);
     382        }
    382383    } else if (var == NILLNODE) {
    383         return ((Var *) NIL);
     384        return ((Var *) NIL);
    384385    } else {
    385         return ((Var *) Lst_Datum (var));
     386        return ((Var *) Lst_Datum (var));
    386387    }
    387388}
     
    390391 *-----------------------------------------------------------------------
    391392 * VarAdd  --
    392  *      Add a new variable of name name and value val to the given context
    393  *
    394  * Results:
    395  *      None
    396  *
    397  * Side Effects:
    398  *      The new variable is placed at the front of the given context
    399  *      The name and val arguments are duplicated so they may
    400  *      safely be freed.
     393 *      Add a new variable of name name and value val to the given context
     394 *
     395 * Results:
     396 *      None
     397 *
     398 * Side Effects:
     399 *      The new variable is placed at the front of the given context
     400 *      The name and val arguments are duplicated so they may
     401 *      safely be freed.
    401402 *-----------------------------------------------------------------------
    402403 */
    403404static void
    404405VarAdd (name, val, ctxt)
    405     char           *name;       /* name of variable to add */
    406     char           *val;        /* value to set it to */
    407     GNode          *ctxt;       /* context in which to set it */
     406    char           *name;       /* name of variable to add */
     407    char           *val;        /* value to set it to */
     408    GNode          *ctxt;       /* context in which to set it */
    408409{
    409410    register Var   *v;
    410     int           len;
     411    int           len;
    411412
    412413    v = (Var *) emalloc (sizeof (Var));
     
    423424    (void) Lst_AtEnd (allVars, (ClientData) v);
    424425    if (DEBUG(VAR)) {
    425         printf("%s:%s = %s\n", ctxt->name, name, val);
     426        printf("%s:%s = %s\n", ctxt->name, name, val);
    426427    }
    427428}
     
    431432 *-----------------------------------------------------------------------
    432433 * VarDelete  --
    433  *      Delete a variable and all the space associated with it.
    434  *
    435  * Results:
    436  *      None
    437  *
    438  * Side Effects:
    439  *      None
     434 *      Delete a variable and all the space associated with it.
     435 *
     436 * Results:
     437 *      None
     438 *
     439 * Side Effects:
     440 *      None
    440441 *-----------------------------------------------------------------------
    441442 */
     
    455456 *-----------------------------------------------------------------------
    456457 * Var_Delete --
    457  *      Remove a variable from a context.
    458  *
    459  * Results:
    460  *      None.
    461  *
    462  * Side Effects:
    463  *      The Var structure is removed and freed.
     458 *      Remove a variable from a context.
     459 *
     460 * Results:
     461 *      None.
     462 *
     463 * Side Effects:
     464 *      The Var structure is removed and freed.
    464465 *
    465466 *-----------------------------------------------------------------------
     
    467468void
    468469Var_Delete(name, ctxt)
    469     char          *name;
    470     GNode         *ctxt;
    471 {
    472     LstNode       ln;
     470    char          *name;
     471    GNode         *ctxt;
     472{
     473    LstNode       ln;
    473474
    474475    if (DEBUG(VAR)) {
    475         printf("%s:delete %s\n", ctxt->name, name);
     476        printf("%s:delete %s\n", ctxt->name, name);
    476477    }
    477478    ln = Lst_Find(ctxt->context, (ClientData)name, VarCmp);
    478479    if (ln != NILLNODE) {
    479         register Var      *v;
    480 
    481         v = (Var *)Lst_Datum(ln);
    482         Lst_Remove(ctxt->context, ln);
    483         ln = Lst_Member(allVars, v);
    484         Lst_Remove(allVars, ln);
    485         VarDelete((ClientData) v);
     480        register Var      *v;
     481
     482        v = (Var *)Lst_Datum(ln);
     483        Lst_Remove(ctxt->context, ln);
     484        ln = Lst_Member(allVars, v);
     485        Lst_Remove(allVars, ln);
     486        VarDelete((ClientData) v);
    486487    }
    487488}
     
    490491 *-----------------------------------------------------------------------
    491492 * Var_Set --
    492  *      Set the variable name to the value val in the given context.
    493  *
    494  * Results:
    495  *      None.
    496  *
    497  * Side Effects:
    498  *      If the variable doesn't yet exist, a new record is created for it.
    499  *      Else the old value is freed and the new one stuck in its place
     493 *      Set the variable name to the value val in the given context.
     494 *
     495 * Results:
     496 *      None.
     497 *
     498 * Side Effects:
     499 *      If the variable doesn't yet exist, a new record is created for it.
     500 *      Else the old value is freed and the new one stuck in its place
    500501 *
    501502 * Notes:
    502  *      The variable is searched for only in its context before being
    503  *      created in that context. I.e. if the context is VAR_GLOBAL,
    504  *      only VAR_GLOBAL->context is searched. Likewise if it is VAR_CMD, only
    505  *      VAR_CMD->context is searched. This is done to avoid the literally
    506  *      thousands of unnecessary strcmp's that used to be done to
    507  *      set, say, $(@) or $(<).
     503 *      The variable is searched for only in its context before being
     504 *      created in that context. I.e. if the context is VAR_GLOBAL,
     505 *      only VAR_GLOBAL->context is searched. Likewise if it is VAR_CMD, only
     506 *      VAR_CMD->context is searched. This is done to avoid the literally
     507 *      thousands of unnecessary strcmp's that used to be done to
     508 *      set, say, $(@) or $(<).
    508509 *-----------------------------------------------------------------------
    509510 */
    510511void
    511512Var_Set (name, val, ctxt)
    512     char           *name;       /* name of variable to set */
    513     char           *val;        /* value to give to the variable */
    514     GNode          *ctxt;       /* context in which to set it */
     513    char           *name;       /* name of variable to set */
     514    char           *val;        /* value to give to the variable */
     515    GNode          *ctxt;       /* context in which to set it */
    515516{
    516517    register Var   *v;
     
    523524    v = VarFind (name, ctxt, 0);
    524525    if (v == (Var *) NIL) {
    525         VarAdd (name, val, ctxt);
     526        VarAdd (name, val, ctxt);
    526527    } else {
    527         Buf_Discard(v->val, Buf_Size(v->val));
    528         Buf_AddBytes(v->val, strlen(val), (Byte *)val);
    529 
    530         if (DEBUG(VAR)) {
    531             printf("%s:%s = %s\n", ctxt->name, name, val);
    532         }
     528        Buf_Discard(v->val, Buf_Size(v->val));
     529        Buf_AddBytes(v->val, strlen(val), (Byte *)val);
     530
     531        if (DEBUG(VAR)) {
     532            printf("%s:%s = %s\n", ctxt->name, name, val);
     533        }
    533534    }
    534535    /*
     
    540541        kEnvSet(name, val, TRUE);
    541542        #else
    542         setenv(name, val, 1);
     543        setenv(name, val, 1);
    543544        #endif
    544545    }
     
    548549 *-----------------------------------------------------------------------
    549550 * Var_Append --
    550  *      The variable of the given name has the given value appended to it in
    551  *      the given context.
    552  *
    553  * Results:
    554  *      None
    555  *
    556  * Side Effects:
    557  *      If the variable doesn't exist, it is created. Else the strings
    558  *      are concatenated (with a space in between).
     551 *      The variable of the given name has the given value appended to it in
     552 *      the given context.
     553 *
     554 * Results:
     555 *      None
     556 *
     557 * Side Effects:
     558 *      If the variable doesn't exist, it is created. Else the strings
     559 *      are concatenated (with a space in between).
    559560 *
    560561 * Notes:
    561  *      Only if the variable is being sought in the global context is the
    562  *      environment searched.
    563  *      XXX: Knows its calling circumstances in that if called with ctxt
    564  *      an actual target, it will only search that context since only
    565  *      a local variable could be being appended to. This is actually
    566  *      a big win and must be tolerated.
     562 *      Only if the variable is being sought in the global context is the
     563 *      environment searched.
     564 *      XXX: Knows its calling circumstances in that if called with ctxt
     565 *      an actual target, it will only search that context since only
     566 *      a local variable could be being appended to. This is actually
     567 *      a big win and must be tolerated.
    567568 *-----------------------------------------------------------------------
    568569 */
    569570void
    570571Var_Append (name, val, ctxt)
    571     char           *name;       /* Name of variable to modify */
    572     char           *val;        /* String to append to it */
    573     GNode          *ctxt;       /* Context in which this should occur */
     572    char           *name;       /* Name of variable to modify */
     573    char           *val;        /* String to append to it */
     574    GNode          *ctxt;       /* Context in which this should occur */
    574575{
    575576    register Var   *v;
     
    578579
    579580    if (v == (Var *) NIL) {
    580         VarAdd (name, val, ctxt);
     581        VarAdd (name, val, ctxt);
    581582    } else {
    582         Buf_AddByte(v->val, (Byte)' ');
    583         Buf_AddBytes(v->val, strlen(val), (Byte *)val);
    584 
    585         if (DEBUG(VAR)) {
    586             printf("%s:%s = %s\n", ctxt->name, name,
    587                    (char *) Buf_GetAll(v->val, (int *)NULL));
    588         }
    589 
    590         if (v->flags & VAR_FROM_ENV) {
    591             /*
    592              * If the original variable came from the environment, we
    593              * have to install it in the global context (we could place
    594              * it in the environment, but then we should provide a way to
    595              * export other variables...)
    596              */
    597             v->flags &= ~VAR_FROM_ENV;
    598             Lst_AtFront(ctxt->context, (ClientData)v);
    599         }
     583        Buf_AddByte(v->val, (Byte)' ');
     584        Buf_AddBytes(v->val, strlen(val), (Byte *)val);
     585
     586        if (DEBUG(VAR)) {
     587            printf("%s:%s = %s\n", ctxt->name, name,
     588                   (char *) Buf_GetAll(v->val, (int *)NULL));
     589        }
     590
     591        if (v->flags & VAR_FROM_ENV) {
     592            /*
     593             * If the original variable came from the environment, we
     594             * have to install it in the global context (we could place
     595             * it in the environment, but then we should provide a way to
     596             * export other variables...)
     597             */
     598            v->flags &= ~VAR_FROM_ENV;
     599            Lst_AtFront(ctxt->context, (ClientData)v);
     600        }
    600601    }
    601602}
     
    604605 *-----------------------------------------------------------------------
    605606 * Var_Exists --
    606  *      See if the given variable exists.
    607  *
    608  * Results:
    609  *      TRUE if it does, FALSE if it doesn't
    610  *
    611  * Side Effects:
    612  *      None.
     607 *      See if the given variable exists.
     608 *
     609 * Results:
     610 *      TRUE if it does, FALSE if it doesn't
     611 *
     612 * Side Effects:
     613 *      None.
    613614 *
    614615 *-----------------------------------------------------------------------
     
    616617Boolean
    617618Var_Exists(name, ctxt)
    618     char          *name;        /* Variable to find */
    619     GNode         *ctxt;        /* Context in which to start search */
    620 {
    621     Var           *v;
     619    char          *name;        /* Variable to find */
     620    GNode         *ctxt;        /* Context in which to start search */
     621{
     622    Var           *v;
    622623
    623624    v = VarFind(name, ctxt, FIND_CMD|FIND_GLOBAL|FIND_ENV);
    624625
    625626    if (v == (Var *)NIL) {
    626         return(FALSE);
     627        return(FALSE);
    627628    } else if (v->flags & VAR_FROM_ENV) {
    628         efree(v->name);
    629         Buf_Destroy(v->val, TRUE);
    630         efree((char *)v);
     629        efree(v->name);
     630        Buf_Destroy(v->val, TRUE);
     631        efree((char *)v);
    631632    }
    632633    return(TRUE);
     
    636637 *-----------------------------------------------------------------------
    637638 * Var_Value --
    638  *      Return the value of the named variable in the given context
    639  *
    640  * Results:
    641  *      The value if the variable exists, NULL if it doesn't
    642  *
    643  * Side Effects:
    644  *      None
     639 *      Return the value of the named variable in the given context
     640 *
     641 * Results:
     642 *      The value if the variable exists, NULL if it doesn't
     643 *
     644 * Side Effects:
     645 *      None
    645646 *-----------------------------------------------------------------------
    646647 */
    647648char *
    648649Var_Value (name, ctxt, frp)
    649     char           *name;       /* name to find */
    650     GNode          *ctxt;       /* context in which to search for it */
    651     char           **frp;
     650    char           *name;       /* name to find */
     651    GNode          *ctxt;       /* context in which to search for it */
     652    char           **frp;
    652653{
    653654    Var            *v;
     
    656657    *frp = NULL;
    657658    if (v != (Var *) NIL) {
    658         char *p = ((char *)Buf_GetAll(v->val, (int *)NULL));
    659         if (v->flags & VAR_FROM_ENV) {
    660             Buf_Destroy(v->val, FALSE);
    661             efree((Address) v);
    662             *frp = p;
    663         }
    664         return p;
     659        char *p = ((char *)Buf_GetAll(v->val, (int *)NULL));
     660        if (v->flags & VAR_FROM_ENV) {
     661            Buf_Destroy(v->val, FALSE);
     662            efree((Address) v);
     663            *frp = p;
     664        }
     665        return p;
    665666    } else {
    666         return ((char *) NULL);
     667        return ((char *) NULL);
    667668    }
    668669}
     
    671672 *-----------------------------------------------------------------------
    672673 * VarHead --
    673  *      Remove the tail of the given word and place the result in the given
    674  *      buffer.
    675  *
    676  * Results:
    677  *      TRUE if characters were added to the buffer (a space needs to be
    678  *      added to the buffer before the next word).
    679  *
    680  * Side Effects:
    681  *      The trimmed word is added to the buffer.
     674 *      Remove the tail of the given word and place the result in the given
     675 *      buffer.
     676 *
     677 * Results:
     678 *      TRUE if characters were added to the buffer (a space needs to be
     679 *      added to the buffer before the next word).
     680 *
     681 * Side Effects:
     682 *      The trimmed word is added to the buffer.
    682683 *
    683684 *-----------------------------------------------------------------------
     
    685686static Boolean
    686687VarHead (word, addSpace, buf, dummy)
    687     char          *word;        /* Word to trim */
    688     Boolean       addSpace;     /* True if need to add a space to the buffer
    689                                 * before sticking in the head */
    690     Buffer        buf;          /* Buffer in which to store it */
    691     ClientData    dummy;
     688    char          *word;        /* Word to trim */
     689    Boolean       addSpace;     /* True if need to add a space to the buffer
     690                                * before sticking in the head */
     691    Buffer        buf;          /* Buffer in which to store it */
     692    ClientData    dummy;
    692693{
    693694    register char *slash;
     
    695696    slash = strrchr (word, '/');
    696697    if (slash != (char *)NULL) {
    697         if (addSpace) {
    698             Buf_AddByte (buf, (Byte)' ');
    699         }
    700         *slash = '\0';
    701         Buf_AddBytes (buf, strlen (word), (Byte *)word);
    702         *slash = '/';
    703         return (TRUE);
     698        if (addSpace) {
     699            Buf_AddByte (buf, (Byte)' ');
     700        }
     701        *slash = '\0';
     702        Buf_AddBytes (buf, strlen (word), (Byte *)word);
     703        *slash = '/';
     704        return (TRUE);
    704705    } else {
    705         /*
    706         * If no directory part, give . (q.v. the POSIX standard)
    707         */
    708         if (addSpace) {
    709             Buf_AddBytes(buf, 2, (Byte *)" .");
    710         } else {
    711             Buf_AddByte(buf, (Byte)'.');
    712         }
     706        /*
     707        * If no directory part, give . (q.v. the POSIX standard)
     708        */
     709        if (addSpace) {
     710            Buf_AddBytes(buf, 2, (Byte *)" .");
     711        } else {
     712            Buf_AddByte(buf, (Byte)'.');
     713        }
    713714    }
    714715    return(dummy ? TRUE : TRUE);
     
    718719 *-----------------------------------------------------------------------
    719720 * VarTail --
    720  *      Remove the head of the given word and place the result in the given
    721  *      buffer.
    722  *
    723  * Results:
    724  *      TRUE if characters were added to the buffer (a space needs to be
    725  *      added to the buffer before the next word).
    726  *
    727  * Side Effects:
    728  *      The trimmed word is added to the buffer.
     721 *      Remove the head of the given word and place the result in the given
     722 *      buffer.
     723 *
     724 * Results:
     725 *      TRUE if characters were added to the buffer (a space needs to be
     726 *      added to the buffer before the next word).
     727 *
     728 * Side Effects:
     729 *      The trimmed word is added to the buffer.
    729730 *
    730731 *-----------------------------------------------------------------------
     
    732733static Boolean
    733734VarTail (word, addSpace, buf, dummy)
    734     char          *word;        /* Word to trim */
    735     Boolean       addSpace;     /* TRUE if need to stick a space in the
    736                                 * buffer before adding the tail */
    737     Buffer        buf;          /* Buffer in which to store it */
    738     ClientData    dummy;
     735    char          *word;        /* Word to trim */
     736    Boolean       addSpace;     /* TRUE if need to stick a space in the
     737                                * buffer before adding the tail */
     738    Buffer        buf;          /* Buffer in which to store it */
     739    ClientData    dummy;
    739740{
    740741    register char *slash;
    741742
    742743    if (addSpace) {
    743         Buf_AddByte (buf, (Byte)' ');
     744        Buf_AddByte (buf, (Byte)' ');
    744745    }
    745746
    746747    slash = strrchr (word, '/');
    747748    if (slash != (char *)NULL) {
    748         *slash++ = '\0';
    749         Buf_AddBytes (buf, strlen(slash), (Byte *)slash);
    750         slash[-1] = '/';
     749        *slash++ = '\0';
     750        Buf_AddBytes (buf, strlen(slash), (Byte *)slash);
     751        slash[-1] = '/';
    751752    } else {
    752         Buf_AddBytes (buf, strlen(word), (Byte *)word);
     753        Buf_AddBytes (buf, strlen(word), (Byte *)word);
    753754    }
    754755    return (dummy ? TRUE : TRUE);
     
    758759 *-----------------------------------------------------------------------
    759760 * VarSuffix --
    760  *      Place the suffix of the given word in the given buffer.
    761  *
    762  * Results:
    763  *      TRUE if characters were added to the buffer (a space needs to be
    764  *      added to the buffer before the next word).
    765  *
    766  * Side Effects:
    767  *      The suffix from the word is placed in the buffer.
     761 *      Place the suffix of the given word in the given buffer.
     762 *
     763 * Results:
     764 *      TRUE if characters were added to the buffer (a space needs to be
     765 *      added to the buffer before the next word).
     766 *
     767 * Side Effects:
     768 *      The suffix from the word is placed in the buffer.
    768769 *
    769770 *-----------------------------------------------------------------------
     
    771772static Boolean
    772773VarSuffix (word, addSpace, buf, dummy)
    773     char          *word;        /* Word to trim */
    774     Boolean       addSpace;     /* TRUE if need to add a space before placing
    775                                 * the suffix in the buffer */
    776     Buffer        buf;          /* Buffer in which to store it */
    777     ClientData    dummy;
     774    char          *word;        /* Word to trim */
     775    Boolean       addSpace;     /* TRUE if need to add a space before placing
     776                                * the suffix in the buffer */
     777    Buffer        buf;          /* Buffer in which to store it */
     778    ClientData    dummy;
    778779{
    779780    register char *dot;
     
    781782    dot = strrchr (word, '.');
    782783    if (dot != (char *)NULL) {
    783         if (addSpace) {
    784             Buf_AddByte (buf, (Byte)' ');
    785         }
    786         *dot++ = '\0';
    787         Buf_AddBytes (buf, strlen (dot), (Byte *)dot);
    788         dot[-1] = '.';
    789         addSpace = TRUE;
     784        if (addSpace) {
     785            Buf_AddByte (buf, (Byte)' ');
     786        }
     787        *dot++ = '\0';
     788        Buf_AddBytes (buf, strlen (dot), (Byte *)dot);
     789        dot[-1] = '.';
     790        addSpace = TRUE;
    790791    }
    791792    return (dummy ? addSpace : addSpace);
     
    795796 *-----------------------------------------------------------------------
    796797 * VarRoot --
    797  *      Remove the suffix of the given word and place the result in the
    798  *      buffer.
    799  *
    800  * Results:
    801  *      TRUE if characters were added to the buffer (a space needs to be
    802  *      added to the buffer before the next word).
    803  *
    804  * Side Effects:
    805  *      The trimmed word is added to the buffer.
     798 *      Remove the suffix of the given word and place the result in the
     799 *      buffer.
     800 *
     801 * Results:
     802 *      TRUE if characters were added to the buffer (a space needs to be
     803 *      added to the buffer before the next word).
     804 *
     805 * Side Effects:
     806 *      The trimmed word is added to the buffer.
    806807 *
    807808 *-----------------------------------------------------------------------
     
    809810static Boolean
    810811VarRoot (word, addSpace, buf, dummy)
    811     char          *word;        /* Word to trim */
    812     Boolean       addSpace;     /* TRUE if need to add a space to the buffer
    813                                 * before placing the root in it */
    814     Buffer        buf;          /* Buffer in which to store it */
    815     ClientData    dummy;
     812    char          *word;        /* Word to trim */
     813    Boolean       addSpace;     /* TRUE if need to add a space to the buffer
     814                                * before placing the root in it */
     815    Buffer        buf;          /* Buffer in which to store it */
     816    ClientData    dummy;
    816817{
    817818    register char *dot;
    818819
    819820    if (addSpace) {
    820         Buf_AddByte (buf, (Byte)' ');
     821        Buf_AddByte (buf, (Byte)' ');
    821822    }
    822823
    823824    dot = strrchr (word, '.');
    824825    if (dot != (char *)NULL) {
    825         *dot = '\0';
    826         Buf_AddBytes (buf, strlen (word), (Byte *)word);
    827         *dot = '.';
     826        *dot = '\0';
     827        Buf_AddBytes (buf, strlen (word), (Byte *)word);
     828        *dot = '.';
    828829    } else {
    829         Buf_AddBytes (buf, strlen(word), (Byte *)word);
     830        Buf_AddBytes (buf, strlen(word), (Byte *)word);
    830831    }
    831832    return (dummy ? TRUE : TRUE);
    832833}
    833834
    834 #if defined(NMAKE) || defined(KMK)
     835#ifdef USE_BASEANDROOT_MODIFIERS
    835836/*-
    836837 *-----------------------------------------------------------------------
    837838 * VarBase --
    838  *      Remove the head and suffix of the given word and place the result
    839  *      in the given buffer.
    840  *
    841  * Results:
    842  *      TRUE if characters were added to the buffer (a space needs to be
    843  *      added to the buffer before the next word).
    844  *
    845  * Side Effects:
    846  *      The trimmed word is added to the buffer.
     839 *      Remove the head and suffix of the given word and place the result
     840 *      in the given buffer.
     841 *
     842 * Results:
     843 *      TRUE if characters were added to the buffer (a space needs to be
     844 *      added to the buffer before the next word).
     845 *
     846 * Side Effects:
     847 *      The trimmed word is added to the buffer.
    847848 *
    848849 *-----------------------------------------------------------------------
     
    850851static Boolean
    851852VarBase (word, addSpace, buf, dummy)
    852     char          *word;        /* Word to trim */
    853     Boolean       addSpace;     /* TRUE if need to stick a space in the
    854                                 * buffer before adding the tail */
    855     Buffer        buf;          /* Buffer in which to store it */
    856     ClientData    dummy;
     853    char          *word;        /* Word to trim */
     854    Boolean       addSpace;     /* TRUE if need to stick a space in the
     855                                * buffer before adding the tail */
     856    Buffer        buf;          /* Buffer in which to store it */
     857    ClientData    dummy;
    857858{
    858859    register char *slash;
    859860
    860861    if (addSpace) {
    861         Buf_AddByte (buf, (Byte)' ');
     862        Buf_AddByte (buf, (Byte)' ');
    862863    }
    863864
    864865    slash = strrchr (word, '/');
    865866    if (slash != (char *)NULL) {
    866         register char *dot;
     867        register char *dot;
    867868        *slash++ = '\0';
    868869        dot = strrchr (slash, '.');
     
    875876        else
    876877            Buf_AddBytes (buf, strlen(slash), (Byte *)slash);
    877         slash[-1] = '/';
     878        slash[-1] = '/';
    878879    } else {
    879         register char *dot;
     880        register char *dot;
    880881        dot = strrchr (slash, '.');
    881882        if (dot)
     
    896897 *-----------------------------------------------------------------------
    897898 * VarMatch --
    898  *      Place the word in the buffer if it matches the given pattern.
    899  *      Callback function for VarModify to implement the :M modifier.
    900  *
    901  * Results:
    902  *      TRUE if a space should be placed in the buffer before the next
    903  *      word.
    904  *
    905  * Side Effects:
    906  *      The word may be copied to the buffer.
     899 *      Place the word in the buffer if it matches the given pattern.
     900 *      Callback function for VarModify to implement the :M modifier.
     901 *
     902 * Results:
     903 *      TRUE if a space should be placed in the buffer before the next
     904 *      word.
     905 *
     906 * Side Effects:
     907 *      The word may be copied to the buffer.
    907908 *
    908909 *-----------------------------------------------------------------------
     
    910911static Boolean
    911912VarMatch (word, addSpace, buf, pattern)
    912     char          *word;        /* Word to examine */
    913     Boolean       addSpace;     /* TRUE if need to add a space to the
    914                                 * buffer before adding the word, if it
    915                                 * matches */
    916     Buffer        buf;          /* Buffer in which to store it */
    917     ClientData    pattern;      /* Pattern the word must match */
     913    char          *word;        /* Word to examine */
     914    Boolean       addSpace;     /* TRUE if need to add a space to the
     915                                * buffer before adding the word, if it
     916                                * matches */
     917    Buffer        buf;          /* Buffer in which to store it */
     918    ClientData    pattern;      /* Pattern the word must match */
    918919{
    919920    if (Str_Match(word, (char *) pattern)) {
    920         if (addSpace) {
    921             Buf_AddByte(buf, (Byte)' ');
    922         }
    923         addSpace = TRUE;
    924         Buf_AddBytes(buf, strlen(word), (Byte *)word);
     921        if (addSpace) {
     922            Buf_AddByte(buf, (Byte)' ');
     923        }
     924        addSpace = TRUE;
     925        Buf_AddBytes(buf, strlen(word), (Byte *)word);
    925926    }
    926927    return(addSpace);
     
    931932 *-----------------------------------------------------------------------
    932933 * VarSYSVMatch --
    933  *      Place the word in the buffer if it matches the given pattern.
    934  *      Callback function for VarModify to implement the System V %
    935  *      modifiers.
    936  *
    937  * Results:
    938  *      TRUE if a space should be placed in the buffer before the next
    939  *      word.
    940  *
    941  * Side Effects:
    942  *      The word may be copied to the buffer.
     934 *      Place the word in the buffer if it matches the given pattern.
     935 *      Callback function for VarModify to implement the System V %
     936 *      modifiers.
     937 *
     938 * Results:
     939 *      TRUE if a space should be placed in the buffer before the next
     940 *      word.
     941 *
     942 * Side Effects:
     943 *      The word may be copied to the buffer.
    943944 *
    944945 *-----------------------------------------------------------------------
     
    946947static Boolean
    947948VarSYSVMatch (word, addSpace, buf, patp)
    948     char          *word;        /* Word to examine */
    949     Boolean       addSpace;     /* TRUE if need to add a space to the
    950                                 * buffer before adding the word, if it
    951                                 * matches */
    952     Buffer        buf;          /* Buffer in which to store it */
    953     ClientData    patp;         /* Pattern the word must match */
     949    char          *word;        /* Word to examine */
     950    Boolean       addSpace;     /* TRUE if need to add a space to the
     951                                * buffer before adding the word, if it
     952                                * matches */
     953    Buffer        buf;          /* Buffer in which to store it */
     954    ClientData    patp;         /* Pattern the word must match */
    954955{
    955956    int len;
    956957    char *ptr;
    957     VarPattern    *pat = (VarPattern *) patp;
     958    VarPattern    *pat = (VarPattern *) patp;
    958959
    959960    if (addSpace)
    960         Buf_AddByte(buf, (Byte)' ');
     961        Buf_AddByte(buf, (Byte)' ');
    961962
    962963    addSpace = TRUE;
    963964
    964965    if ((ptr = Str_SYSVMatch(word, pat->lhs, &len)) != NULL)
    965         Str_SYSVSubst(buf, pat->rhs, ptr, len);
     966        Str_SYSVSubst(buf, pat->rhs, ptr, len);
    966967    else
    967         Buf_AddBytes(buf, strlen(word), (Byte *) word);
     968        Buf_AddBytes(buf, strlen(word), (Byte *) word);
    968969
    969970    return(addSpace);
     
    975976 *-----------------------------------------------------------------------
    976977 * VarNoMatch --
    977  *      Place the word in the buffer if it doesn't match the given pattern.
    978  *      Callback function for VarModify to implement the :N modifier.
    979  *
    980  * Results:
    981  *      TRUE if a space should be placed in the buffer before the next
    982  *      word.
    983  *
    984  * Side Effects:
    985  *      The word may be copied to the buffer.
     978 *      Place the word in the buffer if it doesn't match the given pattern.
     979 *      Callback function for VarModify to implement the :N modifier.
     980 *
     981 * Results:
     982 *      TRUE if a space should be placed in the buffer before the next
     983 *      word.
     984 *
     985 * Side Effects:
     986 *      The word may be copied to the buffer.
    986987 *
    987988 *-----------------------------------------------------------------------
     
    989990static Boolean
    990991VarNoMatch (word, addSpace, buf, pattern)
    991     char          *word;        /* Word to examine */
    992     Boolean       addSpace;     /* TRUE if need to add a space to the
    993                                 * buffer before adding the word, if it
    994                                 * matches */
    995     Buffer        buf;          /* Buffer in which to store it */
    996     ClientData    pattern;      /* Pattern the word must match */
     992    char          *word;        /* Word to examine */
     993    Boolean       addSpace;     /* TRUE if need to add a space to the
     994                                * buffer before adding the word, if it
     995                                * matches */
     996    Buffer        buf;          /* Buffer in which to store it */
     997    ClientData    pattern;      /* Pattern the word must match */
    997998{
    998999    if (!Str_Match(word, (char *) pattern)) {
    999         if (addSpace) {
    1000             Buf_AddByte(buf, (Byte)' ');
    1001         }
    1002         addSpace = TRUE;
    1003         Buf_AddBytes(buf, strlen(word), (Byte *)word);
     1000        if (addSpace) {
     1001            Buf_AddByte(buf, (Byte)' ');
     1002        }
     1003        addSpace = TRUE;
     1004        Buf_AddBytes(buf, strlen(word), (Byte *)word);
    10041005    }
    10051006    return(addSpace);
     
    10101011 *-----------------------------------------------------------------------
    10111012 * VarSubstitute --
    1012  *      Perform a string-substitution on the given word, placing the
    1013  *      result in the passed buffer.
    1014  *
    1015  * Results:
    1016  *      TRUE if a space is needed before more characters are added.
    1017  *
    1018  * Side Effects:
    1019  *      None.
     1013 *      Perform a string-substitution on the given word, placing the
     1014 *      result in the passed buffer.
     1015 *
     1016 * Results:
     1017 *      TRUE if a space is needed before more characters are added.
     1018 *
     1019 * Side Effects:
     1020 *      None.
    10201021 *
    10211022 *-----------------------------------------------------------------------
     
    10231024static Boolean
    10241025VarSubstitute (word, addSpace, buf, patternp)
    1025     char                *word;      /* Word to modify */
    1026     Boolean             addSpace;   /* True if space should be added before
    1027                                      * other characters */
    1028     Buffer              buf;        /* Buffer for result */
    1029     ClientData          patternp;   /* Pattern for substitution */
    1030 {
    1031     register int        wordLen;    /* Length of word */
    1032     register char       *cp;        /* General pointer */
    1033     VarPattern  *pattern = (VarPattern *) patternp;
     1026    char                *word;      /* Word to modify */
     1027    Boolean             addSpace;   /* True if space should be added before
     1028                                     * other characters */
     1029    Buffer              buf;        /* Buffer for result */
     1030    ClientData          patternp;   /* Pattern for substitution */
     1031{
     1032    register int        wordLen;    /* Length of word */
     1033    register char       *cp;        /* General pointer */
     1034    VarPattern  *pattern = (VarPattern *) patternp;
    10341035
    10351036    wordLen = strlen(word);
    10361037    if (1) { /* substitute in each word of the variable */
    1037         /*
    1038         * Break substitution down into simple anchored cases
    1039         * and if none of them fits, perform the general substitution case.
    1040         */
    1041         if ((pattern->flags & VAR_MATCH_START) &&
    1042             (strncmp(word, pattern->lhs, pattern->leftLen) == 0)) {
    1043                 /*
    1044                 * Anchored at start and beginning of word matches pattern
    1045                 */
    1046                 if ((pattern->flags & VAR_MATCH_END) &&
    1047                     (wordLen == pattern->leftLen)) {
    1048                         /*
    1049                         * Also anchored at end and matches to the end (word
    1050                         * is same length as pattern) add space and rhs only
    1051                         * if rhs is non-null.
    1052                         */
    1053                         if (pattern->rightLen != 0) {
    1054                             if (addSpace) {
    1055                                 Buf_AddByte(buf, (Byte)' ');
    1056                             }
    1057                             addSpace = TRUE;
    1058                             Buf_AddBytes(buf, pattern->rightLen,
    1059                                         (Byte *)pattern->rhs);
    1060                         }
    1061                 } else if (pattern->flags & VAR_MATCH_END) {
    1062                     /*
    1063                      * Doesn't match to end -- copy word wholesale
    1064                      */
    1065                     goto nosub;
    1066                 } else {
    1067                     /*
    1068                      * Matches at start but need to copy in trailing characters
    1069                      */
    1070                     if ((pattern->rightLen + wordLen - pattern->leftLen) != 0){
    1071                         if (addSpace) {
    1072                             Buf_AddByte(buf, (Byte)' ');
    1073                         }
    1074                         addSpace = TRUE;
    1075                     }
    1076                     Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs);
    1077                     Buf_AddBytes(buf, wordLen - pattern->leftLen,
    1078                                 (Byte *)(word + pattern->leftLen));
    1079                 }
    1080         } else if (pattern->flags & VAR_MATCH_START) {
    1081             /*
    1082              * Had to match at start of word and didn't -- copy whole word.
    1083              */
    1084             goto nosub;
    1085         } else if (pattern->flags & VAR_MATCH_END) {
    1086             /*
    1087              * Anchored at end, Find only place match could occur (leftLen
    1088              * characters from the end of the word) and see if it does. Note
    1089              * that because the $ will be left at the end of the lhs, we have
    1090              * to use strncmp.
    1091              */
    1092             cp = word + (wordLen - pattern->leftLen);
    1093             if ((cp >= word) &&
    1094                 (strncmp(cp, pattern->lhs, pattern->leftLen) == 0)) {
    1095                 /*
    1096                 * Match found. If we will place characters in the buffer,
    1097                 * add a space before hand as indicated by addSpace, then
    1098                 * stuff in the initial, unmatched part of the word followed
    1099                 * by the right-hand-side.
    1100                 */
    1101                 if (((cp - word) + pattern->rightLen) != 0) {
    1102                     if (addSpace) {
    1103                         Buf_AddByte(buf, (Byte)' ');
    1104                     }
    1105                     addSpace = TRUE;
    1106                 }
    1107                 Buf_AddBytes(buf, cp - word, (Byte *)word);
    1108                 Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs);
    1109             } else {
    1110                 /*
    1111                 * Had to match at end and didn't. Copy entire word.
    1112                 */
    1113                 goto nosub;
    1114             }
    1115         } else {
    1116             /*
    1117              * Pattern is unanchored: search for the pattern in the word using
    1118              * String_FindSubstring, copying unmatched portions and the
    1119              * right-hand-side for each match found, handling non-global
    1120              * substitutions correctly, etc. When the loop is done, any
    1121              * remaining part of the word (word and wordLen are adjusted
    1122              * accordingly through the loop) is copied straight into the
    1123              * buffer.
    1124              * addSpace is set FALSE as soon as a space is added to the
    1125              * buffer.
    1126              */
    1127             register Boolean done;
    1128             int origSize;
    1129 
    1130             done = FALSE;
    1131             origSize = Buf_Size(buf);
    1132             while (!done) {
    1133                 cp = Str_FindSubstring(word, pattern->lhs);
    1134                 if (cp != (char *)NULL) {
    1135                     if (addSpace && (((cp - word) + pattern->rightLen) != 0)){
    1136                         Buf_AddByte(buf, (Byte)' ');
    1137                         addSpace = FALSE;
    1138                     }
    1139                     Buf_AddBytes(buf, cp-word, (Byte *)word);
    1140                     Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs);
    1141                     wordLen -= (cp - word) + pattern->leftLen;
    1142                     word = cp + pattern->leftLen;
    1143                     if (wordLen == 0 || (pattern->flags & VAR_SUB_GLOBAL) == 0){
    1144                         done = TRUE;
    1145                     }
    1146                 } else {
    1147                     done = TRUE;
    1148                 }
    1149             }
    1150             if (wordLen != 0) {
    1151                 if (addSpace) {
    1152                     Buf_AddByte(buf, (Byte)' ');
    1153                 }
    1154                 Buf_AddBytes(buf, wordLen, (Byte *)word);
    1155             }
    1156             /*
    1157              * If added characters to the buffer, need to add a space
    1158              * before we add any more. If we didn't add any, just return
    1159              * the previous value of addSpace.
    1160              */
    1161             return ((Buf_Size(buf) != origSize) || addSpace);
    1162         }
    1163         /*
    1164         * Common code for anchored substitutions:
    1165         * addSpace was set TRUE if characters were added to the buffer.
    1166         */
    1167         return (addSpace);
     1038        /*
     1039        * Break substitution down into simple anchored cases
     1040        * and if none of them fits, perform the general substitution case.
     1041        */
     1042        if ((pattern->flags & VAR_MATCH_START) &&
     1043            (strncmp(word, pattern->lhs, pattern->leftLen) == 0)) {
     1044                /*
     1045                * Anchored at start and beginning of word matches pattern
     1046                */
     1047                if ((pattern->flags & VAR_MATCH_END) &&
     1048                    (wordLen == pattern->leftLen)) {
     1049                        /*
     1050                        * Also anchored at end and matches to the end (word
     1051                        * is same length as pattern) add space and rhs only
     1052                        * if rhs is non-null.
     1053                        */
     1054                        if (pattern->rightLen != 0) {
     1055                            if (addSpace) {
     1056                                Buf_AddByte(buf, (Byte)' ');
     1057                            }
     1058                            addSpace = TRUE;
     1059                            Buf_AddBytes(buf, pattern->rightLen,
     1060                                        (Byte *)pattern->rhs);
     1061                        }
     1062                } else if (pattern->flags & VAR_MATCH_END) {
     1063                    /*
     1064                     * Doesn't match to end -- copy word wholesale
     1065                     */
     1066                    goto nosub;
     1067                } else {
     1068                    /*
     1069                     * Matches at start but need to copy in trailing characters
     1070                     */
     1071                    if ((pattern->rightLen + wordLen - pattern->leftLen) != 0){
     1072                        if (addSpace) {
     1073                            Buf_AddByte(buf, (Byte)' ');
     1074                        }
     1075                        addSpace = TRUE;
     1076                    }
     1077                    Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs);
     1078                    Buf_AddBytes(buf, wordLen - pattern->leftLen,
     1079                                (Byte *)(word + pattern->leftLen));
     1080                }
     1081        } else if (pattern->flags & VAR_MATCH_START) {
     1082            /*
     1083             * Had to match at start of word and didn't -- copy whole word.
     1084             */
     1085            goto nosub;
     1086        } else if (pattern->flags & VAR_MATCH_END) {
     1087            /*
     1088             * Anchored at end, Find only place match could occur (leftLen
     1089             * characters from the end of the word) and see if it does. Note
     1090             * that because the $ will be left at the end of the lhs, we have
     1091             * to use strncmp.
     1092             */
     1093            cp = word + (wordLen - pattern->leftLen);
     1094            if ((cp >= word) &&
     1095                (strncmp(cp, pattern->lhs, pattern->leftLen) == 0)) {
     1096                /*
     1097                * Match found. If we will place characters in the buffer,
     1098                * add a space before hand as indicated by addSpace, then
     1099                * stuff in the initial, unmatched part of the word followed
     1100                * by the right-hand-side.
     1101                */
     1102                if (((cp - word) + pattern->rightLen) != 0) {
     1103                    if (addSpace) {
     1104                        Buf_AddByte(buf, (Byte)' ');
     1105                    }
     1106                    addSpace = TRUE;
     1107                }
     1108                Buf_AddBytes(buf, cp - word, (Byte *)word);
     1109                Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs);
     1110            } else {
     1111                /*
     1112                * Had to match at end and didn't. Copy entire word.
     1113                */
     1114                goto nosub;
     1115            }
     1116        } else {
     1117            /*
     1118             * Pattern is unanchored: search for the pattern in the word using
     1119             * String_FindSubstring, copying unmatched portions and the
     1120             * right-hand-side for each match found, handling non-global
     1121             * substitutions correctly, etc. When the loop is done, any
     1122             * remaining part of the word (word and wordLen are adjusted
     1123             * accordingly through the loop) is copied straight into the
     1124             * buffer.
     1125             * addSpace is set FALSE as soon as a space is added to the
     1126             * buffer.
     1127             */
     1128            register Boolean done;
     1129            int origSize;
     1130
     1131            done = FALSE;
     1132            origSize = Buf_Size(buf);
     1133            while (!done) {
     1134                cp = Str_FindSubstring(word, pattern->lhs);
     1135                if (cp != (char *)NULL) {
     1136                    if (addSpace && (((cp - word) + pattern->rightLen) != 0)){
     1137                        Buf_AddByte(buf, (Byte)' ');
     1138                        addSpace = FALSE;
     1139                    }
     1140                    Buf_AddBytes(buf, cp-word, (Byte *)word);
     1141                    Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs);
     1142                    wordLen -= (cp - word) + pattern->leftLen;
     1143                    word = cp + pattern->leftLen;
     1144                    if (wordLen == 0 || (pattern->flags & VAR_SUB_GLOBAL) == 0){
     1145                        done = TRUE;
     1146                    }
     1147                } else {
     1148                    done = TRUE;
     1149                }
     1150            }
     1151            if (wordLen != 0) {
     1152                if (addSpace) {
     1153                    Buf_AddByte(buf, (Byte)' ');
     1154                }
     1155                Buf_AddBytes(buf, wordLen, (Byte *)word);
     1156            }
     1157            /*
     1158             * If added characters to the buffer, need to add a space
     1159             * before we add any more. If we didn't add any, just return
     1160             * the previous value of addSpace.
     1161             */
     1162            return ((Buf_Size(buf) != origSize) || addSpace);
     1163        }
     1164        /*
     1165        * Common code for anchored substitutions:
     1166        * addSpace was set TRUE if characters were added to the buffer.
     1167        */
     1168        return (addSpace);
    11681169    }
    11691170 nosub:
    11701171    if (addSpace) {
    1171         Buf_AddByte(buf, (Byte)' ');
     1172        Buf_AddByte(buf, (Byte)' ');
    11721173    }
    11731174    Buf_AddBytes(buf, wordLen, (Byte *)word);
     
    11781179 *-----------------------------------------------------------------------
    11791180 * VarREError --
    1180  *      Print the error caused by a regcomp or regexec call.
    1181  *
    1182  * Results:
    1183  *      None.
    1184  *
    1185  * Side Effects:
    1186  *      An error gets printed.
     1181 *      Print the error caused by a regcomp or regexec call.
     1182 *
     1183 * Results:
     1184 *      None.
     1185 *
     1186 * Side Effects:
     1187 *      An error gets printed.
    11871188 *
    11881189 *-----------------------------------------------------------------------
     
    12081209 *-----------------------------------------------------------------------
    12091210 * VarRESubstitute --
    1210  *      Perform a regex substitution on the given word, placing the
    1211  *      result in the passed buffer.
    1212  *
    1213  * Results:
    1214  *      TRUE if a space is needed before more characters are added.
    1215  *
    1216  * Side Effects:
    1217  *      None.
     1211 *      Perform a regex substitution on the given word, placing the
     1212 *      result in the passed buffer.
     1213 *
     1214 * Results:
     1215 *      TRUE if a space is needed before more characters are added.
     1216 *
     1217 * Side Effects:
     1218 *      None.
    12181219 *
    12191220 *-----------------------------------------------------------------------
     
    12331234    int flags = 0;
    12341235
    1235 #define MAYBE_ADD_SPACE()               \
    1236         if (addSpace && !added)         \
    1237             Buf_AddByte(buf, ' ');      \
    1238         added = 1
     1236#define MAYBE_ADD_SPACE()               \
     1237        if (addSpace && !added)         \
     1238            Buf_AddByte(buf, ' ');      \
     1239        added = 1
    12391240
    12401241    added = 0;
     
    12431244
    12441245    if ((pat->flags & (VAR_SUB_ONE|VAR_SUB_MATCHED)) ==
    1245         (VAR_SUB_ONE|VAR_SUB_MATCHED))
    1246         xrv = REG_NOMATCH;
     1246        (VAR_SUB_ONE|VAR_SUB_MATCHED))
     1247        xrv = REG_NOMATCH;
    12471248    else {
    12481249    tryagain:
    1249         xrv = regexec(&pat->re, wp, pat->nsub, pat->matches, flags);
     1250        xrv = regexec(&pat->re, wp, pat->nsub, pat->matches, flags);
    12501251    }
    12511252
    12521253    switch (xrv) {
    12531254    case 0:
    1254         pat->flags |= VAR_SUB_MATCHED;
    1255         if (pat->matches[0].rm_so > 0) {
    1256             MAYBE_ADD_SPACE();
    1257             Buf_AddBytes(buf, pat->matches[0].rm_so, wp);
    1258         }
    1259 
    1260         for (rp = pat->replace; *rp; rp++) {
    1261             if ((*rp == '\\') && ((rp[1] == '&') || (rp[1] == '\\'))) {
    1262                 MAYBE_ADD_SPACE();
    1263                 Buf_AddByte(buf,rp[1]);
    1264                 rp++;
    1265             }
    1266             else if ((*rp == '&') ||
    1267                 ((*rp == '\\') && isdigit((unsigned char)rp[1]))) {
    1268                 int n;
    1269                 char *subbuf;
    1270                 int sublen;
    1271                 char errstr[3];
    1272 
    1273                 if (*rp == '&') {
    1274                     n = 0;
    1275                     errstr[0] = '&';
    1276                     errstr[1] = '\0';
    1277                 } else {
    1278                     n = rp[1] - '0';
    1279                     errstr[0] = '\\';
    1280                     errstr[1] = rp[1];
    1281                     errstr[2] = '\0';
    1282                     rp++;
    1283                 }
    1284 
    1285                 if (n > pat->nsub) {
    1286                     Error("No subexpression %s", &errstr[0]);
    1287                     subbuf = "";
    1288                     sublen = 0;
    1289                 } else if ((pat->matches[n].rm_so == -1) &&
    1290                            (pat->matches[n].rm_eo == -1)) {
    1291                     Error("No match for subexpression %s", &errstr[0]);
    1292                     subbuf = "";
    1293                     sublen = 0;
    1294                 } else {
    1295                     subbuf = wp + pat->matches[n].rm_so;
    1296                     sublen = pat->matches[n].rm_eo - pat->matches[n].rm_so;
    1297                 }
    1298 
    1299                 if (sublen > 0) {
    1300                     MAYBE_ADD_SPACE();
    1301                     Buf_AddBytes(buf, sublen, subbuf);
    1302                 }
    1303             } else {
    1304                 MAYBE_ADD_SPACE();
    1305                 Buf_AddByte(buf, *rp);
    1306             }
    1307         }
    1308         wp += pat->matches[0].rm_eo;
    1309         if (pat->flags & VAR_SUB_GLOBAL) {
    1310             flags |= REG_NOTBOL;
    1311             if (pat->matches[0].rm_so == 0 && pat->matches[0].rm_eo == 0) {
    1312                 MAYBE_ADD_SPACE();
    1313                 Buf_AddByte(buf, *wp);
    1314                 wp++;
    1315 
    1316             }
    1317             if (*wp)
    1318                 goto tryagain;
    1319         }
    1320         if (*wp) {
    1321             MAYBE_ADD_SPACE();
    1322             Buf_AddBytes(buf, strlen(wp), wp);
    1323         }
    1324         break;
     1255        pat->flags |= VAR_SUB_MATCHED;
     1256        if (pat->matches[0].rm_so > 0) {
     1257            MAYBE_ADD_SPACE();
     1258            Buf_AddBytes(buf, pat->matches[0].rm_so, wp);
     1259        }
     1260
     1261        for (rp = pat->replace; *rp; rp++) {
     1262            if ((*rp == '\\') && ((rp[1] == '&') || (rp[1] == '\\'))) {
     1263                MAYBE_ADD_SPACE();
     1264                Buf_AddByte(buf,rp[1]);
     1265                rp++;
     1266            }
     1267            else if ((*rp == '&') ||
     1268                ((*rp == '\\') && isdigit((unsigned char)rp[1]))) {
     1269                int n;
     1270                char *subbuf;
     1271                int sublen;
     1272                char errstr[3];
     1273
     1274                if (*rp == '&') {
     1275                    n = 0;
     1276                    errstr[0] = '&';
     1277                    errstr[1] = '\0';
     1278                } else {
     1279                    n = rp[1] - '0';
     1280                    errstr[0] = '\\';
     1281                    errstr[1] = rp[1];
     1282                    errstr[2] = '\0';
     1283                    rp++;
     1284                }
     1285
     1286                if (n > pat->nsub) {
     1287                    Error("No subexpression %s", &errstr[0]);
     1288                    subbuf = "";
     1289                    sublen = 0;
     1290                } else if ((pat->matches[n].rm_so == -1) &&
     1291                           (pat->matches[n].rm_eo == -1)) {
     1292                    Error("No match for subexpression %s", &errstr[0]);
     1293                    subbuf = "";
     1294                    sublen = 0;
     1295                } else {
     1296                    subbuf = wp + pat->matches[n].rm_so;
     1297                    sublen = pat->matches[n].rm_eo - pat->matches[n].rm_so;
     1298                }
     1299
     1300                if (sublen > 0) {
     1301                    MAYBE_ADD_SPACE();
     1302                    Buf_AddBytes(buf, sublen, subbuf);
     1303                }
     1304            } else {
     1305                MAYBE_ADD_SPACE();
     1306                Buf_AddByte(buf, *rp);
     1307            }
     1308        }
     1309        wp += pat->matches[0].rm_eo;
     1310        if (pat->flags & VAR_SUB_GLOBAL) {
     1311            flags |= REG_NOTBOL;
     1312            if (pat->matches[0].rm_so == 0 && pat->matches[0].rm_eo == 0) {
     1313                MAYBE_ADD_SPACE();
     1314                Buf_AddByte(buf, *wp);
     1315                wp++;
     1316
     1317            }
     1318            if (*wp)
     1319                goto tryagain;
     1320        }
     1321        if (*wp) {
     1322            MAYBE_ADD_SPACE();
     1323            Buf_AddBytes(buf, strlen(wp), wp);
     1324        }
     1325        break;
    13251326    default:
    1326         VarREError(xrv, &pat->re, "Unexpected regex error");
     1327        VarREError(xrv, &pat->re, "Unexpected regex error");
    13271328       /* fall through */
    13281329    case REG_NOMATCH:
    1329         if (*wp) {
    1330             MAYBE_ADD_SPACE();
    1331             Buf_AddBytes(buf,strlen(wp),wp);
    1332         }
    1333         break;
     1330        if (*wp) {
     1331            MAYBE_ADD_SPACE();
     1332            Buf_AddBytes(buf,strlen(wp),wp);
     1333        }
     1334        break;
    13341335    }
    13351336    return(addSpace||added);
     
    13401341 *-----------------------------------------------------------------------
    13411342 * VarModify --
    1342  *      Modify each of the words of the passed string using the given
    1343  *      function. Used to implement all modifiers.
    1344  *
    1345  * Results:
    1346  *      A string of all the words modified appropriately.
    1347  *
    1348  * Side Effects:
    1349  *      None.
     1343 *      Modify each of the words of the passed string using the given
     1344 *      function. Used to implement all modifiers.
     1345 *
     1346 * Results:
     1347 *      A string of all the words modified appropriately.
     1348 *
     1349 * Side Effects:
     1350 *      None.
    13501351 *
    13511352 *-----------------------------------------------------------------------
     
    13531354static char *
    13541355VarModify (str, modProc, datum)
    1355     char          *str;             /* String whose words should be trimmed */
    1356                                     /* Function to use to modify them */
    1357     Boolean       (*modProc) __P((char *, Boolean, Buffer, ClientData));
    1358     ClientData    datum;            /* Datum to pass it */
    1359 {
    1360     Buffer        buf;              /* Buffer for the new string */
    1361     Boolean       addSpace;         /* TRUE if need to add a space to the
    1362                                      * buffer before adding the trimmed
    1363                                      * word */
    1364     char **av;                      /* word list [first word does not count] */
     1356    char          *str;             /* String whose words should be trimmed */
     1357                                    /* Function to use to modify them */
     1358    Boolean       (*modProc) __P((char *, Boolean, Buffer, ClientData));
     1359    ClientData    datum;            /* Datum to pass it */
     1360{
     1361    Buffer        buf;              /* Buffer for the new string */
     1362    Boolean       addSpace;         /* TRUE if need to add a space to the
     1363                                     * buffer before adding the trimmed
     1364                                     * word */
     1365    char **av;                      /* word list [first word does not count] */
    13651366    int ac, i;
    13661367
     
    13711372
    13721373    for (i = 1; i < ac; i++)
    1373         addSpace = (*modProc)(av[i], addSpace, buf, datum);
     1374        addSpace = (*modProc)(av[i], addSpace, buf, datum);
    13741375
    13751376    Buf_AddByte (buf, '\0');
     
    13821383 *-----------------------------------------------------------------------
    13831384 * VarGetPattern --
    1384  *      Pass through the tstr looking for 1) escaped delimiters,
    1385  *      '$'s and backslashes (place the escaped character in
    1386  *      uninterpreted) and 2) unescaped $'s that aren't before
    1387  *      the delimiter (expand the variable substitution unless flags
    1388  *      has VAR_NOSUBST set).
    1389  *      Return the expanded string or NULL if the delimiter was missing
    1390  *      If pattern is specified, handle escaped ampersands, and replace
    1391  *      unescaped ampersands with the lhs of the pattern.
    1392  *
    1393  * Results:
    1394  *      A string of all the words modified appropriately.
    1395  *      If length is specified, return the string length of the buffer
    1396  *      If flags is specified and the last character of the pattern is a
    1397  *      $ set the VAR_MATCH_END bit of flags.
    1398  *
    1399  * Side Effects:
    1400  *      None.
     1385 *      Pass through the tstr looking for 1) escaped delimiters,
     1386 *      '$'s and backslashes (place the escaped character in
     1387 *      uninterpreted) and 2) unescaped $'s that aren't before
     1388 *      the delimiter (expand the variable substitution unless flags
     1389 *      has VAR_NOSUBST set).
     1390 *      Return the expanded string or NULL if the delimiter was missing
     1391 *      If pattern is specified, handle escaped ampersands, and replace
     1392 *      unescaped ampersands with the lhs of the pattern.
     1393 *
     1394 * Results:
     1395 *      A string of all the words modified appropriately.
     1396 *      If length is specified, return the string length of the buffer
     1397 *      If flags is specified and the last character of the pattern is a
     1398 *      $ set the VAR_MATCH_END bit of flags.
     1399 *
     1400 * Side Effects:
     1401 *      None.
    14011402 *-----------------------------------------------------------------------
    14021403 */
     
    14151416    int junk;
    14161417    if (length == NULL)
    1417         length = &junk;
     1418        length = &junk;
    14181419
    14191420#define IS_A_MATCH(cp, delim) \
     
    14281429     */
    14291430    for (cp = *tstr; *cp && (*cp != delim); cp++) {
    1430         if (IS_A_MATCH(cp, delim)) {
    1431             Buf_AddByte(buf, (Byte) cp[1]);
    1432             cp++;
    1433         } else if (*cp == '$') {
    1434             if (cp[1] == delim) {
    1435                 if (flags == NULL)
    1436                     Buf_AddByte(buf, (Byte) *cp);
    1437                 else
    1438                     /*
    1439                      * Unescaped $ at end of pattern => anchor
    1440                      * pattern at end.
    1441                      */
    1442                     *flags |= VAR_MATCH_END;
    1443             } else {
    1444                 if (flags == NULL || (*flags & VAR_NOSUBST) == 0) {
    1445                     char   *cp2;
    1446                     int     len;
    1447                     Boolean freeIt;
    1448 
    1449                     /*
    1450                      * If unescaped dollar sign not before the
    1451                      * delimiter, assume it's a variable
    1452                      * substitution and recurse.
    1453                      */
    1454                     cp2 = Var_Parse(cp, ctxt, err, &len, &freeIt);
    1455                     Buf_AddBytes(buf, strlen(cp2), (Byte *) cp2);
    1456                     if (freeIt)
    1457                         efree(cp2);
    1458                     cp += len - 1;
    1459                 } else {
    1460                     char *cp2 = &cp[1];
    1461 
    1462                     if (*cp2 == '(' || *cp2 == '{') {
    1463                         /*
    1464                         * Find the end of this variable reference
    1465                         * and suck it in without further ado.
    1466                         * It will be interperated later.
    1467                         */
    1468                         int have = *cp2;
    1469                         int want = (*cp2 == '(') ? ')' : '}';
    1470                         int depth = 1;
    1471 
    1472                         for (++cp2; *cp2 != '\0' && depth > 0; ++cp2) {
    1473                             if (cp2[-1] != '\\') {
    1474                                 if (*cp2 == have)
    1475                                     ++depth;
    1476                                 if (*cp2 == want)
    1477                                     --depth;
    1478                             }
    1479                         }
    1480                         Buf_AddBytes(buf, cp2 - cp, (Byte *)cp);
    1481                         cp = --cp2;
    1482                     } else
    1483                         Buf_AddByte(buf, (Byte) *cp);
    1484                 }
    1485             }
    1486         }
    1487         else if (pattern && *cp == '&')
    1488             Buf_AddBytes(buf, pattern->leftLen, (Byte *)pattern->lhs);
    1489         else
    1490             Buf_AddByte(buf, (Byte) *cp);
     1431        if (IS_A_MATCH(cp, delim)) {
     1432            Buf_AddByte(buf, (Byte) cp[1]);
     1433            cp++;
     1434        } else if (*cp == '$') {
     1435            if (cp[1] == delim) {
     1436                if (flags == NULL)
     1437                    Buf_AddByte(buf, (Byte) *cp);
     1438                else
     1439                    /*
     1440                     * Unescaped $ at end of pattern => anchor
     1441                     * pattern at end.
     1442                     */
     1443                    *flags |= VAR_MATCH_END;
     1444            } else {
     1445                if (flags == NULL || (*flags & VAR_NOSUBST) == 0) {
     1446                    char   *cp2;
     1447                    int     len;
     1448                    Boolean freeIt;
     1449
     1450                    /*
     1451                     * If unescaped dollar sign not before the
     1452                     * delimiter, assume it's a variable
     1453                     * substitution and recurse.
     1454                     */
     1455                    cp2 = Var_Parse(cp, ctxt, err, &len, &freeIt);
     1456                    Buf_AddBytes(buf, strlen(cp2), (Byte *) cp2);
     1457                    if (freeIt)
     1458                        efree(cp2);
     1459                    cp += len - 1;
     1460                } else {
     1461                    char *cp2 = &cp[1];
     1462
     1463                    if (*cp2 == '(' || *cp2 == '{') {
     1464                        /*
     1465                        * Find the end of this variable reference
     1466                        * and suck it in without further ado.
     1467                        * It will be interperated later.
     1468                        */
     1469                        int have = *cp2;
     1470                        int want = (*cp2 == '(') ? ')' : '}';
     1471                        int depth = 1;
     1472
     1473                        for (++cp2; *cp2 != '\0' && depth > 0; ++cp2) {
     1474                            if (cp2[-1] != '\\') {
     1475                                if (*cp2 == have)
     1476                                    ++depth;
     1477                                if (*cp2 == want)
     1478                                    --depth;
     1479                            }
     1480                        }
     1481                        Buf_AddBytes(buf, cp2 - cp, (Byte *)cp);
     1482                        cp = --cp2;
     1483                    } else
     1484                        Buf_AddByte(buf, (Byte) *cp);
     1485                }
     1486            }
     1487        }
     1488        else if (pattern && *cp == '&')
     1489            Buf_AddBytes(buf, pattern->leftLen, (Byte *)pattern->lhs);
     1490        else
     1491            Buf_AddByte(buf, (Byte) *cp);
    14911492    }
    14921493
     
    14941495
    14951496    if (*cp != delim) {
    1496         *tstr = cp;
    1497         *length = 0;
    1498         return NULL;
     1497        *tstr = cp;
     1498        *length = 0;
     1499        return NULL;
    14991500    }
    15001501    else {
    1501         *tstr = ++cp;
    1502         cp = (char *) Buf_GetAll(buf, length);
    1503         *length -= 1;   /* Don't count the NULL */
    1504         Buf_Destroy(buf, FALSE);
    1505         return cp;
     1502        *tstr = ++cp;
     1503        cp = (char *) Buf_GetAll(buf, length);
     1504        *length -= 1;   /* Don't count the NULL */
     1505        Buf_Destroy(buf, FALSE);
     1506        return cp;
    15061507    }
    15071508}
     
    15111512 *-----------------------------------------------------------------------
    15121513 * VarQuote --
    1513  *      Quote shell meta-characters in the string
    1514  *
    1515  * Results:
    1516  *      The quoted string
    1517  *
    1518  * Side Effects:
    1519  *      None.
     1514 *      Quote shell meta-characters in the string
     1515 *
     1516 * Results:
     1517 *      The quoted string
     1518 *
     1519 * Side Effects:
     1520 *      None.
    15201521 *
    15211522 *-----------------------------------------------------------------------
     
    15231524static char *
    15241525VarQuote(str)
    1525         char *str;
    1526 {
    1527 
    1528     Buffer        buf;
     1526        char *str;
     1527{
     1528
     1529    Buffer        buf;
    15291530    /* This should cover most shells :-( */
    15301531    static char meta[] = "\n \t'`\";&<>()|*?{}[]\\$!#^~";
     
    15321533    buf = Buf_Init (MAKE_BSIZE);
    15331534    for (; *str; str++) {
    1534         if (strchr(meta, *str) != NULL)
    1535             Buf_AddByte(buf, (Byte)'\\');
    1536         Buf_AddByte(buf, (Byte)*str);
     1535        if (strchr(meta, *str) != NULL)
     1536            Buf_AddByte(buf, (Byte)'\\');
     1537        Buf_AddByte(buf, (Byte)*str);
    15371538    }
    15381539    Buf_AddByte(buf, (Byte) '\0');
     
    15451546 *-----------------------------------------------------------------------
    15461547 * Var_Parse --
    1547  *      Given the start of a variable invocation, extract the variable
    1548  *      name and find its value, then modify it according to the
    1549  *      specification.
    1550  *
    1551  * Results:
    1552  *      The (possibly-modified) value of the variable or var_Error if the
    1553  *      specification is invalid. The length of the specification is
    1554  *      placed in *lengthPtr (for invalid specifications, this is just
    1555  *      2...?).
    1556  *      A Boolean in *freePtr telling whether the returned string should
    1557  *      be freed by the caller.
    1558  *
    1559  * Side Effects:
    1560  *      None.
     1548 *      Given the start of a variable invocation, extract the variable
     1549 *      name and find its value, then modify it according to the
     1550 *      specification.
     1551 *
     1552 * Results:
     1553 *      The (possibly-modified) value of the variable or var_Error if the
     1554 *      specification is invalid. The length of the specification is
     1555 *      placed in *lengthPtr (for invalid specifications, this is just
     1556 *      2...?).
     1557 *      A Boolean in *freePtr telling whether the returned string should
     1558 *      be freed by the caller.
     1559 *
     1560 * Side Effects:
     1561 *      None.
    15611562 *
    15621563 *-----------------------------------------------------------------------
     
    15641565char *
    15651566Var_Parse (str, ctxt, err, lengthPtr, freePtr)
    1566     char          *str;         /* The string to parse */
    1567     GNode         *ctxt;        /* The context for the variable */
    1568     Boolean         err;        /* TRUE if undefined variables are an error */
    1569     int             *lengthPtr; /* OUT: The length of the specification */
    1570     Boolean         *freePtr;   /* OUT: TRUE if caller should efree result */
    1571 {
    1572     register char   *tstr;      /* Pointer into str */
    1573     Var             *v;         /* Variable in invocation */
    1574     char            *cp;        /* Secondary pointer into str (place marker
    1575                                 * for tstr) */
    1576     Boolean         haveModifier;/* TRUE if have modifiers for the variable */
    1577     register char   endc;       /* Ending character when variable in parens
    1578                                 * or braces */
    1579     register char   startc=0;   /* Starting character when variable in parens
    1580                                 * or braces */
    1581     int             cnt;        /* Used to count brace pairs when variable in
    1582                                 * in parens or braces */
    1583     char            *start;
    1584     char             delim;
    1585     Boolean         dynamic;    /* TRUE if the variable is local and we're
    1586                                 * expanding it in a non-local context. This
    1587                                 * is done to support dynamic sources. The
    1588                                 * result is just the invocation, unaltered */
    1589     int         vlen;           /* length of variable name, after embedded variable
    1590                                 * expansion */
     1567    char          *str;         /* The string to parse */
     1568    GNode         *ctxt;        /* The context for the variable */
     1569    Boolean         err;        /* TRUE if undefined variables are an error */
     1570    int             *lengthPtr; /* OUT: The length of the specification */
     1571    Boolean         *freePtr;   /* OUT: TRUE if caller should efree result */
     1572{
     1573    register char   *tstr;      /* Pointer into str */
     1574    Var             *v;         /* Variable in invocation */
     1575    char            *cp;        /* Secondary pointer into str (place marker
     1576                                * for tstr) */
     1577    Boolean         haveModifier;/* TRUE if have modifiers for the variable */
     1578    register char   endc;       /* Ending character when variable in parens
     1579                                * or braces */
     1580    register char   startc=0;   /* Starting character when variable in parens
     1581                                * or braces */
     1582    int             cnt;        /* Used to count brace pairs when variable in
     1583                                * in parens or braces */
     1584    char            *start;
     1585    char             delim;
     1586    Boolean         dynamic;    /* TRUE if the variable is local and we're
     1587                                * expanding it in a non-local context. This
     1588                                * is done to support dynamic sources. The
     1589                                * result is just the invocation, unaltered */
     1590    int         vlen;           /* length of variable name, after embedded variable
     1591                                * expansion */
    15911592
    15921593    *freePtr = FALSE;
    15931594    dynamic = FALSE;
    15941595    start = str;
    1595 //debugkso: fprintf(stderr, "var: str=%s\n", str);
    15961596
    15971597    if (str[1] != '(' && str[1] != '{') {
    1598         /*
    1599         * If it's not bounded by braces of some sort, life is much simpler.
    1600         * We just need to check for the first character and return the
    1601         * value if it exists.
    1602         */
    1603         char      name[2];
    1604 
    1605         name[0] = str[1];
    1606         name[1] = '\0';
    1607 
    1608         v = VarFind (name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD);
    1609         if (v == (Var *)NIL) {
    1610             *lengthPtr = 2;
    1611 
    1612             if ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)) {
    1613                 /*
    1614                 * If substituting a local variable in a non-local context,
    1615                 * assume it's for dynamic source stuff. We have to handle
    1616                 * this specially and return the longhand for the variable
    1617                 * with the dollar sign escaped so it makes it back to the
    1618                 * caller. Only four of the local variables are treated
    1619                 * specially as they are the only four that will be set
    1620                 * when dynamic sources are expanded.
    1621                 */
    1622                 /* XXX: It looks like $% and $! are reversed here */
    1623                 switch (str[1]) {
    1624                     case '@':
    1625                         return("$(.TARGET)");
    1626                     case '%':
    1627                         return("$(.ARCHIVE)");
    1628                     case '*':
    1629                         return("$(.PREFIX)");
    1630                     case '!':
    1631                         return("$(.MEMBER)");
     1598        /*
     1599        * If it's not bounded by braces of some sort, life is much simpler.
     1600        * We just need to check for the first character and return the
     1601        * value if it exists.
     1602        */
     1603        char      name[2];
     1604
     1605        name[0] = str[1];
     1606        name[1] = '\0';
     1607
     1608        v = VarFind (name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD);
     1609        if (v == (Var *)NIL) {
     1610            *lengthPtr = 2;
     1611
     1612            if ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)) {
     1613                /*
     1614                * If substituting a local variable in a non-local context,
     1615                * assume it's for dynamic source stuff. We have to handle
     1616                * this specially and return the longhand for the variable
     1617                * with the dollar sign escaped so it makes it back to the
     1618                * caller. Only four of the local variables are treated
     1619                * specially as they are the only four that will be set
     1620                * when dynamic sources are expanded.
     1621                */
     1622                /* XXX: It looks like $% and $! are reversed here */
     1623                switch (str[1]) {
     1624                    case '@':
     1625                        return("$(.TARGET)");
     1626                    case '%':
     1627                        return("$(.ARCHIVE)");
     1628                    case '*':
     1629                        return("$(.PREFIX)");
     1630                    case '!':
     1631                        return("$(.MEMBER)");
    16321632                    #ifdef USE_PARENTS
    1633                     case '^':
    1634                         return("$(.PARENTS)");
     1633                    case '^':
     1634                        return("$(.PARENTS)");
    16351635                    #endif
    1636                 }
    1637             }
    1638             /*
    1639              * Error
    1640              */
    1641             return (err ? var_Error : varNoError);
    1642         } else {
    1643             haveModifier = FALSE;
    1644             tstr = &str[1];
    1645             endc = str[1];
    1646         }
     1636                }
     1637            }
     1638            /*
     1639             * Error
     1640             */
     1641            return (err ? var_Error : varNoError);
     1642        } else {
     1643            haveModifier = FALSE;
     1644            tstr = &str[1];
     1645            endc = str[1];
     1646        }
    16471647    } else {
    1648         /* build up expanded variable name in this buffer */
    1649         Buffer  buf = Buf_Init(MAKE_BSIZE);
    1650 
    1651         startc = str[1];
    1652         endc = startc == '(' ? ')' : '}';
    1653 
    1654         /*
    1655         * Skip to the end character or a colon, whichever comes first,
    1656         * replacing embedded variables as we go.
    1657         */
    1658         for (tstr = str + 2; *tstr != '\0' && *tstr != endc && *tstr != ':'; tstr++)
    1659                 if (*tstr == '$') {
    1660                         int     rlen;
    1661                         Boolean rfree;
    1662                         char*   rval = Var_Parse(tstr, ctxt, err, &rlen, &rfree);
    1663 
    1664                         if (rval == var_Error) {
    1665                                 Fatal("Error expanding embedded variable.");
    1666                         } else if (rval != NULL) {
    1667                                 Buf_AddBytes(buf, strlen(rval), (Byte *) rval);
    1668                                 if (rfree)
    1669                                         efree(rval);
    1670                         }
    1671                         tstr += rlen - 1;
    1672                 } else
    1673                         Buf_AddByte(buf, (Byte) *tstr);
    1674        
    1675         if (*tstr == '\0') {
    1676             /*
    1677              * If we never did find the end character, return NULL
    1678              * right now, setting the length to be the distance to
    1679              * the end of the string, since that's what make does.
    1680              */
    1681             *lengthPtr = tstr - str;
    1682             return (var_Error);
    1683         }
    1684        
    1685         haveModifier = (*tstr == ':');
    1686         *tstr = '\0';
    1687 
    1688         Buf_AddByte(buf, (Byte) '\0');
    1689         str = Buf_GetAll(buf, NULL);
    1690         vlen = strlen(str);
    1691 
    1692         v = VarFind (str, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD);
    1693         if ((v == (Var *)NIL) && (ctxt != VAR_CMD) && (ctxt != VAR_GLOBAL) &&
    1694 #if defined(NMAKE) || defined(KMK)
    1695             (vlen == 2) && (str[1] == 'F' || str[1] == 'D' || str[1] == 'B' || str[1] == 'R'))
     1648        /* build up expanded variable name in this buffer */
     1649        Buffer  buf = Buf_Init(MAKE_BSIZE);
     1650
     1651        startc = str[1];
     1652        endc = startc == '(' ? ')' : '}';
     1653
     1654        /*
     1655        * Skip to the end character or a colon, whichever comes first,
     1656        * replacing embedded variables as we go.
     1657        */
     1658        for (tstr = str + 2; *tstr != '\0' && *tstr != endc && *tstr != ':'; tstr++)
     1659                if (*tstr == '$') {
     1660                        int     rlen;
     1661                        Boolean rfree;
     1662                        char*   rval = Var_Parse(tstr, ctxt, err, &rlen, &rfree);
     1663
     1664                        if (rval == var_Error) {
     1665                                Fatal("Error expanding embedded variable.");
     1666                        } else if (rval != NULL) {
     1667                                Buf_AddBytes(buf, strlen(rval), (Byte *) rval);
     1668                                if (rfree)
     1669                                        efree(rval);
     1670                        }
     1671                        tstr += rlen - 1;
     1672                } else
     1673                        Buf_AddByte(buf, (Byte) *tstr);
     1674
     1675        if (*tstr == '\0') {
     1676            /*
     1677             * If we never did find the end character, return NULL
     1678             * right now, setting the length to be the distance to
     1679             * the end of the string, since that's what make does.
     1680             */
     1681            *lengthPtr = tstr - str;
     1682            return (var_Error);
     1683        }
     1684
     1685        haveModifier = (*tstr == ':');
     1686        *tstr = '\0';
     1687
     1688        Buf_AddByte(buf, (Byte) '\0');
     1689        str = Buf_GetAll(buf, NULL);
     1690        vlen = strlen(str);
     1691
     1692        v = VarFind (str, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD);
     1693        if ((v == (Var *)NIL) && (ctxt != VAR_CMD) && (ctxt != VAR_GLOBAL) &&
     1694#ifdef USE_BASEANDROOT_MODIFIERS
     1695            (vlen == 2) && (str[1] == 'F' || str[1] == 'D' || str[1] == 'B' || str[1] == 'R'))
    16961696#else
    1697             (vlen == 2) && (str[1] == 'F' || str[1] == 'D'))
     1697            (vlen == 2) && (str[1] == 'F' || str[1] == 'D'))
    16981698#endif
    1699         {
    1700             /*
    1701              * Check for bogus D and F forms of local variables since we're
    1702              * in a local context and the name is the right length.
    1703              */
    1704             switch(str[0]) {
    1705                 case '@':
    1706                 case '%':
    1707                 case '*':
    1708                 case '!':
    1709                 case '>':
    1710                 case '<':
    1711                 {
    1712                     char    vname[2];
    1713                     char    *val;
    1714 
    1715                     /*
    1716                      * Well, it's local -- go look for it.
    1717                      */
    1718                     vname[0] = str[0];
    1719                     vname[1] = '\0';
    1720                     v = VarFind(vname, ctxt, 0);
    1721 
    1722                     if (v != (Var *)NIL && !haveModifier) {
    1723                         /*
    1724                         * No need for nested expansion or anything, as we're
    1725                         * the only one who sets these things and we sure don't
    1726                         * put nested invocations in them...
    1727                         */
    1728                         val = (char *)Buf_GetAll(v->val, (int *)NULL);
    1729 
    1730 #if defined(NMAKE) || defined(KMK)
    1731                         switch (str[1])
     1699        {
     1700            /*
     1701             * Check for bogus D and F forms of local variables since we're
     1702             * in a local context and the name is the right length.
     1703             */
     1704            switch(str[0]) {
     1705                case '@':
     1706                case '%':
     1707                case '*':
     1708                case '!':
     1709                case '>':
     1710                case '<':
     1711                {
     1712                    char    vname[2];
     1713                    char    *val;
     1714
     1715                    /*
     1716                     * Well, it's local -- go look for it.
     1717                     */
     1718                    vname[0] = str[0];
     1719                    vname[1] = '\0';
     1720                    v = VarFind(vname, ctxt, 0);
     1721
     1722                    if (v != (Var *)NIL && !haveModifier) {
     1723                        /*
     1724                        * No need for nested expansion or anything, as we're
     1725                        * the only one who sets these things and we sure don't
     1726                        * put nested invocations in them...
     1727                        */
     1728                        val = (char *)Buf_GetAll(v->val, (int *)NULL);
     1729
     1730#ifdef USE_BASEANDROOT_MODIFIERS
     1731                        switch (str[1])
    17321732                        {
    17331733                        case 'D': val = VarModify(val, VarHead, (ClientData)0); break;
     
    17351735                        case 'R': val = VarModify(val, VarRoot, (ClientData)0); break;
    17361736                        default:  val = VarModify(val, VarTail, (ClientData)0); break;
    1737                         }
     1737                        }
    17381738#else
    1739                         if (str[1] == 'D') {
    1740                             val = VarModify(val, VarHead, (ClientData)0);
    1741                         } else {
    1742                             val = VarModify(val, VarTail, (ClientData)0);
    1743                         }
     1739                        if (str[1] == 'D') {
     1740                            val = VarModify(val, VarHead, (ClientData)0);
     1741                        } else {
     1742                            val = VarModify(val, VarTail, (ClientData)0);
     1743                        }
    17441744#endif
    1745                         /*
    1746                          * Resulting string is dynamically allocated, so
    1747                          * tell caller to efree it.
    1748                          */
    1749                         *freePtr = TRUE;
    1750                         *lengthPtr = tstr-start+1;
    1751                         *tstr = endc;
    1752                         Buf_Destroy(buf, TRUE);
    1753                         return(val);
    1754                     }
    1755                     break;
    1756                 }
    1757             }
    1758         }
    1759 
    1760         if (v == (Var *)NIL) {
    1761 //debugkso: fprintf(stderr, "\tv == (Var *)NIL vlen=%d str=%s\n", vlen, str);
    1762 
    1763             if (((vlen == 1) ||
    1764                  (((vlen == 2) && (str[1] == 'F' ||
    1765 #if defined(NMAKE) || defined(KMK)
     1745                        /*
     1746                         * Resulting string is dynamically allocated, so
     1747                         * tell caller to efree it.
     1748                         */
     1749                        *freePtr = TRUE;
     1750                        *lengthPtr = tstr-start+1;
     1751                        *tstr = endc;
     1752                        Buf_Destroy(buf, TRUE);
     1753                        return(val);
     1754                    }
     1755                    break;
     1756                }
     1757            }
     1758        }
     1759
     1760        if (v == (Var *)NIL) {
     1761
     1762            if (((vlen == 1) ||
     1763                 (((vlen == 2) && (str[1] == 'F' ||
     1764#ifdef USE_BASEANDROOT_MODIFIERS
    17661765                                         str[1] == 'D' || str[1] == 'B' || str[1] == 'R')))) &&
    17671766#else
    1768                                         str[1] == 'D')))) &&
     1767                                        str[1] == 'D')))) &&
    17691768#endif
    1770                 ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)))
    1771             {
    1772                 /*
    1773                 * If substituting a local variable in a non-local context,
    1774                 * assume it's for dynamic source stuff. We have to handle
    1775                 * this specially and return the longhand for the variable
    1776                 * with the dollar sign escaped so it makes it back to the
    1777                 * caller. Only four of the local variables are treated
    1778                 * specially as they are the only four that will be set
    1779                 * when dynamic sources are expanded.
    1780                 */
    1781                 switch (str[0]) {
    1782                     case '@':
    1783                     case '%':
    1784                     case '*':
    1785                     case '!':
     1769                ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)))
     1770            {
     1771                /*
     1772                * If substituting a local variable in a non-local context,
     1773                * assume it's for dynamic source stuff. We have to handle
     1774                * this specially and return the longhand for the variable
     1775                * with the dollar sign escaped so it makes it back to the
     1776                * caller. Only four of the local variables are treated
     1777                * specially as they are the only four that will be set
     1778                * when dynamic sources are expanded.
     1779                */
     1780                switch (str[0]) {
     1781                    case '@':
     1782                    case '%':
     1783                    case '*':
     1784                    case '!':
    17861785                    #ifdef USE_PARENTS
    1787                     case '^':
     1786                    case '^':
    17881787                    #endif
    1789                         dynamic = TRUE;
    1790                         break;
    1791                 }
    1792             } else if ((vlen > 2) && (str[0] == '.') &&
    1793                        isupper((unsigned char) str[1]) &&
    1794                        ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)))
    1795             {
    1796                 int     len;
    1797 
    1798                 len = vlen - 1;
    1799                 if ((strncmp(str, ".TARGET", len) == 0) ||
    1800                     (strncmp(str, ".ARCHIVE", len) == 0) ||
    1801                     (strncmp(str, ".PREFIX", len) == 0) ||
     1788                        dynamic = TRUE;
     1789                        break;
     1790                }
     1791            } else if ((vlen > 2) && (str[0] == '.') &&
     1792                       isupper((unsigned char) str[1]) &&
     1793                       ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)))
     1794            {
     1795                int     len;
     1796
     1797                len = vlen - 1;
     1798                if ((strncmp(str, ".TARGET", len) == 0) ||
     1799                    (strncmp(str, ".ARCHIVE", len) == 0) ||
     1800                    (strncmp(str, ".PREFIX", len) == 0) ||
    18021801                    #ifdef USE_PARENTS
    1803                     (strncmp(str, ".PARENTS", len) == 0) ||
     1802                    (strncmp(str, ".PARENTS", len) == 0) ||
    18041803                    #endif
    1805                     (strncmp(str, ".MEMBER", len) == 0))
    1806                 {
    1807                     dynamic = TRUE;
    1808                 }
    1809             }
    1810 
    1811             if (!haveModifier) {
    1812                 /*
    1813                 * No modifiers -- have specification length so we can return
    1814                 * now.
    1815                 */
    1816                 *lengthPtr = tstr - start + 1;
    1817                 *tstr = endc;
    1818                 if (dynamic) {
    1819                     str = emalloc(*lengthPtr + 1);
    1820                     strncpy(str, start, *lengthPtr);
    1821                     str[*lengthPtr] = '\0';
    1822                     *freePtr = TRUE;
    1823                     Buf_Destroy(buf, TRUE);
    1824                     return(str);
    1825                 } else {
    1826                     Buf_Destroy(buf, TRUE);
    1827                     return (err ? var_Error : varNoError);
    1828                 }
    1829             } else {
    1830                 /*
    1831                 * Still need to get to the end of the variable specification,
    1832                 * so kludge up a Var structure for the modifications
    1833                 */
    1834                 v = (Var *) emalloc(sizeof(Var));
    1835                 v->name = &str[1];
    1836                 v->val = Buf_Init(1);
    1837                 v->flags = VAR_JUNK;
    1838             }
    1839         }
    1840         Buf_Destroy(buf, TRUE);
     1804                    (strncmp(str, ".MEMBER", len) == 0))
     1805                {
     1806                    dynamic = TRUE;
     1807                }
     1808            }
     1809
     1810            if (!haveModifier) {
     1811                /*
     1812                * No modifiers -- have specification length so we can return
     1813                * now.
     1814                */
     1815                *lengthPtr = tstr - start + 1;
     1816                *tstr = endc;
     1817                if (dynamic) {
     1818                    str = emalloc(*lengthPtr + 1);
     1819                    strncpy(str, start, *lengthPtr);
     1820                    str[*lengthPtr] = '\0';
     1821                    *freePtr = TRUE;
     1822                    Buf_Destroy(buf, TRUE);
     1823                    return(str);
     1824                } else {
     1825                    Buf_Destroy(buf, TRUE);
     1826                    return (err ? var_Error : varNoError);
     1827                }
     1828            } else {
     1829                /*
     1830                * Still need to get to the end of the variable specification,
     1831                * so kludge up a Var structure for the modifications
     1832                */
     1833                v = (Var *) emalloc(sizeof(Var));
     1834                v->name = &str[1];
     1835                v->val = Buf_Init(1);
     1836                v->flags = VAR_JUNK;
     1837            }
     1838        }
     1839        Buf_Destroy(buf, TRUE);
    18411840    }
    18421841
    18431842    if (v->flags & VAR_IN_USE) {
    1844         Fatal("Variable %s is recursive.", v->name);
    1845         /*NOTREACHED*/
     1843        Fatal("Variable %s is recursive.", v->name);
     1844        /*NOTREACHED*/
    18461845    } else {
    1847         v->flags |= VAR_IN_USE;
     1846        v->flags |= VAR_IN_USE;
    18481847    }
    18491848    /*
     
    18581857    str = (char *)Buf_GetAll(v->val, (int *)NULL);
    18591858    if (strchr (str, '$') != (char *)NULL) {
    1860         str = Var_Subst(NULL, str, ctxt, err);
    1861         *freePtr = TRUE;
     1859        str = Var_Subst(NULL, str, ctxt, err);
     1860        *freePtr = TRUE;
    18621861    }
    18631862
     
    18671866     * Now we need to apply any modifiers the user wants applied.
    18681867     * These are:
    1869      *            :M<pattern>   words which match the given <pattern>.
    1870      *                          <pattern> is of the standard file
    1871      *                          wildcarding form.
    1872      *            :S<d><pat1><d><pat2><d>[g]
    1873      *                          Substitute <pat2> for <pat1> in the value
    1874      *            :C<d><pat1><d><pat2><d>[g]
    1875      *                          Substitute <pat2> for regex <pat1> in the value
    1876      *            :H            Substitute the head of each word
    1877      *            :T            Substitute the tail of each word
    1878      *            :E            Substitute the extension (minus '.') of
    1879      *                          each word
    1880      *            :R            Substitute the root of each word
    1881      *                          (pathname minus the suffix).
    1882      *            :lhs=rhs      Like :S, but the rhs goes to the end of
    1883      *                          the invocation.
    1884      *            :U            Converts variable to upper-case.
    1885      *            :L            Converts variable to lower-case.
     1868     *            :M<pattern>   words which match the given <pattern>.
     1869     *                          <pattern> is of the standard file
     1870     *                          wildcarding form.
     1871     *            :S<d><pat1><d><pat2><d>[g]
     1872     *                          Substitute <pat2> for <pat1> in the value
     1873     *            :C<d><pat1><d><pat2><d>[g]
     1874     *                          Substitute <pat2> for regex <pat1> in the value
     1875     *            :H            Substitute the head of each word
     1876     *            :T            Substitute the tail of each word
     1877     *            :E            Substitute the extension (minus '.') of
     1878     *                          each word
     1879     *            :R            Substitute the root of each word
     1880     *                          (pathname minus the suffix).
     1881     *            :lhs=rhs      Like :S, but the rhs goes to the end of
     1882     *                          the invocation.
     1883     *            :U            Converts variable to upper-case.
     1884     *            :L            Converts variable to lower-case.
    18861885     */
    18871886    if ((str != (char *)NULL) && haveModifier) {
    1888         /*
    1889         * Skip initial colon while putting it back.
    1890         */
    1891         *tstr++ = ':';
    1892         while (*tstr != endc) {
    1893             char        *newStr;    /* New value to return */
    1894             char        termc;      /* Character which terminated scan */
    1895 
    1896             if (DEBUG(VAR)) {
    1897                 printf("Applying :%c to \"%s\"\n", *tstr, str);
    1898             }
    1899             switch (*tstr) {
    1900                 case 'U':
    1901                         if (tstr[1] == endc || tstr[1] == ':') {
    1902                                 Buffer buf;
    1903                                 buf = Buf_Init(MAKE_BSIZE);
    1904                                 for (cp = str; *cp ; cp++)
    1905                                         Buf_AddByte(buf, (Byte) toupper(*cp));
    1906 
    1907                                 Buf_AddByte(buf, (Byte) '\0');
    1908                                 newStr = (char *) Buf_GetAll(buf, (int *) NULL);
    1909                                 Buf_Destroy(buf, FALSE);
    1910 
    1911                                 cp = tstr + 1;
    1912                                 termc = *cp;
    1913                                 break;
    1914                         }
    1915                         /* FALLTHROUGH */
    1916                 case 'L':
    1917                         if (tstr[1] == endc || tstr[1] == ':') {
    1918                                 Buffer buf;
    1919                                 buf = Buf_Init(MAKE_BSIZE);
    1920                                 for (cp = str; *cp ; cp++)
    1921                                         Buf_AddByte(buf, (Byte) tolower(*cp));
    1922 
    1923                                 Buf_AddByte(buf, (Byte) '\0');
    1924                                 newStr = (char *) Buf_GetAll(buf, (int *) NULL);
    1925                                 Buf_Destroy(buf, FALSE);
    1926 
    1927                                 cp = tstr + 1;
    1928                                 termc = *cp;
    1929                                 break;
    1930                         }
    1931                         /* FALLTHROUGH */
    1932                 case 'N':
    1933                 case 'M':
    1934                 {
    1935                     char    *pattern;
    1936                     char    *cp2;
    1937                     Boolean copy;
    1938 
    1939                     copy = FALSE;
    1940                     for (cp = tstr + 1;
    1941                         *cp != '\0' && *cp != ':' && *cp != endc;
    1942                         cp++)
    1943                     {
    1944                         if (*cp == '\\' && (cp[1] == ':' || cp[1] == endc)){
    1945                             copy = TRUE;
    1946                             cp++;
    1947                         }
    1948                     }
    1949                     termc = *cp;
    1950                     *cp = '\0';
    1951                     if (copy) {
    1952                         /*
    1953                         * Need to compress the \:'s out of the pattern, so
    1954                         * allocate enough room to hold the uncompressed
    1955                         * pattern (note that cp started at tstr+1, so
    1956                         * cp - tstr takes the null byte into account) and
    1957                         * compress the pattern into the space.
    1958                         */
    1959                         pattern = emalloc(cp - tstr);
    1960                         for (cp2 = pattern, cp = tstr + 1;
    1961                              *cp != '\0';
    1962                              cp++, cp2++)
    1963                         {
    1964                             if ((*cp == '\\') &&
    1965                                 (cp[1] == ':' || cp[1] == endc)) {
    1966                                     cp++;
    1967                             }
    1968                             *cp2 = *cp;
    1969                         }
    1970                         *cp2 = '\0';
    1971                     } else {
    1972                         pattern = &tstr[1];
    1973                     }
    1974                     if (*tstr == 'M' || *tstr == 'm') {
    1975                         newStr = VarModify(str, VarMatch, (ClientData)pattern);
    1976                     } else {
    1977                         newStr = VarModify(str, VarNoMatch,
    1978                                            (ClientData)pattern);
    1979                     }
    1980                     if (copy) {
    1981                         efree(pattern);
    1982                     }
    1983                     break;
    1984                 }
    1985                 case 'S':
    1986                 {
    1987                     VarPattern      pattern;
    1988                     register char   delim;
    1989                     Buffer          buf;        /* Buffer for patterns */
    1990 
    1991                     pattern.flags = 0;
    1992                     delim = tstr[1];
    1993                     tstr += 2;
    1994 
    1995                     /*
    1996                      * If pattern begins with '^', it is anchored to the
    1997                      * start of the word -- skip over it and flag pattern.
    1998                      */
    1999                     if (*tstr == '^') {
    2000                         pattern.flags |= VAR_MATCH_START;
    2001                         tstr += 1;
    2002                     }
    2003 
    2004                     buf = Buf_Init(0);
    2005 
    2006                     /*
    2007                      * Pass through the lhs looking for 1) escaped delimiters,
    2008                      * '$'s and backslashes (place the escaped character in
    2009                      * uninterpreted) and 2) unescaped $'s that aren't before
    2010                      * the delimiter (expand the variable substitution).
    2011                      * The result is left in the Buffer buf.
    2012                      */
    2013                     for (cp = tstr; *cp != '\0' && *cp != delim; cp++) {
    2014                         if ((*cp == '\\') &&
    2015                             ((cp[1] == delim) ||
    2016                              (cp[1] == '$') ||
    2017                              (cp[1] == '\\')))
    2018                         {
    2019                             Buf_AddByte(buf, (Byte)cp[1]);
    2020                             cp++;
    2021                         } else if (*cp == '$') {
    2022                             if (cp[1] != delim) {
    2023                                 /*
    2024                                 * If unescaped dollar sign not before the
    2025                                 * delimiter, assume it's a variable
    2026                                 * substitution and recurse.
    2027                                 */
    2028                                 char        *cp2;
    2029                                 int         len;
    2030                                 Boolean     freeIt;
    2031 
    2032                                 cp2 = Var_Parse(cp, ctxt, err, &len, &freeIt);
    2033                                 Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2);
    2034                                 if (freeIt) {
    2035                                     efree(cp2);
    2036                                 }
    2037                                 cp += len - 1;
    2038                             } else {
    2039                                 /*
    2040                                 * Unescaped $ at end of pattern => anchor
    2041                                 * pattern at end.
    2042                                 */
    2043                                 pattern.flags |= VAR_MATCH_END;
    2044                             }
    2045                         } else {
    2046                             Buf_AddByte(buf, (Byte)*cp);
    2047                         }
    2048                     }
    2049 
    2050                     Buf_AddByte(buf, (Byte)'\0');
    2051 
    2052                     /*
    2053                      * If lhs didn't end with the delimiter, complain and
    2054                      * return NULL
    2055                      */
    2056                     if (*cp != delim) {
    2057                         *lengthPtr = cp - start + 1;
    2058                         if (*freePtr) {
    2059                             efree(str);
    2060                         }
    2061                         Buf_Destroy(buf, TRUE);
    2062                         Error("Unclosed substitution for %s (%c missing)",
    2063                               v->name, delim);
    2064                         return (var_Error);
    2065                     }
    2066 
    2067                     /*
    2068                      * Fetch pattern and destroy buffer, but preserve the data
    2069                      * in it, since that's our lhs. Note that Buf_GetAll
    2070                      * will return the actual number of bytes, which includes
    2071                      * the null byte, so we have to decrement the length by
    2072                      * one.
    2073                      */
    2074                     pattern.lhs = (char *)Buf_GetAll(buf, &pattern.leftLen);
    2075                     pattern.leftLen--;
    2076                     Buf_Destroy(buf, FALSE);
    2077 
    2078                     /*
    2079                      * Now comes the replacement string. Three things need to
    2080                      * be done here: 1) need to compress escaped delimiters and
    2081                      * ampersands and 2) need to replace unescaped ampersands
    2082                      * with the l.h.s. (since this isn't regexp, we can do
    2083                      * it right here) and 3) expand any variable substitutions.
    2084                      */
    2085                     buf = Buf_Init(0);
    2086 
    2087                     tstr = cp + 1;
    2088                     for (cp = tstr; *cp != '\0' && *cp != delim; cp++) {
    2089                         if ((*cp == '\\') &&
    2090                             ((cp[1] == delim) ||
    2091                              (cp[1] == '&') ||
    2092                              (cp[1] == '\\') ||
    2093                              (cp[1] == '$')))
    2094                         {
    2095                             Buf_AddByte(buf, (Byte)cp[1]);
    2096                             cp++;
    2097                         } else if ((*cp == '$') && (cp[1] != delim)) {
    2098                             char    *cp2;
    2099                             int     len;
    2100                             Boolean freeIt;
    2101 
    2102                             cp2 = Var_Parse(cp, ctxt, err, &len, &freeIt);
    2103                             Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2);
    2104                             cp += len - 1;
    2105                             if (freeIt) {
    2106                                 efree(cp2);
    2107                             }
    2108                         } else if (*cp == '&') {
    2109                             Buf_AddBytes(buf, pattern.leftLen,
    2110                                         (Byte *)pattern.lhs);
    2111                         } else {
    2112                             Buf_AddByte(buf, (Byte)*cp);
    2113                         }
    2114                     }
    2115 
    2116                     Buf_AddByte(buf, (Byte)'\0');
    2117 
    2118                     /*
    2119                      * If didn't end in delimiter character, complain
    2120                      */
    2121                     if (*cp != delim) {
    2122                         *lengthPtr = cp - start + 1;
    2123                         if (*freePtr) {
    2124                             efree(str);
    2125                         }
    2126                         Buf_Destroy(buf, TRUE);
    2127                         Error("Unclosed substitution for %s (%c missing)",
    2128                               v->name, delim);
    2129                         return (var_Error);
    2130                     }
    2131 
    2132                     pattern.rhs = (char *)Buf_GetAll(buf, &pattern.rightLen);
    2133                     pattern.rightLen--;
    2134                     Buf_Destroy(buf, FALSE);
    2135 
    2136                     /*
    2137                      * Check for global substitution. If 'g' after the final
    2138                      * delimiter, substitution is global and is marked that
    2139                      * way.
    2140                      */
    2141                     cp++;
    2142                     if (*cp == 'g') {
    2143                         pattern.flags |= VAR_SUB_GLOBAL;
    2144                         cp++;
    2145                     }
    2146 
    2147                     termc = *cp;
    2148                     newStr = VarModify(str, VarSubstitute,
    2149                                        (ClientData)&pattern);
    2150                     /*
    2151                      * Free the two strings.
    2152                      */
    2153                     efree(pattern.lhs);
    2154                     efree(pattern.rhs);
    2155                     break;
    2156                 }
    2157                 case 'C':
    2158                 {
    2159                     VarREPattern    pattern;
    2160                     char           *re;
    2161                     int             error;
    2162 
    2163                     pattern.flags = 0;
    2164                     delim = tstr[1];
    2165                     tstr += 2;
    2166 
    2167                     cp = tstr;
    2168 
    2169                     if ((re = VarGetPattern(ctxt, err, &cp, delim, NULL,
    2170                         NULL, NULL)) == NULL) {
    2171                         /* was: goto cleanup */
    2172                         *lengthPtr = cp - start + 1;
    2173                         if (*freePtr)
    2174                             efree(str);
    2175                         if (delim != '\0')
    2176                             Error("Unclosed substitution for %s (%c missing)",
    2177                                   v->name, delim);
    2178                         return (var_Error);
    2179                     }
    2180 
    2181                     if ((pattern.replace = VarGetPattern(ctxt, err, &cp,
    2182                         delim, NULL, NULL, NULL)) == NULL){
    2183                         efree(re);
    2184 
    2185                         /* was: goto cleanup */
    2186                         *lengthPtr = cp - start + 1;
    2187                         if (*freePtr)
    2188                             efree(str);
    2189                         if (delim != '\0')
    2190                             Error("Unclosed substitution for %s (%c missing)",
    2191                                   v->name, delim);
    2192                         return (var_Error);
    2193                     }
    2194 
    2195                     for (;; cp++) {
    2196                         switch (*cp) {
    2197                         case 'g':
    2198                             pattern.flags |= VAR_SUB_GLOBAL;
    2199                             continue;
    2200                         case '1':
    2201                             pattern.flags |= VAR_SUB_ONE;
    2202                             continue;
    2203                         }
    2204                         break;
    2205                     }
    2206 
    2207                     termc = *cp;
    2208 
    2209                     error = regcomp(&pattern.re, re, REG_EXTENDED);
    2210                     efree(re);
    2211                     if (error)  {
    2212                         *lengthPtr = cp - start + 1;
    2213                         VarREError(error, &pattern.re, "RE substitution error");
    2214                         efree(pattern.replace);
    2215                         return (var_Error);
    2216                     }
    2217 
    2218                     pattern.nsub = pattern.re.re_nsub + 1;
    2219                     if (pattern.nsub < 1)
    2220                         pattern.nsub = 1;
    2221                     if (pattern.nsub > 10)
    2222                         pattern.nsub = 10;
    2223                     pattern.matches = emalloc(pattern.nsub *
    2224                                               sizeof(regmatch_t));
    2225                     newStr = VarModify(str, VarRESubstitute,
    2226                                        (ClientData) &pattern);
    2227                     regfree(&pattern.re);
    2228                     efree(pattern.replace);
    2229                     efree(pattern.matches);
    2230                     break;
    2231                 }
    2232                 case 'Q':
    2233                     if (tstr[1] == endc || tstr[1] == ':') {
    2234                         newStr = VarQuote (str);
    2235                         cp = tstr + 1;
    2236                         termc = *cp;
    2237                         break;
    2238                     }
    2239                     /*FALLTHRU*/
    2240                 case 'T':
    2241                     if (tstr[1] == endc || tstr[1] == ':') {
    2242                         newStr = VarModify (str, VarTail, (ClientData)0);
    2243                         cp = tstr + 1;
    2244                         termc = *cp;
    2245                         break;
    2246                     }
    2247                     /*FALLTHRU*/
    2248                 case 'H':
    2249                     if (tstr[1] == endc || tstr[1] == ':') {
    2250                         newStr = VarModify (str, VarHead, (ClientData)0);
    2251                         cp = tstr + 1;
    2252                         termc = *cp;
    2253                         break;
    2254                     }
    2255                     /*FALLTHRU*/
    2256                 case 'E':
    2257                     if (tstr[1] == endc || tstr[1] == ':') {
    2258                         newStr = VarModify (str, VarSuffix, (ClientData)0);
    2259                         cp = tstr + 1;
    2260                         termc = *cp;
    2261                         break;
    2262                     }
    2263                     /*FALLTHRU*/
    2264                 case 'R':
    2265                     if (tstr[1] == endc || tstr[1] == ':') {
    2266                         newStr = VarModify (str, VarRoot, (ClientData)0);
    2267                         cp = tstr + 1;
    2268                         termc = *cp;
    2269                         break;
    2270                     }
    2271                     /*FALLTHRU*/
     1887        /*
     1888        * Skip initial colon while putting it back.
     1889        */
     1890        *tstr++ = ':';
     1891        while (*tstr != endc) {
     1892            char        *newStr;    /* New value to return */
     1893            char        termc;      /* Character which terminated scan */
     1894
     1895            if (DEBUG(VAR)) {
     1896                printf("Applying :%c to \"%s\"\n", *tstr, str);
     1897            }
     1898            switch (*tstr) {
     1899                case 'U':
     1900                        if (tstr[1] == endc || tstr[1] == ':') {
     1901                                Buffer buf;
     1902                                buf = Buf_Init(MAKE_BSIZE);
     1903                                for (cp = str; *cp ; cp++)
     1904                                        Buf_AddByte(buf, (Byte) toupper(*cp));
     1905
     1906                                Buf_AddByte(buf, (Byte) '\0');
     1907                                newStr = (char *) Buf_GetAll(buf, (int *) NULL);
     1908                                Buf_Destroy(buf, FALSE);
     1909
     1910                                cp = tstr + 1;
     1911                                termc = *cp;
     1912                                break;
     1913                        }
     1914                        /* FALLTHROUGH */
     1915                case 'L':
     1916                        if (tstr[1] == endc || tstr[1] == ':') {
     1917                                Buffer buf;
     1918                                buf = Buf_Init(MAKE_BSIZE);
     1919                                for (cp = str; *cp ; cp++)
     1920                                        Buf_AddByte(buf, (Byte) tolower(*cp));
     1921
     1922                                Buf_AddByte(buf, (Byte) '\0');
     1923                                newStr = (char *) Buf_GetAll(buf, (int *) NULL);
     1924                                Buf_Destroy(buf, FALSE);
     1925
     1926                                cp = tstr + 1;
     1927                                termc = *cp;
     1928                                break;
     1929                        }
     1930                        /* FALLTHROUGH */
     1931                case 'N':
     1932                case 'M':
     1933                {
     1934                    char    *pattern;
     1935                    char    *cp2;
     1936                    Boolean copy;
     1937
     1938                    copy = FALSE;
     1939                    for (cp = tstr + 1;
     1940                        *cp != '\0' && *cp != ':' && *cp != endc;
     1941                        cp++)
     1942                    {
     1943                        if (*cp == '\\' && (cp[1] == ':' || cp[1] == endc)){
     1944                            copy = TRUE;
     1945                            cp++;
     1946                        }
     1947                    }
     1948                    termc = *cp;
     1949                    *cp = '\0';
     1950                    if (copy) {
     1951                        /*
     1952                        * Need to compress the \:'s out of the pattern, so
     1953                        * allocate enough room to hold the uncompressed
     1954                        * pattern (note that cp started at tstr+1, so
     1955                        * cp - tstr takes the null byte into account) and
     1956                        * compress the pattern into the space.
     1957                        */
     1958                        pattern = emalloc(cp - tstr);
     1959                        for (cp2 = pattern, cp = tstr + 1;
     1960                             *cp != '\0';
     1961                             cp++, cp2++)
     1962                        {
     1963                            if ((*cp == '\\') &&
     1964                                (cp[1] == ':' || cp[1] == endc)) {
     1965                                    cp++;
     1966                            }
     1967                            *cp2 = *cp;
     1968                        }
     1969                        *cp2 = '\0';
     1970                    } else {
     1971                        pattern = &tstr[1];
     1972                    }
     1973                    if (*tstr == 'M' || *tstr == 'm') {
     1974                        newStr = VarModify(str, VarMatch, (ClientData)pattern);
     1975                    } else {
     1976                        newStr = VarModify(str, VarNoMatch,
     1977                                           (ClientData)pattern);
     1978                    }
     1979                    if (copy) {
     1980                        efree(pattern);
     1981                    }
     1982                    break;
     1983                }
     1984                case 'S':
     1985                {
     1986                    VarPattern      pattern;
     1987                    register char   delim;
     1988                    Buffer          buf;        /* Buffer for patterns */
     1989
     1990                    pattern.flags = 0;
     1991                    delim = tstr[1];
     1992                    tstr += 2;
     1993
     1994                    /*
     1995                     * If pattern begins with '^', it is anchored to the
     1996                     * start of the word -- skip over it and flag pattern.
     1997                     */
     1998                    if (*tstr == '^') {
     1999                        pattern.flags |= VAR_MATCH_START;
     2000                        tstr += 1;
     2001                    }
     2002
     2003                    buf = Buf_Init(0);
     2004
     2005                    /*
     2006                     * Pass through the lhs looking for 1) escaped delimiters,
     2007                     * '$'s and backslashes (place the escaped character in
     2008                     * uninterpreted) and 2) unescaped $'s that aren't before
     2009                     * the delimiter (expand the variable substitution).
     2010                     * The result is left in the Buffer buf.
     2011                     */
     2012                    for (cp = tstr; *cp != '\0' && *cp != delim; cp++) {
     2013                        if ((*cp == '\\') &&
     2014                            ((cp[1] == delim) ||
     2015                             (cp[1] == '$') ||
     2016                             (cp[1] == '\\')))
     2017                        {
     2018                            Buf_AddByte(buf, (Byte)cp[1]);
     2019                            cp++;
     2020                        } else if (*cp == '$') {
     2021                            if (cp[1] != delim) {
     2022                                /*
     2023                                * If unescaped dollar sign not before the
     2024                                * delimiter, assume it's a variable
     2025                                * substitution and recurse.
     2026                                */
     2027                                char        *cp2;
     2028                                int         len;
     2029                                Boolean     freeIt;
     2030
     2031                                cp2 = Var_Parse(cp, ctxt, err, &len, &freeIt);
     2032                                Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2);
     2033                                if (freeIt) {
     2034                                    efree(cp2);
     2035                                }
     2036                                cp += len - 1;
     2037                            } else {
     2038                                /*
     2039                                * Unescaped $ at end of pattern => anchor
     2040                                * pattern at end.
     2041                                */
     2042                                pattern.flags |= VAR_MATCH_END;
     2043                            }
     2044                        } else {
     2045                            Buf_AddByte(buf, (Byte)*cp);
     2046                        }
     2047                    }
     2048
     2049                    Buf_AddByte(buf, (Byte)'\0');
     2050
     2051                    /*
     2052                     * If lhs didn't end with the delimiter, complain and
     2053                     * return NULL
     2054                     */
     2055                    if (*cp != delim) {
     2056                        *lengthPtr = cp - start + 1;
     2057                        if (*freePtr) {
     2058                            efree(str);
     2059                        }
     2060                        Buf_Destroy(buf, TRUE);
     2061                        Error("Unclosed substitution for %s (%c missing)",
     2062                              v->name, delim);
     2063                        return (var_Error);
     2064                    }
     2065
     2066                    /*
     2067                     * Fetch pattern and destroy buffer, but preserve the data
     2068                     * in it, since that's our lhs. Note that Buf_GetAll
     2069                     * will return the actual number of bytes, which includes
     2070                     * the null byte, so we have to decrement the length by
     2071                     * one.
     2072                     */
     2073                    pattern.lhs = (char *)Buf_GetAll(buf, &pattern.leftLen);
     2074                    pattern.leftLen--;
     2075                    Buf_Destroy(buf, FALSE);
     2076
     2077                    /*
     2078                     * Now comes the replacement string. Three things need to
     2079                     * be done here: 1) need to compress escaped delimiters and
     2080                     * ampersands and 2) need to replace unescaped ampersands
     2081                     * with the l.h.s. (since this isn't regexp, we can do
     2082                     * it right here) and 3) expand any variable substitutions.
     2083                     */
     2084                    buf = Buf_Init(0);
     2085
     2086                    tstr = cp + 1;
     2087                    for (cp = tstr; *cp != '\0' && *cp != delim; cp++) {
     2088                        if ((*cp == '\\') &&
     2089                            ((cp[1] == delim) ||
     2090                             (cp[1] == '&') ||
     2091                             (cp[1] == '\\') ||
     2092                             (cp[1] == '$')))
     2093                        {
     2094                            Buf_AddByte(buf, (Byte)cp[1]);
     2095                            cp++;
     2096                        } else if ((*cp == '$') && (cp[1] != delim)) {
     2097                            char    *cp2;
     2098                            int     len;
     2099                            Boolean freeIt;
     2100
     2101                            cp2 = Var_Parse(cp, ctxt, err, &len, &freeIt);
     2102                            Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2);
     2103                            cp += len - 1;
     2104                            if (freeIt) {
     2105                                efree(cp2);
     2106                            }
     2107                        } else if (*cp == '&') {
     2108                            Buf_AddBytes(buf, pattern.leftLen,
     2109                                        (Byte *)pattern.lhs);
     2110                        } else {
     2111                            Buf_AddByte(buf, (Byte)*cp);
     2112                        }
     2113                    }
     2114
     2115                    Buf_AddByte(buf, (Byte)'\0');
     2116
     2117                    /*
     2118                     * If didn't end in delimiter character, complain
     2119                     */
     2120                    if (*cp != delim) {
     2121                        *lengthPtr = cp - start + 1;
     2122                        if (*freePtr) {
     2123                            efree(str);
     2124                        }
     2125                        Buf_Destroy(buf, TRUE);
     2126                        Error("Unclosed substitution for %s (%c missing)",
     2127                              v->name, delim);
     2128                        return (var_Error);
     2129                    }
     2130
     2131                    pattern.rhs = (char *)Buf_GetAll(buf, &pattern.rightLen);
     2132                    pattern.rightLen--;
     2133                    Buf_Destroy(buf, FALSE);
     2134
     2135                    /*
     2136                     * Check for global substitution. If 'g' after the final
     2137                     * delimiter, substitution is global and is marked that
     2138                     * way.
     2139                     */
     2140                    cp++;
     2141                    if (*cp == 'g') {
     2142                        pattern.flags |= VAR_SUB_GLOBAL;
     2143                        cp++;
     2144                    }
     2145
     2146                    termc = *cp;
     2147                    newStr = VarModify(str, VarSubstitute,
     2148                                       (ClientData)&pattern);
     2149                    /*
     2150                     * Free the two strings.
     2151                     */
     2152                    efree(pattern.lhs);
     2153                    efree(pattern.rhs);
     2154                    break;
     2155                }
     2156                case 'C':
     2157                {
     2158                    VarREPattern    pattern;
     2159                    char           *re;
     2160                    int             error;
     2161
     2162                    pattern.flags = 0;
     2163                    delim = tstr[1];
     2164                    tstr += 2;
     2165
     2166                    cp = tstr;
     2167
     2168                    if ((re = VarGetPattern(ctxt, err, &cp, delim, NULL,
     2169                        NULL, NULL)) == NULL) {
     2170                        /* was: goto cleanup */
     2171                        *lengthPtr = cp - start + 1;
     2172                        if (*freePtr)
     2173                            efree(str);
     2174                        if (delim != '\0')
     2175                            Error("Unclosed substitution for %s (%c missing)",
     2176                                  v->name, delim);
     2177                        return (var_Error);
     2178                    }
     2179
     2180                    if ((pattern.replace = VarGetPattern(ctxt, err, &cp,
     2181                        delim, NULL, NULL, NULL)) == NULL){
     2182                        efree(re);
     2183
     2184                        /* was: goto cleanup */
     2185                        *lengthPtr = cp - start + 1;
     2186                        if (*freePtr)
     2187                            efree(str);
     2188                        if (delim != '\0')
     2189                            Error("Unclosed substitution for %s (%c missing)",
     2190                                  v->name, delim);
     2191                        return (var_Error);
     2192                    }
     2193
     2194                    for (;; cp++) {
     2195                        switch (*cp) {
     2196                        case 'g':
     2197                            pattern.flags |= VAR_SUB_GLOBAL;
     2198                            continue;
     2199                        case '1':
     2200                            pattern.flags |= VAR_SUB_ONE;
     2201                            continue;
     2202                        }
     2203                        break;
     2204                    }
     2205
     2206                    termc = *cp;
     2207
     2208                    error = regcomp(&pattern.re, re, REG_EXTENDED);
     2209                    efree(re);
     2210                    if (error)  {
     2211                        *lengthPtr = cp - start + 1;
     2212                        VarREError(error, &pattern.re, "RE substitution error");
     2213                        efree(pattern.replace);
     2214                        return (var_Error);
     2215                    }
     2216
     2217                    pattern.nsub = pattern.re.re_nsub + 1;
     2218                    if (pattern.nsub < 1)
     2219                        pattern.nsub = 1;
     2220                    if (pattern.nsub > 10)
     2221                        pattern.nsub = 10;
     2222                    pattern.matches = emalloc(pattern.nsub *
     2223                                              sizeof(regmatch_t));
     2224                    newStr = VarModify(str, VarRESubstitute,
     2225                                       (ClientData) &pattern);
     2226                    regfree(&pattern.re);
     2227                    efree(pattern.replace);
     2228                    efree(pattern.matches);
     2229                    break;
     2230                }
     2231                case 'Q':
     2232                    if (tstr[1] == endc || tstr[1] == ':') {
     2233                        newStr = VarQuote (str);
     2234                        cp = tstr + 1;
     2235                        termc = *cp;
     2236                        break;
     2237                    }
     2238                    /*FALLTHRU*/
     2239                case 'T':
     2240                    if (tstr[1] == endc || tstr[1] == ':') {
     2241                        newStr = VarModify (str, VarTail, (ClientData)0);
     2242                        cp = tstr + 1;
     2243                        termc = *cp;
     2244                        break;
     2245                    }
     2246                    /*FALLTHRU*/
     2247                case 'H':
     2248                    if (tstr[1] == endc || tstr[1] == ':') {
     2249                        newStr = VarModify (str, VarHead, (ClientData)0);
     2250                        cp = tstr + 1;
     2251                        termc = *cp;
     2252                        break;
     2253                    }
     2254                    /*FALLTHRU*/
     2255                case 'E':
     2256                    if (tstr[1] == endc || tstr[1] == ':') {
     2257                        newStr = VarModify (str, VarSuffix, (ClientData)0);
     2258                        cp = tstr + 1;
     2259                        termc = *cp;
     2260                        break;
     2261                    }
     2262                    /*FALLTHRU*/
     2263                case 'R':
     2264                    if (tstr[1] == endc || tstr[1] == ':') {
     2265                        newStr = VarModify (str, VarRoot, (ClientData)0);
     2266                        cp = tstr + 1;
     2267                        termc = *cp;
     2268                        break;
     2269                    }
     2270                    /*FALLTHRU*/
    22722271#ifdef SUNSHCMD
    2273                 case 's':
    2274                     if (tstr[1] == 'h' && (tstr[2] == endc || tstr[2] == ':')) {
    2275                         char *err;
    2276                         newStr = Cmd_Exec (str, &err);
    2277                         if (err)
    2278                             Error (err, str);
    2279                         cp = tstr + 2;
    2280                         termc = *cp;
    2281                         break;
    2282                     }
    2283                     /*FALLTHRU*/
     2272                case 's':
     2273                    if (tstr[1] == 'h' && (tstr[2] == endc || tstr[2] == ':')) {
     2274                        char *err;
     2275                        newStr = Cmd_Exec (str, &err);
     2276                        if (err)
     2277                            Error (err, str);
     2278                        cp = tstr + 2;
     2279                        termc = *cp;
     2280                        break;
     2281                    }
     2282                    /*FALLTHRU*/
    22842283#endif
    2285                 default:
    2286                 {
     2284                default:
     2285                {
    22872286#if defined(SYSVVARSUB) || defined(NMAKE)
    2288                     /*
    2289                      * This can either be a bogus modifier or a System-V
    2290                      * substitution command.
    2291                      */
    2292                     VarPattern      pattern;
    2293                     Boolean         eqFound;
    2294 
    2295                     pattern.flags = 0;
    2296                     eqFound = FALSE;
    2297                     /*
    2298                      * First we make a pass through the string trying
    2299                      * to verify it is a SYSV-make-style translation:
    2300                      * it must be: <string1>=<string2>)
    2301                      */
    2302                     cp = tstr;
    2303                     cnt = 1;
    2304                     while (*cp != '\0' && cnt) {
    2305                         if (*cp == '=') {
    2306                             eqFound = TRUE;
    2307                             /* continue looking for endc */
    2308                         }
    2309                         else if (*cp == endc)
    2310                             cnt--;
    2311                         else if (*cp == startc)
    2312                             cnt++;
    2313                         if (cnt)
    2314                             cp++;
    2315                     }
     2287                    /*
     2288                     * This can either be a bogus modifier or a System-V
     2289                     * substitution command.
     2290                     */
     2291                    VarPattern      pattern;
     2292                    Boolean         eqFound;
     2293
     2294                    pattern.flags = 0;
     2295                    eqFound = FALSE;
     2296                    /*
     2297                     * First we make a pass through the string trying
     2298                     * to verify it is a SYSV-make-style translation:
     2299                     * it must be: <string1>=<string2>)
     2300                     */
     2301                    cp = tstr;
     2302                    cnt = 1;
     2303                    while (*cp != '\0' && cnt) {
     2304                        if (*cp == '=') {
     2305                            eqFound = TRUE;
     2306                            /* continue looking for endc */
     2307                        }
     2308                        else if (*cp == endc)
     2309                            cnt--;
     2310                        else if (*cp == startc)
     2311                            cnt++;
     2312                        if (cnt)
     2313                            cp++;
     2314                    }
    23162315fprintf(stderr, "debug: cp=\"%s\" endc=%c eqFound=%d tstr=\"%s\"\n", cp, endc, eqFound, tstr);
    2317                     if (*cp == endc && eqFound) {
    2318 
    2319                         /*
    2320                         * Now we break this sucker into the lhs and
    2321                         * rhs. We must null terminate them of course.
    2322                         */
    2323                         for (cp = tstr; *cp != '='; cp++)
    2324                             continue;
    2325                         pattern.lhs = tstr;
    2326                         pattern.leftLen = cp - tstr;
    2327                         *cp++ = '\0';
    2328 
    2329                         pattern.rhs = cp;
    2330                         cnt = 1;
    2331                         while (cnt) {
    2332                             if (*cp == endc)
    2333                                 cnt--;
    2334                             else if (*cp == startc)
    2335                                 cnt++;
    2336                             if (cnt)
    2337                                 cp++;
    2338                         }
    2339                         pattern.rightLen = cp - pattern.rhs;
    2340                         *cp = '\0';
    2341 
    2342                         /*
    2343                         * SYSV modifications happen through the whole
    2344                         * string. Note the pattern is anchored at the end.
    2345                         */
    2346                         newStr = VarModify(str, VarSYSVMatch,
    2347                                            (ClientData)&pattern);
    2348 
    2349                         /*
    2350                         * Restore the nulled characters
    2351                         */
    2352                         pattern.lhs[pattern.leftLen] = '=';
    2353                         pattern.rhs[pattern.rightLen] = endc;
    2354                         termc = endc;
    2355                     } else
     2316                    if (*cp == endc && eqFound) {
     2317
     2318                        /*
     2319                        * Now we break this sucker into the lhs and
     2320                        * rhs. We must null terminate them of course.
     2321                        */
     2322                        for (cp = tstr; *cp != '='; cp++)
     2323                            continue;
     2324                        pattern.lhs = tstr;
     2325                        pattern.leftLen = cp - tstr;
     2326                        *cp++ = '\0';
     2327
     2328                        pattern.rhs = cp;
     2329                        cnt = 1;
     2330                        while (cnt) {
     2331                            if (*cp == endc)
     2332                                cnt--;
     2333                            else if (*cp == startc)
     2334                                cnt++;
     2335                            if (cnt)
     2336                                cp++;
     2337                        }
     2338                        pattern.rightLen = cp - pattern.rhs;
     2339                        *cp = '\0';
     2340
     2341                        /*
     2342                        * SYSV modifications happen through the whole
     2343                        * string. Note the pattern is anchored at the end.
     2344                        */
     2345                        newStr = VarModify(str, VarSYSVMatch,
     2346                                           (ClientData)&pattern);
     2347
     2348                        /*
     2349                        * Restore the nulled characters
     2350                        */
     2351                        pattern.lhs[pattern.leftLen] = '=';
     2352                        pattern.rhs[pattern.rightLen] = endc;
     2353                        termc = endc;
     2354                    } else
    23562355#endif
    2357                     {
    2358                         Error ("Unknown modifier '%c'\n", *tstr);
    2359                         for (cp = tstr+1;
    2360                              *cp != ':' && *cp != endc && *cp != '\0';
    2361                              cp++)
    2362                                 continue;
    2363                         termc = *cp;
    2364                         newStr = var_Error;
    2365                     }
    2366                 }
    2367             }
    2368             if (DEBUG(VAR)) {
    2369                 printf("Result is \"%s\"\n", newStr);
    2370             }
    2371 
    2372             if (*freePtr) {
    2373                 efree (str);
    2374             }
    2375             str = newStr;
    2376             if (str != var_Error) {
    2377                 *freePtr = TRUE;
    2378             } else {
    2379                 *freePtr = FALSE;
    2380             }
    2381             if (termc == '\0') {
    2382                 Error("Unclosed variable specification for %s", v->name);
    2383             } else if (termc == ':') {
    2384                 *cp++ = termc;
    2385             } else {
    2386                 *cp = termc;
    2387             }
    2388             tstr = cp;
    2389         }
    2390         *lengthPtr = tstr - start + 1;
     2356                    {
     2357                        Error ("Unknown modifier '%c'\n", *tstr);
     2358                        for (cp = tstr+1;
     2359                             *cp != ':' && *cp != endc && *cp != '\0';
     2360                             cp++)
     2361                                continue;
     2362                        termc = *cp;
     2363                        newStr = var_Error;
     2364                    }
     2365                }
     2366            }
     2367            if (DEBUG(VAR)) {
     2368                printf("Result is \"%s\"\n", newStr);
     2369            }
     2370
     2371            if (*freePtr) {
     2372                efree (str);
     2373            }
     2374            str = newStr;
     2375            if (str != var_Error) {
     2376                *freePtr = TRUE;
     2377            } else {
     2378                *freePtr = FALSE;
     2379            }
     2380            if (termc == '\0') {
     2381                Error("Unclosed variable specification for %s", v->name);
     2382            } else if (termc == ':') {
     2383                *cp++ = termc;
     2384            } else {
     2385                *cp = termc;
     2386            }
     2387            tstr = cp;
     2388        }
     2389        *lengthPtr = tstr - start + 1;
    23912390    } else {
    2392         *lengthPtr = tstr - start + 1;
    2393         *tstr = endc;
     2391        *lengthPtr = tstr - start + 1;
     2392        *tstr = endc;
    23942393    }
    23952394
    23962395    if (v->flags & VAR_FROM_ENV) {
    2397         Boolean   destroy = FALSE;
    2398 
    2399         if (str != (char *)Buf_GetAll(v->val, (int *)NULL)) {
    2400             destroy = TRUE;
    2401         } else {
    2402             /*
    2403              * Returning the value unmodified, so tell the caller to efree
    2404              * the thing.
    2405              */
    2406             *freePtr = TRUE;
    2407         }
    2408         Buf_Destroy(v->val, destroy);
    2409         efree((Address)v);
     2396        Boolean   destroy = FALSE;
     2397
     2398        if (str != (char *)Buf_GetAll(v->val, (int *)NULL)) {
     2399            destroy = TRUE;
     2400        } else {
     2401            /*
     2402             * Returning the value unmodified, so tell the caller to efree
     2403             * the thing.
     2404             */
     2405            *freePtr = TRUE;
     2406        }
     2407        Buf_Destroy(v->val, destroy);
     2408        efree((Address)v);
    24102409    } else if (v->flags & VAR_JUNK) {
    2411         /*
    2412         * Perform any efree'ing needed and set *freePtr to FALSE so the caller
    2413         * doesn't try to efree a static pointer.
    2414         */
    2415         if (*freePtr) {
    2416             efree(str);
    2417         }
    2418         *freePtr = FALSE;
    2419         Buf_Destroy(v->val, TRUE);
    2420         efree((Address)v);
    2421         if (dynamic) {
    2422             str = emalloc(*lengthPtr + 1);
    2423             strncpy(str, start, *lengthPtr);
    2424             str[*lengthPtr] = '\0';
    2425             *freePtr = TRUE;
    2426         } else {
    2427             str = err ? var_Error : varNoError;
    2428         }
     2410        /*
     2411        * Perform any efree'ing needed and set *freePtr to FALSE so the caller
     2412        * doesn't try to efree a static pointer.
     2413        */
     2414        if (*freePtr) {
     2415            efree(str);
     2416        }
     2417        *freePtr = FALSE;
     2418        Buf_Destroy(v->val, TRUE);
     2419        efree((Address)v);
     2420        if (dynamic) {
     2421            str = emalloc(*lengthPtr + 1);
     2422            strncpy(str, start, *lengthPtr);
     2423            str[*lengthPtr] = '\0';
     2424            *freePtr = TRUE;
     2425        } else {
     2426            str = err ? var_Error : varNoError;
     2427        }
    24292428    }
    24302429    return (str);
     
    24342433 *-----------------------------------------------------------------------
    24352434 * Var_Subst  --
    2436  *      Substitute for all variables in the given string in the given context
    2437  *      If undefErr is TRUE, Parse_Error will be called when an undefined
    2438  *      variable is encountered.
    2439  *
    2440  * Results:
    2441  *      The resulting string.
    2442  *
    2443  * Side Effects:
    2444  *      None. The old string must be freed by the caller
     2435 *      Substitute for all variables in the given string in the given context
     2436 *      If undefErr is TRUE, Parse_Error will be called when an undefined
     2437 *      variable is encountered.
     2438 *
     2439 * Results:
     2440 *      The resulting string.
     2441 *
     2442 * Side Effects:
     2443 *      None. The old string must be freed by the caller
    24452444 *-----------------------------------------------------------------------
    24462445 */
    24472446char *
    24482447Var_Subst (var, str, ctxt, undefErr)
    2449     char          *var;             /* Named variable || NULL for all */
    2450     char          *str;             /* the string in which to substitute */
    2451     GNode         *ctxt;            /* the context wherein to find variables */
    2452     Boolean       undefErr;         /* TRUE if undefineds are an error */
    2453 {
    2454     Buffer        buf;              /* Buffer for forming things */
    2455     char          *val;             /* Value to substitute for a variable */
    2456     int           length;           /* Length of the variable invocation */
    2457     Boolean       doFree;           /* Set true if val should be freed */
     2448    char          *var;             /* Named variable || NULL for all */
     2449    char          *str;             /* the string in which to substitute */
     2450    GNode         *ctxt;            /* the context wherein to find variables */
     2451    Boolean       undefErr;         /* TRUE if undefineds are an error */
     2452{
     2453    Buffer        buf;              /* Buffer for forming things */
     2454    char          *val;             /* Value to substitute for a variable */
     2455    int           length;           /* Length of the variable invocation */
     2456    Boolean       doFree;           /* Set true if val should be freed */
    24582457    static Boolean errorReported;   /* Set true if an error has already
    2459                                      * been reported to prevent a plethora
    2460                                      * of messages when recursing */
     2458                                     * been reported to prevent a plethora
     2459                                     * of messages when recursing */
    24612460
    24622461    buf = Buf_Init (MAKE_BSIZE);
     
    24642463
    24652464    while (*str) {
    2466         if (var == NULL && (*str == '$') && (str[1] == '$')) {
    2467             /*
    2468              * A dollar sign may be escaped either with another dollar sign.
    2469              * In such a case, we skip over the escape character and store the
    2470              * dollar sign into the buffer directly.
    2471              */
    2472             str++;
    2473             Buf_AddByte(buf, (Byte)*str);
    2474             str++;
    2475         } else if (*str != '$') {
    2476             /*
    2477              * Skip as many characters as possible -- either to the end of
    2478              * the string or to the next dollar sign (variable invocation).
    2479              */
    2480             char  *cp;
    2481 
    2482             for (cp = str++; *str != '$' && *str != '\0'; str++)
    2483                 continue;
    2484             Buf_AddBytes(buf, str - cp, (Byte *)cp);
    2485         } else {
    2486             if (var != NULL) {
    2487                 int expand;
    2488                 for (;;) {
    2489                     if (str[1] != '(' && str[1] != '{') {
    2490                         if (str[1] != *var) {
    2491                             Buf_AddBytes(buf, 2, (Byte *) str);
    2492                             str += 2;
    2493                             expand = FALSE;
    2494                         }
    2495                         else
    2496                             expand = TRUE;
    2497                         break;
    2498                     }
    2499                     else {
    2500                         char *p;
    2501 
    2502                         /*
    2503                         * Scan up to the end of the variable name.
    2504                         */
    2505                         for (p = &str[2]; *p &&
    2506                              *p != ':' && *p != ')' && *p != '}'; p++)
    2507                             if (*p == '$')
    2508                                 break;
    2509                         /*
    2510                         * A variable inside the variable. We cannot expand
    2511                         * the external variable yet, so we try again with
    2512                         * the nested one
    2513                         */
    2514                         if (*p == '$') {
    2515                             Buf_AddBytes(buf, p - str, (Byte *) str);
    2516                             str = p;
    2517                             continue;
    2518                         }
    2519 
    2520                         if (strncmp(var, str + 2, p - str - 2) != 0 ||
    2521                             var[p - str - 2] != '\0') {
    2522                             /*
    2523                              * Not the variable we want to expand, scan
    2524                              * until the next variable
    2525                              */
    2526                             for (;*p != '$' && *p != '\0'; p++)
    2527                                 continue;
    2528                             Buf_AddBytes(buf, p - str, (Byte *) str);
    2529                             str = p;
    2530                             expand = FALSE;
    2531                         }
    2532                         else
    2533                             expand = TRUE;
    2534                         break;
    2535                     }
    2536                 }
    2537                 if (!expand)
    2538                     continue;
    2539             }
    2540 
    2541             val = Var_Parse (str, ctxt, undefErr, &length, &doFree);
    2542 
    2543             /*
    2544              * When we come down here, val should either point to the
    2545              * value of this variable, suitably modified, or be NULL.
    2546              * Length should be the total length of the potential
    2547              * variable invocation (from $ to end character...)
    2548              */
    2549             if (val == var_Error || val == varNoError) {
    2550                 /*
    2551                 * If performing old-time variable substitution, skip over
    2552                 * the variable and continue with the substitution. Otherwise,
    2553                 * store the dollar sign and advance str so we continue with
    2554                 * the string...
    2555                 */
    2556                 if (oldVars) {
    2557                     str += length;
    2558                 } else if (undefErr) {
    2559                     /*
    2560                      * If variable is undefined, complain and skip the
    2561                      * variable. The complaint will stop us from doing anything
    2562                      * when the file is parsed.
    2563                      */
    2564                     if (!errorReported) {
    2565                         Parse_Error (PARSE_FATAL,
    2566                                      "Undefined variable \"%.*s\"",length,str);
    2567                     }
    2568                     str += length;
    2569                     errorReported = TRUE;
    2570                 } else {
    2571                     Buf_AddByte (buf, (Byte)*str);
    2572                     str += 1;
    2573                 }
    2574             } else {
    2575                 /*
    2576                 * We've now got a variable structure to store in. But first,
    2577                 * advance the string pointer.
    2578                 */
    2579                 str += length;
    2580 
    2581                 /*
    2582                 * Copy all the characters from the variable value straight
    2583                 * into the new string.
    2584                 */
    2585                 Buf_AddBytes (buf, strlen (val), (Byte *)val);
    2586                 if (doFree) {
    2587                     efree ((Address)val);
    2588                 }
    2589             }
    2590         }
     2465        if (var == NULL && (*str == '$') && (str[1] == '$')) {
     2466            /*
     2467             * A dollar sign may be escaped either with another dollar sign.
     2468             * In such a case, we skip over the escape character and store the
     2469             * dollar sign into the buffer directly.
     2470             */
     2471            str++;
     2472            Buf_AddByte(buf, (Byte)*str);
     2473            str++;
     2474        } else if (*str != '$') {
     2475            /*
     2476             * Skip as many characters as possible -- either to the end of
     2477             * the string or to the next dollar sign (variable invocation).
     2478             */
     2479            char  *cp;
     2480
     2481            for (cp = str++; *str != '$' && *str != '\0'; str++)
     2482                continue;
     2483            Buf_AddBytes(buf, str - cp, (Byte *)cp);
     2484        } else {
     2485            if (var != NULL) {
     2486                int expand;
     2487                for (;;) {
     2488                    if (str[1] != '(' && str[1] != '{') {
     2489                        if (str[1] != *var) {
     2490                            Buf_AddBytes(buf, 2, (Byte *) str);
     2491                            str += 2;
     2492                            expand = FALSE;
     2493                        }
     2494                        else
     2495                            expand = TRUE;
     2496                        break;
     2497                    }
     2498                    else {
     2499                        char *p;
     2500
     2501                        /*
     2502                        * Scan up to the end of the variable name.
     2503                        */
     2504                        for (p = &str[2]; *p &&
     2505                             *p != ':' && *p != ')' && *p != '}'; p++)
     2506                            if (*p == '$')
     2507                                break;
     2508                        /*
     2509                        * A variable inside the variable. We cannot expand
     2510                        * the external variable yet, so we try again with
     2511                        * the nested one
     2512                        */
     2513                        if (*p == '$') {
     2514                            Buf_AddBytes(buf, p - str, (Byte *) str);
     2515                            str = p;
     2516                            continue;
     2517                        }
     2518
     2519                        if (strncmp(var, str + 2, p - str - 2) != 0 ||
     2520                            var[p - str - 2] != '\0') {
     2521                            /*
     2522                             * Not the variable we want to expand, scan
     2523                             * until the next variable
     2524                             */
     2525                            for (;*p != '$' && *p != '\0'; p++)
     2526                                continue;
     2527                            Buf_AddBytes(buf, p - str, (Byte *) str);
     2528                            str = p;
     2529                            expand = FALSE;
     2530                        }
     2531                        else
     2532                            expand = TRUE;
     2533                        break;
     2534                    }
     2535                }
     2536                if (!expand)
     2537                    continue;
     2538            }
     2539
     2540            val = Var_Parse (str, ctxt, undefErr, &length, &doFree);
     2541
     2542            /*
     2543             * When we come down here, val should either point to the
     2544             * value of this variable, suitably modified, or be NULL.
     2545             * Length should be the total length of the potential
     2546             * variable invocation (from $ to end character...)
     2547             */
     2548            if (val == var_Error || val == varNoError) {
     2549                /*
     2550                * If performing old-time variable substitution, skip over
     2551                * the variable and continue with the substitution. Otherwise,
     2552                * store the dollar sign and advance str so we continue with
     2553                * the string...
     2554                */
     2555                if (oldVars) {
     2556                    str += length;
     2557                } else if (undefErr) {
     2558                    /*
     2559                     * If variable is undefined, complain and skip the
     2560                     * variable. The complaint will stop us from doing anything
     2561                     * when the file is parsed.
     2562                     */
     2563                    if (!errorReported) {
     2564                        Parse_Error (PARSE_FATAL,
     2565                                     "Undefined variable \"%.*s\"",length,str);
     2566                    }
     2567                    str += length;
     2568                    errorReported = TRUE;
     2569                } else {
     2570                    Buf_AddByte (buf, (Byte)*str);
     2571                    str += 1;
     2572                }
     2573            } else {
     2574                /*
     2575                * We've now got a variable structure to store in. But first,
     2576                * advance the string pointer.
     2577                */
     2578                str += length;
     2579
     2580                /*
     2581                * Copy all the characters from the variable value straight
     2582                * into the new string.
     2583                */
     2584                Buf_AddBytes (buf, strlen (val), (Byte *)val);
     2585                if (doFree) {
     2586                    efree ((Address)val);
     2587                }
     2588            }
     2589        }
    25912590    }
    25922591
     
    26002599 *-----------------------------------------------------------------------
    26012600 * Var_GetTail --
    2602  *      Return the tail from each of a list of words. Used to set the
    2603  *      System V local variables.
    2604  *
    2605  * Results:
    2606  *      The resulting string.
    2607  *
    2608  * Side Effects:
    2609  *      None.
     2601 *      Return the tail from each of a list of words. Used to set the
     2602 *      System V local variables.
     2603 *
     2604 * Results:
     2605 *      The resulting string.
     2606 *
     2607 * Side Effects:
     2608 *      None.
    26102609 *
    26112610 *-----------------------------------------------------------------------
     
    26132612char *
    26142613Var_GetTail(file)
    2615     char        *file;      /* Filename to modify */
     2614    char        *file;      /* Filename to modify */
    26162615{
    26172616    return(VarModify(file, VarTail, (ClientData)0));
     
    26212620 *-----------------------------------------------------------------------
    26222621 * Var_GetHead --
    2623  *      Find the leading components of a (list of) filename(s).
    2624  *      XXX: VarHead does not replace foo by ., as (sun) System V make
    2625  *      does.
    2626  *
    2627  * Results:
    2628  *      The leading components.
    2629  *
    2630  * Side Effects:
    2631  *      None.
     2622 *      Find the leading components of a (list of) filename(s).
     2623 *      XXX: VarHead does not replace foo by ., as (sun) System V make
     2624 *      does.
     2625 *
     2626 * Results:
     2627 *      The leading components.
     2628 *
     2629 * Side Effects:
     2630 *      None.
    26322631 *
    26332632 *-----------------------------------------------------------------------
     
    26352634char *
    26362635Var_GetHead(file)
    2637     char        *file;      /* Filename to manipulate */
     2636    char        *file;      /* Filename to manipulate */
    26382637{
    26392638    return(VarModify(file, VarHead, (ClientData)0));
     
    26432642 *-----------------------------------------------------------------------
    26442643 * Var_Init --
    2645  *      Initialize the module
    2646  *
    2647  * Results:
    2648  *      None
    2649  *
    2650  * Side Effects:
    2651  *      The VAR_CMD and VAR_GLOBAL contexts are created
     2644 *      Initialize the module
     2645 *
     2646 * Results:
     2647 *      None
     2648 *
     2649 * Side Effects:
     2650 *      The VAR_CMD and VAR_GLOBAL contexts are created
    26522651 *-----------------------------------------------------------------------
    26532652 */
     
    26832682 *-----------------------------------------------------------------------
    26842683 * Var_Dump --
    2685  *      print all variables in a context
     2684 *      print all variables in a context
    26862685 *-----------------------------------------------------------------------
    26872686 */
Note: See TracChangeset for help on using the changeset viewer.