remove obstack support
[uclibc-ng.git] / libc / stdlib / setenv.c
blobecc30253632d56cce39ed6388ccfec1258554766
1 /* Copyright (C) 1992,95,96,97,98,99,2000,2001 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 Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the 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 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; see the file COPYING.LIB. If
16 not, see <http://www.gnu.org/licenses/>.
18 modified for uClibc by Erik Andersen <andersen@codepoet.org>
21 #include <features.h>
22 #include <errno.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
28 #include <bits/uClibc_mutex.h>
29 __UCLIBC_MUTEX_STATIC(mylock, PTHREAD_MUTEX_INITIALIZER);
32 /* If this variable is not a null pointer we allocated the current
33 environment. */
34 static char **last_environ;
37 /* This function is used by `setenv' and `putenv'. The difference between
38 the two functions is that for the former must create a new string which
39 is then placed in the environment, while the argument of `putenv'
40 must be used directly. This is all complicated by the fact that we try
41 to reuse values once generated for a `setenv' call since we can never
42 free the strings. [in uclibc, we do not] */
43 static int __add_to_environ(const char *name, const char *value,
44 int replace)
46 register char **ep;
47 register size_t size;
48 char *var_val;
49 char **new_environ;
50 /* name may come from putenv() and thus may contain "=VAL" part */
51 const size_t namelen = strchrnul(name, '=') - name;
52 int rv = -1;
54 __UCLIBC_MUTEX_LOCK(mylock);
56 /* We have to get the pointer now that we have the lock and not earlier
57 since another thread might have created a new environment. */
58 ep = __environ;
60 size = 0;
61 if (ep != NULL) {
62 while (*ep != NULL) {
63 if (!strncmp(*ep, name, namelen) && (*ep)[namelen] == '=') {
64 /* Found */
65 if (!replace)
66 goto DONE_OK;
67 goto REPLACE;
69 ++size;
70 ++ep;
74 /* Not found, add at the end */
76 /* We allocated this space; we can extend it. */
77 new_environ = realloc(last_environ, (size + 2) * sizeof(char *));
78 if (new_environ == NULL) {
79 /* __set_errno(ENOMEM); */
80 goto DONE;
82 if (__environ != last_environ) {
83 memcpy(new_environ, __environ, size * sizeof(char *));
85 last_environ = __environ = new_environ;
87 ep = &new_environ[size];
88 /* Ensure env is NULL terminated in case malloc below fails */
89 ep[0] = NULL;
90 ep[1] = NULL;
92 REPLACE:
93 var_val = (char*) name;
94 /* Build VAR=VAL if we called by setenv, not putenv. */
95 if (value != NULL) {
96 const size_t vallen = strlen(value) + 1;
98 var_val = malloc(namelen + 1 + vallen);
99 if (var_val == NULL) {
100 /* __set_errno(ENOMEM); */
101 goto DONE;
103 memcpy(var_val, name, namelen);
104 var_val[namelen] = '=';
105 memcpy(&var_val[namelen + 1], value, vallen);
107 *ep = var_val;
109 DONE_OK:
110 rv = 0;
112 DONE:
113 __UCLIBC_MUTEX_UNLOCK(mylock);
114 return rv;
117 int setenv(const char *name, const char *value, int replace)
119 if (name == NULL || *name == '\0' || strchr (name, '=') != NULL) {
120 __set_errno(EINVAL);
121 return -1;
124 /* NB: setenv("VAR", NULL, 1) inserts "VAR=" string */
125 return __add_to_environ(name, value ? value : "", replace);
127 libc_hidden_def(setenv)
129 int unsetenv(const char *name)
131 const char *eq;
132 size_t len;
133 char **ep;
135 if (name == NULL || *name == '\0'
136 || *(eq = strchrnul(name, '=')) == '='
138 __set_errno(EINVAL);
139 return -1;
141 len = eq - name; /* avoiding strlen this way */
143 __UCLIBC_MUTEX_LOCK(mylock);
144 ep = __environ;
145 /* NB: clearenv(); unsetenv("foo"); should not segfault */
146 if (ep) while (*ep != NULL) {
147 if (!strncmp(*ep, name, len) && (*ep)[len] == '=') {
148 /* Found it. Remove this pointer by moving later ones back. */
149 char **dp = ep;
150 do {
151 dp[0] = dp[1];
152 } while (*dp++);
153 /* Continue the loop in case NAME appears again. */
154 } else {
155 ++ep;
158 __UCLIBC_MUTEX_UNLOCK(mylock);
159 return 0;
161 libc_hidden_def(unsetenv)
163 /* The `clearenv' was planned to be added to POSIX.1 but probably
164 never made it. Nevertheless the POSIX.9 standard (POSIX bindings
165 for Fortran 77) requires this function. */
166 int clearenv(void)
168 __UCLIBC_MUTEX_LOCK(mylock);
169 /* If we allocated this environment we can free it.
170 * If we did not allocate this environment, it's NULL already
171 * and is safe to free(). */
172 free(last_environ);
173 last_environ = NULL;
174 /* Clearing environ removes the whole environment. */
175 __environ = NULL;
176 __UCLIBC_MUTEX_UNLOCK(mylock);
177 return 0;
180 /* Put STRING, which is of the form "NAME=VALUE", in the environment. */
181 int putenv(char *string)
183 if (strchr(string, '=') != NULL) {
184 return __add_to_environ(string, NULL, 1);
186 return unsetenv(string);