home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / crt / src / putenv.c < prev    next >
C/C++ Source or Header  |  1998-06-17  |  13KB  |  474 lines

  1. /***
  2. *putenv.c - put an environment variable into the environment
  3. *
  4. *       Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. *       defines _putenv() - adds a new variable to environment; does not
  8. *       change global environment, only the process' environment.
  9. *
  10. *******************************************************************************/
  11.  
  12. #ifdef _WIN32
  13.  
  14.  
  15. #include <windows.h>
  16. #include <cruntime.h>
  17. #include <internal.h>
  18. #include <mtdll.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <tchar.h>
  22. #include <dbgint.h>
  23.  
  24. #ifndef CRTDLL
  25.  
  26. /*
  27.  * Flag checked by getenv() and _putenv() to determine if the environment has
  28.  * been initialized.
  29.  */
  30. extern int __env_initialized;
  31.  
  32. #endif  /* CRTDLL */
  33.  
  34. /***
  35. *int _putenv(option) - add/replace/remove variable in environment
  36. *
  37. *Purpose:
  38. *       option should be of the form "option=value".  If a string with the
  39. *       given option part already exists, it is replaced with the given
  40. *       string; otherwise the given string is added to the environment.
  41. *       If the string is of the form "option=", then the string is
  42. *       removed from the environment, if it exists.  If the string has
  43. *       no equals sign, error is returned.
  44. *
  45. *Entry:
  46. *       char *option - option string to set in the environment list.
  47. *           should be of the form "option=value".
  48. *
  49. *Exit:
  50. *       returns 0 if OK, -1 if fails.
  51. *
  52. *Exceptions:
  53. *
  54. *Warning:
  55. *       This code will not work if variables are removed from the
  56. *       environment by deleting them from environ[].  Use _putenv("option=")
  57. *       to remove a variable.
  58. *
  59. *******************************************************************************/
  60.  
  61. #ifdef _MT
  62.  
  63. #ifdef WPRFLAG
  64. int __cdecl _wputenv (
  65. #else  /* WPRFLAG */
  66. int __cdecl _putenv (
  67. #endif  /* WPRFLAG */
  68.         const _TSCHAR *option
  69.         )
  70. {
  71.         int retval;
  72.  
  73.         _mlock(_ENV_LOCK);
  74.  
  75. #ifdef WPRFLAG
  76.         retval = _wputenv_lk(option);
  77. #else  /* WPRFLAG */
  78.         retval = _putenv_lk(option);
  79. #endif  /* WPRFLAG */
  80.  
  81.         _munlock(_ENV_LOCK);
  82.  
  83.         return retval;
  84. }
  85.  
  86. #ifdef WPRFLAG
  87. int __cdecl _wputenv_lk (
  88. #else  /* WPRFLAG */
  89. int __cdecl _putenv_lk (
  90. #endif  /* WPRFLAG */
  91.         const _TSCHAR *option
  92.         )
  93.  
  94. #else  /* _MT */
  95.  
  96. #ifdef WPRFLAG
  97. int __cdecl _wputenv (
  98. #else  /* WPRFLAG */
  99. int __cdecl _putenv (
  100. #endif  /* WPRFLAG */
  101.         const _TSCHAR *option
  102.         )
  103.  
  104. #endif  /* _MT */
  105.  
  106. {
  107.         int size;
  108.         _TSCHAR * newoption;
  109.  
  110. #ifndef CRTDLL
  111.         /*
  112.          * Make sure the environment is initialized.
  113.          */
  114.         if  ( !__env_initialized )
  115.             return -1;
  116. #endif  /* CRTDLL */
  117.  
  118.         /*
  119.          * At startup, we obtain the 'native' flavor of environment strings
  120.          * from the OS. So a "main" program has _environ and a "wmain" has
  121.          * _wenviron loaded at startup. Only when the user gets or puts the
  122.          * 'other' flavor do we convert it.
  123.          */
  124.  
  125.         /* copy the new environent string */
  126.         if ( (newoption = (_TSCHAR *)_malloc_crt((_tcslen(option)+1) *
  127.              sizeof(_TSCHAR))) == NULL )
  128.             return -1;
  129.  
  130.         _tcscpy(newoption, option);
  131.  
  132. #ifdef WPRFLAG
  133.         if (__crtwsetenv(newoption, 1) != 0)
  134.             return -1;
  135.  
  136.         /* If other environment type exists, set it */
  137.         if (_environ)
  138.         {
  139.             char *mboption;
  140.  
  141.             /* find out how much space is needed */
  142.             if ( (size = WideCharToMultiByte(CP_OEMCP, 0, option, -1, NULL,
  143.                  0, NULL, NULL)) == 0 )
  144.                 return -1;
  145.  
  146.             /* allocate space for variable */
  147.             if ((mboption = (char *) _malloc_crt(size * sizeof(char))) == NULL)
  148.                 return -1;
  149.  
  150.             /* convert it */
  151.             if ( WideCharToMultiByte(CP_OEMCP, 0, option, -1, mboption, size,
  152.                  NULL, NULL) == 0 )
  153.                 return -1;
  154.  
  155.             /* set it - this is not primary call, so set primary == 0 */
  156.             if (__crtsetenv(mboption, 0) != 0)
  157.                 return -1;
  158.         }
  159. #else  /* WPRFLAG */
  160.         /* Set requested environment type, primary call */
  161.         if (__crtsetenv(newoption, 1) != 0)
  162.             return -1;
  163.  
  164.         /* If other environment type exists, set it */
  165.         if (_wenviron)
  166.         {
  167.             wchar_t *woption;
  168.  
  169.             /* find out how much space is needed */
  170.             if ( (size = MultiByteToWideChar(CP_OEMCP, 0, option, -1, NULL, 0))
  171.                  == 0)
  172.                 return -1;
  173.  
  174.             /* allocate space for variable */
  175.             if ( (woption = (wchar_t *) _malloc_crt(size * sizeof(wchar_t)))
  176.                  == NULL )
  177.                 return -1;
  178.  
  179.             /* convert it */
  180.             if ( MultiByteToWideChar(CP_OEMCP, 0, option, -1, woption, size)
  181.                  == 0 )
  182.                 return -1;
  183.  
  184.             /* set it - this is not primary call, so set primary == 0 */
  185.             if (__crtwsetenv(woption, 0) != 0)
  186.                 return -1;
  187.         }
  188. #endif  /* WPRFLAG */
  189.  
  190.         return 0;
  191. }
  192.  
  193.  
  194.  
  195. /***
  196. *int findenv(name, len) - [STATIC]
  197. *
  198. *Purpose:
  199. *       Scan for the given string within the environment
  200. *
  201. *Entry:
  202. *
  203. *Exit:
  204. *       Returns the offset in "environ[]" of the given variable
  205. *       Returns the negative of the length of environ[] if not found.
  206. *       Returns 0 if the environment is empty.
  207. *
  208. *       [NOTE: That a 0 return can mean that the environment is empty
  209. *       or that the string was found as the first entry in the array.]
  210. *
  211. *Exceptions:
  212. *
  213. *******************************************************************************/
  214.  
  215. #ifdef WPRFLAG
  216. static int __cdecl wfindenv (
  217. #else  /* WPRFLAG */
  218. static int __cdecl findenv (
  219. #endif  /* WPRFLAG */
  220.         const _TSCHAR *name,
  221.         int len
  222.         )
  223. {
  224.         _TSCHAR **env;
  225.  
  226.         for ( env = _tenviron ; *env != NULL ; env++ ) {
  227.             /*
  228.              * See if first len characters match, up to case
  229.              */
  230.             if ( _tcsnicoll(name, *env, len) == 0 )
  231.                 /*
  232.                  * the next character of the environment string must
  233.                  * be an '=' or a '\0'
  234.                  */
  235.                 if ( (*env)[len] == _T('=') || (*env)[len] == _T('\0') )
  236.                     return(env - _tenviron);
  237. //
  238. // We cannot break here since findenv must report the total number of strings.
  239. //              else
  240. //                  break;
  241.         }
  242.  
  243.         return(-(env - _tenviron));
  244. }
  245.  
  246.  
  247. #else  /* _WIN32 */
  248.  
  249.  
  250. #include <cruntime.h>
  251. #include <errno.h>
  252. #include <malloc.h>
  253. #include <stdlib.h>
  254. #include <string.h>
  255. #include <internal.h>
  256. #include <mtdll.h>
  257. #include <memory.h>
  258. #include <dbgint.h>
  259.  
  260. static int __cdecl findenv(const char *name, int len);
  261.  
  262. /***
  263. *int _putenv(option) - add/replace/remove variable in environment
  264. *
  265. *Purpose:
  266. *       option should be of the form "option=value".  If a string with the
  267. *       given option part already exists, it is replaced with the given
  268. *       string; otherwise the given string is added to the environment.
  269. *       If the string is of the form "option=", then the string is
  270. *       removed from the environment, if it exists.  If the string has
  271. *       no equals sign, error is returned.
  272. *
  273. *Entry:
  274. *       char *option - option string to set in the environment list.
  275. *           should be of the form "option=value".
  276. *
  277. *Exit:
  278. *       returns 0 if OK, -1 if fails.
  279. *
  280. *Exceptions:
  281. *
  282. *Warning:
  283. *       This code will not work if variables are removed from the
  284. *       environment by deleting them from environ[].  Use _putenv("option=")
  285. *       to remove a variable.
  286. *
  287. *******************************************************************************/
  288.  
  289. #ifdef _MT
  290.  
  291. int __cdecl _putenv (
  292.         const char *option
  293.         )
  294. {
  295.         int retval;
  296.  
  297.         _mlock(_ENV_LOCK);
  298.  
  299.         retval = _putenv_lk(option);
  300.  
  301.         _munlock(_ENV_LOCK);
  302.  
  303.         return retval;
  304. }
  305.  
  306. int __cdecl _putenv_lk (
  307.         const char *option
  308.         )
  309.  
  310. #else  /* _MT */
  311.  
  312. int __cdecl _putenv (
  313.         const char *option
  314.         )
  315.  
  316. #endif  /* _MT */
  317.  
  318. {
  319.         char **env;
  320.         const char *equal;
  321.         int ix;
  322.         int remove;     /* 1 means remove string from environment */
  323.  
  324.         /* check that the option string is valid and find the equal sign
  325.          */
  326.         if ( (option == NULL) || ((equal = strchr(option, '=')) == NULL) )
  327.             return(-1);
  328.  
  329.         /* check for the special case of '=' being the very first character
  330.          * of option. though the use of '=' in an environment variable name
  331.          * is documented as being illegal, the 'current directory' strings
  332.          * all look like this:
  333.          *
  334.          *  =<Drive Letter>:=<Drive Letter><fully qualified path>
  335.          *
  336.          * handle this by setting the equal pointer to point to the second
  337.          * '=' if it exists. Otherwise, handle as before.
  338.          */
  339.         if ( option == equal )
  340.             if ( (equal = strchr(option + 1, '=')) == NULL )
  341.                 equal = option;
  342.  
  343.         /* if the character following '=' is null, we are removing the
  344.          * the environment variable. Otherwise, we are adding or updating
  345.          * an environment variable.
  346.          */
  347.         remove = (*(equal + 1) == '\0');
  348.  
  349.         /* see if _environ array exists */
  350.         if (_environ == NULL) {
  351.             if ( remove )
  352.                 return 0;
  353.             else {
  354.                 /* get an array and init it to NULL */
  355.                 if ( (_environ = _malloc_crt(sizeof(void *))) == NULL)
  356.                     return -1;
  357.                 *_environ = NULL;
  358.             }
  359.         }
  360.  
  361.         /* init env pointer */
  362.  
  363.         env = _environ;
  364.  
  365.         /* See if the string is already in the environment */
  366.  
  367.         ix = findenv(option, equal - option);
  368.  
  369.         if ((ix >= 0) && (*env != NULL)) {
  370.             /* String is already in the environment -- overwrite/remove it.
  371.              */
  372.             if (remove) {
  373.                 /* removing -- move all the later strings up */
  374.                 for ( ; env[ix] != NULL; ++ix) {
  375.                     env[ix] = env[ix+1];
  376.                 }
  377.  
  378.                 /* shrink the environment memory block
  379.                    (ix now has number of strings, including NULL) --
  380.                    this realloc probably can't fail, since we're
  381.                    shrinking a mem block, but we're careful anyway. */
  382.                 if (env = (char **) _realloc_crt(env, ix * sizeof(char *)))
  383.                     _environ = env;
  384.             }
  385.             else {
  386.                 /* replace the option */
  387.                 env[ix] = (char *) option;
  388.             }
  389.         }
  390.         else {
  391.             /*
  392.              * String is NOT in the environment
  393.              */
  394.             if ( !remove )  {
  395.  
  396.                 /*
  397.                  * Append the string to the environ table. Note that
  398.                  * table must be grown to do this.
  399.                  */
  400.                 if (ix < 0)
  401.                     ix = -ix;    /* ix = length of environ table */
  402.  
  403.                 if ( (env = (char **)_realloc_crt(env, sizeof(char *) *
  404.                     (ix + 2))) == NULL )
  405.                     return -1;
  406.  
  407.                 env[ix] = (char *)option;
  408.                 env[ix + 1] = NULL;
  409.                 _environ = env;
  410.             }
  411.             else
  412.                 /*
  413.                  * We are asked to remove an environment var that
  414.                  * isn't there...just return success
  415.                  */
  416.                 return 0;
  417.         }
  418.  
  419.         return 0;
  420. }
  421.  
  422.  
  423. /***
  424. *int findenv(name, len) - [STATIC]
  425. *
  426. *Purpose:
  427. *       Scan for the given string within the environment
  428. *
  429. *Entry:
  430. *
  431. *Exit:
  432. *       Returns the offset in "environ[]" of the given variable
  433. *       Returns the negative of the length of environ[] if not found.
  434. *       Returns 0 if the environment is empty.
  435. *
  436. *       [NOTE: That a 0 return can mean that the environment is empty
  437. *       or that the string was found as the first entry in the array.]
  438. *
  439. *Exceptions:
  440. *
  441. *******************************************************************************/
  442.  
  443. static int __cdecl findenv (
  444.         const char *name,
  445.         int len
  446.         )
  447. {
  448.         char **env;
  449.  
  450.         for ( env = _environ ; *env != NULL ; env++ ) {
  451.             /*
  452.              * See if first len characters match, up to case
  453.              */
  454.             if ( _strnicmp(name, *env, len) == 0 )
  455.                 /*
  456.                  * the next character of the environment string must
  457.                  * be an '=' or a '\0'
  458.                  */
  459.                 if ( (*env)[len] == '=' || (*env)[len] == '\0' )
  460.                     return(env - _environ);
  461. //
  462. // We cannot break here since findenv must report the total number of strings.
  463. //              else
  464. //                  break;
  465.         }
  466.  
  467.         return(-(env - _environ));
  468. }
  469.  
  470.  
  471.  
  472. #endif  /* _WIN32 */
  473.  
  474.