File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libiconv / srclib / setenv.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 22:57:48 2012 UTC (12 years, 4 months ago) by misho
Branches: libiconv, MAIN
CVS tags: v1_13_1, HEAD
libiconv

    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>