(root)/
gcc-13.2.0/
libiberty/
setenv.c
       1  /* Copyright (C) 1992-2023 Free Software Foundation, Inc.
       2     This file based on setenv.c in the GNU C Library.
       3  
       4     The GNU C Library is free software; you can redistribute it and/or
       5     modify it under the terms of the GNU Library General Public License as
       6     published by the Free Software Foundation; either version 2 of the
       7     License, or (at your option) any later version.
       8  
       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     Library General Public License for more details.
      13  
      14     You should have received a copy of the GNU Library General Public
      15     License along with the GNU C Library; see the file COPYING.LIB.  If not,
      16     write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
      17     Boston, MA 02110-1301, USA.  */
      18  
      19  
      20  /*
      21  
      22  @deftypefn Supplemental int setenv (const char *@var{name}, @
      23    const char *@var{value}, int @var{overwrite})
      24  @deftypefnx Supplemental void unsetenv (const char *@var{name})
      25  
      26  @code{setenv} adds @var{name} to the environment with value
      27  @var{value}.  If the name was already present in the environment,
      28  the new value will be stored only if @var{overwrite} is nonzero.
      29  The companion @code{unsetenv} function removes @var{name} from the
      30  environment.  This implementation is not safe for multithreaded code.
      31  
      32  @end deftypefn
      33  
      34  */
      35  
      36  #if HAVE_CONFIG_H
      37  # include <config.h>
      38  #endif
      39  
      40  #define setenv libiberty_setenv
      41  #define unsetenv libiberty_unsetenv
      42  
      43  #include "ansidecl.h"
      44  #include <sys/types.h> /* For `size_t' */
      45  #include <stdio.h>     /* For `NULL' */
      46  
      47  #include <errno.h>
      48  #if !defined(errno) && !defined(HAVE_ERRNO_DECL)
      49  extern int errno;
      50  #endif
      51  #define __set_errno(ev) ((errno) = (ev))
      52  
      53  #if HAVE_STDLIB_H
      54  # include <stdlib.h>
      55  #endif
      56  #if HAVE_STRING_H
      57  # include <string.h>
      58  #endif
      59  #if HAVE_UNISTD_H
      60  # include <unistd.h>
      61  #endif
      62  
      63  #define __environ	environ
      64  #include "environ.h"
      65  
      66  #undef setenv
      67  #undef unsetenv
      68  
      69  /* LOCK and UNLOCK are defined as no-ops.  This makes the libiberty
      70   * implementation MT-Unsafe. */
      71  #define LOCK
      72  #define UNLOCK
      73  
      74  /* Below this point, it's verbatim code from the glibc-2.0 implementation */
      75  
      76  /* If this variable is not a null pointer we allocated the current
      77     environment.  */
      78  static char **last_environ;
      79  
      80  
      81  int
      82  setenv (const char *name, const char *value, int replace)
      83  {
      84    register char **ep = 0;
      85    register size_t size;
      86    const size_t namelen = strlen (name);
      87    const size_t vallen = strlen (value) + 1;
      88  
      89    LOCK;
      90  
      91    size = 0;
      92    if (__environ != NULL)
      93      {
      94        for (ep = __environ; *ep != NULL; ++ep)
      95  	if (!strncmp (*ep, name, namelen) && (*ep)[namelen] == '=')
      96  	  break;
      97  	else
      98  	  ++size;
      99      }
     100  
     101    if (__environ == NULL || *ep == NULL)
     102      {
     103        char **new_environ;
     104        if (__environ == last_environ && __environ != NULL)
     105  	/* We allocated this space; we can extend it.  */
     106  	new_environ = (char **) realloc (last_environ,
     107  					 (size + 2) * sizeof (char *));
     108        else
     109  	new_environ = (char **) malloc ((size + 2) * sizeof (char *));
     110  
     111        if (new_environ == NULL)
     112  	{
     113  	  UNLOCK;
     114  	  return -1;
     115  	}
     116  
     117        new_environ[size] = (char *) malloc (namelen + 1 + vallen);
     118        if (new_environ[size] == NULL)
     119  	{
     120  	  free ((char *) new_environ);
     121  	  __set_errno (ENOMEM);
     122  	  UNLOCK;
     123  	  return -1;
     124  	}
     125  
     126        if (__environ != last_environ)
     127  	memcpy ((char *) new_environ, (char *) __environ,
     128  		size * sizeof (char *));
     129  
     130        memcpy (new_environ[size], name, namelen);
     131        new_environ[size][namelen] = '=';
     132        memcpy (&new_environ[size][namelen + 1], value, vallen);
     133  
     134        new_environ[size + 1] = NULL;
     135  
     136        last_environ = __environ = new_environ;
     137      }
     138    else if (replace)
     139      {
     140        size_t len = strlen (*ep);
     141        if (len + 1 < namelen + 1 + vallen)
     142  	{
     143  	  /* The existing string is too short; malloc a new one.  */
     144  	  char *new_string = (char *) malloc (namelen + 1 + vallen);
     145  	  if (new_string == NULL)
     146  	    {
     147  	      UNLOCK;
     148  	      return -1;
     149  	    }
     150  	  *ep = new_string;
     151  	}
     152        memcpy (*ep, name, namelen);
     153        (*ep)[namelen] = '=';
     154        memcpy (&(*ep)[namelen + 1], value, vallen);
     155      }
     156  
     157    UNLOCK;
     158  
     159    return 0;
     160  }
     161  
     162  void
     163  unsetenv (const char *name)
     164  {
     165    const size_t len = strlen (name);
     166    char **ep;
     167  
     168    LOCK;
     169  
     170    for (ep = __environ; *ep; ++ep)
     171      if (!strncmp (*ep, name, len) && (*ep)[len] == '=')
     172        {
     173  	/* Found it.  Remove this pointer by moving later ones back.  */
     174  	char **dp = ep;
     175  	do
     176  	  dp[0] = dp[1];
     177  	while (*dp++);
     178  	/* Continue the loop in case NAME appears again.  */
     179        }
     180  
     181    UNLOCK;
     182  }