Annotation of micropolis/src/tcl/tclenv.c, revision 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.