os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/generic/tclEnv.c
Update contrib.
4 * Tcl support for environment variables, including a setenv
5 * procedure. This file contains the generic portion of the
6 * environment module. It is primarily responsible for keeping
7 * the "env" arrays in sync with the system environment variables.
9 * Copyright (c) 1991-1994 The Regents of the University of California.
10 * Copyright (c) 1994-1998 Sun Microsystems, Inc.
11 * Portions Copyright (c) 2007-2008 Nokia Corporation and/or its subsidiaries. All rights reserved.
13 * See the file "license.terms" for information on usage and redistribution
14 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
16 * RCS: @(#) $Id: tclEnv.c,v 1.20.2.3 2006/10/31 22:25:08 das Exp $
22 TCL_DECLARE_MUTEX(envMutex) /* To serialize access to environ */
24 static int cacheSize = 0; /* Number of env strings in environCache. */
25 static char **environCache = NULL;
26 /* Array containing all of the environment
27 * strings that Tcl has allocated. */
30 static char **ourEnviron = NULL;/* Cache of the array that we allocate.
31 * We need to track this in case another
32 * subsystem swaps around the environ array
35 static int environSize = 0; /* Non-zero means that the environ array was
36 * malloced and has this many total entries
37 * allocated to it (not all may be in use at
38 * once). Zero means that the environment
39 * array is in its original static state. */
45 #if defined(__APPLE__) && defined(__DYNAMIC__)
46 #include <crt_externs.h>
47 __private_extern__ char **environ;
48 char **environ = NULL;
52 * Declarations for local procedures defined in this file:
55 static char * EnvTraceProc _ANSI_ARGS_((ClientData clientData,
56 Tcl_Interp *interp, CONST char *name1,
57 CONST char *name2, int flags));
58 static void ReplaceString _ANSI_ARGS_((CONST char *oldStr,
60 void TclSetEnv _ANSI_ARGS_((CONST char *name,
62 void TclUnsetEnv _ANSI_ARGS_((CONST char *name));
64 #if defined (__CYGWIN__) && defined(__WIN32__)
65 static void TclCygwinPutenv _ANSI_ARGS_((CONST char *string));
69 *----------------------------------------------------------------------
73 * This procedure is invoked for an interpreter to make environment
74 * variables accessible from that interpreter via the "env"
81 * The interpreter is added to a list of interpreters managed
82 * by us, so that its view of envariables can be kept consistent
83 * with the view in other interpreters. If this is the first
84 * call to TclSetupEnv, then additional initialization happens,
85 * such as copying the environment to dynamically-allocated space
86 * for ease of management.
88 *----------------------------------------------------------------------
93 Tcl_Interp *interp; /* Interpreter whose "env" array is to be
96 Tcl_DString envString;
103 #if defined(__APPLE__) && defined(__DYNAMIC__)
104 environ = *_NSGetEnviron();
108 * Synchronize the values in the environ array with the contents
109 * of the Tcl "env" variable. To do this:
110 * 1) Remove the trace that fires when the "env" var is unset.
111 * 2) Unset the "env" variable.
112 * 3) If there are no environ variables, create an empty "env"
113 * array. Otherwise populate the array with current values.
114 * 4) Add a trace that synchronizes the "env" array.
117 Tcl_UntraceVar2(interp, "env", (char *) NULL,
118 TCL_GLOBAL_ONLY | TCL_TRACE_WRITES | TCL_TRACE_UNSETS |
119 TCL_TRACE_READS | TCL_TRACE_ARRAY, EnvTraceProc,
122 Tcl_UnsetVar2(interp, "env", (char *) NULL, TCL_GLOBAL_ONLY);
124 if (environ[0] == NULL) {
127 varNamePtr = Tcl_NewStringObj("env", -1);
128 Tcl_IncrRefCount(varNamePtr);
129 TclArraySet(interp, varNamePtr, NULL);
130 Tcl_DecrRefCount(varNamePtr);
132 Tcl_MutexLock(&envMutex);
133 for (i = 0; environ[i] != NULL; i++) {
134 p1 = Tcl_ExternalToUtfDString(NULL, environ[i], -1, &envString);
135 p2 = strchr(p1, '=');
138 * This condition seem to happen occasionally under some
139 * versions of Solaris; ignore the entry.
146 Tcl_SetVar2(interp, "env", p1, p2, TCL_GLOBAL_ONLY);
147 Tcl_DStringFree(&envString);
149 Tcl_MutexUnlock(&envMutex);
152 Tcl_TraceVar2(interp, "env", (char *) NULL,
153 TCL_GLOBAL_ONLY | TCL_TRACE_WRITES | TCL_TRACE_UNSETS |
154 TCL_TRACE_READS | TCL_TRACE_ARRAY, EnvTraceProc,
159 *----------------------------------------------------------------------
163 * Set an environment variable, replacing an existing value
164 * or creating a new variable if there doesn't exist a variable
165 * by the given name. This procedure is intended to be a
166 * stand-in for the UNIX "setenv" procedure so that applications
167 * using that procedure will interface properly to Tcl. To make
168 * it a stand-in, the Makefile must define "TclSetEnv" to "setenv".
174 * The environ array gets updated.
176 *----------------------------------------------------------------------
180 TclSetEnv(name, value)
181 CONST char *name; /* Name of variable whose value is to be
183 CONST char *value; /* New value for variable (UTF-8). */
185 Tcl_DString envString;
186 int index, length, nameLength;
191 * Figure out where the entry is going to go. If the name doesn't
192 * already exist, enlarge the array if necessary to make room. If the
193 * name exists, free its old entry.
196 Tcl_MutexLock(&envMutex);
197 index = TclpFindVariable(name, &length);
202 * We need to handle the case where the environment may be changed
203 * outside our control. environSize is only valid if the current
204 * environment is the one we allocated. [Bug 979640]
206 if ((ourEnviron != environ) || ((length + 2) > environSize)) {
209 newEnviron = (char **) ckalloc((unsigned)
210 ((length + 5) * sizeof(char *)));
211 memcpy((VOID *) newEnviron, (VOID *) environ,
212 length*sizeof(char *));
213 if ((environSize != 0) && (ourEnviron != NULL)) {
214 ckfree((char *) ourEnviron);
216 environ = ourEnviron = newEnviron;
217 environSize = length + 5;
218 #if defined(__APPLE__) && defined(__DYNAMIC__)
220 char ***e = _NSGetEnviron();
226 environ[index + 1] = NULL;
229 nameLength = strlen(name);
234 * Compare the new value to the existing value. If they're
235 * the same then quit immediately (e.g. don't rewrite the
236 * value or propagate it to other interpreters). Otherwise,
237 * when there are N interpreters there will be N! propagations
238 * of the same value among the interpreters.
241 env = Tcl_ExternalToUtfDString(NULL, environ[index], -1, &envString);
242 if (strcmp(value, (env + length + 1)) == 0) {
243 Tcl_DStringFree(&envString);
244 Tcl_MutexUnlock(&envMutex);
247 Tcl_DStringFree(&envString);
249 oldValue = environ[index];
254 * Create a new entry. Build a complete UTF string that contains
255 * a "name=value" pattern. Then convert the string to the native
256 * encoding, and set the environ array value.
259 p = (char *) ckalloc((unsigned) (nameLength + strlen(value) + 2));
262 strcpy(p+nameLength+1, value);
263 p2 = Tcl_UtfToExternalDString(NULL, p, -1, &envString);
266 * Copy the native string to heap memory.
269 p = (char *) ckrealloc(p, (unsigned) (strlen(p2) + 1));
271 Tcl_DStringFree(&envString);
275 * Update the system environment.
279 index = TclpFindVariable(name, &length);
285 * Watch out for versions of putenv that copy the string (e.g. VC++).
286 * In this case we need to free the string immediately. Otherwise
287 * update the string in the cache.
290 if ((index != -1) && (environ[index] == p)) {
291 ReplaceString(oldValue, p);
292 #ifdef HAVE_PUTENV_THAT_COPIES
294 /* This putenv() copies instead of taking ownership */
299 Tcl_MutexUnlock(&envMutex);
301 if (!strcmp(name, "HOME")) {
303 * If the user's home directory has changed, we must invalidate
304 * the filesystem cache, because '~' expansions will now be
307 Tcl_FSMountsChanged(NULL);
312 *----------------------------------------------------------------------
316 * Set an environment variable. Similar to setenv except that
317 * the information is passed in a single string of the form
318 * NAME=value, rather than as separate name strings. This procedure
319 * is intended to be a stand-in for the UNIX "putenv" procedure
320 * so that applications using that procedure will interface
321 * properly to Tcl. To make it a stand-in, the Makefile will
322 * define "Tcl_PutEnv" to "putenv".
328 * The environ array gets updated, as do all of the interpreters
331 *----------------------------------------------------------------------
336 CONST char *string; /* Info about environment variable in the
337 * form NAME=value. (native) */
339 Tcl_DString nameString;
343 if (string == NULL) {
348 * First convert the native string to UTF. Then separate the
349 * string into name and value parts, and call TclSetEnv to do
350 * all of the real work.
353 name = Tcl_ExternalToUtfDString(NULL, string, -1, &nameString);
354 value = strchr(name, '=');
356 if ((value != NULL) && (value != name)) {
358 TclSetEnv(name, value+1);
361 Tcl_DStringFree(&nameString);
366 *----------------------------------------------------------------------
370 * Remove an environment variable, updating the "env" arrays
371 * in all interpreters managed by us. This function is intended
372 * to replace the UNIX "unsetenv" function (but to do this the
373 * Makefile must be modified to redefine "TclUnsetEnv" to
380 * Interpreters are updated, as is environ.
382 *----------------------------------------------------------------------
387 CONST char *name; /* Name of variable to remove (UTF-8). */
392 #ifdef USE_PUTENV_FOR_UNSET
393 Tcl_DString envString;
399 Tcl_MutexLock(&envMutex);
400 index = TclpFindVariable(name, &length);
403 * First make sure that the environment variable exists to avoid
404 * doing needless work and to avoid recursion on the unset.
408 Tcl_MutexUnlock(&envMutex);
412 * Remember the old value so we can free it if Tcl created the string.
415 oldValue = environ[index];
418 * Update the system environment. This must be done before we
419 * update the interpreters or we will recurse.
422 #ifdef USE_PUTENV_FOR_UNSET
424 * For those platforms that support putenv to unset, Linux indicates
425 * that no = should be included, and Windows requires it.
428 string = ckalloc((unsigned int) length+2);
429 memcpy((VOID *) string, (VOID *) name, (size_t) length);
430 string[length] = '=';
431 string[length+1] = '\0';
433 string = ckalloc((unsigned int) length+1);
434 memcpy((VOID *) string, (VOID *) name, (size_t) length);
435 string[length] = '\0';
438 Tcl_UtfToExternalDString(NULL, string, -1, &envString);
439 string = ckrealloc(string, (unsigned) (Tcl_DStringLength(&envString)+1));
440 strcpy(string, Tcl_DStringValue(&envString));
441 Tcl_DStringFree(&envString);
446 * Watch out for versions of putenv that copy the string (e.g. VC++).
447 * In this case we need to free the string immediately. Otherwise
448 * update the string in the cache.
451 if (environ[index] == string) {
452 ReplaceString(oldValue, string);
453 #ifdef HAVE_PUTENV_THAT_COPIES
455 /* This putenv() copies instead of taking ownership */
460 for (envPtr = environ+index+1; ; envPtr++) {
461 envPtr[-1] = *envPtr;
462 if (*envPtr == NULL) {
466 ReplaceString(oldValue, NULL);
469 Tcl_MutexUnlock(&envMutex);
473 *---------------------------------------------------------------------------
477 * Retrieve the value of an environment variable.
480 * The result is a pointer to a string specifying the value of the
481 * environment variable, or NULL if that environment variable does
482 * not exist. Storage for the result string is allocated in valuePtr;
483 * the caller must call Tcl_DStringFree() when the result is no
489 *----------------------------------------------------------------------
493 TclGetEnv(name, valuePtr)
494 CONST char *name; /* Name of environment variable to find
496 Tcl_DString *valuePtr; /* Uninitialized or free DString in which
497 * the value of the environment variable is
503 Tcl_MutexLock(&envMutex);
504 index = TclpFindVariable(name, &length);
509 result = Tcl_ExternalToUtfDString(NULL, environ[index], -1, &envStr);
511 if (*result == '=') {
513 Tcl_DStringInit(valuePtr);
514 Tcl_DStringAppend(valuePtr, result, -1);
515 result = Tcl_DStringValue(valuePtr);
519 Tcl_DStringFree(&envStr);
521 Tcl_MutexUnlock(&envMutex);
526 *----------------------------------------------------------------------
530 * This procedure is invoked whenever an environment variable
531 * is read, modified or deleted. It propagates the change to the global
535 * Always returns NULL to indicate success.
538 * Environment variable changes get propagated. If the whole
539 * "env" array is deleted, then we stop managing things for
540 * this interpreter (usually this happens because the whole
541 * interpreter is being deleted).
543 *----------------------------------------------------------------------
548 EnvTraceProc(clientData, interp, name1, name2, flags)
549 ClientData clientData; /* Not used. */
550 Tcl_Interp *interp; /* Interpreter whose "env" variable is
552 CONST char *name1; /* Better be "env". */
553 CONST char *name2; /* Name of variable being modified, or NULL
554 * if whole array is being deleted (UTF-8). */
555 int flags; /* Indicates what's happening. */
558 * For array traces, let TclSetupEnv do all the work.
561 if (flags & TCL_TRACE_ARRAY) {
567 * If name2 is NULL, then return and do nothing.
575 * If a value is being set, call TclSetEnv to do all of the work.
578 if (flags & TCL_TRACE_WRITES) {
581 value = Tcl_GetVar2(interp, "env", name2, TCL_GLOBAL_ONLY);
582 TclSetEnv(name2, value);
586 * If a value is being read, call TclGetEnv to do all of the work.
589 if (flags & TCL_TRACE_READS) {
590 Tcl_DString valueString;
593 value = TclGetEnv(name2, &valueString);
595 return "no such variable";
597 Tcl_SetVar2(interp, name1, name2, value, 0);
598 Tcl_DStringFree(&valueString);
602 * For unset traces, let TclUnsetEnv do all the work.
605 if (flags & TCL_TRACE_UNSETS) {
612 *----------------------------------------------------------------------
616 * Replace one string with another in the environment variable
617 * cache. The cache keeps track of all of the environment
618 * variables that Tcl has modified so they can be freed later.
624 * May free the old string.
626 *----------------------------------------------------------------------
630 ReplaceString(oldStr, newStr)
631 CONST char *oldStr; /* Old environment string. */
632 char *newStr; /* New environment string. */
638 * Check to see if the old value was allocated by Tcl. If so,
639 * it needs to be deallocated to avoid memory leaks. Note that this
640 * algorithm is O(n), not O(1). This will result in n-squared behavior
641 * if lots of environment changes are being made.
644 for (i = 0; i < cacheSize; i++) {
645 if ((environCache[i] == oldStr) || (environCache[i] == NULL)) {
651 * Replace or delete the old value.
654 if (environCache[i]) {
655 ckfree(environCache[i]);
659 environCache[i] = newStr;
661 for (; i < cacheSize-1; i++) {
662 environCache[i] = environCache[i+1];
664 environCache[cacheSize-1] = NULL;
667 int allocatedSize = (cacheSize + 5) * sizeof(char *);
670 * We need to grow the cache in order to hold the new string.
673 newCache = (char **) ckalloc((unsigned) allocatedSize);
674 (VOID *) memset(newCache, (int) 0, (size_t) allocatedSize);
677 memcpy((VOID *) newCache, (VOID *) environCache,
678 (size_t) (cacheSize * sizeof(char*)));
679 ckfree((char *) environCache);
681 environCache = newCache;
682 environCache[cacheSize] = newStr;
683 environCache[cacheSize+1] = NULL;
689 *----------------------------------------------------------------------
691 * TclFinalizeEnvironment --
693 * This function releases any storage allocated by this module
694 * that isn't still in use by the global environment. Any
695 * strings that are still in the environment will be leaked.
701 * May deallocate storage.
703 *----------------------------------------------------------------------
707 TclFinalizeEnvironment()
710 * For now we just deallocate the cache array and none of the environment
711 * strings. This may leak more memory that strictly necessary, since some
712 * of the strings may no longer be in the environment. However,
713 * determining which ones are ok to delete is n-squared, and is pretty
714 * unlikely, so we don't bother.
718 ckfree((char *) environCache);
727 #if defined(__CYGWIN__) && defined(__WIN32__)
732 * When using cygwin, when an environment variable changes, we need to synch
733 * with both the cygwin environment (in case the application C code calls
734 * fork) and the Windows environment (in case the application TCL code calls
735 * exec, which calls the Windows CreateProcess function).
744 /* Get the name and value, so that we can change the environment
745 variable for Windows. */
746 name = (char *) alloca (strlen (str) + 1);
748 for (value = name; *value != '=' && *value != '\0'; ++value)
750 if (*value == '\0') {
756 if (*value == '\0') {
760 /* Set the cygwin environment variable. */
769 * Before changing the environment variable in Windows, if this is PATH,
770 * we need to convert the value back to a Windows style path.
772 * FIXME: The calling program may know it is running under windows, and
773 * may have set the path to a Windows path, or, worse, appended or
774 * prepended a Windows path to PATH.
776 if (strcmp (name, "PATH") != 0) {
777 /* If this is Path, eliminate any PATH variable, to prevent any
779 if (strcmp (name, "Path") == 0) {
780 SetEnvironmentVariable ("PATH", (char *) NULL);
784 SetEnvironmentVariable (name, value);
788 /* Eliminate any Path variable, to prevent any confusion. */
789 SetEnvironmentVariable ("Path", (char *) NULL);
797 size = cygwin_posix_to_win32_path_list_buf_size (value);
798 buf = (char *) alloca (size + 1);
799 cygwin_posix_to_win32_path_list (value, buf);
802 SetEnvironmentVariable (name, buf);
806 #endif /* __CYGWIN__ && __WIN32__ */