OSDN Git Service

Rework setenv, getenv and friends per the latest glibc code, but cleaned
authorEric Andersen <andersen@codepoet.org>
Thu, 30 May 2002 23:49:43 +0000 (23:49 -0000)
committerEric Andersen <andersen@codepoet.org>
Thu, 30 May 2002 23:49:43 +0000 (23:49 -0000)
up for readability.   Merge in putenv.  Add clearenv as a side effect.
 -Erik

libc/stdlib/Makefile
libc/stdlib/getenv.c
libc/stdlib/putenv.c [deleted file]
libc/stdlib/setenv.c

index e69ec4e..d7cdb31 100644 (file)
@@ -45,9 +45,9 @@ MSRC2=atexit.c
 MOBJ2=atexit.o on_exit.o __exit_handler.o exit.o
 
 CSRC = abort.c getenv.c mktemp.c realpath.c \
-       mkstemp.c mkstemp64.c putenv.c rand.c random.c random_r.c setenv.c \
-       system.c div.c ldiv.c getpt.c ptsname.c grantpt.c unlockpt.c gcvt.c
-CSRC+=  drand48.c drand48-iter.c drand48_r.c erand48.c erand48_r.c \
+       mkstemp.c mkstemp64.c rand.c random.c random_r.c setenv.c \
+       system.c div.c ldiv.c getpt.c ptsname.c grantpt.c unlockpt.c
+CSRC+=  gcvt.c drand48.c drand48-iter.c drand48_r.c erand48.c erand48_r.c \
        jrand48.c jrand48_r.c lrand48.c lrand48_r.c mrand48.c mrand48_r.c \
        nrand48.c nrand48_r.c rand_r.c srand48.c srand48_r.c
 ifeq ($(HAS_FLOATING_POINT),true)
index ca50402..588f696 100644 (file)
@@ -7,20 +7,19 @@
 #include <unistd.h>
 #include <malloc.h>
 
-char *getenv(var)
-const char *var;
+char *getenv(const char *var)
 {
-       char **p;
-       int len;
+    char **p;
+    int len;
 
-       len = strlen(var);
+    len = strlen(var);
 
-       if (!__environ)
-               return 0;
+    if (!__environ)
+       return NULL;
 
-       for (p = __environ; *p; p++) {
-               if (memcmp(var, *p, len) == 0 && (*p)[len] == '=')
-                       return *p + len + 1;
-       }
-       return 0;
+    for (p = __environ; *p; p++) {
+       if (memcmp(var, *p, len) == 0 && (*p)[len] == '=')
+           return *p + len + 1;
+    }
+    return NULL;
 }
diff --git a/libc/stdlib/putenv.c b/libc/stdlib/putenv.c
deleted file mode 100644 (file)
index b5a202b..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
- * This file is part of the Linux-8086 C library and is distributed
- * under the GNU Library General Public License.
- */
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <malloc.h>
-
-#define ADD_NUM 4
-
-int putenv (char *var)
-{
-       static char **mall_env = 0;
-       static int extras = 0;
-       char **p, **d;
-       char *r;
-       int len;
-
-       r = strchr(var, '=');
-       if (r == 0)
-               len = strlen(var);
-       else
-               len = r - var;
-
-       if (!__environ) {
-               __environ = (char **) malloc(ADD_NUM * sizeof(char *));
-               memset(__environ, 0, sizeof(char *) * ADD_NUM);
-
-               extras = ADD_NUM;
-       }
-
-       for (p = __environ; *p; p++) {
-               if (memcmp(var, *p, len) == 0 && (*p)[len] == '=') {
-                       while ((p[0] = p[1]))
-                               p++;
-                       extras++;
-                       break;
-               }
-       }
-       if (r == 0)
-               return 0;
-       if (extras <= 0) {                      /* Need more space */
-               d = malloc((p - __environ + 1 + ADD_NUM) * sizeof(char *));
-
-               if (d == 0)
-                       return -1;
-
-               memcpy((void *) d, (void *) __environ,
-
-                          (p - __environ + 1) * sizeof(char *));
-               p = d + (p - __environ);
-               extras = ADD_NUM;
-
-               if (mall_env)
-                       free(mall_env);
-               __environ = d;
-               mall_env = d;
-       }
-       *p++ = strdup((char *) var);
-       *p = '\0';
-       extras--;
-
-       return 0;
-}
index d304cb4..a7c2cb3 100644 (file)
-/* Copyright (C) 1992, 1995 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
-modify it under the terms of the GNU Library General Public License as
-published by the Free Software Foundation; either version 2 of the
-License, or (at your option) any later version.
-
-The GNU C Library is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-Library General Public License for more details.
-
-You should have received a copy of the GNU Library General Public
-License along with the GNU C Library; see the file COPYING.LIB.  If
-not, write to the Free Software Foundation, Inc., 675 Mass Ave,
-Cambridge, MA 02139, USA.  */
-
+/* Copyright (C) 1992,95,96,97,98,99,2000,2001 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
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  
+   
+   modified for uClibc by Erik Andersen <andersen@codepoet.org>
+   */
+
+#include <features.h>
+#include <errno.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
-#include <errno.h>
-
 
-#if defined(_REENTRENT) || defined(_THREAD_SAFE)
-# include <pthread.h>
+#ifdef __UCLIBC_HAS_THREADS__
+/* 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
+
+/* If this variable is not a null pointer we allocated the current
+   environment.  */
+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 __add_to_environ (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 = value != NULL ? strlen (value) + 1 : 0;
+
+    LOCK;
+
+    /* We have to get the pointer now that we have the lock and not earlier
+       since another thread might have created a new environment.  */
+    ep = __environ;
+
+    size = 0;
+    if (ep != NULL) {
+       for (; *ep != NULL; ++ep) {
+           if (!strncmp (*ep, name, namelen) && (*ep)[namelen] == '=')
+               break;
+           else
+               ++size;
+       }
+    }
 
-/* We need to initialize the mutex.  For this we use a method provided
-   by pthread function 'pthread_once'.  For this we need a once block.  */
-static pthread_once__t _once_block = pthread_once_init;
+    if (ep == NULL || *ep == NULL) {
+       char **new_environ;
 
-/* This is the mutex which protects the global environment of simultaneous
-   modifications.  */
-static pthread_mutex_t _setenv_mutex;
+       /* We allocated this space; we can extend it.  */
+       new_environ = (char **) realloc (last_environ,
+               (size + 2) * sizeof (char *));
+       if (new_environ == NULL) {
+           UNLOCK;
+           return -1;
+       }
 
-static void
-DEFUN_VOID(_init_setenv_mutex)
-{
-  pthread_mutex_init(&_setenv_mutex, pthread_mutexattr_default);
-}
+       /* 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.  */
+           new_environ[size] = (char *) malloc (namelen + 1 + vallen);
+           if (new_environ[size] == NULL) {
+               __set_errno (ENOMEM);
+               UNLOCK;
+               return -1;
+           }
 
-# define LOCK() \
-   do { pthread_once(&_once_block, _init_setenv_mutex);
-        pthread_mutex_lock(&_setenv_mutex); } while (0)
-# define UNLOCK() pthread_mutex_unlock(&_setenv_mutex)
+           memcpy (new_environ[size], name, namelen);
+           new_environ[size][namelen] = '=';
+           memcpy (&new_environ[size][namelen + 1], value, vallen);
+       }
 
-#else /* !_REENTRENT && !_THREAD_SAFE */
+       if (__environ != last_environ) {
+           memcpy ((char *) new_environ, (char *) __environ,
+                   size * sizeof (char *));
+       }
 
-# define LOCK()
-# define UNLOCK()
+       new_environ[size + 1] = NULL;
+       last_environ = __environ = new_environ;
+    } else if (replace) {
+       char *np;
+
+       /* Use the user string if given.  */
+       if (combined != NULL) {
+           np = (char *) combined;
+       } else {
+           np = malloc (namelen + 1 + vallen);
+           if (np == NULL) {
+               UNLOCK;
+               return -1;
+           }
+           memcpy (np, name, namelen);
+           np[namelen] = '=';
+           memcpy (&np[namelen + 1], value, vallen);
+       }
+       *ep = np;
+    }
 
-#endif /* _REENTRENT || _THREAD_SAFE */
+    UNLOCK;
+    return 0;
+}
 
-int setenv(const char *name, const char *value, int replace)
+int setenv (const char *name, const char *value, int replace)
 {
-  register char **ep;
-  register size_t size;
-  const size_t namelen = strlen (name);
-  const size_t vallen = strlen (value);
-  int result = 0;
-
-  LOCK();
-
-  size = 0;
-  for (ep = __environ; *ep != NULL; ++ep)
-    if (!memcmp (*ep, name, namelen) && (*ep)[namelen] == '=')
-      break;
-    else
-      ++size;
-  
-  if (*ep == NULL)
-    {
-      static char **last_environ = NULL;
-      char **new_environ = (char **) malloc((size + 2) * sizeof(char *));
-      if (new_environ == NULL)
-       {
-         result = -1;
-         goto do_return;
-       }
-      (void) memcpy((__ptr_t) new_environ, (__ptr_t) __environ, size * sizeof(char *));
-
-      new_environ[size] = malloc (namelen + 1 + vallen + 1);
-      if (new_environ[size] == NULL)
-       {
-         free (new_environ);
-         __set_errno(ENOMEM);
-         result = -1;
-         goto do_return;
-       }
-      memcpy (new_environ[size], name, namelen);
-      new_environ[size][namelen] = '=';
-      memcpy (&new_environ[size][namelen + 1], value, vallen + 1);
+    return __add_to_environ (name, value, NULL, replace);
+}
 
-      new_environ[size + 1] = NULL;
+int unsetenv (const char *name)
+{
+    size_t len;
+    char **ep;
 
-      if (last_environ != NULL)
-       free ((__ptr_t) last_environ);
-      last_environ = new_environ;
-      __environ = new_environ;
+    if (name == NULL || *name == '\0' || strchr (name, '=') != NULL) {
+       __set_errno (EINVAL);
+       return -1;
     }
-  else if (replace)
-    {
-      size_t len = strlen (*ep);
-      if (len < namelen + 1 + vallen)
-       {
-         char *new = malloc (namelen + 1 + vallen + 1);
-         if (new == NULL)
-           {
-             result = -1;
-             goto do_return;
-           }
-         *ep = new;
-         memcpy (*ep, name, namelen);
-         (*ep)[namelen] = '=';
+
+    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;
        }
-      memcpy (&(*ep)[namelen + 1], value, vallen + 1);
     }
-
-do_return:
-  UNLOCK();
-  return result;
+    UNLOCK;
+    return 0;
 }
 
+/* The `clearenv' was planned to be added to POSIX.1 but probably
+   never made it.  Nevertheless the POSIX.9 standard (POSIX bindings
+   for Fortran 77) requires this function.  */
+int clearenv (void)
+{
+    LOCK;
+    if (__environ == last_environ && __environ != NULL) {
+       /* We allocated this environment so we can free it.  */
+       free (__environ);
+       last_environ = NULL;
+    }
+    /* Clear the environment pointer removes the whole environment.  */
+    __environ = NULL;
+    UNLOCK;
+    return 0;
+}
 
-int unsetenv (const char *name)
+/* Put STRING, which is of the form "NAME=VALUE", in the environment.  */
+int putenv (char *string)
 {
-  register char **ep;
-  register char **dp;
-  const size_t namelen = strlen (name);
-
-  LOCK();
-
-  for (dp = ep = __environ; *ep != NULL; ++ep)
-    if (memcmp (*ep, name, namelen) || (*ep)[namelen] != '=')
-      {
-       *dp = *ep;
-       ++dp;
-      }
-  *dp = NULL;
-
-  UNLOCK();
-  return 0;
+    int result;
+    const char *const name_end = strchr (string, '=');
+
+    if (name_end != NULL) {
+       char *name = strndup(string, name_end - string);
+       result = __add_to_environ (name, NULL, string, 1);
+       free(name);
+       return(result);
+    }
+    __unsetenv (string);
+    return 0;
 }
+