tclenv.c

来自「tcl是工具命令语言」· C语言 代码 · 共 781 行 · 第 1/2 页

C
781
字号
     * First make sure that the environment variable exists to avoid     * doing needless work and to avoid recursion on the unset.     */        if (index == -1) {	Tcl_MutexUnlock(&envMutex);	return;    }    /*     * Remember the old value so we can free it if Tcl created the string.     */    oldValue = environ[index];    /*     * Update the system environment.  This must be done before we      * update the interpreters or we will recurse.     */#ifdef USE_PUTENV    string = ckalloc((unsigned int) length+2);    memcpy((VOID *) string, (VOID *) name, (size_t) length);    string[length] = '=';    string[length+1] = '\0';        Tcl_UtfToExternalDString(NULL, string, -1, &envString);    string = ckrealloc(string, (unsigned) (Tcl_DStringLength(&envString)+1));    strcpy(string, Tcl_DStringValue(&envString));    Tcl_DStringFree(&envString);    putenv(string);    /*     * Watch out for versions of putenv that copy the string (e.g. VC++).     * In this case we need to free the string immediately.  Otherwise     * update the string in the cache.     */    if (environ[index] == string) {	ReplaceString(oldValue, string);    }#else    for (envPtr = environ+index+1; ; envPtr++) {	envPtr[-1] = *envPtr;	if (*envPtr == NULL) {	    break;	}    }    ReplaceString(oldValue, NULL);#endif    Tcl_MutexUnlock(&envMutex);}/* *--------------------------------------------------------------------------- * * TclGetEnv -- * *	Retrieve the value of an environment variable. * * Results: *	The result is a pointer to a string specifying the value of the *	environment variable, or NULL if that environment variable does *	not exist.  Storage for the result string is allocated in valuePtr; *	the caller must call Tcl_DStringFree() when the result is no *	longer needed. * * Side effects: *	None. * *---------------------------------------------------------------------- */CONST char *TclGetEnv(name, valuePtr)    CONST char *name;		/* Name of environment variable to find				 * (UTF-8). */    Tcl_DString *valuePtr;	/* Uninitialized or free DString in which				 * the value of the environment variable is				 * stored. */{    int length, index;    CONST char *result;    Tcl_MutexLock(&envMutex);    index = TclpFindVariable(name, &length);    result = NULL;    if (index != -1) {	Tcl_DString envStr;		result = Tcl_ExternalToUtfDString(NULL, environ[index], -1, &envStr);	result += length;	if (*result == '=') {	    result++;	    Tcl_DStringInit(valuePtr);	    Tcl_DStringAppend(valuePtr, result, -1);	    result = Tcl_DStringValue(valuePtr);	} else {	    result = NULL;	}	Tcl_DStringFree(&envStr);    }    Tcl_MutexUnlock(&envMutex);    return result;}/* *---------------------------------------------------------------------- * * EnvTraceProc -- * *	This procedure is invoked whenever an environment variable *	is read, modified or deleted.  It propagates the change to the global *	"environ" array. * * Results: *	Always returns NULL to indicate success. * * Side effects: *	Environment variable changes get propagated.  If the whole *	"env" array is deleted, then we stop managing things for *	this interpreter (usually this happens because the whole *	interpreter is being deleted). * *---------------------------------------------------------------------- */	/* ARGSUSED */static char *EnvTraceProc(clientData, interp, name1, name2, flags)    ClientData clientData;	/* Not used. */    Tcl_Interp *interp;		/* Interpreter whose "env" variable is				 * being modified. */    CONST char *name1;		/* Better be "env". */    CONST char *name2;		/* Name of variable being modified, or NULL				 * if whole array is being deleted (UTF-8). */    int flags;			/* Indicates what's happening. */{    /*     * For array traces, let TclSetupEnv do all the work.     */    if (flags & TCL_TRACE_ARRAY) {	TclSetupEnv(interp);	return NULL;    }    /*     * If name2 is NULL, then return and do nothing.     */         if (name2 == NULL) {	return NULL;    }    /*     * If a value is being set, call TclSetEnv to do all of the work.     */    if (flags & TCL_TRACE_WRITES) {	CONST char *value;		value = Tcl_GetVar2(interp, "env", name2, TCL_GLOBAL_ONLY);	TclSetEnv(name2, value);    }    /*     * If a value is being read, call TclGetEnv to do all of the work.     */    if (flags & TCL_TRACE_READS) {	Tcl_DString valueString;	CONST char *value;	value = TclGetEnv(name2, &valueString);	if (value == NULL) {	    return "no such variable";	}	Tcl_SetVar2(interp, name1, name2, value, 0);	Tcl_DStringFree(&valueString);    }    /*     * For unset traces, let TclUnsetEnv do all the work.     */    if (flags & TCL_TRACE_UNSETS) {	TclUnsetEnv(name2);    }    return NULL;}/* *---------------------------------------------------------------------- * * ReplaceString -- * *	Replace one string with another in the environment variable *	cache.  The cache keeps track of all of the environment *	variables that Tcl has modified so they can be freed later. * * Results: *	None. * * Side effects: *	May free the old string. * *---------------------------------------------------------------------- */static voidReplaceString(oldStr, newStr)    CONST char *oldStr;		/* Old environment string. */    char *newStr;		/* New environment string. */{    int i;    char **newCache;    /*     * Check to see if the old value was allocated by Tcl.  If so,     * it needs to be deallocated to avoid memory leaks.  Note that this     * algorithm is O(n), not O(1).  This will result in n-squared behavior     * if lots of environment changes are being made.     */    for (i = 0; i < cacheSize; i++) {	if ((environCache[i] == oldStr) || (environCache[i] == NULL)) {	    break;	}    }    if (i < cacheSize) {	/*	 * Replace or delete the old value.	 */	if (environCache[i]) {	    ckfree(environCache[i]);	}	    	if (newStr) {	    environCache[i] = newStr;	} else {	    for (; i < cacheSize-1; i++) {		environCache[i] = environCache[i+1];	    }	    environCache[cacheSize-1] = NULL;	}    } else {	        int allocatedSize = (cacheSize + 5) * sizeof(char *);	/*	 * We need to grow the cache in order to hold the new string.	 */	newCache = (char **) ckalloc((unsigned) allocatedSize);        (VOID *) memset(newCache, (int) 0, (size_t) allocatedSize);        	if (environCache) {	    memcpy((VOID *) newCache, (VOID *) environCache,		    (size_t) (cacheSize * sizeof(char*)));	    ckfree((char *) environCache);	}	environCache = newCache;	environCache[cacheSize] = newStr;	environCache[cacheSize+1] = NULL;	cacheSize += 5;    }}/* *---------------------------------------------------------------------- * * TclFinalizeEnvironment -- * *	This function releases any storage allocated by this module *	that isn't still in use by the global environment.  Any *	strings that are still in the environment will be leaked. * * Results: *	None. * * Side effects: *	May deallocate storage. * *---------------------------------------------------------------------- */voidTclFinalizeEnvironment(){    /*     * For now we just deallocate the cache array and none of the environment     * strings.  This may leak more memory that strictly necessary, since some     * of the strings may no longer be in the environment.  However,     * determining which ones are ok to delete is n-squared, and is pretty     * unlikely, so we don't bother.     */    if (environCache) {	ckfree((char *) environCache);	environCache = NULL;	cacheSize    = 0;#ifndef USE_PUTENV	environSize  = 0;#endif    }}#if defined(__CYGWIN__) && defined(__WIN32__)#include <windows.h>/* * When using cygwin, when an environment variable changes, we need to synch * with both the cygwin environment (in case the application C code calls * fork) and the Windows environment (in case the application TCL code calls * exec, which calls the Windows CreateProcess function). */static voidTclCygwinPutenv(str)    const char *str;{    char *name, *value;    /* Get the name and value, so that we can change the environment       variable for Windows.  */    name = (char *) alloca (strlen (str) + 1);    strcpy (name, str);    for (value = name; *value != '=' && *value != '\0'; ++value)	;    if (*value == '\0') {	    /* Can't happen.  */	    return;	}    *value = '\0';    ++value;    if (*value == '\0') {	value = NULL;    }    /* Set the cygwin environment variable.  */#undef putenv    if (value == NULL) {	unsetenv (name);    } else {	putenv(str);    }    /*     * Before changing the environment variable in Windows, if this is PATH,     * we need to convert the value back to a Windows style path.     *     * FIXME: The calling program may know it is running under windows, and     * may have set the path to a Windows path, or, worse, appended or     * prepended a Windows path to PATH.     */    if (strcmp (name, "PATH") != 0) {	/* If this is Path, eliminate any PATH variable, to prevent any	   confusion.  */	if (strcmp (name, "Path") == 0) {	    SetEnvironmentVariable ("PATH", (char *) NULL);	    unsetenv ("PATH");	}	SetEnvironmentVariable (name, value);    } else {	char *buf;	    /* Eliminate any Path variable, to prevent any confusion.  */	SetEnvironmentVariable ("Path", (char *) NULL);	unsetenv ("Path");	if (value == NULL) {	    buf = NULL;	} else {	    int size;	    size = cygwin_posix_to_win32_path_list_buf_size (value);	    buf = (char *) alloca (size + 1);	    cygwin_posix_to_win32_path_list (value, buf);	}	SetEnvironmentVariable (name, buf);    }}#endif /* __CYGWIN__ && __WIN32__ */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?