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