Minor fixups to port to Solaris 10 with Sun C 5.8.
[gnulib.git] / lib / putenv.c
1 /* Copyright (C) 1991, 1994, 1997, 1998, 2000, 2003, 2004, 2005, 2006
2    Free Software Foundation, Inc.
3
4    NOTE: The canonical source of this file is maintained with the GNU C
5    Library.  Bugs can be reported to bug-glibc@prep.ai.mit.edu.
6
7    This program is free software; you can redistribute it and/or modify it
8    under the terms of the GNU General Public License as published by the
9    Free Software Foundation; either version 2, or (at your option) any
10    later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software Foundation,
19    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
20
21 #include <config.h>
22
23 /* undef putenv here, because some (e.g., Solaris 10) declare putenv in
24    with a non-const argument.  That would conflict with the declaration of
25    rpl_putenv below (due to the #define putenv rpl_putenv from config.h).  */
26 #undef putenv
27 int rpl_putenv (char const *);
28
29 #include <stddef.h>
30
31 /* Include errno.h *after* sys/types.h to work around header problems
32    on AIX 3.2.5.  */
33 #include <errno.h>
34 #ifndef __set_errno
35 # define __set_errno(ev) ((errno) = (ev))
36 #endif
37
38 #include <stdlib.h>
39 #include <string.h>
40 #include <unistd.h>
41
42 #if HAVE_GNU_LD
43 # define environ __environ
44 #else
45 extern char **environ;
46 #endif
47
48 #if _LIBC
49 /* This lock protects against simultaneous modifications of `environ'.  */
50 # include <bits/libc-lock.h>
51 __libc_lock_define_initialized (static, envlock)
52 # define LOCK   __libc_lock_lock (envlock)
53 # define UNLOCK __libc_lock_unlock (envlock)
54 #else
55 # define LOCK
56 # define UNLOCK
57 #endif
58
59 static int
60 unsetenv (const char *name)
61 {
62   size_t len;
63   char **ep;
64
65   if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
66     {
67       __set_errno (EINVAL);
68       return -1;
69     }
70
71   len = strlen (name);
72
73   LOCK;
74
75   ep = environ;
76   while (*ep != NULL)
77     if (!strncmp (*ep, name, len) && (*ep)[len] == '=')
78       {
79         /* Found it.  Remove this pointer by moving later ones back.  */
80         char **dp = ep;
81
82         do
83           dp[0] = dp[1];
84         while (*dp++);
85         /* Continue the loop in case NAME appears again.  */
86       }
87     else
88       ++ep;
89
90   UNLOCK;
91
92   return 0;
93 }
94
95
96 /* Put STRING, which is of the form "NAME=VALUE", in the environment.
97    If STRING contains no `=', then remove STRING from the environment.  */
98 int
99 rpl_putenv (const char *string)
100 {
101   const char *const name_end = strchr (string, '=');
102   register size_t size;
103   register char **ep;
104
105   if (name_end == NULL)
106     {
107       /* Remove the variable from the environment.  */
108       return unsetenv (string);
109     }
110
111   size = 0;
112   for (ep = environ; *ep != NULL; ++ep)
113     if (!strncmp (*ep, string, name_end - string) &&
114         (*ep)[name_end - string] == '=')
115       break;
116     else
117       ++size;
118
119   if (*ep == NULL)
120     {
121       static char **last_environ = NULL;
122       char **new_environ = (char **) malloc ((size + 2) * sizeof (char *));
123       if (new_environ == NULL)
124         return -1;
125       (void) memcpy ((void *) new_environ, (void *) environ,
126                      size * sizeof (char *));
127       new_environ[size] = (char *) string;
128       new_environ[size + 1] = NULL;
129       if (last_environ != NULL)
130         free (last_environ);
131       last_environ = new_environ;
132       environ = new_environ;
133     }
134   else
135     *ep = (char *) string;
136
137   return 0;
138 }