[BACK]Return to var.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / make

Annotation of src/usr.bin/make/var.c, Revision 1.45

1.45    ! espie       1: /*     $OpenBSD: var.c,v 1.44 2000/07/17 23:26:50 espie Exp $  */
1.6       millert     2: /*     $NetBSD: var.c,v 1.18 1997/03/18 19:24:46 christos Exp $        */
1.1       deraadt     3:
                      4: /*
1.17      espie       5:  * Copyright (c) 1999 Marc Espie.
                      6:  *
                      7:  * Extensive code modifications for the OpenBSD project.
                      8:  *
                      9:  * Redistribution and use in source and binary forms, with or without
                     10:  * modification, are permitted provided that the following conditions
                     11:  * are met:
                     12:  * 1. Redistributions of source code must retain the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer.
                     14:  * 2. Redistributions in binary form must reproduce the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer in the
                     16:  *    documentation and/or other materials provided with the distribution.
                     17:  *
                     18:  * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS
                     19:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
                     20:  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
                     21:  * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OPENBSD
                     22:  * PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
                     23:  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
                     24:  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     25:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     26:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     27:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
                     28:  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     29:  */
                     30:
                     31: /*
1.5       millert    32:  * Copyright (c) 1988, 1989, 1990, 1993
                     33:  *     The Regents of the University of California.  All rights reserved.
1.1       deraadt    34:  * Copyright (c) 1989 by Berkeley Softworks
                     35:  * All rights reserved.
                     36:  *
                     37:  * This code is derived from software contributed to Berkeley by
                     38:  * Adam de Boor.
                     39:  *
                     40:  * Redistribution and use in source and binary forms, with or without
                     41:  * modification, are permitted provided that the following conditions
                     42:  * are met:
                     43:  * 1. Redistributions of source code must retain the above copyright
                     44:  *    notice, this list of conditions and the following disclaimer.
                     45:  * 2. Redistributions in binary form must reproduce the above copyright
                     46:  *    notice, this list of conditions and the following disclaimer in the
                     47:  *    documentation and/or other materials provided with the distribution.
                     48:  * 3. All advertising materials mentioning features or use of this software
                     49:  *    must display the following acknowledgement:
                     50:  *     This product includes software developed by the University of
                     51:  *     California, Berkeley and its contributors.
                     52:  * 4. Neither the name of the University nor the names of its contributors
                     53:  *    may be used to endorse or promote products derived from this software
                     54:  *    without specific prior written permission.
                     55:  *
                     56:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     57:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     58:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     59:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     60:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     61:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     62:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     63:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     64:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     65:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     66:  * SUCH DAMAGE.
                     67:  */
                     68:
                     69: #ifndef lint
                     70: #if 0
1.5       millert    71: static char sccsid[] = "@(#)var.c      8.3 (Berkeley) 3/19/94";
1.1       deraadt    72: #else
1.45    ! espie      73: static char rcsid[] = "$OpenBSD: var.c,v 1.44 2000/07/17 23:26:50 espie Exp $";
1.1       deraadt    74: #endif
                     75: #endif /* not lint */
                     76:
                     77: /*-
                     78:  * var.c --
                     79:  *     Variable-handling functions
                     80:  *
                     81:  * Interface:
                     82:  *     Var_Set             Set the value of a variable in the given
                     83:  *                         context. The variable is created if it doesn't
                     84:  *                         yet exist. The value and variable name need not
                     85:  *                         be preserved.
                     86:  *
                     87:  *     Var_Append          Append more characters to an existing variable
                     88:  *                         in the given context. The variable needn't
                     89:  *                         exist already -- it will be created if it doesn't.
                     90:  *                         A space is placed between the old value and the
                     91:  *                         new one.
                     92:  *
                     93:  *     Var_Exists          See if a variable exists.
                     94:  *
                     95:  *     Var_Value           Return the value of a variable in a context or
                     96:  *                         NULL if the variable is undefined.
                     97:  *
                     98:  *     Var_Subst           Substitute named variable, or all variables if
                     99:  *                         NULL in a string using
                    100:  *                         the given context as the top-most one. If the
                    101:  *                         third argument is non-zero, Parse_Error is
                    102:  *                         called if any variables are undefined.
                    103:  *
                    104:  *     Var_Parse           Parse a variable expansion from a string and
                    105:  *                         return the result and the number of characters
                    106:  *                         consumed.
                    107:  *
                    108:  *     Var_Delete          Delete a variable in a context.
                    109:  *
                    110:  *     Var_Init            Initialize this module.
                    111:  *
                    112:  * Debugging:
                    113:  *     Var_Dump            Print out all variables defined in the given
                    114:  *                         context.
                    115:  *
                    116:  * XXX: There's a lot of duplication in these functions.
                    117:  */
                    118:
                    119: #include    <ctype.h>
1.6       millert   120: #ifndef MAKE_BOOTSTRAP
1.9       deraadt   121: #include    <sys/types.h>
1.6       millert   122: #include    <regex.h>
                    123: #endif
                    124: #include    <stdlib.h>
1.35      espie     125: #include    <stddef.h>
1.1       deraadt   126: #include    "make.h"
                    127: #include    "buf.h"
1.38      espie     128: #include    "ohash.h"
                    129: #include    "hashconsts.h"
1.43      espie     130: #include    "varmodifiers.h"
1.34      espie     131:
1.37      espie     132: static SymTable *CTXT_GLOBAL, *CTXT_CMD, *CTXT_ENV;
                    133:
1.34      espie     134: static char *varnames[] = {
                    135:     TARGET,
                    136:     OODATE,
                    137:     ALLSRC,
                    138:     IMPSRC,
                    139:     PREFIX,
                    140:     ARCHIVE,
                    141:     MEMBER };
                    142:
1.1       deraadt   143: /*
                    144:  * This is a harmless return value for Var_Parse that can be used by Var_Subst
                    145:  * to determine if there was an error in parsing -- easier than returning
                    146:  * a flag, as things outside this module don't give a hoot.
                    147:  */
                    148: char   var_Error[] = "";
                    149:
                    150: /*
                    151:  * Similar to var_Error, but returned when the 'err' flag for Var_Parse is
                    152:  * set false. Why not just use a constant? Well, gcc likes to condense
                    153:  * identical string instances...
                    154:  */
                    155: static char    varNoError[] = "";
                    156:
                    157: /*
                    158:  * Internally, variables are contained in four different contexts.
                    159:  *     1) the environment. They may not be changed. If an environment
                    160:  *         variable is appended-to, the result is placed in the global
                    161:  *         context.
                    162:  *     2) the global context. Variables set in the Makefile are located in
                    163:  *         the global context. It is the penultimate context searched when
                    164:  *         substituting.
                    165:  *     3) the command-line context. All variables set on the command line
                    166:  *        are placed in this context. They are UNALTERABLE once placed here.
                    167:  *     4) the local context. Each target has associated with it a context
                    168:  *        list. On this list are located the structures describing such
                    169:  *        local variables as $(@) and $(*)
                    170:  * The four contexts are searched in the reverse order from which they are
                    171:  * listed.
                    172:  */
1.37      espie     173: GSymT          *VAR_GLOBAL;    /* variables from the makefile */
                    174: GSymT          *VAR_CMD;       /* variables defined on the command-line */
                    175: static GSymT   *VAR_ENV;       /* variables read from env */
1.1       deraadt   176:
1.39      espie     177: #define FIND_MINE      0x1   /* look in CTXT_CMD and CTXT_GLOBAL */
                    178: #define FIND_ENV       0x2   /* look in the environment */
1.1       deraadt   179:
1.37      espie     180: typedef struct Var_ {
1.23      espie     181:     BUFFER       val;          /* its value */
1.1       deraadt   182:     int                  flags;        /* miscellaneous status flags */
                    183: #define VAR_IN_USE     1           /* Variable's value currently being used.
                    184:                                     * Used to avoid recursion */
                    185: #define VAR_JUNK       4           /* Variable is a junk variable that
                    186:                                     * should be destroyed when done with
                    187:                                     * it. Used by Var_Parse for undefined,
                    188:                                     * modified variables */
1.38      espie     189:     char          name[1];     /* the variable's name */
1.1       deraadt   190: }  Var;
                    191:
1.38      espie     192: static struct hash_info var_info = {
                    193:        offsetof(Var, name),
                    194:     NULL, hash_alloc, hash_free, element_alloc };
                    195: static int quick_lookup __P((const char *, const char **, u_int32_t *));
1.23      espie     196: #define VarValue(v)    Buf_Retrieve(&((v)->val))
1.39      espie     197: static Var *varfind __P((const char *, const char *, SymTable *, int, int, u_int32_t));
                    198: static Var *VarFind_interval __P((const char *, const char *, SymTable *, int));
                    199: #define VarFind(n, ctxt, flags)        VarFind_interval(n, NULL, ctxt, flags)
                    200: static Var *VarAdd __P((const char *, const char *, GSymT *));
1.32      espie     201: static void VarDelete __P((void *));
                    202: static void VarPrintVar __P((void *));
1.38      espie     203: static const char *context_name __P((GSymT *));
1.39      espie     204: static Var *new_var __P((const char *, const char *));
                    205: static Var *getvar __P((GSymT *, const char *, const char *, u_int32_t));
1.45    ! espie     206: static Var *var_name_with_dollar __P((char *, char **, SymTable *, Boolean, char));
1.37      espie     207:
                    208: void
                    209: SymTable_Init(ctxt)
                    210:     SymTable   *ctxt;
                    211: {
                    212:     static SymTable sym_template;
                    213:     memcpy(ctxt, &sym_template, sizeof(*ctxt));
                    214: }
                    215:
                    216: void
                    217: SymTable_Destroy(ctxt)
                    218:     SymTable   *ctxt;
                    219: {
                    220:     int i;
                    221:
                    222:     for (i = 0; i < LOCAL_SIZE; i++)
                    223:        if (ctxt->locals[i] != NULL)
                    224:            VarDelete(ctxt->locals[i]);
                    225: }
                    226:
1.38      espie     227: static int
                    228: quick_lookup(name, end, pk)
                    229:     const char *name;
                    230:     const char **end;
                    231:     u_int32_t *pk;
                    232: {
                    233:     size_t len;
                    234:
                    235:     *pk = hash_interval(name, end);
                    236:     len = *end - name;
                    237:        /* substitute short version for long local name */
                    238:     switch (*pk % MAGICSLOTS) {                    /* MAGICSLOTS should be the    */
                    239:     case K_LONGALLSRC % MAGICSLOTS:        /* smallest constant yielding  */
                    240:                                            /* distinct case values        */
                    241:        if (*pk == K_LONGALLSRC && strncmp(name, LONGALLSRC, len) == 0 &&
                    242:            len == strlen(LONGALLSRC))
                    243:            return ALLSRC_INDEX;
                    244:        break;
                    245:     case K_LONGARCHIVE % MAGICSLOTS:
                    246:        if (*pk == K_LONGARCHIVE && strncmp(name, LONGARCHIVE, len) == 0 &&
                    247:            len == strlen(LONGARCHIVE))
                    248:            return ARCHIVE_INDEX;
                    249:        break;
                    250:     case K_LONGIMPSRC % MAGICSLOTS:
                    251:        if (*pk == K_LONGIMPSRC && strncmp(name, LONGIMPSRC, len) == 0 &&
                    252:            len == strlen(LONGIMPSRC))
                    253:            return IMPSRC_INDEX;
                    254:        break;
                    255:     case K_LONGMEMBER % MAGICSLOTS:
                    256:        if (*pk == K_LONGMEMBER && strncmp(name, LONGMEMBER, len) == 0 &&
                    257:            len == strlen(LONGMEMBER))
                    258:            return MEMBER_INDEX;
                    259:        break;
                    260:     case K_LONGOODATE % MAGICSLOTS:
                    261:        if (*pk == K_LONGOODATE && strncmp(name, LONGOODATE, len) == 0 &&
                    262:            len == strlen(LONGOODATE))
                    263:            return OODATE_INDEX;
                    264:        break;
                    265:     case K_LONGPREFIX % MAGICSLOTS:
                    266:        if (*pk == K_LONGPREFIX && strncmp(name, LONGPREFIX, len) == 0 &&
                    267:            len == strlen(LONGPREFIX))
                    268:            return PREFIX_INDEX;
                    269:        break;
                    270:     case K_LONGTARGET % MAGICSLOTS:
                    271:        if (*pk == K_LONGTARGET && strncmp(name, LONGTARGET, len) == 0 &&
                    272:            len == strlen(LONGTARGET))
                    273:            return TARGET_INDEX;
                    274:        break;
                    275:     case K_TARGET % MAGICSLOTS:
                    276:        if (name[0] == TARGET[0] && len == 1)
                    277:            return TARGET_INDEX;
                    278:        break;
                    279:     case K_OODATE % MAGICSLOTS:
                    280:        if (name[0] == OODATE[0] && len == 1)
                    281:            return OODATE_INDEX;
                    282:        break;
                    283:     case K_ALLSRC % MAGICSLOTS:
                    284:        if (name[0] == ALLSRC[0] && len == 1)
                    285:            return ALLSRC_INDEX;
                    286:        break;
                    287:     case K_IMPSRC % MAGICSLOTS:
                    288:        if (name[0] == IMPSRC[0] && len == 1)
                    289:            return IMPSRC_INDEX;
                    290:        break;
                    291:     case K_PREFIX % MAGICSLOTS:
                    292:        if (name[0] == PREFIX[0] && len == 1)
                    293:            return PREFIX_INDEX;
                    294:        break;
                    295:     case K_ARCHIVE % MAGICSLOTS:
                    296:        if (name[0] == ARCHIVE[0] && len == 1)
                    297:            return ARCHIVE_INDEX;
                    298:        break;
                    299:     case K_MEMBER % MAGICSLOTS:
                    300:        if (name[0] == MEMBER[0] && len == 1)
                    301:            return MEMBER_INDEX;
                    302:        break;
                    303:     default:
                    304:        break;
                    305:     }
                    306:     return -1;
                    307: }
1.37      espie     308:
                    309: void
                    310: Varq_Set(idx, val, gn)
                    311:     int        idx;
                    312:     char       *val;
                    313:     GNode      *gn;
                    314: {
1.38      espie     315:     /* We only look for a variable in the given context since anything set
                    316:      * here will override anything in a lower context, so there's not much
                    317:      * point in searching them all just to save a bit of memory...  */
1.37      espie     318:     Var *v = gn->context.locals[idx];
                    319:
                    320:     if (v == NULL) {
                    321:        v = new_var(varnames[idx], val);
                    322:        v->flags = 0;
                    323:        gn->context.locals[idx] = v;
                    324:     } else {
                    325:        Buf_Reset(&(v->val));
                    326:        Buf_AddString(&(v->val), val);
                    327:
                    328:     }
                    329:     if (DEBUG(VAR))
                    330:        printf("%s:%s = %s\n", gn->name, varnames[idx], val);
                    331: }
                    332:
                    333: void
                    334: Varq_Append(idx, val, gn)
                    335:     int                idx;
                    336:     char       *val;
                    337:     GNode      *gn;
                    338: {
                    339:     Var *v = gn->context.locals[idx];
                    340:
                    341:     if (v == NULL) {
                    342:        v = new_var(varnames[idx], val);
                    343:        v->flags = 0;
                    344:        gn->context.locals[idx] = v;
                    345:     } else {
                    346:        Buf_AddSpace(&(v->val));
                    347:        Buf_AddString(&(v->val), val);
                    348:     }
                    349:     if (DEBUG(VAR))
                    350:        printf("%s:%s = %s\n", gn->name, varnames[idx], VarValue(v));
                    351: }
                    352:
                    353: char *
                    354: Varq_Value(idx, gn)
                    355:     int                idx;
                    356:     GNode      *gn;
                    357: {
                    358:     Var *v = gn->context.locals[idx];
                    359:
                    360:     if (v != NULL)
                    361:        return VarValue(v);
                    362:     else
                    363:        return NULL;
                    364: }
                    365:
                    366: Boolean
                    367: Varq_Exists(idx, gn)
                    368:     int                idx;
                    369:     GNode      *gn;
                    370: {
                    371:     return gn->context.locals[idx] != NULL;
                    372: }
1.1       deraadt   373:
1.35      espie     374:
1.38      espie     375: static const char *
1.35      espie     376: context_name(ctxt)
1.37      espie     377:     GSymT *ctxt;
1.35      espie     378: {
                    379:     if (ctxt == VAR_GLOBAL)
                    380:        return "Global";
1.37      espie     381:     else if (ctxt == VAR_CMD)
1.35      espie     382:        return "Command";
1.37      espie     383:     else
1.35      espie     384:        return "Environment";
                    385: }
                    386:
1.37      espie     387: /* Create a variable, to pass to VarAdd.  */
                    388: static Var *
                    389: new_var(name, val)
1.39      espie     390:     const char *name;
                    391:     const char *val;
1.37      espie     392: {
                    393:     Var *v;
1.38      espie     394:     const char *end = NULL;
1.37      espie     395:
1.38      espie     396:     v = hash_create_entry(&var_info, name, &end);
1.37      espie     397:
                    398:     if (val != NULL) {
                    399:        size_t len = strlen(val);
                    400:        Buf_Init(&(v->val), len+1);
                    401:        Buf_AddChars(&(v->val), len, val);
                    402:     } else
                    403:        Buf_Init(&(v->val), 1);
                    404:
                    405:     return v;
                    406: }
                    407:
1.38      espie     408: static Var *
                    409: getvar(ctxt, name, end, k)
                    410:     GSymT      *ctxt;
1.39      espie     411:     const char         *name;
1.38      espie     412:     const char *end;
                    413:     u_int32_t  k;
1.1       deraadt   414: {
1.38      espie     415:     return hash_find(ctxt, hash_lookup_interval(ctxt, name, end, k));
1.37      espie     416: }
                    417:
1.1       deraadt   418: /*-
                    419:  *-----------------------------------------------------------------------
1.39      espie     420:  * VarFind_interval --
1.1       deraadt   421:  *     Find the given variable in the given context and any other contexts
1.39      espie     422:  *     indicated.  if end is NULL, name is a string, otherwise, only
                    423:  *      the interval name - end  is concerned.
1.1       deraadt   424:  *
                    425:  * Results:
                    426:  *     A pointer to the structure describing the desired variable or
1.26      espie     427:  *     NULL if the variable does not exist.
1.1       deraadt   428:  *
                    429:  * Side Effects:
1.17      espie     430:  *     Caches env variables in the VAR_ENV context.
1.1       deraadt   431:  *-----------------------------------------------------------------------
                    432:  */
                    433: static Var *
1.39      espie     434: VarFind_interval(name, end, ctxt, flags)
                    435:     const char          *name; /* name to find */
                    436:     const char         *end;   /* end of name */
1.35      espie     437:     SymTable           *ctxt;  /* context in which to find it */
1.39      espie     438:     int                flags;  /* FIND_MINE set means to look in the
                    439:                                 * CTXT_GLOBAL and CTXT_CMD contexts also.
1.1       deraadt   440:                                 * FIND_ENV set means to look in the
1.39      espie     441:                                 * environment */
1.1       deraadt   442: {
1.38      espie     443:     int                idx;
                    444:     u_int32_t          k;
                    445:
                    446:     idx = quick_lookup(name, &end, &k);
1.39      espie     447:     return varfind(name, end, ctxt, flags, idx, k);
                    448: }
                    449:
                    450: static Var *
                    451: varfind(name, end, ctxt, flags, idx, k)
                    452:     const char         *name;
                    453:     const char         *end;
                    454:     SymTable           *ctxt;
                    455:     int                        flags;
                    456:     int                        idx;
                    457:     u_int32_t          k;
                    458: {
                    459:     Var                        *v;
1.1       deraadt   460:
                    461:     /*
                    462:      * First look for the variable in the given context. If it's not there,
                    463:      * look for it in VAR_CMD, VAR_GLOBAL and the environment, in that order,
                    464:      * depending on the FIND_* flags in 'flags'
                    465:      */
1.37      espie     466:     if (ctxt == NULL)
                    467:        v = NULL;
                    468:     else if (ctxt == CTXT_GLOBAL || ctxt == CTXT_CMD || ctxt == CTXT_ENV)
1.38      espie     469:        v = getvar((GSymT *)ctxt, name, end, k);
1.37      espie     470:     else {
1.38      espie     471:        if (idx == -1)
                    472:            v = NULL;
                    473:        else
                    474:            v = ctxt->locals[idx];
1.37      espie     475:     }
                    476:     if (v != NULL)
                    477:        return v;
                    478:
1.39      espie     479:     if ((flags & FIND_MINE) && ctxt != CTXT_CMD)
1.38      espie     480:        v = getvar(VAR_CMD, name, end, k);
1.37      espie     481:     if (v != NULL)
                    482:        return v;
                    483:
1.39      espie     484:     if (!checkEnvFirst && (flags & FIND_MINE) && ctxt != CTXT_GLOBAL)
1.38      espie     485:        v = getvar(VAR_GLOBAL, name, end, k);
1.37      espie     486:     if (v != NULL)
                    487:        return v;
                    488:
                    489:     if ((flags & FIND_ENV)) {
                    490:        char *env;
1.42      espie     491:        char *n;
1.37      espie     492:
1.38      espie     493:        v = getvar(VAR_ENV, name, end, k);
1.37      espie     494:        if (v != NULL)
                    495:            return v;
1.1       deraadt   496:
1.42      espie     497:        /* getenv requires a null-terminated name */
                    498:        n = interval_dup(name, end);
                    499:        env = getenv(n);
                    500:        free(n);
                    501:        if (env != NULL)
1.37      espie     502:            return VarAdd(name, env, VAR_ENV);
                    503:     }
1.17      espie     504:
1.39      espie     505:     if (checkEnvFirst && (flags & FIND_MINE) && ctxt != CTXT_GLOBAL)
1.38      espie     506:        v = getvar(VAR_GLOBAL, name, end, k);
1.37      espie     507:     return v;
1.1       deraadt   508: }
                    509:
                    510: /*-
                    511:  *-----------------------------------------------------------------------
                    512:  * VarAdd  --
                    513:  *     Add a new variable of name name and value val to the given context
                    514:  *
                    515:  * Results:
1.17      espie     516:  *     The added variable
1.1       deraadt   517:  *
                    518:  * Side Effects:
                    519:  *     The new variable is placed at the front of the given context
                    520:  *     The name and val arguments are duplicated so they may
                    521:  *     safely be freed.
                    522:  *-----------------------------------------------------------------------
                    523:  */
1.17      espie     524: static Var *
                    525: VarAdd(name, val, ctxt)
1.39      espie     526:     const char *name;  /* name of variable to add */
                    527:     const char *val;   /* value to set it to */
1.37      espie     528:     GSymT      *ctxt;  /* context in which to set it */
1.1       deraadt   529: {
1.38      espie     530:     Var        *v;
                    531:     const char         *end = NULL;
                    532:     int        idx;
                    533:     u_int32_t  k;
1.1       deraadt   534:
1.37      espie     535:     v = new_var(name, val);
1.1       deraadt   536:
                    537:     v->flags = 0;
                    538:
1.38      espie     539:     idx = quick_lookup(name, &end, &k);
                    540:
                    541:     if (idx != -1) {
                    542:        Parse_Error(PARSE_FATAL, "Trying to set dynamic variable %s",
                    543:            v->name);
                    544:     } else
                    545:        hash_insert(ctxt, hash_lookup_interval(ctxt, name, end, k), v);
1.17      espie     546:     return v;
1.1       deraadt   547: }
                    548:
                    549:
                    550: /*-
                    551:  *-----------------------------------------------------------------------
                    552:  * VarDelete  --
                    553:  *     Delete a variable and all the space associated with it.
                    554:  *
                    555:  * Results:
                    556:  *     None
                    557:  *
                    558:  * Side Effects:
                    559:  *     None
                    560:  *-----------------------------------------------------------------------
                    561:  */
                    562: static void
                    563: VarDelete(vp)
1.32      espie     564:     void *vp;
1.1       deraadt   565: {
                    566:     Var *v = (Var *) vp;
1.23      espie     567:     Buf_Destroy(&(v->val));
                    568:     free(v);
1.1       deraadt   569: }
                    570:
                    571:
                    572:
                    573: /*-
                    574:  *-----------------------------------------------------------------------
                    575:  * Var_Delete --
                    576:  *     Remove a variable from a context.
                    577:  *
                    578:  * Results:
                    579:  *     None.
                    580:  *
                    581:  * Side Effects:
                    582:  *     The Var structure is removed and freed.
                    583:  *
                    584:  *-----------------------------------------------------------------------
                    585:  */
                    586: void
                    587: Var_Delete(name, ctxt)
                    588:     char         *name;
1.37      espie     589:     GSymT        *ctxt;
1.1       deraadt   590: {
1.38      espie     591:     Var *v;
                    592:     u_int32_t k;
                    593:     const char *end = NULL;
1.1       deraadt   594:
1.37      espie     595:     if (DEBUG(VAR))
1.35      espie     596:        printf("%s:delete %s\n", context_name(ctxt), name);
1.38      espie     597:     (void)quick_lookup(name, &end, &k);
                    598:     v = hash_remove(ctxt, hash_lookup_interval(ctxt, name, end, k));
1.37      espie     599:
1.38      espie     600:     if (v != NULL)
1.30      espie     601:        VarDelete(v);
1.1       deraadt   602: }
                    603:
                    604: /*-
                    605:  *-----------------------------------------------------------------------
                    606:  * Var_Set --
                    607:  *     Set the variable name to the value val in the given context.
                    608:  *
                    609:  * Results:
                    610:  *     None.
                    611:  *
                    612:  * Side Effects:
                    613:  *     If the variable doesn't yet exist, a new record is created for it.
                    614:  *     Else the old value is freed and the new one stuck in its place
                    615:  *
                    616:  * Notes:
                    617:  *     The variable is searched for only in its context before being
                    618:  *     created in that context. I.e. if the context is VAR_GLOBAL,
                    619:  *     only VAR_GLOBAL->context is searched. Likewise if it is VAR_CMD, only
                    620:  *     VAR_CMD->context is searched. This is done to avoid the literally
                    621:  *     thousands of unnecessary strcmp's that used to be done to
                    622:  *     set, say, $(@) or $(<).
                    623:  *-----------------------------------------------------------------------
                    624:  */
                    625: void
1.35      espie     626: Var_Set(name, val, ctxt)
1.37      espie     627:     char       *name;  /* name of variable to set */
                    628:     char       *val;   /* value to give to the variable */
                    629:     GSymT       *ctxt; /* context in which to set it */
1.1       deraadt   630: {
                    631:     register Var   *v;
                    632:
                    633:     /*
                    634:      * We only look for a variable in the given context since anything set
                    635:      * here will override anything in a lower context, so there's not much
                    636:      * point in searching them all just to save a bit of memory...
                    637:      */
1.37      espie     638:     v = VarFind(name, (SymTable *)ctxt, 0);
1.38      espie     639:     if (v == NULL)
1.17      espie     640:        (void)VarAdd(name, val, ctxt);
1.38      espie     641:     else {
1.23      espie     642:        Buf_Reset(&(v->val));
                    643:        Buf_AddString(&(v->val), val);
1.1       deraadt   644:
                    645:     }
1.37      espie     646:     if (DEBUG(VAR))
                    647:        printf("%s:%s = %s\n", context_name(ctxt), name, val);
1.1       deraadt   648:     /*
                    649:      * Any variables given on the command line are automatically exported
1.17      espie     650:      * to the environment (as per POSIX standard).
                    651:      * We put them into the env cache directly.
                    652:      * (Note that additions to VAR_CMD occur very early, so VAR_ENV is
                    653:      * actually empty at this point).
1.1       deraadt   654:      */
                    655:     if (ctxt == VAR_CMD) {
                    656:        setenv(name, val, 1);
1.17      espie     657:        (void)VarAdd(name, val, VAR_ENV);
1.1       deraadt   658:     }
                    659: }
                    660:
                    661: /*-
                    662:  *-----------------------------------------------------------------------
                    663:  * Var_Append --
                    664:  *     The variable of the given name has the given value appended to it in
                    665:  *     the given context.
                    666:  *
                    667:  * Results:
                    668:  *     None
                    669:  *
                    670:  * Side Effects:
                    671:  *     If the variable doesn't exist, it is created. Else the strings
                    672:  *     are concatenated (with a space in between).
                    673:  *
                    674:  * Notes:
                    675:  *     Only if the variable is being sought in the global context is the
                    676:  *     environment searched.
                    677:  *     XXX: Knows its calling circumstances in that if called with ctxt
                    678:  *     an actual target, it will only search that context since only
                    679:  *     a local variable could be being appended to. This is actually
                    680:  *     a big win and must be tolerated.
                    681:  *-----------------------------------------------------------------------
                    682:  */
                    683: void
1.35      espie     684: Var_Append(name, val, ctxt)
1.37      espie     685:     char       *name;  /* Name of variable to modify */
                    686:     char       *val;   /* String to append to it */
                    687:     GSymT      *ctxt;  /* Context in which this should occur */
1.1       deraadt   688: {
                    689:     register Var   *v;
                    690:
1.37      espie     691:     v = VarFind(name, (SymTable *)ctxt, (ctxt == VAR_GLOBAL) ? FIND_ENV : 0);
1.1       deraadt   692:
1.26      espie     693:     if (v == NULL) {
1.17      espie     694:        (void)VarAdd(name, val, ctxt);
1.1       deraadt   695:     } else {
1.23      espie     696:        Buf_AddSpace(&(v->val));
                    697:        Buf_AddString(&(v->val), val);
1.1       deraadt   698:
                    699:
                    700:     }
1.37      espie     701:     if (DEBUG(VAR))
                    702:        printf("%s:%s = %s\n", context_name(ctxt), name, VarValue(v));
1.1       deraadt   703: }
                    704:
                    705: /*-
                    706:  *-----------------------------------------------------------------------
                    707:  * Var_Exists --
                    708:  *     See if the given variable exists.
                    709:  *
                    710:  * Results:
                    711:  *     TRUE if it does, FALSE if it doesn't
                    712:  *
                    713:  * Side Effects:
                    714:  *     None.
                    715:  *
                    716:  *-----------------------------------------------------------------------
                    717:  */
                    718: Boolean
                    719: Var_Exists(name, ctxt)
1.37      espie     720:     char       *name;          /* Variable to find */
                    721:     GSymT      *ctxt;          /* Context in which to start search */
1.1       deraadt   722: {
                    723:     Var                  *v;
                    724:
1.39      espie     725:     v = VarFind(name, (SymTable *)ctxt, FIND_MINE|FIND_ENV);
1.1       deraadt   726:
1.26      espie     727:     if (v == NULL)
1.17      espie     728:        return FALSE;
                    729:     else
                    730:        return TRUE;
1.1       deraadt   731: }
                    732:
                    733: /*-
                    734:  *-----------------------------------------------------------------------
                    735:  * Var_Value --
                    736:  *     Return the value of the named variable in the given context
                    737:  *
                    738:  * Results:
                    739:  *     The value if the variable exists, NULL if it doesn't
                    740:  *
                    741:  * Side Effects:
                    742:  *     None
                    743:  *-----------------------------------------------------------------------
                    744:  */
                    745: char *
1.18      espie     746: Var_Value(name, ctxt)
1.37      espie     747:     char       *name;  /* name to find */
                    748:     GSymT      *ctxt;  /* context in which to search for it */
1.1       deraadt   749: {
                    750:     Var            *v;
                    751:
1.39      espie     752:     v = VarFind(name, (SymTable *)ctxt, FIND_ENV | FIND_MINE);
1.26      espie     753:     if (v != NULL)
1.23      espie     754:        return VarValue(v);
1.21      espie     755:     else
1.17      espie     756:        return NULL;
1.1       deraadt   757: }
                    758:
1.45    ! espie     759: /*
        !           760:  *-----------------------------------------------------------------------
        !           761:  * v = var_name_with_dollar(str, &pos, ctxt, err, endc)
        !           762:  *   handle variable name that contains a dollar
        !           763:  *   str points to the first letter of the variable name,
        !           764:  *   &pos to the current position in the name (first dollar at invocation,
        !           765:  *   end of name specification at return).
        !           766:  *   returns the corresponding variable.
        !           767:  *-----------------------------------------------------------------------
        !           768:  */
        !           769: static Var *
        !           770: var_name_with_dollar(str, pos, ctxt, err, endc)
        !           771:     char *str;                 /* First dollar in variable name */
        !           772:     char **pos;                        /* Current position in variable spec */
        !           773:     SymTable           *ctxt;          /* The context for the variable */
        !           774:     Boolean    err;            /* TRUE if undefined variables are an error */
        !           775:     char       endc;           /* End character for spec */
        !           776: {
        !           777:     BUFFER buf;                        /* Store the variable name */
        !           778:     size_t sublen;             /* Deal with recursive expansions */
        !           779:     Boolean subfree;
        !           780:     char *n;                   /* Sub name */
        !           781:     Var *v;
        !           782:
        !           783:     Buf_Init(&buf, MAKE_BSIZE);
        !           784:
        !           785:     while (1) {
        !           786:        Buf_AddInterval(&buf, str, *pos);
        !           787:        n = Var_Parse(*pos, ctxt, err, &sublen, &subfree);
        !           788:        if (n != NULL)
        !           789:            Buf_AddString(&buf, n);
        !           790:        if (subfree)
        !           791:            free(n);
        !           792:        *pos += sublen;
        !           793:        str = *pos;
        !           794:        for (; **pos != '$'; (*pos)++) {
        !           795:            if (**pos == '\0' || **pos == endc || **pos == ':') {
        !           796:                v = VarFind(Buf_Retrieve(&buf), ctxt, FIND_ENV | FIND_MINE);
        !           797:                Buf_Destroy(&buf);
        !           798:                return v;
        !           799:            }
        !           800:        }
        !           801:     }
        !           802: }
        !           803:
1.1       deraadt   804: /*-
                    805:  *-----------------------------------------------------------------------
                    806:  * Var_Parse --
                    807:  *     Given the start of a variable invocation, extract the variable
                    808:  *     name and find its value, then modify it according to the
                    809:  *     specification.
                    810:  *
                    811:  * Results:
                    812:  *     The (possibly-modified) value of the variable or var_Error if the
                    813:  *     specification is invalid. The length of the specification is
                    814:  *     placed in *lengthPtr (for invalid specifications, this is just
                    815:  *     2...?).
                    816:  *     A Boolean in *freePtr telling whether the returned string should
                    817:  *     be freed by the caller.
                    818:  *-----------------------------------------------------------------------
                    819:  */
                    820: char *
1.35      espie     821: Var_Parse(str, ctxt, err, lengthPtr, freePtr)
1.44      espie     822:     char       *str;           /* The string to parse */
                    823:     SymTable           *ctxt;          /* The context for the variable */
                    824:     Boolean    err;            /* TRUE if undefined variables are an error */
                    825:     size_t     *lengthPtr;     /* OUT: The length of the specification */
                    826:     Boolean    *freePtr;       /* OUT: TRUE if caller should free result */
                    827: {
                    828:     char       *tstr;          /* Pointer into str */
                    829:     Var                *v;             /* Variable in invocation */
                    830:     char       endc;           /* Ending character when variable in parens
1.1       deraadt   831:                                 * or braces */
1.44      espie     832:     char       *start;
                    833:     char       *val;           /* Variable value  */
                    834:     u_int32_t  k;
                    835:     int                idx;
1.5       millert   836:
1.1       deraadt   837:     *freePtr = FALSE;
1.44      espie     838:     start = str++;
1.5       millert   839:
1.44      espie     840:     val = NULL;
1.45    ! espie     841:     v = NULL;
        !           842:     idx = 0;
1.44      espie     843:
                    844:     if (*str != '(' && *str != '{') {
                    845:        tstr = str + 1;
                    846:        *lengthPtr = 2;
                    847:        endc = '\0';
1.1       deraadt   848:     } else {
1.44      espie     849:        endc = *str == '(' ? ')' : '}';
                    850:        str++;
1.5       millert   851:
1.44      espie     852:        /* Find eventual modifiers in the variable */
1.45    ! espie     853:        for (tstr = str; *tstr != ':'; tstr++) {
        !           854:            if (*tstr == '$') {
        !           855:                v = var_name_with_dollar(str, &tstr, ctxt, err, endc);
        !           856:                if (*tstr == '\0' || *tstr == endc)
        !           857:                    endc = '\0';
        !           858:                break;
        !           859:            } else if (*tstr == '\0' || *tstr == endc) {
1.44      espie     860:                endc = '\0';
                    861:                break;
1.1       deraadt   862:            }
1.45    ! espie     863:        }
1.44      espie     864:        *lengthPtr = tstr+1 - start;
                    865:     }
1.5       millert   866:
1.45    ! espie     867:     if (v == NULL) {
        !           868:        idx = quick_lookup(str, &tstr, &k);
        !           869:        v = varfind(str, tstr, ctxt, FIND_ENV | FIND_MINE, idx, k);
        !           870:     }
1.44      espie     871:     if (v == NULL) {
                    872:        /* Find out about D and F forms of local variables. */
                    873:        if (idx == -1 && tstr == str+2 && (str[1] == 'D' || str[1] == 'F')) {
                    874:            switch (*str) {
                    875:            case '@':
                    876:                idx = TARGET_INDEX;
                    877:                break;
                    878:            case '!':
                    879:                idx = ARCHIVE_INDEX;
                    880:                break;
                    881:            case '*':
                    882:                idx = PREFIX_INDEX;
                    883:                break;
                    884:            case '%':
                    885:                idx = MEMBER_INDEX;
                    886:                break;
                    887:            default:
                    888:                break;
1.1       deraadt   889:            }
1.44      espie     890:            /* This is a DF form, check if we can expand it now.  */
                    891:            if (idx != -1 && ctxt != NULL && ctxt != CTXT_GLOBAL) {
                    892:                v = varfind(str, str+1, ctxt, 0, idx, 0);
                    893:                /* No need for nested expansion or anything, as we're
                    894:                 * the only one who sets these things and we sure don't
                    895:                 * do nested invocations in them...  */
                    896:                if (v != NULL) {
                    897:                    val = VarValue(v);
                    898:                    if (str[1] == 'D')
                    899:                        val = Var_GetHead(val);
                    900:                    else
                    901:                        val = Var_GetTail(val);
1.1       deraadt   902:                    *freePtr = TRUE;
1.44      espie     903:                }
1.1       deraadt   904:            }
                    905:        }
1.44      espie     906:     } else {
                    907:        if (v->flags & VAR_IN_USE)
                    908:            Fatal("Variable %s is recursive.", v->name);
                    909:            /*NOTREACHED*/
                    910:        else
                    911:            v->flags |= VAR_IN_USE;
                    912:        /* Before doing any modification, we have to make sure the value
                    913:         * has been fully expanded. If it looks like recursion might be
                    914:         * necessary (there's a dollar sign somewhere in the variable's value)
                    915:         * we just call Var_Subst to do any other substitutions that are
                    916:         * necessary. Note that the value returned by Var_Subst will have
                    917:         * been dynamically-allocated, so it will need freeing when we
                    918:         * return.  */
                    919:        val = VarValue(v);
                    920:        if (strchr(val, '$') != NULL) {
                    921:            val = Var_Subst(val, ctxt, err);
                    922:            *freePtr = TRUE;
                    923:        }
                    924:
                    925:        v->flags &= ~VAR_IN_USE;
1.1       deraadt   926:     }
1.44      espie     927:     if (endc != '\0')
                    928:        val = VarModifiers_Apply(val, ctxt, err, freePtr, tstr+1, endc,
1.42      espie     929:            lengthPtr);
1.44      espie     930:     if (val == NULL) {
                    931:        /* Dynamic source that can't be expanded for now: copy the var
                    932:         * specification instead.  */
                    933:        if (idx != -1 && (ctxt == NULL || ctxt == CTXT_GLOBAL)) {
1.42      espie     934:            *freePtr = TRUE;
1.44      espie     935:            val = interval_dup(start, start+ *lengthPtr);
                    936:        } else
                    937:            val = err ? var_Error : varNoError;
1.42      espie     938:     }
1.44      espie     939:
                    940:     return val;
1.42      espie     941: }
                    942:
1.1       deraadt   943: /*-
                    944:  *-----------------------------------------------------------------------
                    945:  * Var_Subst  --
1.24      espie     946:  *     Substitute for all variables in a string in a context
1.1       deraadt   947:  *     If undefErr is TRUE, Parse_Error will be called when an undefined
                    948:  *     variable is encountered.
                    949:  *
                    950:  * Results:
                    951:  *     The resulting string.
                    952:  *
                    953:  * Side Effects:
                    954:  *     None. The old string must be freed by the caller
                    955:  *-----------------------------------------------------------------------
                    956:  */
                    957: char *
1.24      espie     958: Var_Subst(str, ctxt, undefErr)
1.1       deraadt   959:     char         *str;             /* the string in which to substitute */
1.35      espie     960:     SymTable      *ctxt;           /* the context wherein to find variables */
1.1       deraadt   961:     Boolean      undefErr;         /* TRUE if undefineds are an error */
                    962: {
1.24      espie     963:     BUFFER       buf;              /* Buffer for forming things */
1.1       deraadt   964:     static Boolean errorReported;   /* Set true if an error has already
                    965:                                     * been reported to prevent a plethora
                    966:                                     * of messages when recursing */
                    967:
1.23      espie     968:     Buf_Init(&buf, MAKE_BSIZE);
1.1       deraadt   969:     errorReported = FALSE;
                    970:
1.24      espie     971:     for (;;) {
                    972:        char            *val;           /* Value to substitute for a variable */
                    973:        size_t          length;         /* Length of the variable invocation */
                    974:        Boolean         doFree;         /* Set true if val should be freed */
                    975:        const char *cp;
                    976:
                    977:        /* copy uninteresting stuff */
                    978:        for (cp = str; *str != '\0' && *str != '$'; str++)
                    979:            ;
                    980:        Buf_AddInterval(&buf, cp, str);
                    981:        if (*str == '\0')
                    982:            break;
                    983:        if (str[1] == '$') {
                    984:            /* A dollar sign may be escaped with another dollar sign.  */
                    985:            Buf_AddChar(&buf, '$');
                    986:            str += 2;
                    987:            continue;
                    988:        }
                    989:        val = Var_Parse(str, ctxt, undefErr, &length, &doFree);
                    990:        /* When we come down here, val should either point to the
                    991:         * value of this variable, suitably modified, or be NULL.
                    992:         * Length should be the total length of the potential
                    993:         * variable invocation (from $ to end character...) */
                    994:        if (val == var_Error || val == varNoError) {
                    995:            /* If performing old-time variable substitution, skip over
                    996:             * the variable and continue with the substitution. Otherwise,
                    997:             * store the dollar sign and advance str so we continue with
                    998:             * the string...  */
                    999:            if (oldVars) {
                   1000:                str += length;
                   1001:            } else if (undefErr) {
                   1002:                /* If variable is undefined, complain and skip the
                   1003:                 * variable. The complaint will stop us from doing anything
                   1004:                 * when the file is parsed.  */
                   1005:                if (!errorReported) {
                   1006:                    Parse_Error(PARSE_FATAL,
                   1007:                                 "Undefined variable \"%.*s\"",length,str);
                   1008:                }
                   1009:                str += length;
                   1010:                errorReported = TRUE;
                   1011:            } else {
                   1012:                Buf_AddChar(&buf, *str);
                   1013:                str += 1;
                   1014:            }
                   1015:        } else {
                   1016:            /* We've now got a variable structure to store in. But first,
                   1017:             * advance the string pointer.  */
                   1018:            str += length;
                   1019:
                   1020:            /* Copy all the characters from the variable value straight
                   1021:             * into the new string.  */
                   1022:            Buf_AddString(&buf, val);
                   1023:            if (doFree)
                   1024:                free(val);
                   1025:        }
                   1026:     }
                   1027:     return  Buf_Retrieve(&buf);
                   1028: }
1.1       deraadt  1029:
1.24      espie    1030: /*-
                   1031:  *-----------------------------------------------------------------------
                   1032:  * Var_SubstVar  --
                   1033:  *     Substitute for one variable in the given string in the given context
                   1034:  *     If undefErr is TRUE, Parse_Error will be called when an undefined
                   1035:  *     variable is encountered.
                   1036:  *
                   1037:  * Side Effects:
                   1038:  *     Append the result to the buffer
                   1039:  *-----------------------------------------------------------------------
                   1040:  */
                   1041: void
                   1042: Var_SubstVar(buf, str, var, ctxt)
                   1043:     Buffer     buf;            /* Where to store the result */
                   1044:     char       *str;           /* The string in which to substitute */
                   1045:     const char *var;           /* Named variable */
1.37      espie    1046:     GSymT      *ctxt;          /* The context wherein to find variables */
1.24      espie    1047: {
                   1048:     char       *val;           /* Value substituted for a variable */
                   1049:     size_t     length;         /* Length of the variable invocation */
                   1050:     Boolean    doFree;         /* Set true if val should be freed */
                   1051:
                   1052:     for (;;) {
                   1053:        const char *cp;
                   1054:        /* copy uninteresting stuff */
                   1055:        for (cp = str; *str != '\0' && *str != '$'; str++)
                   1056:            ;
                   1057:        Buf_AddInterval(buf, cp, str);
                   1058:        if (*str == '\0')
                   1059:            break;
                   1060:        if (str[1] == '$') {
                   1061:            Buf_AddString(buf, "$$");
                   1062:            str += 2;
                   1063:            continue;
                   1064:        }
                   1065:        if (str[1] != '(' && str[1] != '{') {
                   1066:            if (str[1] != *var || var[1] != '\0') {
                   1067:                Buf_AddChars(buf, 2, str);
                   1068:                str += 2;
1.1       deraadt  1069:                continue;
1.24      espie    1070:            }
1.1       deraadt  1071:        } else {
1.24      espie    1072:            char *p;
                   1073:            char endc;
1.1       deraadt  1074:
1.24      espie    1075:            if (str[1] == '(')
                   1076:                endc = ')';
                   1077:            else if (str[1] == '{')
                   1078:                endc = '}';
                   1079:
                   1080:            /* Find the end of the variable specification.  */
                   1081:            p = str+2;
                   1082:            while (*p != '\0' && *p != ':' && *p != endc && *p != '$')
                   1083:                p++;
                   1084:            /* A variable inside the variable.  We don't know how to
                   1085:             * expand the external variable at this point, so we try
                   1086:             * again with the nested variable.  */
                   1087:            if (*p == '$') {
                   1088:                Buf_AddInterval(buf, str, p);
                   1089:                str = p;
                   1090:                continue;
1.1       deraadt  1091:            }
1.5       millert  1092:
1.24      espie    1093:            if (strncmp(var, str + 2, p - str - 2) != 0 ||
                   1094:                var[p - str - 2] != '\0') {
                   1095:                /* Not the variable we want to expand.  */
                   1096:                Buf_AddInterval(buf, str, p);
                   1097:                str = p;
                   1098:                continue;
                   1099:            }
1.1       deraadt  1100:        }
1.24      espie    1101:        /* okay, so we've found the variable we want to expand.  */
1.37      espie    1102:        val = Var_Parse(str, (SymTable *)ctxt, FALSE, &length, &doFree);
1.24      espie    1103:        /* We've now got a variable structure to store in. But first,
                   1104:         * advance the string pointer.  */
                   1105:        str += length;
                   1106:
                   1107:        /* Copy all the characters from the variable value straight
                   1108:         * into the new string.  */
                   1109:        Buf_AddString(buf, val);
                   1110:        if (doFree)
                   1111:            free(val);
1.1       deraadt  1112:     }
                   1113: }
                   1114:
                   1115: /*-
                   1116:  *-----------------------------------------------------------------------
                   1117:  * Var_Init --
                   1118:  *     Initialize the module
                   1119:  *
                   1120:  * Side Effects:
1.5       millert  1121:  *     The VAR_CMD and VAR_GLOBAL contexts are created
1.1       deraadt  1122:  *-----------------------------------------------------------------------
                   1123:  */
                   1124: void
1.33      espie    1125: Var_Init()
1.1       deraadt  1126: {
1.37      espie    1127:     static GSymT global_vars, cmd_vars, env_vars;
1.35      espie    1128:
                   1129:     VAR_GLOBAL = &global_vars;
                   1130:     VAR_CMD = &cmd_vars;
                   1131:     VAR_ENV = &env_vars;
1.38      espie    1132:     hash_init(VAR_GLOBAL, 10, &var_info);
                   1133:     hash_init(VAR_CMD, 5, &var_info);
                   1134:     hash_init(VAR_ENV, 5, &var_info);
1.37      espie    1135:     CTXT_GLOBAL = (SymTable *)VAR_GLOBAL;
                   1136:     CTXT_CMD = (SymTable *)VAR_CMD;
                   1137:     CTXT_ENV = (SymTable *)VAR_ENV;
1.1       deraadt  1138: }
                   1139:
                   1140:
                   1141: void
1.33      espie    1142: Var_End()
1.1       deraadt  1143: {
1.37      espie    1144: #ifdef CLEANUP
1.38      espie    1145:     Var *v;
                   1146:     unsigned int i;
                   1147:
                   1148:     for (v = hash_first(VAR_GLOBAL, &i); v != NULL;
                   1149:        v = hash_next(VAR_GLOBAL, &i))
                   1150:            VarDelete(v);
                   1151:     for (v = hash_first(VAR_CMD, &i); v != NULL;
                   1152:        v = hash_next(VAR_CMD, &i))
                   1153:            VarDelete(v);
                   1154:     for (v = hash_first(VAR_ENV, &i); v != NULL;
                   1155:        v = hash_next(VAR_ENV, &i))
                   1156:            VarDelete(v);
1.37      espie    1157: #endif
1.1       deraadt  1158: }
1.5       millert  1159:
1.1       deraadt  1160:
                   1161: /****************** PRINT DEBUGGING INFO *****************/
1.31      espie    1162: static void
                   1163: VarPrintVar(vp)
1.32      espie    1164:     void *vp;
1.1       deraadt  1165: {
1.31      espie    1166:     Var    *v = (Var *)vp;
                   1167:
1.23      espie    1168:     printf("%-16s = %s\n", v->name, VarValue(v));
1.1       deraadt  1169: }
                   1170:
                   1171: /*-
                   1172:  *-----------------------------------------------------------------------
                   1173:  * Var_Dump --
                   1174:  *     print all variables in a context
                   1175:  *-----------------------------------------------------------------------
                   1176:  */
                   1177: void
1.35      espie    1178: Var_Dump(ctxt)
1.37      espie    1179:    GSymT       *ctxt;
1.1       deraadt  1180: {
1.38      espie    1181:        Var *v;
                   1182:        unsigned int i;
                   1183:
                   1184:        for (v = hash_first(ctxt, &i); v != NULL;
                   1185:            v = hash_next(ctxt, &i))
                   1186:                VarPrintVar(v);
1.1       deraadt  1187: }
1.37      espie    1188: