aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog10
-rw-r--r--include/stdlib.h3
-rw-r--r--sysdeps/generic/putenv.c4
-rw-r--r--sysdeps/generic/setenv.c152
4 files changed, 96 insertions, 73 deletions
diff --git a/ChangeLog b/ChangeLog
index 2208c60..61b75f3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,15 @@
1999-07-29 Ulrich Drepper <drepper@cygnus.com>
+ * sysdeps/generic/setenv.c: Move setenv code in new function
+ __add_to_environ. Add new parameter specifying already
+ constructed string for the environment.
+ (setenv): Call __add_to_environ with new parameter set to NULL.
+ (unsetenv): Really test all elements for duplicated name. Missed those
+ cases where the two are following each other.
+ * sysdeps/generic/putenv.c: Use __add_to_environ instead of setenv.
+ * include/stdlib.h: Add prototype of __add_to_environ.
+ * stdlib/tst-environ.c: New file.
+
* sysdeps/i386/bits/string.h (__memset_cc): Fix typo in last patch.
* nis/nss_nis/nis-initgroups.c (_nss_nis_initgroups): Correct size
diff --git a/include/stdlib.h b/include/stdlib.h
index c15d364..187c458 100644
--- a/include/stdlib.h
+++ b/include/stdlib.h
@@ -46,6 +46,9 @@ extern char *__canonicalize_file_name __P ((__const char *__name));
extern char *__realpath __P ((__const char *__name, char *__resolved));
extern int __ptsname_r __P ((int __fd, char *__buf, size_t __buflen));
extern int __getpt __P ((void));
+
+extern int __add_to_environ (const char *name, const char *value,
+ const char *combines, int replace);
#endif
#undef __Need_M_And_C
diff --git a/sysdeps/generic/putenv.c b/sysdeps/generic/putenv.c
index 3fcd5f9..75fafad 100644
--- a/sysdeps/generic/putenv.c
+++ b/sysdeps/generic/putenv.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991, 94, 95, 96, 97, 98 Free Software Foundation, Inc.
+/* Copyright (C) 1991, 94, 95, 96, 97, 98, 99 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -64,7 +64,7 @@ putenv (string)
memcpy (name, string, name_end - string);
name[name_end - string] = '\0';
#endif
- return __setenv (name, name_end + 1, 1);
+ return __add_to_environ (name, NULL, string, 1);
}
__unsetenv (string);
diff --git a/sysdeps/generic/setenv.c b/sysdeps/generic/setenv.c
index a5818d0..fc58e9b 100644
--- a/sysdeps/generic/setenv.c
+++ b/sysdeps/generic/setenv.c
@@ -16,23 +16,6 @@
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-/* Issues:
-
- 1. putenv must not use setenv since the string provided by the user
- must be used, not a copy
-
- 2. a common function should determine the place where to insert the
- new entry and if necessary take care of extending the array
-
- 3. It must be kept track of whether an entry was inserted via putenv
- or setenv. In the former case the entry must not be put into
- the search tree since removing it could mean it will not be
- available anymore (e.g., when allocated on the stack)
-
- To handle this an array parallel to the __environ array must specify
- whether the entry was added via putenv or not
-*/
-
#if HAVE_CONFIG_H
# include <config.h>
#endif
@@ -117,16 +100,23 @@ static void *known_values;
static char **last_environ;
+/* This function is used by `setenv' and `putenv'. The difference between
+ the two functions is that for the former must create a new string which
+ is then placed in the environment, while the argument of `putenv'
+ must be used directly. This is all complicated by the fact that we try
+ to reuse values once generated for a `setenv' call since we can never
+ free the strings. */
int
-setenv (name, value, replace)
+__add_to_environ (name, value, combined, replace)
const char *name;
const char *value;
+ const char *combined;
int replace;
{
register char **ep;
register size_t size;
const size_t namelen = strlen (name);
- const size_t vallen = strlen (value) + 1;
+ const size_t vallen = value != NULL ? strlen (value) + 1 : 0;
LOCK;
@@ -156,37 +146,49 @@ setenv (name, value, replace)
return -1;
}
- /* See whether the value is already known. */
+ /* If the whole entry is given add it. */
+ if (combined != NULL)
+ /* We must not add the string to the search tree since it belongs
+ to the user. */
+ new_environ[size] = (char *) combined;
+ else
+ {
+ /* See whether the value is already known. */
#ifdef USE_TSEARCH
- new_value = alloca (namelen + 1 + vallen);
+ new_value = (char *) alloca (namelen + 1 + vallen);
# ifdef _LIBC
- __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1),
- value, vallen);
+ __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1),
+ value, vallen);
# else
- memcpy (new_value, name, namelen);
- new_value[namelen] = '=';
- memcpy (&new_value[namelen + 1], value, vallen);
+ memcpy (new_value, name, namelen);
+ new_value[namelen] = '=';
+ memcpy (&new_value[namelen + 1], value, vallen);
# endif
- new_environ[size] = KNOWN_VALUE (new_value);
- if (new_environ[size] == NULL)
-#endif
- {
- new_environ[size] = malloc (namelen + 1 + vallen);
+ new_environ[size] = KNOWN_VALUE (new_value);
if (new_environ[size] == NULL)
+#endif
{
- __set_errno (ENOMEM);
- UNLOCK;
- return -1;
- }
+ new_environ[size] = (char *) malloc (namelen + 1 + vallen);
+ if (new_environ[size] == NULL)
+ {
+ __set_errno (ENOMEM);
+ UNLOCK;
+ return -1;
+ }
#ifdef USE_TSEARCH
- memcpy (new_environ[size], new_value, namelen + 1 + vallen);
+ memcpy (new_environ[size], new_value, namelen + 1 + vallen);
#else
- memcpy (new_environ[size], name, namelen);
- new_environ[size][namelen] = '=';
- memcpy (&new_environ[size][namelen + 1], value, vallen);
+ memcpy (new_environ[size], name, namelen);
+ new_environ[size][namelen] = '=';
+ memcpy (&new_environ[size][namelen + 1], value, vallen);
#endif
+ /* And save the value now. We cannot do this when we remove
+ the string since then we cannot decide whether it is a
+ user string or not. */
+ STORE_VALUE (new_environ[size]);
+ }
}
if (__environ != last_environ)
@@ -199,43 +201,47 @@ setenv (name, value, replace)
}
else if (replace)
{
- char *new_value;
char *np;
- /* The existing string is too short; malloc a new one. */
+ /* Use the user string if given. */
+ if (combined != NULL)
+ np = (char *) combined;
+ else
+ {
#ifdef USE_TSEARCH
- new_value = alloca (namelen + 1 + vallen);
+ char *new_value = alloca (namelen + 1 + vallen);
# ifdef _LIBC
- __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1),
- value, vallen);
+ __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1),
+ value, vallen);
# else
- memcpy (new_value, name, namelen);
- new_value[namelen] = '=';
- memcpy (&new_value[namelen + 1], value, vallen);
+ memcpy (new_value, name, namelen);
+ new_value[namelen] = '=';
+ memcpy (&new_value[namelen + 1], value, vallen);
# endif
- np = KNOWN_VALUE (new_value);
- if (np == NULL)
-#endif
- {
- np = malloc (namelen + 1 + vallen);
+ np = KNOWN_VALUE (new_value);
if (np == NULL)
+#endif
{
- UNLOCK;
- return -1;
- }
+ np = malloc (namelen + 1 + vallen);
+ if (np == NULL)
+ {
+ UNLOCK;
+ return -1;
+ }
#ifdef USE_TSEARCH
- memcpy (np, new_value, namelen + 1 + vallen);
+ memcpy (np, new_value, namelen + 1 + vallen);
#else
- memcpy (np, name, namelen);
- np[namelen] = '=';
- memcpy (&np[namelen + 1], value, vallen);
+ memcpy (np, name, namelen);
+ np[namelen] = '=';
+ memcpy (&np[namelen + 1], value, vallen);
#endif
+ /* And remember the value. */
+ STORE_VALUE (np);
+ }
}
- /* Keep the old value around. */
- STORE_VALUE (*ep);
*ep = np;
}
@@ -244,6 +250,15 @@ setenv (name, value, replace)
return 0;
}
+int
+setenv (name, value, replace)
+ const char *name;
+ const char *value;
+ int replace;
+{
+ return __add_to_environ (name, value, NULL, replace);
+}
+
void
unsetenv (name)
const char *name;
@@ -253,20 +268,20 @@ unsetenv (name)
LOCK;
- for (ep = __environ; *ep != NULL; ++ep)
+ ep = __environ;
+ while (*ep != NULL)
if (!strncmp (*ep, name, len) && (*ep)[len] == '=')
{
/* Found it. Remove this pointer by moving later ones back. */
char **dp = ep;
- /* Store the value so that we can reuse it later. */
- STORE_VALUE (*ep);
-
do
dp[0] = dp[1];
while (*dp++);
/* Continue the loop in case NAME appears again. */
}
+ else
+ ++ep;
UNLOCK;
}
@@ -281,12 +296,7 @@ clearenv ()
if (__environ == last_environ && __environ != NULL)
{
- /* We allocated this environment so we can free it. Store all the
- strings. */
- char **ep = __environ;
- while (*ep != NULL)
- STORE_VALUE (*ep++);
-
+ /* We allocated this environment so we can free it. */
free (__environ);
last_environ = NULL;
}