faccessat: port to Solaris 10
[gnulib.git] / lib / putenv.c
index 77f720f..3c0f7ea 100644 (file)
@@ -1,11 +1,12 @@
-/* Copyright (C) 1991, 1994, 1997, 1998 Free Software Foundation, Inc.
+/* Copyright (C) 1991, 1994, 1997-1998, 2000, 2003-2012 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.
 
 
    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.
 
-   This program is free software; you can redistribute it and/or modify it
+   This program is free software: you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by the
    under the terms of the GNU General Public License as published by the
-   Free Software Foundation; either version 2, or (at your option) any
+   Free Software Foundation; either version 3 of the License, or any
    later version.
 
    This program is distributed in the hope that it will be useful,
    later version.
 
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software Foundation,
-   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 
-#include <errno.h>
-
-#if HAVE_CONFIG_H
-# include <config.h>
-#endif
+#include <config.h>
 
 
-/* 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
+/* Specification.  */
+#include <stdlib.h>
 
 
-#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>
+#ifndef __set_errno
+# define __set_errno(ev) ((errno) = (ev))
 #endif
 
 #endif
 
-#if defined (__GNU_LIBRARY__) || defined (HAVE_STRING_H)
-# include <string.h>
-#endif
-#if defined (__GNU_LIBRARY__) || defined (HAVE_UNISTD_H)
-# include <unistd.h>
-#endif
+#include <string.h>
+#include <unistd.h>
 
 
-#if !defined (__GNU_LIBRARY__) && !defined (HAVE_STRCHR)
-# define strchr index
-#endif
-#if !defined (__GNU_LIBRARY__) && !defined (HAVE_MEMCPY)
-# define memcpy(d,s,n) bcopy ((s), (d), (n))
+#if _LIBC
+# if HAVE_GNU_LD
+#  define environ __environ
+# else
+extern char **environ;
+# endif
 #endif
 
 #endif
 
-#if HAVE_GNU_LD
-# define environ __environ
+#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
 #else
-extern char **environ;
+# define LOCK
+# define UNLOCK
 #endif
 
 #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
 int
-rpl_putenv (const char *string)
+putenv (char *string)
 {
   const char *const name_end = strchr (string, '=');
   register size_t size;
 {
   const char *const name_end = strchr (string, '=');
   register size_t size;
@@ -75,24 +102,13 @@ rpl_putenv (const char *string)
   if (name_end == NULL)
     {
       /* Remove the variable from the environment.  */
   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;
   for (ep = environ; *ep != NULL; ++ep)
     if (!strncmp (*ep, string, name_end - string) &&
     }
 
   size = 0;
   for (ep = environ; *ep != NULL; ++ep)
     if (!strncmp (*ep, string, name_end - string) &&
-       (*ep)[name_end - string] == '=')
+        (*ep)[name_end - string] == '=')
       break;
     else
       ++size;
       break;
     else
       ++size;
@@ -102,18 +118,17 @@ rpl_putenv (const char *string)
       static char **last_environ = NULL;
       char **new_environ = (char **) malloc ((size + 2) * sizeof (char *));
       if (new_environ == NULL)
       static char **last_environ = NULL;
       char **new_environ = (char **) malloc ((size + 2) * sizeof (char *));
       if (new_environ == NULL)
-       return -1;
+        return -1;
       (void) memcpy ((void *) new_environ, (void *) environ,
       (void) memcpy ((void *) new_environ, (void *) environ,
-                    size * sizeof (char *));
+                     size * sizeof (char *));
       new_environ[size] = (char *) string;
       new_environ[size + 1] = NULL;
       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;
     }
   else
       last_environ = new_environ;
       environ = new_environ;
     }
   else
-    *ep = (char *) string;
+    *ep = string;
 
   return 0;
 }
 
   return 0;
 }