tclenv.c

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

C
781
字号
/*  * 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-1998 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * RCS: @(#) $Id: tclEnv.c,v 1.20 2003/01/14 02:06:11 mdejong Exp $ */#include "tclInt.h"#include "tclPort.h"TCL_DECLARE_MUTEX(envMutex)	/* To serialize access to environ */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/* * For MacOS X */#if defined(__APPLE__) && defined(__DYNAMIC__)#include <crt_externs.h>char **environ = NULL;#endif/* * Declarations for local procedures defined in this file: */static char *		EnvTraceProc _ANSI_ARGS_((ClientData clientData,			    Tcl_Interp *interp, CONST char *name1, 			    CONST char *name2, int flags));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));#if defined (__CYGWIN__) && defined(__WIN32__)static void		TclCygwinPutenv _ANSI_ARGS_((CONST char *string));#endif/* *---------------------------------------------------------------------- * * 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 TclSetupEnv, 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. */{    Tcl_DString envString;    char *p1, *p2;    int i;    /*     * For MacOS X     */#if defined(__APPLE__) && defined(__DYNAMIC__)    environ = *_NSGetEnviron();#endif    /*     * Synchronize the values in the environ array with the contents     * of the Tcl "env" variable.  To do this:     *    1) Remove the trace that fires when the "env" var is unset.     *    2) Unset the "env" variable.     *    3) If there are no environ variables, create an empty "env"     *       array.  Otherwise populate the array with current values.     *    4) Add a trace that synchronizes the "env" array.     */        Tcl_UntraceVar2(interp, "env", (char *) NULL,	    TCL_GLOBAL_ONLY | TCL_TRACE_WRITES | TCL_TRACE_UNSETS |	    TCL_TRACE_READS | TCL_TRACE_ARRAY,  EnvTraceProc,	    (ClientData) NULL);        Tcl_UnsetVar2(interp, "env", (char *) NULL, TCL_GLOBAL_ONLY);         if (environ[0] == NULL) {	Tcl_Obj *varNamePtr;		varNamePtr = Tcl_NewStringObj("env", -1);	Tcl_IncrRefCount(varNamePtr);	TclArraySet(interp, varNamePtr, NULL);		Tcl_DecrRefCount(varNamePtr);    } else {	Tcl_MutexLock(&envMutex);	for (i = 0; environ[i] != NULL; i++) {	    p1 = Tcl_ExternalToUtfDString(NULL, environ[i], -1, &envString);	    p2 = strchr(p1, '=');	    if (p2 == NULL) {		/*		 * This condition seem to happen occasionally under some		 * versions of Solaris; ignore the entry.		 */				continue;	    }	    p2++;	    p2[-1] = '\0';	    Tcl_SetVar2(interp, "env", p1, p2, TCL_GLOBAL_ONLY);		    Tcl_DStringFree(&envString);	}	Tcl_MutexUnlock(&envMutex);    }    Tcl_TraceVar2(interp, "env", (char *) NULL,	    TCL_GLOBAL_ONLY | TCL_TRACE_WRITES | TCL_TRACE_UNSETS |	    TCL_TRACE_READS | TCL_TRACE_ARRAY,  EnvTraceProc,	    (ClientData) NULL);}/* *---------------------------------------------------------------------- * * 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. * *---------------------------------------------------------------------- */voidTclSetEnv(name, value)    CONST char *name;		/* Name of variable whose value is to be				 * set (UTF-8). */    CONST char *value;		/* New value for variable (UTF-8). */{    Tcl_DString envString;    int index, length, nameLength;    char *p, *oldValue;    CONST char *p2;    /*     * 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.     */    Tcl_MutexLock(&envMutex);    index = TclpFindVariable(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;#if defined(__APPLE__) && defined(__DYNAMIC__)	    {	    char ***e = _NSGetEnviron();	    *e = environ;	    }#endif	}	index = length;	environ[index + 1] = NULL;#endif	oldValue = NULL;	nameLength = strlen(name);    } else {	CONST char *env;	/*	 * 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.	 */	env = Tcl_ExternalToUtfDString(NULL, environ[index], -1, &envString);	if (strcmp(value, (env + length + 1)) == 0) {	    Tcl_DStringFree(&envString);	    Tcl_MutexUnlock(&envMutex);	    return;	}	Tcl_DStringFree(&envString);	oldValue = environ[index];	nameLength = length;    }	    /*     * Create a new entry.  Build a complete UTF string that contains     * a "name=value" pattern.  Then convert the string to the native     * encoding, and set the environ array value.     */    p = (char *) ckalloc((unsigned) (nameLength + strlen(value) + 2));    strcpy(p, name);    p[nameLength] = '=';    strcpy(p+nameLength+1, value);    p2 = Tcl_UtfToExternalDString(NULL, p, -1, &envString);    /*     * Copy the native string to heap memory.     */        p = (char *) ckrealloc(p, (unsigned) (strlen(p2) + 1));    strcpy(p, p2);    Tcl_DStringFree(&envString);#ifdef USE_PUTENV    /*     * Update the system environment.     */    putenv(p);    index = TclpFindVariable(name, &length);#else    environ[index] = p;#endif    /*     * 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 ((index != -1) && (environ[index] == p)) {	ReplaceString(oldValue, p);#ifdef HAVE_PUTENV_THAT_COPIES    } else {	/* This putenv() copies instead of taking ownership */	ckfree(p);#endif    }    Tcl_MutexUnlock(&envMutex);        if (!strcmp(name, "HOME")) {	/* 	 * If the user's home directory has changed, we must invalidate	 * the filesystem cache, because '~' expansions will now be	 * incorrect.	 */        Tcl_FSMountsChanged(NULL);    }}/* *---------------------------------------------------------------------- * * 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. (native) */{    Tcl_DString nameString;       CONST char *name;    char *value;    if (string == NULL) {	return 0;    }    /*     * First convert the native string to UTF.  Then separate the     * string into name and value parts, and call TclSetEnv to do     * all of the real work.     */    name = Tcl_ExternalToUtfDString(NULL, string, -1, &nameString);    value = strchr(name, '=');    if ((value != NULL) && (value != name)) {	value[0] = '\0';	TclSetEnv(name, value+1);    }    Tcl_DStringFree(&nameString);    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: *	Interpreters are updated, as is environ. * *---------------------------------------------------------------------- */voidTclUnsetEnv(name)    CONST char *name;		/* Name of variable to remove (UTF-8). */{    char *oldValue;    int length;    int index;#ifdef USE_PUTENV    Tcl_DString envString;    char *string;#else    char **envPtr;#endif    Tcl_MutexLock(&envMutex);    index = TclpFindVariable(name, &length);    /*

⌨️ 快捷键说明

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