Update.
[glibc.git] / sysdeps / generic / setenv.c
blob21d9b675cb1b648febf4f7646d1e404aa0c04106
1 /* Copyright (C) 1992, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
14 You should have received a copy of the GNU Library General Public
15 License along with the GNU C Library; see the file COPYING.LIB. If not,
16 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, USA. */
19 #if HAVE_CONFIG_H
20 # include <config.h>
21 #endif
23 #include <errno.h>
24 #if !_LIBC
25 # if !defined errno && !defined HAVE_ERRNO_DECL
26 extern int errno;
27 # endif
28 # define __set_errno(ev) ((errno) = (ev))
29 #endif
31 #if _LIBC || HAVE_STDLIB_H
32 # include <stdlib.h>
33 #endif
34 #if _LIBC || HAVE_STRING_H
35 # include <string.h>
36 #endif
37 #if _LIBC || HAVE_UNISTD_H
38 # include <unistd.h>
39 #endif
41 #if !_LIBC
42 # define __environ environ
43 # ifndef HAVE_ENVIRON_DECL
44 extern char **environ;
45 # endif
46 #endif
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
59 /* In the GNU C library we must keep the namespace clean. */
60 #ifdef _LIBC
61 # define setenv __setenv
62 # define unsetenv __unsetenv
63 # define clearenv __clearenv
64 # define tfind __tfind
65 # define tsearch __tsearch
66 #endif
68 /* In the GNU C library implementation we try to be more clever and
69 allow arbitrary many changes of the environment given that the used
70 values are from a small set. Outside glibc this will eat up all
71 memory after a while. */
72 #if defined _LIBC || (defined HAVE_SEARCH_H && defined HAVE_TSEARCH \
73 && defined __GNUC__)
74 # define USE_TSEARCH 1
75 # include <search.h>
77 /* This is a pointer to the root of the search tree with the known
78 values. */
79 static void *known_values;
81 # define KNOWN_VALUE(Str) \
82 ({ \
83 void *value = tfind (Str, &known_values, (__compar_fn_t) strcmp); \
84 value != NULL ? *(char **) value : NULL; \
86 # define STORE_VALUE(Str) \
87 tsearch (Str, &known_values, (__compar_fn_t) strcmp)
89 #else
90 # undef USE_TSEARCH
92 # define KNOWN_VALUE(Str) NULL
93 # define STORE_VALUE(Str) do { } while (0)
95 #endif
98 /* If this variable is not a null pointer we allocated the current
99 environment. */
100 static char **last_environ;
104 setenv (name, value, replace)
105 const char *name;
106 const char *value;
107 int replace;
109 register char **ep;
110 register size_t size;
111 const size_t namelen = strlen (name);
112 const size_t vallen = strlen (value) + 1;
114 LOCK;
116 size = 0;
117 if (__environ != NULL)
119 for (ep = __environ; *ep != NULL; ++ep)
120 if (!strncmp (*ep, name, namelen) && (*ep)[namelen] == '=')
121 break;
122 else
123 ++size;
126 if (__environ == NULL || *ep == NULL)
128 char **new_environ;
129 #ifdef USE_TSEARCH
130 char *new_value;
131 #endif
133 /* We allocated this space; we can extend it. */
134 new_environ = (char **) realloc (last_environ,
135 (size + 2) * sizeof (char *));
136 if (new_environ == NULL)
138 UNLOCK;
139 return -1;
142 /* See whether the value is already known. */
143 #ifdef USE_TSEARCH
144 new_value = alloca (namelen + 1 + vallen);
145 # ifdef _LIBC
146 __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1),
147 value, vallen);
148 # else
149 memcpy (new_value, name, namelen);
150 new_value[namelen] = '=';
151 memcpy (&new_value[namelen + 1], value, vallen);
152 # endif
154 new_environ[size] = KNOWN_VALUE (new_value);
155 if (new_environ[size] == NULL)
156 #endif
158 new_environ[size] = malloc (namelen + 1 + vallen);
159 if (new_environ[size] == NULL)
161 __set_errno (ENOMEM);
162 UNLOCK;
163 return -1;
166 #ifdef USE_TSEARCH
167 memcpy (new_environ[size], new_value, namelen + 1 + vallen);
168 #else
169 memcpy (new_environ[size], name, namelen);
170 new_environ[size][namelen] = '=';
171 memcpy (&new_environ[size][namelen + 1], value, vallen);
172 #endif
175 if (__environ != last_environ)
176 memcpy ((char *) new_environ, (char *) __environ,
177 size * sizeof (char *));
179 new_environ[size + 1] = NULL;
181 last_environ = __environ = new_environ;
183 else if (replace)
185 char *new_value;
186 char *np;
188 /* The existing string is too short; malloc a new one. */
189 #ifdef USE_TSEARCH
190 new_value = alloca (namelen + 1 + vallen);
191 # ifdef _LIBC
192 __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1),
193 value, vallen);
194 # else
195 memcpy (new_value, name, namelen);
196 new_value[namelen] = '=';
197 memcpy (&new_value[namelen + 1], value, vallen);
198 # endif
200 np = KNOWN_VALUE (new_value);
201 if (np == NULL)
202 #endif
204 np = malloc (namelen + 1 + vallen);
205 if (np == NULL)
207 UNLOCK;
208 return -1;
211 #ifdef USE_TSEARCH
212 memcpy (np, new_value, namelen + 1 + vallen);
213 #else
214 memcpy (np, name, namelen);
215 np[namelen] = '=';
216 memcpy (&np[namelen + 1], value, vallen);
217 #endif
220 /* Keep the old value around. */
221 STORE_VALUE (*ep);
222 *ep = np;
225 UNLOCK;
227 return 0;
230 void
231 unsetenv (name)
232 const char *name;
234 const size_t len = strlen (name);
235 char **ep;
237 LOCK;
239 for (ep = __environ; *ep != NULL; ++ep)
240 if (!strncmp (*ep, name, len) && (*ep)[len] == '=')
242 /* Found it. Remove this pointer by moving later ones back. */
243 char **dp = ep;
245 /* Store the value so that we can reuse it later. */
246 STORE_VALUE (*ep);
249 dp[0] = dp[1];
250 while (*dp++);
251 /* Continue the loop in case NAME appears again. */
254 UNLOCK;
257 /* The `clearenv' was planned to be added to POSIX.1 but probably
258 never made it. Nevertheless the POSIX.9 standard (POSIX bindings
259 for Fortran 77) requires this function. */
261 clearenv ()
263 LOCK;
265 if (__environ == last_environ && __environ != NULL)
267 /* We allocated this environment so we can free it. Store all the
268 strings. */
269 char **ep = __environ;
270 while (*ep != NULL)
271 STORE_VALUE (*ep++);
273 free (__environ);
274 last_environ = NULL;
277 /* Clear the environment pointer removes the whole environment. */
278 __environ = NULL;
280 UNLOCK;
282 return 0;
284 #ifdef _LIBC
285 # undef setenv
286 # undef unsetenv
287 # undef clearenv
288 weak_alias (__setenv, setenv)
289 weak_alias (__unsetenv, unsetenv)
290 weak_alias (__clearenv, clearenv)
291 #endif