os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/generic/tclEnv.c
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 /* 
     2  * tclEnv.c --
     3  *
     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.
     8  *
     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.  
    12  *
    13  * See the file "license.terms" for information on usage and redistribution
    14  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
    15  *
    16  * RCS: @(#) $Id: tclEnv.c,v 1.20.2.3 2006/10/31 22:25:08 das Exp $
    17  */
    18 
    19 #include "tclInt.h"
    20 #include "tclPort.h"
    21 
    22 TCL_DECLARE_MUTEX(envMutex)	/* To serialize access to environ */
    23 
    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. */
    28 
    29 #ifndef USE_PUTENV
    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
    33 				 * like we do.
    34 				 */
    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. */
    40 #endif
    41 
    42 /*
    43  * For MacOS X
    44  */
    45 #if defined(__APPLE__) && defined(__DYNAMIC__)
    46 #include <crt_externs.h>
    47 __private_extern__ char **environ;
    48 char **environ = NULL;
    49 #endif
    50 
    51 /*
    52  * Declarations for local procedures defined in this file:
    53  */
    54 
    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,
    59 			    char *newStr));
    60 void			TclSetEnv _ANSI_ARGS_((CONST char *name,
    61 			    CONST char *value));
    62 void			TclUnsetEnv _ANSI_ARGS_((CONST char *name));
    63 
    64 #if defined (__CYGWIN__) && defined(__WIN32__)
    65 static void		TclCygwinPutenv _ANSI_ARGS_((CONST char *string));
    66 #endif
    67 
    68 /*
    69  *----------------------------------------------------------------------
    70  *
    71  * TclSetupEnv --
    72  *
    73  *	This procedure is invoked for an interpreter to make environment
    74  *	variables accessible from that interpreter via the "env"
    75  *	associative array.
    76  *
    77  * Results:
    78  *	None.
    79  *
    80  * Side effects:
    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.
    87  *
    88  *----------------------------------------------------------------------
    89  */
    90 
    91 void
    92 TclSetupEnv(interp)
    93     Tcl_Interp *interp;		/* Interpreter whose "env" array is to be
    94 				 * managed. */
    95 {
    96     Tcl_DString envString;
    97     char *p1, *p2;
    98     int i;
    99 
   100     /*
   101      * For MacOS X
   102      */
   103 #if defined(__APPLE__) && defined(__DYNAMIC__)
   104     environ = *_NSGetEnviron();
   105 #endif
   106 
   107     /*
   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.
   115      */
   116     
   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,
   120 	    (ClientData) NULL);
   121     
   122     Tcl_UnsetVar2(interp, "env", (char *) NULL, TCL_GLOBAL_ONLY); 
   123     
   124     if (environ[0] == NULL) {
   125 	Tcl_Obj *varNamePtr;
   126 	
   127 	varNamePtr = Tcl_NewStringObj("env", -1);
   128 	Tcl_IncrRefCount(varNamePtr);
   129 	TclArraySet(interp, varNamePtr, NULL);	
   130 	Tcl_DecrRefCount(varNamePtr);
   131     } else {
   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, '=');
   136 	    if (p2 == NULL) {
   137 		/*
   138 		 * This condition seem to happen occasionally under some
   139 		 * versions of Solaris; ignore the entry.
   140 		 */
   141 		
   142 		continue;
   143 	    }
   144 	    p2++;
   145 	    p2[-1] = '\0';
   146 	    Tcl_SetVar2(interp, "env", p1, p2, TCL_GLOBAL_ONLY);	
   147 	    Tcl_DStringFree(&envString);
   148 	}
   149 	Tcl_MutexUnlock(&envMutex);
   150     }
   151 
   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,
   155 	    (ClientData) NULL);
   156 }
   157 
   158 /*
   159  *----------------------------------------------------------------------
   160  *
   161  * TclSetEnv --
   162  *
   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".
   169  *
   170  * Results:
   171  *	None.
   172  *
   173  * Side effects:
   174  *	The environ array gets updated.
   175  *
   176  *----------------------------------------------------------------------
   177  */
   178 
   179 void
   180 TclSetEnv(name, value)
   181     CONST char *name;		/* Name of variable whose value is to be
   182 				 * set (UTF-8). */
   183     CONST char *value;		/* New value for variable (UTF-8). */
   184 {
   185     Tcl_DString envString;
   186     int index, length, nameLength;
   187     char *p, *oldValue;
   188     CONST char *p2;
   189 
   190     /*
   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.
   194      */
   195 
   196     Tcl_MutexLock(&envMutex);
   197     index = TclpFindVariable(name, &length);
   198 
   199     if (index == -1) {
   200 #ifndef USE_PUTENV
   201 	/*
   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]
   205 	 */
   206 	if ((ourEnviron != environ) || ((length + 2) > environSize)) {
   207 	    char **newEnviron;
   208 
   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);
   215 	    }
   216 	    environ = ourEnviron = newEnviron;
   217 	    environSize = length + 5;
   218 #if defined(__APPLE__) && defined(__DYNAMIC__)
   219 	    {
   220 	    char ***e = _NSGetEnviron();
   221 	    *e = environ;
   222 	    }
   223 #endif
   224 	}
   225 	index = length;
   226 	environ[index + 1] = NULL;
   227 #endif
   228 	oldValue = NULL;
   229 	nameLength = strlen(name);
   230     } else {
   231 	CONST char *env;
   232 
   233 	/*
   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.
   239 	 */
   240 
   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);
   245 	    return;
   246 	}
   247 	Tcl_DStringFree(&envString);
   248 
   249 	oldValue = environ[index];
   250 	nameLength = length;
   251     }
   252 
   253     /*
   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.
   257      */
   258 
   259     p = (char *) ckalloc((unsigned) (nameLength + strlen(value) + 2));
   260     strcpy(p, name);
   261     p[nameLength] = '=';
   262     strcpy(p+nameLength+1, value);
   263     p2 = Tcl_UtfToExternalDString(NULL, p, -1, &envString);
   264 
   265     /*
   266      * Copy the native string to heap memory.
   267      */
   268     
   269     p = (char *) ckrealloc(p, (unsigned) (strlen(p2) + 1));
   270     strcpy(p, p2);
   271     Tcl_DStringFree(&envString);
   272 
   273 #ifdef USE_PUTENV
   274     /*
   275      * Update the system environment.
   276      */
   277 
   278     putenv(p);
   279     index = TclpFindVariable(name, &length);
   280 #else
   281     environ[index] = p;
   282 #endif
   283 
   284     /*
   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.
   288      */
   289 
   290     if ((index != -1) && (environ[index] == p)) {
   291 	ReplaceString(oldValue, p);
   292 #ifdef HAVE_PUTENV_THAT_COPIES
   293     } else {
   294 	/* This putenv() copies instead of taking ownership */
   295 	ckfree(p);
   296 #endif
   297     }
   298 
   299     Tcl_MutexUnlock(&envMutex);
   300     
   301     if (!strcmp(name, "HOME")) {
   302 	/* 
   303 	 * If the user's home directory has changed, we must invalidate
   304 	 * the filesystem cache, because '~' expansions will now be
   305 	 * incorrect.
   306 	 */
   307         Tcl_FSMountsChanged(NULL);
   308     }
   309 }
   310 
   311 /*
   312  *----------------------------------------------------------------------
   313  *
   314  * Tcl_PutEnv --
   315  *
   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".
   323  *
   324  * Results:
   325  *	None.
   326  *
   327  * Side effects:
   328  *	The environ array gets updated, as do all of the interpreters
   329  *	that we manage.
   330  *
   331  *----------------------------------------------------------------------
   332  */
   333 
   334 EXPORT_C int
   335 Tcl_PutEnv(string)
   336     CONST char *string;		/* Info about environment variable in the
   337 				 * form NAME=value. (native) */
   338 {
   339     Tcl_DString nameString;   
   340     CONST char *name;
   341     char *value;
   342 
   343     if (string == NULL) {
   344 	return 0;
   345     }
   346 
   347     /*
   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.
   351      */
   352 
   353     name = Tcl_ExternalToUtfDString(NULL, string, -1, &nameString);
   354     value = strchr(name, '=');
   355 
   356     if ((value != NULL) && (value != name)) {
   357 	value[0] = '\0';
   358 	TclSetEnv(name, value+1);
   359     }
   360 
   361     Tcl_DStringFree(&nameString);
   362     return 0;
   363 }
   364 
   365 /*
   366  *----------------------------------------------------------------------
   367  *
   368  * TclUnsetEnv --
   369  *
   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
   374  *	"unsetenv".
   375  *
   376  * Results:
   377  *	None.
   378  *
   379  * Side effects:
   380  *	Interpreters are updated, as is environ.
   381  *
   382  *----------------------------------------------------------------------
   383  */
   384 
   385 void
   386 TclUnsetEnv(name)
   387     CONST char *name;		/* Name of variable to remove (UTF-8). */
   388 {
   389     char *oldValue;
   390     int length;
   391     int index;
   392 #ifdef USE_PUTENV_FOR_UNSET
   393     Tcl_DString envString;
   394     char *string;
   395 #else
   396     char **envPtr;
   397 #endif
   398 
   399     Tcl_MutexLock(&envMutex);
   400     index = TclpFindVariable(name, &length);
   401 
   402     /*
   403      * First make sure that the environment variable exists to avoid
   404      * doing needless work and to avoid recursion on the unset.
   405      */
   406 
   407     if (index == -1) {
   408 	Tcl_MutexUnlock(&envMutex);
   409 	return;
   410     }
   411     /*
   412      * Remember the old value so we can free it if Tcl created the string.
   413      */
   414 
   415     oldValue = environ[index];
   416 
   417     /*
   418      * Update the system environment.  This must be done before we 
   419      * update the interpreters or we will recurse.
   420      */
   421 
   422 #ifdef USE_PUTENV_FOR_UNSET
   423     /*
   424      * For those platforms that support putenv to unset, Linux indicates
   425      * that no = should be included, and Windows requires it.
   426      */
   427 #ifdef WIN32
   428     string = ckalloc((unsigned int) length+2);
   429     memcpy((VOID *) string, (VOID *) name, (size_t) length);
   430     string[length] = '=';
   431     string[length+1] = '\0';
   432 #else
   433     string = ckalloc((unsigned int) length+1);
   434     memcpy((VOID *) string, (VOID *) name, (size_t) length);
   435     string[length] = '\0';
   436 #endif
   437 
   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);
   442 
   443     putenv(string);
   444 
   445     /*
   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.
   449      */
   450 
   451     if (environ[index] == string) {
   452 	ReplaceString(oldValue, string);
   453 #ifdef HAVE_PUTENV_THAT_COPIES
   454     } else {
   455 	/* This putenv() copies instead of taking ownership */
   456 	ckfree(string);
   457 #endif
   458     }
   459 #else
   460     for (envPtr = environ+index+1; ; envPtr++) {
   461 	envPtr[-1] = *envPtr;
   462 	if (*envPtr == NULL) {
   463 	    break;
   464 	}
   465     }
   466     ReplaceString(oldValue, NULL);
   467 #endif
   468 
   469     Tcl_MutexUnlock(&envMutex);
   470 }
   471 
   472 /*
   473  *---------------------------------------------------------------------------
   474  *
   475  * TclGetEnv --
   476  *
   477  *	Retrieve the value of an environment variable.
   478  *
   479  * Results:
   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
   484  *	longer needed.
   485  *
   486  * Side effects:
   487  *	None.
   488  *
   489  *----------------------------------------------------------------------
   490  */
   491 
   492 CONST char *
   493 TclGetEnv(name, valuePtr)
   494     CONST char *name;		/* Name of environment variable to find
   495 				 * (UTF-8). */
   496     Tcl_DString *valuePtr;	/* Uninitialized or free DString in which
   497 				 * the value of the environment variable is
   498 				 * stored. */
   499 {
   500     int length, index;
   501     CONST char *result;
   502 
   503     Tcl_MutexLock(&envMutex);
   504     index = TclpFindVariable(name, &length);
   505     result = NULL;
   506     if (index != -1) {
   507 	Tcl_DString envStr;
   508 	
   509 	result = Tcl_ExternalToUtfDString(NULL, environ[index], -1, &envStr);
   510 	result += length;
   511 	if (*result == '=') {
   512 	    result++;
   513 	    Tcl_DStringInit(valuePtr);
   514 	    Tcl_DStringAppend(valuePtr, result, -1);
   515 	    result = Tcl_DStringValue(valuePtr);
   516 	} else {
   517 	    result = NULL;
   518 	}
   519 	Tcl_DStringFree(&envStr);
   520     }
   521     Tcl_MutexUnlock(&envMutex);
   522     return result;
   523 }
   524 
   525 /*
   526  *----------------------------------------------------------------------
   527  *
   528  * EnvTraceProc --
   529  *
   530  *	This procedure is invoked whenever an environment variable
   531  *	is read, modified or deleted.  It propagates the change to the global
   532  *	"environ" array.
   533  *
   534  * Results:
   535  *	Always returns NULL to indicate success.
   536  *
   537  * Side effects:
   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).
   542  *
   543  *----------------------------------------------------------------------
   544  */
   545 
   546 	/* ARGSUSED */
   547 static char *
   548 EnvTraceProc(clientData, interp, name1, name2, flags)
   549     ClientData clientData;	/* Not used. */
   550     Tcl_Interp *interp;		/* Interpreter whose "env" variable is
   551 				 * being modified. */
   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. */
   556 {
   557     /*
   558      * For array traces, let TclSetupEnv do all the work.
   559      */
   560 
   561     if (flags & TCL_TRACE_ARRAY) {
   562 	TclSetupEnv(interp);
   563 	return NULL;
   564     }
   565 
   566     /*
   567      * If name2 is NULL, then return and do nothing.
   568      */
   569      
   570     if (name2 == NULL) {
   571 	return NULL;
   572     }
   573 
   574     /*
   575      * If a value is being set, call TclSetEnv to do all of the work.
   576      */
   577 
   578     if (flags & TCL_TRACE_WRITES) {
   579 	CONST char *value;
   580 	
   581 	value = Tcl_GetVar2(interp, "env", name2, TCL_GLOBAL_ONLY);
   582 	TclSetEnv(name2, value);
   583     }
   584 
   585     /*
   586      * If a value is being read, call TclGetEnv to do all of the work.
   587      */
   588 
   589     if (flags & TCL_TRACE_READS) {
   590 	Tcl_DString valueString;
   591 	CONST char *value;
   592 
   593 	value = TclGetEnv(name2, &valueString);
   594 	if (value == NULL) {
   595 	    return "no such variable";
   596 	}
   597 	Tcl_SetVar2(interp, name1, name2, value, 0);
   598 	Tcl_DStringFree(&valueString);
   599     }
   600 
   601     /*
   602      * For unset traces, let TclUnsetEnv do all the work.
   603      */
   604 
   605     if (flags & TCL_TRACE_UNSETS) {
   606 	TclUnsetEnv(name2);
   607     }
   608     return NULL;
   609 }
   610 
   611 /*
   612  *----------------------------------------------------------------------
   613  *
   614  * ReplaceString --
   615  *
   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.
   619  *
   620  * Results:
   621  *	None.
   622  *
   623  * Side effects:
   624  *	May free the old string.
   625  *
   626  *----------------------------------------------------------------------
   627  */
   628 
   629 static void
   630 ReplaceString(oldStr, newStr)
   631     CONST char *oldStr;		/* Old environment string. */
   632     char *newStr;		/* New environment string. */
   633 {
   634     int i;
   635     char **newCache;
   636 
   637     /*
   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.
   642      */
   643 
   644     for (i = 0; i < cacheSize; i++) {
   645 	if ((environCache[i] == oldStr) || (environCache[i] == NULL)) {
   646 	    break;
   647 	}
   648     }
   649     if (i < cacheSize) {
   650 	/*
   651 	 * Replace or delete the old value.
   652 	 */
   653 
   654 	if (environCache[i]) {
   655 	    ckfree(environCache[i]);
   656 	}
   657 
   658 	if (newStr) {
   659 	    environCache[i] = newStr;
   660 	} else {
   661 	    for (; i < cacheSize-1; i++) {
   662 		environCache[i] = environCache[i+1];
   663 	    }
   664 	    environCache[cacheSize-1] = NULL;
   665 	}
   666     } else {
   667         int allocatedSize = (cacheSize + 5) * sizeof(char *);
   668 
   669 	/*
   670 	 * We need to grow the cache in order to hold the new string.
   671 	 */
   672 
   673 	newCache = (char **) ckalloc((unsigned) allocatedSize);
   674         (VOID *) memset(newCache, (int) 0, (size_t) allocatedSize);
   675 
   676 	if (environCache) {
   677 	    memcpy((VOID *) newCache, (VOID *) environCache,
   678 		    (size_t) (cacheSize * sizeof(char*)));
   679 	    ckfree((char *) environCache);
   680 	}
   681 	environCache = newCache;
   682 	environCache[cacheSize] = newStr;
   683 	environCache[cacheSize+1] = NULL;
   684 	cacheSize += 5;
   685     }
   686 }
   687 
   688 /*
   689  *----------------------------------------------------------------------
   690  *
   691  * TclFinalizeEnvironment --
   692  *
   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.
   696  *
   697  * Results:
   698  *	None.
   699  *
   700  * Side effects:
   701  *	May deallocate storage.
   702  *
   703  *----------------------------------------------------------------------
   704  */
   705 
   706 void
   707 TclFinalizeEnvironment()
   708 {
   709     /*
   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.
   715      */
   716 
   717     if (environCache) {
   718 	ckfree((char *) environCache);
   719 	environCache = NULL;
   720 	cacheSize    = 0;
   721 #ifndef USE_PUTENV
   722 	environSize  = 0;
   723 #endif
   724     }
   725 }
   726 
   727 #if defined(__CYGWIN__) && defined(__WIN32__)
   728 
   729 #include <windows.h>
   730 
   731 /*
   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).
   736  */
   737 
   738 static void
   739 TclCygwinPutenv(str)
   740     const char *str;
   741 {
   742     char *name, *value;
   743 
   744     /* Get the name and value, so that we can change the environment
   745        variable for Windows.  */
   746     name = (char *) alloca (strlen (str) + 1);
   747     strcpy (name, str);
   748     for (value = name; *value != '=' && *value != '\0'; ++value)
   749 	;
   750     if (*value == '\0') {
   751 	    /* Can't happen.  */
   752 	    return;
   753 	}
   754     *value = '\0';
   755     ++value;
   756     if (*value == '\0') {
   757 	value = NULL;
   758     }
   759 
   760     /* Set the cygwin environment variable.  */
   761 #undef putenv
   762     if (value == NULL) {
   763 	unsetenv (name);
   764     } else {
   765 	putenv(str);
   766     }
   767 
   768     /*
   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.
   771      *
   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.
   775      */
   776     if (strcmp (name, "PATH") != 0) {
   777 	/* If this is Path, eliminate any PATH variable, to prevent any
   778 	   confusion.  */
   779 	if (strcmp (name, "Path") == 0) {
   780 	    SetEnvironmentVariable ("PATH", (char *) NULL);
   781 	    unsetenv ("PATH");
   782 	}
   783 
   784 	SetEnvironmentVariable (name, value);
   785     } else {
   786 	char *buf;
   787 
   788 	    /* Eliminate any Path variable, to prevent any confusion.  */
   789 	SetEnvironmentVariable ("Path", (char *) NULL);
   790 	unsetenv ("Path");
   791 
   792 	if (value == NULL) {
   793 	    buf = NULL;
   794 	} else {
   795 	    int size;
   796 
   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);
   800 	}
   801 
   802 	SetEnvironmentVariable (name, buf);
   803     }
   804 }
   805 
   806 #endif /* __CYGWIN__ && __WIN32__ */