Include "xalloc.h".
[gnulib.git] / lib / putenv.c
index 77f720f..f5ce1dd 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991, 1994, 1997, 1998 Free Software Foundation, Inc.
+/* Copyright (C) 1991, 1994, 1997, 1998, 2000, 2003 Free Software Foundation, Inc.
 
    NOTE: The canonical source of this file is maintained with the GNU C
    Library.  Bugs can be reported to bug-glibc@prep.ai.mit.edu.
    along with this program; if not, write to the Free Software Foundation,
    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
-#include <errno.h>
-
 #if HAVE_CONFIG_H
 # include <config.h>
 #endif
 
-/* Disable the definition of putenv to rpl_putenv (from config.h) in this
-   file.  Otherwise, we'd get conflicting prototypes for rpl_putenv on
-   systems like Irix 5.3.  */
-#undef putenv
-
-#include <sys/types.h>
+#include <stddef.h>
 
-#if defined (__GNU_LIBRARY__) || defined (HAVE_STDLIB_H)
-/* Some stdlib.h (e.g., Solaris 2.7) declare putenv with a non-const argument.
-   Since that would conflict with the declaration below, we rename putenv in
-   that incompatible prototype.  */
-# define putenv vendor_putenv_prototype
-# include <stdlib.h>
-# undef putenv
+/* Include errno.h *after* sys/types.h to work around header problems
+   on AIX 3.2.5.  */
+#include <errno.h>
+#if !_LIBC
+# if !defined errno
+extern int errno;
+# endif
+# define __set_errno(ev) ((errno) = (ev))
 #endif
 
+/* Don't include stdlib.h because some (e.g., Solaris 7) declare putenv
+   with a non-const argument.  That would conflict with the declaration of
+   rpl_putenv below (due to the #define putenv rpl_putenv from config.h).  */
+
+char *malloc ();
+void free ();
+
 #if defined (__GNU_LIBRARY__) || defined (HAVE_STRING_H)
 # include <string.h>
 #endif
 extern char **environ;
 #endif
 
+#if _LIBC
+/* 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)
+# define UNLOCK        __libc_lock_unlock (envlock)
+#else
+# define LOCK
+# define UNLOCK
+#endif
+
 #ifndef NULL
 # define NULL 0
 #endif
 
+static int
+unsetenv (const char *name)
+{
+  size_t len;
+  char **ep;
+
+  if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
+    {
+      __set_errno (EINVAL);
+      return -1;
+    }
+
+  len = strlen (name);
+
+  LOCK;
+
+  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;
+
+       do
+         dp[0] = dp[1];
+       while (*dp++);
+       /* Continue the loop in case NAME appears again.  */
+      }
+    else
+      ++ep;
+
+  UNLOCK;
+
+  return 0;
+}
+
 
-/* Put STRING, which is of the form "NAME=VALUE", in the environment.  */
+/* Put STRING, which is of the form "NAME=VALUE", in the environment.
+   If STRING contains no `=', then remove STRING from the environment.  */
 int
 rpl_putenv (const char *string)
 {
@@ -75,18 +124,7 @@ rpl_putenv (const char *string)
   if (name_end == NULL)
     {
       /* Remove the variable from the environment.  */
-      size = strlen (string);
-      for (ep = environ; *ep != NULL; ++ep)
-       if (!strncmp (*ep, string, size) && (*ep)[size] == '=')
-         {
-           while (ep[1] != NULL)
-             {
-               ep[0] = ep[1];
-               ++ep;
-             }
-           *ep = NULL;
-           return 0;
-         }
+      return unsetenv (string);
     }
 
   size = 0;
@@ -108,7 +146,7 @@ rpl_putenv (const char *string)
       new_environ[size] = (char *) string;
       new_environ[size + 1] = NULL;
       if (last_environ != NULL)
-       free ((void *) last_environ);
+       free (last_environ);
       last_environ = new_environ;
       environ = new_environ;
     }