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