Annotation of micropolis/src/tcl/tclenv.c, revision 1.1.1.1

1.1       root        1: /* 
                      2:  * tclEnv.c --
                      3:  *
                      4:  *     Tcl support for environment variables, including a setenv
                      5:  *     procedure.
                      6:  *
                      7:  * Copyright 1991 Regents of the University of California
                      8:  * Permission to use, copy, modify, and distribute this
                      9:  * software and its documentation for any purpose and without
                     10:  * fee is hereby granted, provided that this copyright
                     11:  * notice appears in all copies.  The University of California
                     12:  * makes no representations about the suitability of this
                     13:  * software for any purpose.  It is provided "as is" without
                     14:  * express or implied warranty.
                     15:  */
                     16: 
                     17: #ifndef lint
                     18: static char rcsid[] = "$Header: /user6/ouster/tcl/RCS/tclEnv.c,v 1.7 91/09/23 11:22:21 ouster Exp $ SPRITE (Berkeley)";
                     19: #endif /* not lint */
                     20: 
                     21: #include "tclint.h"
                     22: #include "tclunix.h"
                     23: 
                     24: /*
                     25:  * The structure below is used to keep track of all of the interpereters
                     26:  * for which we're managing the "env" array.  It's needed so that they
                     27:  * can all be updated whenever an environment variable is changed
                     28:  * anywhere.
                     29:  */
                     30: 
                     31: typedef struct EnvInterp {
                     32:     Tcl_Interp *interp;                /* Interpreter for which we're managing
                     33:                                 * the env array. */
                     34:     struct EnvInterp *nextPtr; /* Next in list of all such interpreters,
                     35:                                 * or zero. */
                     36: } EnvInterp;
                     37: 
                     38: static EnvInterp *firstInterpPtr;
                     39:                                /* First in list of all managed interpreters,
                     40:                                 * or NULL if none. */
                     41: 
                     42: static int environSize = 0;    /* Non-zero means that the all of the
                     43:                                 * environ-related information is malloc-ed
                     44:                                 * and the environ array itself has this
                     45:                                 * many total entries allocated to it (not
                     46:                                 * all may be in use at once).  Zero means
                     47:                                 * that the environment array is in its
                     48:                                 * original static state. */
                     49: 
                     50: /*
                     51:  * Declarations for local procedures defined in this file:
                     52:  */
                     53: 
                     54: static void            EnvInit _ANSI_ARGS_((void));
                     55: static char *          EnvTraceProc _ANSI_ARGS_((ClientData clientData,
                     56:                            Tcl_Interp *interp, char *name1, char *name2,
                     57:                            int flags));
                     58: static int             FindVariable _ANSI_ARGS_((char *name, int *lengthPtr));
                     59: 
                     60: #ifdef IS_LINUX
                     61: int                    setenv _ANSI_ARGS_((const char *name, const char *value, int replace));
                     62: int                    unsetenv _ANSI_ARGS_((const char *name));
                     63: #else
                     64: void                   setenv _ANSI_ARGS_((char *name, char *value));
                     65: void                   unsetenv _ANSI_ARGS_((char *name));
                     66: #endif
                     67: 
                     68: 
                     69: /*
                     70:  *----------------------------------------------------------------------
                     71:  *
                     72:  * TclSetupEnv --
                     73:  *
                     74:  *     This procedure is invoked for an interpreter to make environment
                     75:  *     variables accessible from that interpreter via the "env"
                     76:  *     associative array.
                     77:  *
                     78:  * Results:
                     79:  *     None.
                     80:  *
                     81:  * Side effects:
                     82:  *     The interpreter is added to a list of interpreters managed
                     83:  *     by us, so that its view of envariables can be kept consistent
                     84:  *     with the view in other interpreters.  If this is the first
                     85:  *     call to Tcl_SetupEnv, then additional initialization happens,
                     86:  *     such as copying the environment to dynamically-allocated space
                     87:  *     for ease of management.
                     88:  *
                     89:  *----------------------------------------------------------------------
                     90:  */
                     91: 
                     92: void
                     93: TclSetupEnv(interp)
                     94:     Tcl_Interp *interp;                /* Interpreter whose "env" array is to be
                     95:                                 * managed. */
                     96: {
                     97:     EnvInterp *eiPtr;
                     98:     int i;
                     99: 
                    100:     /*
                    101:      * First, initialize our environment-related information, if
                    102:      * necessary.
                    103:      */
                    104: 
                    105:     if (environSize == 0) {
                    106:        EnvInit();
                    107:     }
                    108: 
                    109:     /*
                    110:      * Next, add the interpreter to the list of those that we manage.
                    111:      */
                    112: 
                    113:     eiPtr = (EnvInterp *) ckalloc(sizeof(EnvInterp));
                    114:     eiPtr->interp = interp;
                    115:     eiPtr->nextPtr = firstInterpPtr;
                    116:     firstInterpPtr = eiPtr;
                    117: 
                    118:     /*
                    119:      * Store the environment variable values into the interpreter's
                    120:      * "env" array, and arrange for us to be notified on future
                    121:      * writes and unsets to that array.
                    122:      */
                    123: 
                    124:     (void) Tcl_UnsetVar2(interp, "env", (char *) NULL, TCL_GLOBAL_ONLY);
                    125:     for (i = 0; ; i++) {
                    126:        char *p, *p2;
                    127: 
                    128:        p = environ[i];
                    129:        if (p == NULL) {
                    130:            break;
                    131:        }
                    132:        for (p2 = p; *p2 != '='; p2++) {
                    133:            /* Empty loop body. */
                    134:        }
                    135:        *p2 = 0;
                    136:        (void) Tcl_SetVar2(interp, "env", p, p2+1, TCL_GLOBAL_ONLY);
                    137:        *p2 = '=';
                    138:     }
                    139:     Tcl_TraceVar2(interp, "env", (char *) NULL,
                    140:            TCL_GLOBAL_ONLY | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
                    141:            EnvTraceProc, (ClientData) NULL);
                    142: }
                    143: 
                    144: /*
                    145:  *----------------------------------------------------------------------
                    146:  *
                    147:  * FindVariable --
                    148:  *
                    149:  *     Locate the entry in environ for a given name.
                    150:  *
                    151:  * Results:
                    152:  *     The return value is the index in environ of an entry with the
                    153:  *     name "name", or -1 if there is no such entry.   The integer at
                    154:  *     *lengthPtr is filled in with the length of name (if a matching
                    155:  *     entry is found) or the length of the environ array (if no matching
                    156:  *     entry is found).
                    157:  *
                    158:  * Side effects:
                    159:  *     None.
                    160:  *
                    161:  *----------------------------------------------------------------------
                    162:  */
                    163: 
                    164: static int
                    165: FindVariable(name, lengthPtr)
                    166:     char *name;                        /* Name of desired environment variable. */
                    167:     int *lengthPtr;            /* Used to return length of name (for
                    168:                                 * successful searches) or number of non-NULL
                    169:                                 * entries in environ (for unsuccessful
                    170:                                 * searches). */
                    171: {
                    172:     int i;
                    173:     register char *p1, *p2;
                    174: 
                    175:     for (i = 0, p1 = environ[i]; p1 != NULL; i++, p1 = environ[i]) {
                    176:        for (p2 = name; *p2 == *p1; p1++, p2++) {
                    177:            /* NULL loop body. */
                    178:        }
                    179:        if ((*p1 == '=') && (*p2 == '\0')) {
                    180:            *lengthPtr = p2-name;
                    181:            return i;
                    182:        }
                    183:     }
                    184:     *lengthPtr = i;
                    185:     return -1;
                    186: }
                    187: 
                    188: /*
                    189:  *----------------------------------------------------------------------
                    190:  *
                    191:  * setenv --
                    192:  *
                    193:  *     Set an environment variable, replacing an existing value
                    194:  *     or creating a new variable if there doesn't exist a variable
                    195:  *     by the given name.
                    196:  *
                    197:  * Results:
                    198:  *     None.
                    199:  *
                    200:  * Side effects:
                    201:  *     The environ array gets updated, as do all of the interpreters
                    202:  *     that we manage.
                    203:  *
                    204:  *----------------------------------------------------------------------
                    205:  */
                    206: 
                    207: #ifdef IS_LINUX
                    208: int
                    209: setenv(name, value, replace)
                    210:     const char *name;          /* Name of variable whose value is to be
                    211:                                 * set. */
                    212:     const char *value;         /* New value for variable. */
                    213:     int replace;
                    214: #else
                    215: void
                    216: setenv(name, value)
                    217:     char *name;                        /* Name of variable whose value is to be
                    218:                                 * set. */
                    219:     char *value;               /* New value for variable. */
                    220: #endif
                    221: {
                    222:     int index, length, nameLength;
                    223:     char *p;
                    224:     EnvInterp *eiPtr;
                    225: 
                    226:     if (environSize == 0) {
                    227:        EnvInit();
                    228:     }
                    229: 
                    230:     /*
                    231:      * Figure out where the entry is going to go.  If the name doesn't
                    232:      * already exist, enlarge the array if necessary to make room.  If
                    233:      * the name exists, free its old entry.
                    234:      */
                    235: 
                    236:     index = FindVariable((char *)name, &length);
                    237:     if (index == -1) {
                    238:        if ((length+2) > environSize) {
                    239:            char **newEnviron;
                    240: 
                    241:            newEnviron = (char **) ckalloc((unsigned)
                    242:                    ((length+5) * sizeof(char *)));
                    243:            memcpy((VOID *) newEnviron, (VOID *) environ,
                    244:                    length*sizeof(char *));
                    245:            ckfree((char *) environ);
                    246:            environ = newEnviron;
                    247:            environSize = length+5;
                    248:        }
                    249:        index = length;
                    250:        environ[index+1] = NULL;
                    251:        nameLength = strlen(name);
                    252:     } else {
                    253:        ckfree(environ[index]);
                    254:        nameLength = length;
                    255:     }
                    256: 
                    257:     /*
                    258:      * Create a new entry and enter it into the table.
                    259:      */
                    260: 
                    261:     p = (char *) ckalloc((unsigned) (nameLength + strlen(value) + 2));
                    262:     environ[index] = p;
                    263:     strcpy(p, name);
                    264:     p += nameLength;
                    265:     *p = '=';
                    266:     strcpy(p+1, value);
                    267: 
                    268:     /*
                    269:      * Update all of the interpreters.
                    270:      */
                    271: 
                    272:     for (eiPtr= firstInterpPtr; eiPtr != NULL; eiPtr = eiPtr->nextPtr) {
                    273:        (void) Tcl_SetVar2(eiPtr->interp, "env", (char *)name, p+1, TCL_GLOBAL_ONLY);
                    274:     }
                    275: 
                    276: #ifdef IS_LINUX
                    277:     return 0;
                    278: #endif
                    279: 
                    280: }
                    281: 
                    282: /*
                    283:  *----------------------------------------------------------------------
                    284:  *
                    285:  * unsetenv --
                    286:  *
                    287:  *     Remove an environment variable, updating the "env" arrays
                    288:  *     in all interpreters managed by us.
                    289:  *
                    290:  * Results:
                    291:  *     None.
                    292:  *
                    293:  * Side effects:
                    294:  *     Interpreters are updated, as is environ.
                    295:  *
                    296:  *----------------------------------------------------------------------
                    297:  */
                    298: 
                    299: int
                    300: unsetenv(name)
                    301: #ifdef IS_LINUX
                    302:     const char *name;                  /* Name of variable to remove. */
                    303: #else
                    304:     char *name;                        /* Name of variable to remove. */
                    305: #endif
                    306: {
                    307:     int index, dummy;
                    308:     char **envPtr;
                    309:     EnvInterp *eiPtr;
                    310: 
                    311:     if (environSize == 0) {
                    312:        EnvInit();
                    313:     }
                    314: 
                    315:     /*
                    316:      * Update the environ array.
                    317:      */
                    318: 
                    319:     index = FindVariable((char *)name, &dummy);
                    320:     if (index == -1) {
                    321:        return;
                    322:     }
                    323:     ckfree(environ[index]);
                    324:     for (envPtr = environ+index+1; ; envPtr++) {
                    325:        envPtr[-1] = *envPtr;
                    326:        if (*envPtr == NULL) {
                    327:            break;
                    328:        }
                    329:     }
                    330: 
                    331:     /*
                    332:      * Update all of the interpreters.
                    333:      */
                    334: 
                    335:     for (eiPtr = firstInterpPtr; eiPtr != NULL; eiPtr = eiPtr->nextPtr) {
                    336:        (void) Tcl_UnsetVar2(eiPtr->interp, "env", (char *)name, TCL_GLOBAL_ONLY);
                    337:     }
                    338: }
                    339: 
                    340: /*
                    341:  *----------------------------------------------------------------------
                    342:  *
                    343:  * EnvTraceProc --
                    344:  *
                    345:  *     This procedure is invoked whenever an environment variable
                    346:  *     is modified or deleted.  It propagates the change to the
                    347:  *     "environ" array and to any other interpreters for whom
                    348:  *     we're managing an "env" array.
                    349:  *
                    350:  * Results:
                    351:  *     Always returns NULL to indicate success.
                    352:  *
                    353:  * Side effects:
                    354:  *     Environment variable changes get propagated.  If the whole
                    355:  *     "env" array is deleted, then we stop managing things for
                    356:  *     this interpreter (usually this happens because the whole
                    357:  *     interpreter is being deleted).
                    358:  *
                    359:  *----------------------------------------------------------------------
                    360:  */
                    361: 
                    362:        /* ARGSUSED */
                    363: static char *
                    364: EnvTraceProc(clientData, interp, name1, name2, flags)
                    365:     ClientData clientData;     /* Not used. */
                    366:     Tcl_Interp *interp;                /* Interpreter whose "env" variable is
                    367:                                 * being modified. */
                    368:     char *name1;               /* Better be "env". */
                    369:     char *name2;               /* Name of variable being modified, or
                    370:                                 * NULL if whole array is being deleted. */
                    371:     int flags;                 /* Indicates what's happening. */
                    372: {
                    373:     /*
                    374:      * First see if the whole "env" variable is being deleted.  If
                    375:      * so, just forget about this interpreter.
                    376:      */
                    377: 
                    378:     if (name2 == NULL) {
                    379:        register EnvInterp *eiPtr, *prevPtr;
                    380: 
                    381:        if ((flags & (TCL_TRACE_UNSETS|TCL_TRACE_DESTROYED))
                    382:                != (TCL_TRACE_UNSETS|TCL_TRACE_DESTROYED)) {
                    383:            panic("EnvTraceProc called with confusing arguments");
                    384:        }
                    385:        eiPtr = firstInterpPtr;
                    386:        if (eiPtr->interp == interp) {
                    387:            firstInterpPtr = eiPtr->nextPtr;
                    388:        } else {
                    389:            for (prevPtr = eiPtr, eiPtr = eiPtr->nextPtr; ;
                    390:                    prevPtr = eiPtr, eiPtr = eiPtr->nextPtr) {
                    391:                if (eiPtr == NULL) {
                    392:                    panic("EnvTraceProc couldn't find interpreter");
                    393:                }
                    394:                if (eiPtr->interp == interp) {
                    395:                    prevPtr->nextPtr = eiPtr->nextPtr;
                    396:                    break;
                    397:                }
                    398:            }
                    399:        }
                    400:        ckfree((char *) eiPtr);
                    401:        return NULL;
                    402:     }
                    403: 
                    404:     /*
                    405:      * If a value is being set, call setenv to do all of the work.
                    406:      */
                    407: 
                    408:     if (flags & TCL_TRACE_WRITES) {
                    409:        setenv(name2, Tcl_GetVar2(interp, "env", name2, TCL_GLOBAL_ONLY), 0);
                    410:     }
                    411: 
                    412:     if (flags & TCL_TRACE_UNSETS) {
                    413:        unsetenv(name2);
                    414:     }
                    415:     return NULL;
                    416: }
                    417: 
                    418: /*
                    419:  *----------------------------------------------------------------------
                    420:  *
                    421:  * EnvInit --
                    422:  *
                    423:  *     This procedure is called to initialize our management
                    424:  *     of the environ array.
                    425:  *
                    426:  * Results:
                    427:  *     None.
                    428:  *
                    429:  * Side effects:
                    430:  *     Environ gets copied to malloc-ed storage, so that in
                    431:  *     the future we don't have to worry about which entries
                    432:  *     are malloc-ed and which are static.
                    433:  *
                    434:  *----------------------------------------------------------------------
                    435:  */
                    436: 
                    437: static void
                    438: EnvInit()
                    439: {
                    440:     char **newEnviron;
                    441:     int i, length;
                    442: 
                    443:     if (environSize != 0) {
                    444:        return;
                    445:     }
                    446:     for (length = 0; environ[length] != NULL; length++) {
                    447:        /* Empty loop body. */
                    448:     }
                    449:     environSize = length+5;
                    450:     newEnviron = (char **) ckalloc((unsigned)
                    451:                (environSize * sizeof(char *)));
                    452:     for (i = 0; i < length; i++) {
                    453:        newEnviron[i] = (char *) ckalloc((unsigned) (strlen(environ[i]) + 1));
                    454:        strcpy(newEnviron[i], environ[i]);
                    455:     }
                    456:     newEnviron[length] = NULL;
                    457:     environ = newEnviron;
                    458: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.