xref: /netbsd-src/external/gpl3/gdb/dist/libiberty/setenv.c (revision 5173eb0a33e5d83890ba976253e703be4c92557c)
1*5173eb0aSchristos /* Copyright (C) 1992-2024 Free Software Foundation, Inc.
298b9484cSchristos    This file based on setenv.c in the GNU C Library.
398b9484cSchristos 
498b9484cSchristos    The GNU C Library is free software; you can redistribute it and/or
598b9484cSchristos    modify it under the terms of the GNU Library General Public License as
698b9484cSchristos    published by the Free Software Foundation; either version 2 of the
798b9484cSchristos    License, or (at your option) any later version.
898b9484cSchristos 
998b9484cSchristos    The GNU C Library is distributed in the hope that it will be useful,
1098b9484cSchristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
1198b9484cSchristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1298b9484cSchristos    Library General Public License for more details.
1398b9484cSchristos 
1498b9484cSchristos    You should have received a copy of the GNU Library General Public
1598b9484cSchristos    License along with the GNU C Library; see the file COPYING.LIB.  If not,
1698b9484cSchristos    write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
1798b9484cSchristos    Boston, MA 02110-1301, USA.  */
1898b9484cSchristos 
1998b9484cSchristos 
2098b9484cSchristos /*
2198b9484cSchristos 
2298b9484cSchristos @deftypefn Supplemental int setenv (const char *@var{name}, @
2398b9484cSchristos   const char *@var{value}, int @var{overwrite})
2498b9484cSchristos @deftypefnx Supplemental void unsetenv (const char *@var{name})
2598b9484cSchristos 
2698b9484cSchristos @code{setenv} adds @var{name} to the environment with value
2798b9484cSchristos @var{value}.  If the name was already present in the environment,
2898b9484cSchristos the new value will be stored only if @var{overwrite} is nonzero.
2998b9484cSchristos The companion @code{unsetenv} function removes @var{name} from the
3098b9484cSchristos environment.  This implementation is not safe for multithreaded code.
3198b9484cSchristos 
3298b9484cSchristos @end deftypefn
3398b9484cSchristos 
3498b9484cSchristos */
3598b9484cSchristos 
3698b9484cSchristos #if HAVE_CONFIG_H
3798b9484cSchristos # include <config.h>
3898b9484cSchristos #endif
3998b9484cSchristos 
4098b9484cSchristos #define setenv libiberty_setenv
4198b9484cSchristos #define unsetenv libiberty_unsetenv
4298b9484cSchristos 
4398b9484cSchristos #include "ansidecl.h"
4498b9484cSchristos #include <sys/types.h> /* For `size_t' */
4598b9484cSchristos #include <stdio.h>     /* For `NULL' */
4698b9484cSchristos 
4798b9484cSchristos #include <errno.h>
4898b9484cSchristos #if !defined(errno) && !defined(HAVE_ERRNO_DECL)
4998b9484cSchristos extern int errno;
5098b9484cSchristos #endif
5198b9484cSchristos #define __set_errno(ev) ((errno) = (ev))
5298b9484cSchristos 
5398b9484cSchristos #if HAVE_STDLIB_H
5498b9484cSchristos # include <stdlib.h>
5598b9484cSchristos #endif
5698b9484cSchristos #if HAVE_STRING_H
5798b9484cSchristos # include <string.h>
5898b9484cSchristos #endif
5998b9484cSchristos #if HAVE_UNISTD_H
6098b9484cSchristos # include <unistd.h>
6198b9484cSchristos #endif
6298b9484cSchristos 
6398b9484cSchristos #define __environ	environ
64ba340e45Schristos #include "environ.h"
6598b9484cSchristos 
6698b9484cSchristos #undef setenv
6798b9484cSchristos #undef unsetenv
6898b9484cSchristos 
6998b9484cSchristos /* LOCK and UNLOCK are defined as no-ops.  This makes the libiberty
7098b9484cSchristos  * implementation MT-Unsafe. */
7198b9484cSchristos #define LOCK
7298b9484cSchristos #define UNLOCK
7398b9484cSchristos 
7498b9484cSchristos /* Below this point, it's verbatim code from the glibc-2.0 implementation */
7598b9484cSchristos 
7698b9484cSchristos /* If this variable is not a null pointer we allocated the current
7798b9484cSchristos    environment.  */
7898b9484cSchristos static char **last_environ;
7998b9484cSchristos 
8098b9484cSchristos 
8198b9484cSchristos int
8298b9484cSchristos setenv (const char *name, const char *value, int replace)
8398b9484cSchristos {
8498b9484cSchristos   register char **ep = 0;
8598b9484cSchristos   register size_t size;
8698b9484cSchristos   const size_t namelen = strlen (name);
8798b9484cSchristos   const size_t vallen = strlen (value) + 1;
8898b9484cSchristos 
8998b9484cSchristos   LOCK;
9098b9484cSchristos 
9198b9484cSchristos   size = 0;
9298b9484cSchristos   if (__environ != NULL)
9398b9484cSchristos     {
9498b9484cSchristos       for (ep = __environ; *ep != NULL; ++ep)
9598b9484cSchristos 	if (!strncmp (*ep, name, namelen) && (*ep)[namelen] == '=')
9698b9484cSchristos 	  break;
9798b9484cSchristos 	else
9898b9484cSchristos 	  ++size;
9998b9484cSchristos     }
10098b9484cSchristos 
10198b9484cSchristos   if (__environ == NULL || *ep == NULL)
10298b9484cSchristos     {
10398b9484cSchristos       char **new_environ;
10498b9484cSchristos       if (__environ == last_environ && __environ != NULL)
10598b9484cSchristos 	/* We allocated this space; we can extend it.  */
10698b9484cSchristos 	new_environ = (char **) realloc (last_environ,
10798b9484cSchristos 					 (size + 2) * sizeof (char *));
10898b9484cSchristos       else
10998b9484cSchristos 	new_environ = (char **) malloc ((size + 2) * sizeof (char *));
11098b9484cSchristos 
11198b9484cSchristos       if (new_environ == NULL)
11298b9484cSchristos 	{
11398b9484cSchristos 	  UNLOCK;
11498b9484cSchristos 	  return -1;
11598b9484cSchristos 	}
11698b9484cSchristos 
11798b9484cSchristos       new_environ[size] = (char *) malloc (namelen + 1 + vallen);
11898b9484cSchristos       if (new_environ[size] == NULL)
11998b9484cSchristos 	{
12098b9484cSchristos 	  free ((char *) new_environ);
12198b9484cSchristos 	  __set_errno (ENOMEM);
12298b9484cSchristos 	  UNLOCK;
12398b9484cSchristos 	  return -1;
12498b9484cSchristos 	}
12598b9484cSchristos 
12698b9484cSchristos       if (__environ != last_environ)
12798b9484cSchristos 	memcpy ((char *) new_environ, (char *) __environ,
12898b9484cSchristos 		size * sizeof (char *));
12998b9484cSchristos 
13098b9484cSchristos       memcpy (new_environ[size], name, namelen);
13198b9484cSchristos       new_environ[size][namelen] = '=';
13298b9484cSchristos       memcpy (&new_environ[size][namelen + 1], value, vallen);
13398b9484cSchristos 
13498b9484cSchristos       new_environ[size + 1] = NULL;
13598b9484cSchristos 
13698b9484cSchristos       last_environ = __environ = new_environ;
13798b9484cSchristos     }
13898b9484cSchristos   else if (replace)
13998b9484cSchristos     {
14098b9484cSchristos       size_t len = strlen (*ep);
14198b9484cSchristos       if (len + 1 < namelen + 1 + vallen)
14298b9484cSchristos 	{
14398b9484cSchristos 	  /* The existing string is too short; malloc a new one.  */
14498b9484cSchristos 	  char *new_string = (char *) malloc (namelen + 1 + vallen);
14598b9484cSchristos 	  if (new_string == NULL)
14698b9484cSchristos 	    {
14798b9484cSchristos 	      UNLOCK;
14898b9484cSchristos 	      return -1;
14998b9484cSchristos 	    }
15098b9484cSchristos 	  *ep = new_string;
15198b9484cSchristos 	}
15298b9484cSchristos       memcpy (*ep, name, namelen);
15398b9484cSchristos       (*ep)[namelen] = '=';
15498b9484cSchristos       memcpy (&(*ep)[namelen + 1], value, vallen);
15598b9484cSchristos     }
15698b9484cSchristos 
15798b9484cSchristos   UNLOCK;
15898b9484cSchristos 
15998b9484cSchristos   return 0;
16098b9484cSchristos }
16198b9484cSchristos 
16298b9484cSchristos void
16398b9484cSchristos unsetenv (const char *name)
16498b9484cSchristos {
16598b9484cSchristos   const size_t len = strlen (name);
16698b9484cSchristos   char **ep;
16798b9484cSchristos 
16898b9484cSchristos   LOCK;
16998b9484cSchristos 
17098b9484cSchristos   for (ep = __environ; *ep; ++ep)
17198b9484cSchristos     if (!strncmp (*ep, name, len) && (*ep)[len] == '=')
17298b9484cSchristos       {
17398b9484cSchristos 	/* Found it.  Remove this pointer by moving later ones back.  */
17498b9484cSchristos 	char **dp = ep;
17598b9484cSchristos 	do
17698b9484cSchristos 	  dp[0] = dp[1];
17798b9484cSchristos 	while (*dp++);
17898b9484cSchristos 	/* Continue the loop in case NAME appears again.  */
17998b9484cSchristos       }
18098b9484cSchristos 
18198b9484cSchristos   UNLOCK;
18298b9484cSchristos }
183