diff options
Diffstat (limited to 'tests/putenv.c')
-rw-r--r-- | tests/putenv.c | 110 |
1 files changed, 86 insertions, 24 deletions
diff --git a/tests/putenv.c b/tests/putenv.c index 030f567..925bb2f 100644 --- a/tests/putenv.c +++ b/tests/putenv.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1991, 1994, 1997-1998, 2000, 2003-2010 Free Software +/* Copyright (C) 1991, 1994, 1997-1998, 2000, 2003-2015 Free Software Foundation, Inc. NOTE: The canonical source of this file is maintained with the GNU C @@ -34,14 +34,21 @@ #include <string.h> #include <unistd.h> -#if HAVE_GNU_LD -# define environ __environ -#else +#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ +# define WIN32_LEAN_AND_MEAN +# include <windows.h> +#endif + +#if _LIBC +# if HAVE_GNU_LD +# define environ __environ +# else extern char **environ; +# endif #endif #if _LIBC -/* This lock protects against simultaneous modifications of `environ'. */ +/* This lock protects against simultaneous modifications of 'environ'. */ # include <bits/libc-lock.h> __libc_lock_define_initialized (static, envlock) # define LOCK __libc_lock_lock (envlock) @@ -55,7 +62,9 @@ static int _unsetenv (const char *name) { size_t len; +#if !HAVE_DECL__PUTENV char **ep; +#endif if (name == NULL || *name == '\0' || strchr (name, '=') != NULL) { @@ -65,6 +74,21 @@ _unsetenv (const char *name) len = strlen (name); +#if HAVE_DECL__PUTENV + { + int putenv_result, putenv_errno; + char *name_ = malloc (len + 2); + memcpy (name_, name, len); + name_[len] = '='; + name_[len + 1] = 0; + putenv_result = _putenv (name_); + putenv_errno = errno; + free (name_); + __set_errno (putenv_errno); + return putenv_result; + } +#else + LOCK; ep = environ; @@ -85,17 +109,17 @@ _unsetenv (const char *name) UNLOCK; return 0; +#endif } /* Put STRING, which is of the form "NAME=VALUE", in the environment. - If STRING contains no `=', then remove STRING from the environment. */ + If STRING contains no '=', then remove STRING from the environment. */ int putenv (char *string) { - const char *const name_end = strchr (string, '='); - register size_t size; - register char **ep; + const char *name_end = strchr (string, '='); + char **ep; if (name_end == NULL) { @@ -103,30 +127,68 @@ putenv (char *string) return _unsetenv (string); } - size = 0; - for (ep = environ; *ep != NULL; ++ep) - if (!strncmp (*ep, string, name_end - string) && - (*ep)[name_end - string] == '=') +#if HAVE_DECL__PUTENV + /* Rely on _putenv to allocate the new environment. If other + parts of the application use _putenv, the !HAVE_DECL__PUTENV code + would fight over who owns the environ vector, causing a crash. */ + if (name_end[1]) + return _putenv (string); + else + { + /* _putenv ("NAME=") unsets NAME, so invoke _putenv ("NAME= ") + to allocate the environ vector and then replace the new + entry with "NAME=". */ + int putenv_result, putenv_errno; + char *name_x = malloc (name_end - string + sizeof "= "); + if (!name_x) + return -1; + memcpy (name_x, string, name_end - string + 1); + name_x[name_end - string + 1] = ' '; + name_x[name_end - string + 2] = 0; + putenv_result = _putenv (name_x); + putenv_errno = errno; + for (ep = environ; *ep; ep++) + if (strcmp (*ep, name_x) == 0) + { + *ep = string; + break; + } +# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ + if (putenv_result == 0) + { + /* _putenv propagated "NAME= " into the subprocess environment; + fix that by calling SetEnvironmentVariable directly. */ + name_x[name_end - string] = 0; + putenv_result = SetEnvironmentVariable (name_x, "") ? 0 : -1; + putenv_errno = ENOMEM; /* ENOMEM is the only way to fail. */ + } +# endif + free (name_x); + __set_errno (putenv_errno); + return putenv_result; + } +#else + for (ep = environ; *ep; ep++) + if (strncmp (*ep, string, name_end - string) == 0 + && (*ep)[name_end - string] == '=') break; - else - ++size; - if (*ep == NULL) + if (*ep) + *ep = string; + else { static char **last_environ = NULL; - char **new_environ = (char **) malloc ((size + 2) * sizeof (char *)); - if (new_environ == NULL) + size_t size = ep - environ; + char **new_environ = malloc ((size + 2) * sizeof *new_environ); + if (! new_environ) return -1; - (void) memcpy ((void *) new_environ, (void *) environ, - size * sizeof (char *)); - new_environ[size] = (char *) string; - new_environ[size + 1] = NULL; + new_environ[0] = string; + memcpy (new_environ + 1, environ, (size + 1) * sizeof *new_environ); free (last_environ); last_environ = new_environ; environ = new_environ; } - else - *ep = string; return 0; +#endif } |