Mercurial > hg > octave-nkf > gnulib-hg
annotate lib/setenv.c @ 4683:4452e4c45cc4
Assume ANSI C <string.h>, <stdlib.h>.
author | Bruno Haible <bruno@clisp.org> |
---|---|
date | Wed, 10 Sep 2003 14:16:32 +0000 |
parents | e58a1c05a6ba |
children | ce37d22a271f |
rev | line source |
---|---|
4156
99ea86c79f44
Make it possibly to simply write: #include <alloca.h>.
Bruno Haible <bruno@clisp.org>
parents:
4080
diff
changeset
|
1 /* Copyright (C) 1992,1995-1999,2000-2003 Free Software Foundation, Inc. |
4080 | 2 This file is part of the GNU C Library. |
574 | 3 |
4440
e58a1c05a6ba
Update gettext source files from gettext automatically, using srclist-update.
Paul Eggert <eggert@cs.ucla.edu>
parents:
4156
diff
changeset
|
4 This program is free software; you can redistribute it and/or modify |
e58a1c05a6ba
Update gettext source files from gettext automatically, using srclist-update.
Paul Eggert <eggert@cs.ucla.edu>
parents:
4156
diff
changeset
|
5 it under the terms of the GNU General Public License as published by |
e58a1c05a6ba
Update gettext source files from gettext automatically, using srclist-update.
Paul Eggert <eggert@cs.ucla.edu>
parents:
4156
diff
changeset
|
6 the Free Software Foundation; either version 2, or (at your option) |
e58a1c05a6ba
Update gettext source files from gettext automatically, using srclist-update.
Paul Eggert <eggert@cs.ucla.edu>
parents:
4156
diff
changeset
|
7 any later version. |
574 | 8 |
4440
e58a1c05a6ba
Update gettext source files from gettext automatically, using srclist-update.
Paul Eggert <eggert@cs.ucla.edu>
parents:
4156
diff
changeset
|
9 This program is distributed in the hope that it will be useful, |
4080 | 10 but WITHOUT ANY WARRANTY; without even the implied warranty of |
4440
e58a1c05a6ba
Update gettext source files from gettext automatically, using srclist-update.
Paul Eggert <eggert@cs.ucla.edu>
parents:
4156
diff
changeset
|
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
e58a1c05a6ba
Update gettext source files from gettext automatically, using srclist-update.
Paul Eggert <eggert@cs.ucla.edu>
parents:
4156
diff
changeset
|
12 GNU General Public License for more details. |
574 | 13 |
4440
e58a1c05a6ba
Update gettext source files from gettext automatically, using srclist-update.
Paul Eggert <eggert@cs.ucla.edu>
parents:
4156
diff
changeset
|
14 You should have received a copy of the GNU General Public License along |
e58a1c05a6ba
Update gettext source files from gettext automatically, using srclist-update.
Paul Eggert <eggert@cs.ucla.edu>
parents:
4156
diff
changeset
|
15 with this program; if not, write to the Free Software Foundation, |
e58a1c05a6ba
Update gettext source files from gettext automatically, using srclist-update.
Paul Eggert <eggert@cs.ucla.edu>
parents:
4156
diff
changeset
|
16 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ |
574 | 17 |
4080 | 18 #if HAVE_CONFIG_H |
653 | 19 # include <config.h> |
574 | 20 #endif |
4156
99ea86c79f44
Make it possibly to simply write: #include <alloca.h>.
Bruno Haible <bruno@clisp.org>
parents:
4080
diff
changeset
|
21 #include <alloca.h> |
4080 | 22 |
574 | 23 #include <errno.h> |
4080 | 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 | |
574 | 30 |
4683
4452e4c45cc4
Assume ANSI C <string.h>, <stdlib.h>.
Bruno Haible <bruno@clisp.org>
parents:
4440
diff
changeset
|
31 #include <stdlib.h> |
4452e4c45cc4
Assume ANSI C <string.h>, <stdlib.h>.
Bruno Haible <bruno@clisp.org>
parents:
4440
diff
changeset
|
32 #include <string.h> |
574 | 33 #if _LIBC || HAVE_UNISTD_H |
653 | 34 # include <unistd.h> |
574 | 35 #endif |
36 | |
4080 | 37 /* For those losing systems which don't have 'alloca' we have to add |
38 some additional code emulating it. */ | |
39 #if _LIBC || HAVE_ALLOCA | |
40 # define freea(p) /* nothing */ | |
41 #else | |
42 # define alloca(n) malloc (n) | |
43 # define freea(p) free (p) | |
44 #endif | |
45 | |
46 #if !_LIBC | |
2718 | 47 # define __environ environ |
4080 | 48 # ifndef HAVE_ENVIRON_DECL |
49 extern char **environ; | |
50 # endif | |
51 #endif | |
52 | |
53 #if _LIBC | |
54 /* This lock protects against simultaneous modifications of `environ'. */ | |
55 # include <bits/libc-lock.h> | |
56 __libc_lock_define_initialized (static, envlock) | |
57 # define LOCK __libc_lock_lock (envlock) | |
58 # define UNLOCK __libc_lock_unlock (envlock) | |
59 #else | |
60 # define LOCK | |
61 # define UNLOCK | |
62 #endif | |
63 | |
64 /* In the GNU C library we must keep the namespace clean. */ | |
65 #ifdef _LIBC | |
66 # define setenv __setenv | |
67 # define clearenv __clearenv | |
68 # define tfind __tfind | |
69 # define tsearch __tsearch | |
574 | 70 #endif |
71 | |
4080 | 72 /* In the GNU C library implementation we try to be more clever and |
73 allow arbitrarily many changes of the environment given that the used | |
74 values are from a small set. Outside glibc this will eat up all | |
75 memory after a while. */ | |
76 #if defined _LIBC || (defined HAVE_SEARCH_H && defined HAVE_TSEARCH \ | |
77 && defined __GNUC__) | |
78 # define USE_TSEARCH 1 | |
79 # include <search.h> | |
80 typedef int (*compar_fn_t) (const void *, const void *); | |
81 | |
82 /* This is a pointer to the root of the search tree with the known | |
83 values. */ | |
84 static void *known_values; | |
85 | |
86 # define KNOWN_VALUE(Str) \ | |
87 ({ \ | |
88 void *value = tfind (Str, &known_values, (compar_fn_t) strcmp); \ | |
89 value != NULL ? *(char **) value : NULL; \ | |
90 }) | |
91 # define STORE_VALUE(Str) \ | |
92 tsearch (Str, &known_values, (compar_fn_t) strcmp) | |
93 | |
94 #else | |
95 # undef USE_TSEARCH | |
96 | |
97 # define KNOWN_VALUE(Str) NULL | |
98 # define STORE_VALUE(Str) do { } while (0) | |
99 | |
100 #endif | |
101 | |
102 | |
103 /* If this variable is not a null pointer we allocated the current | |
104 environment. */ | |
105 static char **last_environ; | |
106 | |
107 | |
108 /* This function is used by `setenv' and `putenv'. The difference between | |
109 the two functions is that for the former must create a new string which | |
110 is then placed in the environment, while the argument of `putenv' | |
111 must be used directly. This is all complicated by the fact that we try | |
112 to reuse values once generated for a `setenv' call since we can never | |
113 free the strings. */ | |
574 | 114 int |
4080 | 115 __add_to_environ (const char *name, const char *value, const char *combined, |
116 int replace) | |
574 | 117 { |
118 register char **ep; | |
119 register size_t size; | |
120 const size_t namelen = strlen (name); | |
4080 | 121 const size_t vallen = value != NULL ? strlen (value) + 1 : 0; |
122 | |
123 LOCK; | |
124 | |
125 /* We have to get the pointer now that we have the lock and not earlier | |
126 since another thread might have created a new environment. */ | |
127 ep = __environ; | |
574 | 128 |
129 size = 0; | |
4080 | 130 if (ep != NULL) |
131 { | |
132 for (; *ep != NULL; ++ep) | |
133 if (!strncmp (*ep, name, namelen) && (*ep)[namelen] == '=') | |
134 break; | |
135 else | |
136 ++size; | |
137 } | |
574 | 138 |
4080 | 139 if (ep == NULL || *ep == NULL) |
574 | 140 { |
141 char **new_environ; | |
4080 | 142 #ifdef USE_TSEARCH |
143 char *new_value; | |
144 #endif | |
574 | 145 |
4080 | 146 /* We allocated this space; we can extend it. */ |
147 new_environ = | |
148 (char **) (last_environ == NULL | |
149 ? malloc ((size + 2) * sizeof (char *)) | |
150 : realloc (last_environ, (size + 2) * sizeof (char *))); | |
574 | 151 if (new_environ == NULL) |
4080 | 152 { |
153 UNLOCK; | |
154 return -1; | |
155 } | |
156 | |
157 /* If the whole entry is given add it. */ | |
158 if (combined != NULL) | |
159 /* We must not add the string to the search tree since it belongs | |
160 to the user. */ | |
161 new_environ[size] = (char *) combined; | |
162 else | |
163 { | |
164 /* See whether the value is already known. */ | |
165 #ifdef USE_TSEARCH | |
166 new_value = (char *) alloca (namelen + 1 + vallen); | |
167 # ifdef _LIBC | |
168 __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1), | |
169 value, vallen); | |
170 # else | |
171 memcpy (new_value, name, namelen); | |
172 new_value[namelen] = '='; | |
173 memcpy (&new_value[namelen + 1], value, vallen); | |
174 # endif | |
574 | 175 |
4080 | 176 new_environ[size] = KNOWN_VALUE (new_value); |
177 if (new_environ[size] == NULL) | |
178 #endif | |
179 { | |
180 new_environ[size] = (char *) malloc (namelen + 1 + vallen); | |
181 if (new_environ[size] == NULL) | |
182 { | |
183 #ifdef USE_TSEARCH | |
184 freea (new_value); | |
185 #endif | |
186 __set_errno (ENOMEM); | |
187 UNLOCK; | |
188 return -1; | |
189 } | |
190 | |
191 #ifdef USE_TSEARCH | |
192 memcpy (new_environ[size], new_value, namelen + 1 + vallen); | |
193 #else | |
194 memcpy (new_environ[size], name, namelen); | |
195 new_environ[size][namelen] = '='; | |
196 memcpy (&new_environ[size][namelen + 1], value, vallen); | |
197 #endif | |
198 /* And save the value now. We cannot do this when we remove | |
199 the string since then we cannot decide whether it is a | |
200 user string or not. */ | |
201 STORE_VALUE (new_environ[size]); | |
202 } | |
203 #ifdef USE_TSEARCH | |
204 freea (new_value); | |
205 #endif | |
574 | 206 } |
207 | |
208 if (__environ != last_environ) | |
209 memcpy ((char *) new_environ, (char *) __environ, | |
210 size * sizeof (char *)); | |
211 | |
212 new_environ[size + 1] = NULL; | |
213 | |
214 last_environ = __environ = new_environ; | |
215 } | |
216 else if (replace) | |
217 { | |
4080 | 218 char *np; |
219 | |
220 /* Use the user string if given. */ | |
221 if (combined != NULL) | |
222 np = (char *) combined; | |
223 else | |
574 | 224 { |
4080 | 225 #ifdef USE_TSEARCH |
226 char *new_value = alloca (namelen + 1 + vallen); | |
227 # ifdef _LIBC | |
228 __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1), | |
229 value, vallen); | |
230 # else | |
231 memcpy (new_value, name, namelen); | |
232 new_value[namelen] = '='; | |
233 memcpy (&new_value[namelen + 1], value, vallen); | |
234 # endif | |
235 | |
236 np = KNOWN_VALUE (new_value); | |
237 if (np == NULL) | |
238 #endif | |
239 { | |
240 np = malloc (namelen + 1 + vallen); | |
241 if (np == NULL) | |
242 { | |
243 #ifdef USE_TSEARCH | |
244 freea (new_value); | |
245 #endif | |
246 UNLOCK; | |
247 return -1; | |
248 } | |
249 | |
250 #ifdef USE_TSEARCH | |
251 memcpy (np, new_value, namelen + 1 + vallen); | |
252 #else | |
253 memcpy (np, name, namelen); | |
254 np[namelen] = '='; | |
255 memcpy (&np[namelen + 1], value, vallen); | |
256 #endif | |
257 /* And remember the value. */ | |
258 STORE_VALUE (np); | |
259 } | |
260 #ifdef USE_TSEARCH | |
261 freea (new_value); | |
262 #endif | |
574 | 263 } |
4080 | 264 |
265 *ep = np; | |
574 | 266 } |
267 | |
4080 | 268 UNLOCK; |
269 | |
574 | 270 return 0; |
271 } | |
272 | |
4080 | 273 int |
274 setenv (const char *name, const char *value, int replace) | |
275 { | |
276 return __add_to_environ (name, value, NULL, replace); | |
277 } | |
278 | |
279 /* The `clearenv' was planned to be added to POSIX.1 but probably | |
280 never made it. Nevertheless the POSIX.9 standard (POSIX bindings | |
281 for Fortran 77) requires this function. */ | |
282 int | |
283 clearenv () | |
574 | 284 { |
4080 | 285 LOCK; |
286 | |
287 if (__environ == last_environ && __environ != NULL) | |
288 { | |
289 /* We allocated this environment so we can free it. */ | |
290 free (__environ); | |
291 last_environ = NULL; | |
292 } | |
293 | |
294 /* Clear the environment pointer removes the whole environment. */ | |
295 __environ = NULL; | |
574 | 296 |
4080 | 297 UNLOCK; |
298 | |
299 return 0; | |
574 | 300 } |
4080 | 301 |
302 #ifdef _LIBC | |
303 static void | |
304 free_mem (void) | |
305 { | |
306 /* Remove all traces. */ | |
307 clearenv (); | |
308 | |
309 /* Now remove the search tree. */ | |
310 __tdestroy (known_values, free); | |
311 known_values = NULL; | |
312 } | |
313 text_set_element (__libc_subfreeres, free_mem); | |
314 | |
315 | |
316 # undef setenv | |
317 # undef clearenv | |
318 weak_alias (__setenv, setenv) | |
319 weak_alias (__clearenv, clearenv) | |
320 #endif |