📄 tclenv.c
字号:
/* * tclEnv.c -- * * Tcl support for environment variables, including a setenv * procedure. This file contains the generic portion of the * environment module. It is primarily responsible for keeping * the "env" arrays in sync with the system environment variables. * * Copyright (c) 1991-1994 The Regents of the University of California. * Copyright (c) 1994-1996 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * SCCS: @(#) tclEnv.c 1.54 97/10/27 17:47:52 */#include "tclInt.h"#include "tclPort.h"/* * The structure below is used to keep track of all of the interpereters * for which we're managing the "env" array. It's needed so that they * can all be updated whenever an environment variable is changed * anywhere. */typedef struct EnvInterp { Tcl_Interp *interp; /* Interpreter for which we're managing * the env array. */ struct EnvInterp *nextPtr; /* Next in list of all such interpreters, * or zero. */} EnvInterp;static EnvInterp *firstInterpPtr = NULL; /* First in list of all managed interpreters, * or NULL if none. */static int cacheSize = 0; /* Number of env strings in environCache. */static char **environCache = NULL; /* Array containing all of the environment * strings that Tcl has allocated. */#ifndef USE_PUTENVstatic int environSize = 0; /* Non-zero means that the environ array was * malloced and has this many total entries * allocated to it (not all may be in use at * once). Zero means that the environment * array is in its original static state. */#endif/* * Declarations for local procedures defined in this file: */static char * EnvTraceProc _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, char *name1, char *name2, int flags));static int FindVariable _ANSI_ARGS_((CONST char *name, int *lengthPtr));static void ReplaceString _ANSI_ARGS_((CONST char *oldStr, char *newStr));void TclSetEnv _ANSI_ARGS_((CONST char *name, CONST char *value));void TclUnsetEnv _ANSI_ARGS_((CONST char *name));/* *---------------------------------------------------------------------- * * TclSetupEnv -- * * This procedure is invoked for an interpreter to make environment * variables accessible from that interpreter via the "env" * associative array. * * Results: * None. * * Side effects: * The interpreter is added to a list of interpreters managed * by us, so that its view of envariables can be kept consistent * with the view in other interpreters. If this is the first * call to Tcl_SetupEnv, then additional initialization happens, * such as copying the environment to dynamically-allocated space * for ease of management. * *---------------------------------------------------------------------- */voidTclSetupEnv(interp) Tcl_Interp *interp; /* Interpreter whose "env" array is to be * managed. */{ EnvInterp *eiPtr; char *p, *p2; Tcl_DString ds; int i, sz;#ifdef MAC_TCL if (environ == NULL) { environSize = TclMacCreateEnv(); }#endif /* * Next, initialize the DString we are going to use for copying * the names of the environment variables. */ Tcl_DStringInit(&ds); /* * Next, add the interpreter to the list of those that we manage. */ eiPtr = (EnvInterp *) ckalloc(sizeof(EnvInterp)); eiPtr->interp = interp; eiPtr->nextPtr = firstInterpPtr; firstInterpPtr = eiPtr; /* * Store the environment variable values into the interpreter's * "env" array, and arrange for us to be notified on future * writes and unsets to that array. */ (void) Tcl_UnsetVar2(interp, "env", (char *) NULL, TCL_GLOBAL_ONLY); for (i = 0; ; i++) { p = environ[i]; if (p == NULL) { break; } for (p2 = p; *p2 != '='; p2++) { if (*p2 == 0) { /* * This condition doesn't seem like it should ever happen, * but it does seem to happen occasionally under some * versions of Solaris; ignore the entry. */ goto nextEntry; } } sz = p2 - p; Tcl_DStringSetLength(&ds, 0); Tcl_DStringAppend(&ds, p, sz); (void) Tcl_SetVar2(interp, "env", Tcl_DStringValue(&ds), p2+1, TCL_GLOBAL_ONLY); nextEntry: continue; } Tcl_TraceVar2(interp, "env", (char *) NULL, TCL_GLOBAL_ONLY | TCL_TRACE_WRITES | TCL_TRACE_UNSETS, EnvTraceProc, (ClientData) NULL); /* * Finally clean up the DString. */ Tcl_DStringFree(&ds);}/* *---------------------------------------------------------------------- * * TclSetEnv -- * * Set an environment variable, replacing an existing value * or creating a new variable if there doesn't exist a variable * by the given name. This procedure is intended to be a * stand-in for the UNIX "setenv" procedure so that applications * using that procedure will interface properly to Tcl. To make * it a stand-in, the Makefile must define "TclSetEnv" to "setenv". * * Results: * None. * * Side effects: * The environ array gets updated, as do all of the interpreters * that we manage. * *---------------------------------------------------------------------- */voidTclSetEnv(name, value) CONST char *name; /* Name of variable whose value is to be * set. */ CONST char *value; /* New value for variable. */{ int index, length, nameLength; char *p, *oldValue; EnvInterp *eiPtr;#ifdef MAC_TCL if (environ == NULL) { environSize = TclMacCreateEnv(); }#endif /* * Figure out where the entry is going to go. If the name doesn't * already exist, enlarge the array if necessary to make room. If * the name exists, free its old entry. */ index = FindVariable(name, &length); if (index == -1) {#ifndef USE_PUTENV if ((length+2) > environSize) { char **newEnviron; newEnviron = (char **) ckalloc((unsigned) ((length+5) * sizeof(char *))); memcpy((VOID *) newEnviron, (VOID *) environ, length*sizeof(char *)); if (environSize != 0) { ckfree((char *) environ); } environ = newEnviron; environSize = length+5; } index = length; environ[index+1] = NULL;#endif oldValue = NULL; nameLength = strlen(name); } else { /* * Compare the new value to the existing value. If they're * the same then quit immediately (e.g. don't rewrite the * value or propagate it to other interpreters). Otherwise, * when there are N interpreters there will be N! propagations * of the same value among the interpreters. */ if (strcmp(value, environ[index]+length+1) == 0) { return; } oldValue = environ[index]; nameLength = length; } /* * Create a new entry. */ p = (char *) ckalloc((unsigned) (nameLength + strlen(value) + 2)); strcpy(p, name); p[nameLength] = '='; strcpy(p+nameLength+1, value); /* * Update the system environment. */#ifdef USE_PUTENV putenv(p);#else environ[index] = p;#endif /* * Replace the old value with the new value in the cache. */ ReplaceString(oldValue, p); /* * Update all of the interpreters. */ for (eiPtr= firstInterpPtr; eiPtr != NULL; eiPtr = eiPtr->nextPtr) { (void) Tcl_SetVar2(eiPtr->interp, "env", (char *) name, (char *) value, TCL_GLOBAL_ONLY); }}/* *---------------------------------------------------------------------- * * Tcl_PutEnv -- * * Set an environment variable. Similar to setenv except that * the information is passed in a single string of the form * NAME=value, rather than as separate name strings. This procedure * is intended to be a stand-in for the UNIX "putenv" procedure * so that applications using that procedure will interface * properly to Tcl. To make it a stand-in, the Makefile will * define "Tcl_PutEnv" to "putenv". * * Results: * None. * * Side effects: * The environ array gets updated, as do all of the interpreters * that we manage. * *---------------------------------------------------------------------- */intTcl_PutEnv(string) CONST char *string; /* Info about environment variable in the * form NAME=value. */{ int nameLength; char *name, *value; if (string == NULL) { return 0; } /* * Separate the string into name and value parts, then call * TclSetEnv to do all of the real work. */ value = strchr(string, '='); if (value == NULL) { return 0; } nameLength = value - string; if (nameLength == 0) { return 0; } name = (char *) ckalloc((unsigned) nameLength+1); memcpy((VOID *) name, (VOID *) string, (size_t) nameLength); name[nameLength] = 0; TclSetEnv(name, value+1); ckfree(name); return 0;}/* *---------------------------------------------------------------------- * * TclUnsetEnv -- * * Remove an environment variable, updating the "env" arrays * in all interpreters managed by us. This function is intended * to replace the UNIX "unsetenv" function (but to do this the * Makefile must be modified to redefine "TclUnsetEnv" to * "unsetenv". * * Results: * None. * * Side effects:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -