tclEnv.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:20k
源码类别:

通讯编程

开发平台:

Visual C++

  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.  *
  12.  * See the file "license.terms" for information on usage and redistribution
  13.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  14.  *
  15.  * RCS: @(#) $Id: tclEnv.c,v 1.20.2.4 2007/08/07 05:04:48 das Exp $
  16.  */
  17. #include "tclInt.h"
  18. #include "tclPort.h"
  19. TCL_DECLARE_MUTEX(envMutex) /* To serialize access to environ */
  20. static int cacheSize = 0; /* Number of env strings in environCache. */
  21. static char **environCache = NULL;
  22. /* Array containing all of the environment
  23.  * strings that Tcl has allocated. */
  24. #ifndef USE_PUTENV
  25. static char **ourEnviron = NULL;/* Cache of the array that we allocate.
  26.  * We need to track this in case another
  27.  * subsystem swaps around the environ array
  28.  * like we do.
  29.  */
  30. static int environSize = 0; /* Non-zero means that the environ array was
  31.  * malloced and has this many total entries
  32.  * allocated to it (not all may be in use at
  33.  * once).  Zero means that the environment
  34.  * array is in its original static state. */
  35. #endif
  36. /*
  37.  * Declarations for local procedures defined in this file:
  38.  */
  39. static char * EnvTraceProc _ANSI_ARGS_((ClientData clientData,
  40.     Tcl_Interp *interp, CONST char *name1, 
  41.     CONST char *name2, int flags));
  42. static void ReplaceString _ANSI_ARGS_((CONST char *oldStr,
  43.     char *newStr));
  44. void TclSetEnv _ANSI_ARGS_((CONST char *name,
  45.     CONST char *value));
  46. void TclUnsetEnv _ANSI_ARGS_((CONST char *name));
  47. #if defined (__CYGWIN__) && defined(__WIN32__)
  48. static void TclCygwinPutenv _ANSI_ARGS_((CONST char *string));
  49. #endif
  50. /*
  51.  *----------------------------------------------------------------------
  52.  *
  53.  * TclSetupEnv --
  54.  *
  55.  * This procedure is invoked for an interpreter to make environment
  56.  * variables accessible from that interpreter via the "env"
  57.  * associative array.
  58.  *
  59.  * Results:
  60.  * None.
  61.  *
  62.  * Side effects:
  63.  * The interpreter is added to a list of interpreters managed
  64.  * by us, so that its view of envariables can be kept consistent
  65.  * with the view in other interpreters.  If this is the first
  66.  * call to TclSetupEnv, then additional initialization happens,
  67.  * such as copying the environment to dynamically-allocated space
  68.  * for ease of management.
  69.  *
  70.  *----------------------------------------------------------------------
  71.  */
  72. void
  73. TclSetupEnv(interp)
  74.     Tcl_Interp *interp; /* Interpreter whose "env" array is to be
  75.  * managed. */
  76. {
  77.     Tcl_DString envString;
  78.     char *p1, *p2;
  79.     int i;
  80.     /*
  81.      * Synchronize the values in the environ array with the contents
  82.      * of the Tcl "env" variable.  To do this:
  83.      *    1) Remove the trace that fires when the "env" var is unset.
  84.      *    2) Unset the "env" variable.
  85.      *    3) If there are no environ variables, create an empty "env"
  86.      *       array.  Otherwise populate the array with current values.
  87.      *    4) Add a trace that synchronizes the "env" array.
  88.      */
  89.     
  90.     Tcl_UntraceVar2(interp, "env", (char *) NULL,
  91.     TCL_GLOBAL_ONLY | TCL_TRACE_WRITES | TCL_TRACE_UNSETS |
  92.     TCL_TRACE_READS | TCL_TRACE_ARRAY,  EnvTraceProc,
  93.     (ClientData) NULL);
  94.     
  95.     Tcl_UnsetVar2(interp, "env", (char *) NULL, TCL_GLOBAL_ONLY); 
  96.     
  97.     if (environ[0] == NULL) {
  98. Tcl_Obj *varNamePtr;
  99. varNamePtr = Tcl_NewStringObj("env", -1);
  100. Tcl_IncrRefCount(varNamePtr);
  101. TclArraySet(interp, varNamePtr, NULL);
  102. Tcl_DecrRefCount(varNamePtr);
  103.     } else {
  104. Tcl_MutexLock(&envMutex);
  105. for (i = 0; environ[i] != NULL; i++) {
  106.     p1 = Tcl_ExternalToUtfDString(NULL, environ[i], -1, &envString);
  107.     p2 = strchr(p1, '=');
  108.     if (p2 == NULL) {
  109. /*
  110.  * This condition seem to happen occasionally under some
  111.  * versions of Solaris; ignore the entry.
  112.  */
  113. continue;
  114.     }
  115.     p2++;
  116.     p2[-1] = '';
  117.     Tcl_SetVar2(interp, "env", p1, p2, TCL_GLOBAL_ONLY);
  118.     Tcl_DStringFree(&envString);
  119. }
  120. Tcl_MutexUnlock(&envMutex);
  121.     }
  122.     Tcl_TraceVar2(interp, "env", (char *) NULL,
  123.     TCL_GLOBAL_ONLY | TCL_TRACE_WRITES | TCL_TRACE_UNSETS |
  124.     TCL_TRACE_READS | TCL_TRACE_ARRAY,  EnvTraceProc,
  125.     (ClientData) NULL);
  126. }
  127. /*
  128.  *----------------------------------------------------------------------
  129.  *
  130.  * TclSetEnv --
  131.  *
  132.  * Set an environment variable, replacing an existing value
  133.  * or creating a new variable if there doesn't exist a variable
  134.  * by the given name.  This procedure is intended to be a
  135.  * stand-in for the  UNIX "setenv" procedure so that applications
  136.  * using that procedure will interface properly to Tcl.  To make
  137.  * it a stand-in, the Makefile must define "TclSetEnv" to "setenv".
  138.  *
  139.  * Results:
  140.  * None.
  141.  *
  142.  * Side effects:
  143.  * The environ array gets updated.
  144.  *
  145.  *----------------------------------------------------------------------
  146.  */
  147. void
  148. TclSetEnv(name, value)
  149.     CONST char *name; /* Name of variable whose value is to be
  150.  * set (UTF-8). */
  151.     CONST char *value; /* New value for variable (UTF-8). */
  152. {
  153.     Tcl_DString envString;
  154.     int index, length, nameLength;
  155.     char *p, *oldValue;
  156.     CONST char *p2;
  157.     /*
  158.      * Figure out where the entry is going to go.  If the name doesn't
  159.      * already exist, enlarge the array if necessary to make room.  If the
  160.      * name exists, free its old entry.
  161.      */
  162.     Tcl_MutexLock(&envMutex);
  163.     index = TclpFindVariable(name, &length);
  164.     if (index == -1) {
  165. #ifndef USE_PUTENV
  166. /*
  167.  * We need to handle the case where the environment may be changed
  168.  * outside our control.  environSize is only valid if the current
  169.  * environment is the one we allocated. [Bug 979640]
  170.  */
  171. if ((ourEnviron != environ) || ((length + 2) > environSize)) {
  172.     char **newEnviron;
  173.     newEnviron = (char **) ckalloc((unsigned)
  174.     ((length + 5) * sizeof(char *)));
  175.     memcpy((VOID *) newEnviron, (VOID *) environ,
  176.     length*sizeof(char *));
  177.     if ((environSize != 0) && (ourEnviron != NULL)) {
  178. ckfree((char *) ourEnviron);
  179.     }
  180.     environ = ourEnviron = newEnviron;
  181.     environSize = length + 5;
  182. }
  183. index = length;
  184. environ[index + 1] = NULL;
  185. #endif
  186. oldValue = NULL;
  187. nameLength = strlen(name);
  188.     } else {
  189. CONST char *env;
  190. /*
  191.  * Compare the new value to the existing value.  If they're
  192.  * the same then quit immediately (e.g. don't rewrite the
  193.  * value or propagate it to other interpreters).  Otherwise,
  194.  * when there are N interpreters there will be N! propagations
  195.  * of the same value among the interpreters.
  196.  */
  197. env = Tcl_ExternalToUtfDString(NULL, environ[index], -1, &envString);
  198. if (strcmp(value, (env + length + 1)) == 0) {
  199.     Tcl_DStringFree(&envString);
  200.     Tcl_MutexUnlock(&envMutex);
  201.     return;
  202. }
  203. Tcl_DStringFree(&envString);
  204. oldValue = environ[index];
  205. nameLength = length;
  206.     }
  207.     /*
  208.      * Create a new entry.  Build a complete UTF string that contains
  209.      * a "name=value" pattern.  Then convert the string to the native
  210.      * encoding, and set the environ array value.
  211.      */
  212.     p = (char *) ckalloc((unsigned) (nameLength + strlen(value) + 2));
  213.     strcpy(p, name);
  214.     p[nameLength] = '=';
  215.     strcpy(p+nameLength+1, value);
  216.     p2 = Tcl_UtfToExternalDString(NULL, p, -1, &envString);
  217.     /*
  218.      * Copy the native string to heap memory.
  219.      */
  220.     
  221.     p = (char *) ckrealloc(p, (unsigned) (strlen(p2) + 1));
  222.     strcpy(p, p2);
  223.     Tcl_DStringFree(&envString);
  224. #ifdef USE_PUTENV
  225.     /*
  226.      * Update the system environment.
  227.      */
  228.     putenv(p);
  229.     index = TclpFindVariable(name, &length);
  230. #else
  231.     environ[index] = p;
  232. #endif
  233.     /*
  234.      * Watch out for versions of putenv that copy the string (e.g. VC++).
  235.      * In this case we need to free the string immediately.  Otherwise
  236.      * update the string in the cache.
  237.      */
  238.     if ((index != -1) && (environ[index] == p)) {
  239. ReplaceString(oldValue, p);
  240. #ifdef HAVE_PUTENV_THAT_COPIES
  241.     } else {
  242. /* This putenv() copies instead of taking ownership */
  243. ckfree(p);
  244. #endif
  245.     }
  246.     Tcl_MutexUnlock(&envMutex);
  247.     
  248.     if (!strcmp(name, "HOME")) {
  249. /* 
  250.  * If the user's home directory has changed, we must invalidate
  251.  * the filesystem cache, because '~' expansions will now be
  252.  * incorrect.
  253.  */
  254.         Tcl_FSMountsChanged(NULL);
  255.     }
  256. }
  257. /*
  258.  *----------------------------------------------------------------------
  259.  *
  260.  * Tcl_PutEnv --
  261.  *
  262.  * Set an environment variable.  Similar to setenv except that
  263.  * the information is passed in a single string of the form
  264.  * NAME=value, rather than as separate name strings.  This procedure
  265.  * is intended to be a stand-in for the  UNIX "putenv" procedure
  266.  * so that applications using that procedure will interface
  267.  * properly to Tcl.  To make it a stand-in, the Makefile will
  268.  * define "Tcl_PutEnv" to "putenv".
  269.  *
  270.  * Results:
  271.  * None.
  272.  *
  273.  * Side effects:
  274.  * The environ array gets updated, as do all of the interpreters
  275.  * that we manage.
  276.  *
  277.  *----------------------------------------------------------------------
  278.  */
  279. int
  280. Tcl_PutEnv(string)
  281.     CONST char *string; /* Info about environment variable in the
  282.  * form NAME=value. (native) */
  283. {
  284.     Tcl_DString nameString;   
  285.     CONST char *name;
  286.     char *value;
  287.     if (string == NULL) {
  288. return 0;
  289.     }
  290.     /*
  291.      * First convert the native string to UTF.  Then separate the
  292.      * string into name and value parts, and call TclSetEnv to do
  293.      * all of the real work.
  294.      */
  295.     name = Tcl_ExternalToUtfDString(NULL, string, -1, &nameString);
  296.     value = strchr(name, '=');
  297.     if ((value != NULL) && (value != name)) {
  298. value[0] = '';
  299. TclSetEnv(name, value+1);
  300.     }
  301.     Tcl_DStringFree(&nameString);
  302.     return 0;
  303. }
  304. /*
  305.  *----------------------------------------------------------------------
  306.  *
  307.  * TclUnsetEnv --
  308.  *
  309.  * Remove an environment variable, updating the "env" arrays
  310.  * in all interpreters managed by us.  This function is intended
  311.  * to replace the UNIX "unsetenv" function (but to do this the
  312.  * Makefile must be modified to redefine "TclUnsetEnv" to
  313.  * "unsetenv".
  314.  *
  315.  * Results:
  316.  * None.
  317.  *
  318.  * Side effects:
  319.  * Interpreters are updated, as is environ.
  320.  *
  321.  *----------------------------------------------------------------------
  322.  */
  323. void
  324. TclUnsetEnv(name)
  325.     CONST char *name; /* Name of variable to remove (UTF-8). */
  326. {
  327.     char *oldValue;
  328.     int length;
  329.     int index;
  330. #ifdef USE_PUTENV_FOR_UNSET
  331.     Tcl_DString envString;
  332.     char *string;
  333. #else
  334.     char **envPtr;
  335. #endif
  336.     Tcl_MutexLock(&envMutex);
  337.     index = TclpFindVariable(name, &length);
  338.     /*
  339.      * First make sure that the environment variable exists to avoid
  340.      * doing needless work and to avoid recursion on the unset.
  341.      */
  342.     if (index == -1) {
  343. Tcl_MutexUnlock(&envMutex);
  344. return;
  345.     }
  346.     /*
  347.      * Remember the old value so we can free it if Tcl created the string.
  348.      */
  349.     oldValue = environ[index];
  350.     /*
  351.      * Update the system environment.  This must be done before we 
  352.      * update the interpreters or we will recurse.
  353.      */
  354. #ifdef USE_PUTENV_FOR_UNSET
  355.     /*
  356.      * For those platforms that support putenv to unset, Linux indicates
  357.      * that no = should be included, and Windows requires it.
  358.      */
  359. #ifdef WIN32
  360.     string = ckalloc((unsigned int) length+2);
  361.     memcpy((VOID *) string, (VOID *) name, (size_t) length);
  362.     string[length] = '=';
  363.     string[length+1] = '';
  364. #else
  365.     string = ckalloc((unsigned int) length+1);
  366.     memcpy((VOID *) string, (VOID *) name, (size_t) length);
  367.     string[length] = '';
  368. #endif
  369.     Tcl_UtfToExternalDString(NULL, string, -1, &envString);
  370.     string = ckrealloc(string, (unsigned) (Tcl_DStringLength(&envString)+1));
  371.     strcpy(string, Tcl_DStringValue(&envString));
  372.     Tcl_DStringFree(&envString);
  373.     putenv(string);
  374.     /*
  375.      * Watch out for versions of putenv that copy the string (e.g. VC++).
  376.      * In this case we need to free the string immediately.  Otherwise
  377.      * update the string in the cache.
  378.      */
  379.     if (environ[index] == string) {
  380. ReplaceString(oldValue, string);
  381. #ifdef HAVE_PUTENV_THAT_COPIES
  382.     } else {
  383. /* This putenv() copies instead of taking ownership */
  384. ckfree(string);
  385. #endif
  386.     }
  387. #else
  388.     for (envPtr = environ+index+1; ; envPtr++) {
  389. envPtr[-1] = *envPtr;
  390. if (*envPtr == NULL) {
  391.     break;
  392. }
  393.     }
  394.     ReplaceString(oldValue, NULL);
  395. #endif
  396.     Tcl_MutexUnlock(&envMutex);
  397. }
  398. /*
  399.  *---------------------------------------------------------------------------
  400.  *
  401.  * TclGetEnv --
  402.  *
  403.  * Retrieve the value of an environment variable.
  404.  *
  405.  * Results:
  406.  * The result is a pointer to a string specifying the value of the
  407.  * environment variable, or NULL if that environment variable does
  408.  * not exist.  Storage for the result string is allocated in valuePtr;
  409.  * the caller must call Tcl_DStringFree() when the result is no
  410.  * longer needed.
  411.  *
  412.  * Side effects:
  413.  * None.
  414.  *
  415.  *----------------------------------------------------------------------
  416.  */
  417. CONST char *
  418. TclGetEnv(name, valuePtr)
  419.     CONST char *name; /* Name of environment variable to find
  420.  * (UTF-8). */
  421.     Tcl_DString *valuePtr; /* Uninitialized or free DString in which
  422.  * the value of the environment variable is
  423.  * stored. */
  424. {
  425.     int length, index;
  426.     CONST char *result;
  427.     Tcl_MutexLock(&envMutex);
  428.     index = TclpFindVariable(name, &length);
  429.     result = NULL;
  430.     if (index != -1) {
  431. Tcl_DString envStr;
  432. result = Tcl_ExternalToUtfDString(NULL, environ[index], -1, &envStr);
  433. result += length;
  434. if (*result == '=') {
  435.     result++;
  436.     Tcl_DStringInit(valuePtr);
  437.     Tcl_DStringAppend(valuePtr, result, -1);
  438.     result = Tcl_DStringValue(valuePtr);
  439. } else {
  440.     result = NULL;
  441. }
  442. Tcl_DStringFree(&envStr);
  443.     }
  444.     Tcl_MutexUnlock(&envMutex);
  445.     return result;
  446. }
  447. /*
  448.  *----------------------------------------------------------------------
  449.  *
  450.  * EnvTraceProc --
  451.  *
  452.  * This procedure is invoked whenever an environment variable
  453.  * is read, modified or deleted.  It propagates the change to the global
  454.  * "environ" array.
  455.  *
  456.  * Results:
  457.  * Always returns NULL to indicate success.
  458.  *
  459.  * Side effects:
  460.  * Environment variable changes get propagated.  If the whole
  461.  * "env" array is deleted, then we stop managing things for
  462.  * this interpreter (usually this happens because the whole
  463.  * interpreter is being deleted).
  464.  *
  465.  *----------------------------------------------------------------------
  466.  */
  467. /* ARGSUSED */
  468. static char *
  469. EnvTraceProc(clientData, interp, name1, name2, flags)
  470.     ClientData clientData; /* Not used. */
  471.     Tcl_Interp *interp; /* Interpreter whose "env" variable is
  472.  * being modified. */
  473.     CONST char *name1; /* Better be "env". */
  474.     CONST char *name2; /* Name of variable being modified, or NULL
  475.  * if whole array is being deleted (UTF-8). */
  476.     int flags; /* Indicates what's happening. */
  477. {
  478.     /*
  479.      * For array traces, let TclSetupEnv do all the work.
  480.      */
  481.     if (flags & TCL_TRACE_ARRAY) {
  482. TclSetupEnv(interp);
  483. return NULL;
  484.     }
  485.     /*
  486.      * If name2 is NULL, then return and do nothing.
  487.      */
  488.      
  489.     if (name2 == NULL) {
  490. return NULL;
  491.     }
  492.     /*
  493.      * If a value is being set, call TclSetEnv to do all of the work.
  494.      */
  495.     if (flags & TCL_TRACE_WRITES) {
  496. CONST char *value;
  497. value = Tcl_GetVar2(interp, "env", name2, TCL_GLOBAL_ONLY);
  498. TclSetEnv(name2, value);
  499.     }
  500.     /*
  501.      * If a value is being read, call TclGetEnv to do all of the work.
  502.      */
  503.     if (flags & TCL_TRACE_READS) {
  504. Tcl_DString valueString;
  505. CONST char *value;
  506. value = TclGetEnv(name2, &valueString);
  507. if (value == NULL) {
  508.     return "no such variable";
  509. }
  510. Tcl_SetVar2(interp, name1, name2, value, 0);
  511. Tcl_DStringFree(&valueString);
  512.     }
  513.     /*
  514.      * For unset traces, let TclUnsetEnv do all the work.
  515.      */
  516.     if (flags & TCL_TRACE_UNSETS) {
  517. TclUnsetEnv(name2);
  518.     }
  519.     return NULL;
  520. }
  521. /*
  522.  *----------------------------------------------------------------------
  523.  *
  524.  * ReplaceString --
  525.  *
  526.  * Replace one string with another in the environment variable
  527.  * cache.  The cache keeps track of all of the environment
  528.  * variables that Tcl has modified so they can be freed later.
  529.  *
  530.  * Results:
  531.  * None.
  532.  *
  533.  * Side effects:
  534.  * May free the old string.
  535.  *
  536.  *----------------------------------------------------------------------
  537.  */
  538. static void
  539. ReplaceString(oldStr, newStr)
  540.     CONST char *oldStr; /* Old environment string. */
  541.     char *newStr; /* New environment string. */
  542. {
  543.     int i;
  544.     char **newCache;
  545.     /*
  546.      * Check to see if the old value was allocated by Tcl.  If so,
  547.      * it needs to be deallocated to avoid memory leaks.  Note that this
  548.      * algorithm is O(n), not O(1).  This will result in n-squared behavior
  549.      * if lots of environment changes are being made.
  550.      */
  551.     for (i = 0; i < cacheSize; i++) {
  552. if ((environCache[i] == oldStr) || (environCache[i] == NULL)) {
  553.     break;
  554. }
  555.     }
  556.     if (i < cacheSize) {
  557. /*
  558.  * Replace or delete the old value.
  559.  */
  560. if (environCache[i]) {
  561.     ckfree(environCache[i]);
  562. }
  563. if (newStr) {
  564.     environCache[i] = newStr;
  565. } else {
  566.     for (; i < cacheSize-1; i++) {
  567. environCache[i] = environCache[i+1];
  568.     }
  569.     environCache[cacheSize-1] = NULL;
  570. }
  571.     } else {
  572.         int allocatedSize = (cacheSize + 5) * sizeof(char *);
  573. /*
  574.  * We need to grow the cache in order to hold the new string.
  575.  */
  576. newCache = (char **) ckalloc((unsigned) allocatedSize);
  577.         (VOID *) memset(newCache, (int) 0, (size_t) allocatedSize);
  578. if (environCache) {
  579.     memcpy((VOID *) newCache, (VOID *) environCache,
  580.     (size_t) (cacheSize * sizeof(char*)));
  581.     ckfree((char *) environCache);
  582. }
  583. environCache = newCache;
  584. environCache[cacheSize] = newStr;
  585. environCache[cacheSize+1] = NULL;
  586. cacheSize += 5;
  587.     }
  588. }
  589. /*
  590.  *----------------------------------------------------------------------
  591.  *
  592.  * TclFinalizeEnvironment --
  593.  *
  594.  * This function releases any storage allocated by this module
  595.  * that isn't still in use by the global environment.  Any
  596.  * strings that are still in the environment will be leaked.
  597.  *
  598.  * Results:
  599.  * None.
  600.  *
  601.  * Side effects:
  602.  * May deallocate storage.
  603.  *
  604.  *----------------------------------------------------------------------
  605.  */
  606. void
  607. TclFinalizeEnvironment()
  608. {
  609.     /*
  610.      * For now we just deallocate the cache array and none of the environment
  611.      * strings.  This may leak more memory that strictly necessary, since some
  612.      * of the strings may no longer be in the environment.  However,
  613.      * determining which ones are ok to delete is n-squared, and is pretty
  614.      * unlikely, so we don't bother.
  615.      */
  616.     if (environCache) {
  617. ckfree((char *) environCache);
  618. environCache = NULL;
  619. cacheSize    = 0;
  620. #ifndef USE_PUTENV
  621. environSize  = 0;
  622. #endif
  623.     }
  624. }
  625. #if defined(__CYGWIN__) && defined(__WIN32__)
  626. #include <windows.h>
  627. /*
  628.  * When using cygwin, when an environment variable changes, we need to synch
  629.  * with both the cygwin environment (in case the application C code calls
  630.  * fork) and the Windows environment (in case the application TCL code calls
  631.  * exec, which calls the Windows CreateProcess function).
  632.  */
  633. static void
  634. TclCygwinPutenv(str)
  635.     const char *str;
  636. {
  637.     char *name, *value;
  638.     /* Get the name and value, so that we can change the environment
  639.        variable for Windows.  */
  640.     name = (char *) alloca (strlen (str) + 1);
  641.     strcpy (name, str);
  642.     for (value = name; *value != '=' && *value != ''; ++value)
  643. ;
  644.     if (*value == '') {
  645.     /* Can't happen.  */
  646.     return;
  647. }
  648.     *value = '';
  649.     ++value;
  650.     if (*value == '') {
  651. value = NULL;
  652.     }
  653.     /* Set the cygwin environment variable.  */
  654. #undef putenv
  655.     if (value == NULL) {
  656. unsetenv (name);
  657.     } else {
  658. putenv(str);
  659.     }
  660.     /*
  661.      * Before changing the environment variable in Windows, if this is PATH,
  662.      * we need to convert the value back to a Windows style path.
  663.      *
  664.      * FIXME: The calling program may know it is running under windows, and
  665.      * may have set the path to a Windows path, or, worse, appended or
  666.      * prepended a Windows path to PATH.
  667.      */
  668.     if (strcmp (name, "PATH") != 0) {
  669. /* If this is Path, eliminate any PATH variable, to prevent any
  670.    confusion.  */
  671. if (strcmp (name, "Path") == 0) {
  672.     SetEnvironmentVariable ("PATH", (char *) NULL);
  673.     unsetenv ("PATH");
  674. }
  675. SetEnvironmentVariable (name, value);
  676.     } else {
  677. char *buf;
  678.     /* Eliminate any Path variable, to prevent any confusion.  */
  679. SetEnvironmentVariable ("Path", (char *) NULL);
  680. unsetenv ("Path");
  681. if (value == NULL) {
  682.     buf = NULL;
  683. } else {
  684.     int size;
  685.     size = cygwin_posix_to_win32_path_list_buf_size (value);
  686.     buf = (char *) alloca (size + 1);
  687.     cygwin_posix_to_win32_path_list (value, buf);
  688. }
  689. SetEnvironmentVariable (name, buf);
  690.     }
  691. }
  692. #endif /* __CYGWIN__ && __WIN32__ */