189857Sobrien/* Copyright (C) 1992, 1995, 1996, 1997, 2002 Free Software Foundation, Inc.
260484Sobrien   This file based on setenv.c in the GNU C Library.
360484Sobrien
460484Sobrien   The GNU C Library is free software; you can redistribute it and/or
560484Sobrien   modify it under the terms of the GNU Library General Public License as
660484Sobrien   published by the Free Software Foundation; either version 2 of the
760484Sobrien   License, or (at your option) any later version.
860484Sobrien
960484Sobrien   The GNU C Library is distributed in the hope that it will be useful,
1060484Sobrien   but WITHOUT ANY WARRANTY; without even the implied warranty of
1160484Sobrien   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1260484Sobrien   Library General Public License for more details.
1360484Sobrien
1460484Sobrien   You should have received a copy of the GNU Library General Public
1560484Sobrien   License along with the GNU C Library; see the file COPYING.LIB.  If not,
16218822Sdim   write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
17218822Sdim   Boston, MA 02110-1301, USA.  */
1860484Sobrien
1989857Sobrien
2089857Sobrien/*
2189857Sobrien
2289857Sobrien@deftypefn Supplemental int setenv (const char *@var{name}, const char *@var{value}, int @var{overwrite})
2389857Sobrien@deftypefnx Supplemental void unsetenv (const char *@var{name})
2489857Sobrien
2589857Sobrien@code{setenv} adds @var{name} to the environment with value
2689857Sobrien@var{value}.  If the name was already present in the environment,
2789857Sobrienthe new value will be stored only if @var{overwrite} is nonzero.
2889857SobrienThe companion @code{unsetenv} function removes @var{name} from the
2989857Sobrienenvironment.  This implementation is not safe for multithreaded code.
3089857Sobrien
3189857Sobrien@end deftypefn
3289857Sobrien
3389857Sobrien*/
3489857Sobrien
3560484Sobrien#if HAVE_CONFIG_H
3660484Sobrien# include <config.h>
3760484Sobrien#endif
3860484Sobrien
3989857Sobrien#define setenv libiberty_setenv
4089857Sobrien#define unsetenv libiberty_unsetenv
4189857Sobrien
4260484Sobrien#include "ansidecl.h"
4360484Sobrien#include <sys/types.h> /* For `size_t' */
4460484Sobrien#include <stdio.h>     /* For `NULL' */
4560484Sobrien
4660484Sobrien#include <errno.h>
4760484Sobrien#if !defined(errno) && !defined(HAVE_ERRNO_DECL)
4860484Sobrienextern int errno;
4960484Sobrien#endif
5060484Sobrien#define __set_errno(ev) ((errno) = (ev))
5160484Sobrien
5260484Sobrien#if HAVE_STDLIB_H
5360484Sobrien# include <stdlib.h>
5460484Sobrien#endif
5560484Sobrien#if HAVE_STRING_H
5660484Sobrien# include <string.h>
5760484Sobrien#endif
5860484Sobrien#if HAVE_UNISTD_H
5960484Sobrien# include <unistd.h>
6060484Sobrien#endif
6160484Sobrien
6260484Sobrien#define __environ	environ
6360484Sobrien#ifndef HAVE_ENVIRON_DECL
6460484Sobrienextern char **environ;
6560484Sobrien#endif
6660484Sobrien
6789857Sobrien#undef setenv
6889857Sobrien#undef unsetenv
6989857Sobrien
7060484Sobrien/* LOCK and UNLOCK are defined as no-ops.  This makes the libiberty
7160484Sobrien * implementation MT-Unsafe. */
7260484Sobrien#define LOCK
7360484Sobrien#define UNLOCK
7460484Sobrien
7560484Sobrien/* Below this point, it's verbatim code from the glibc-2.0 implementation */
7660484Sobrien
7760484Sobrien/* If this variable is not a null pointer we allocated the current
7860484Sobrien   environment.  */
7960484Sobrienstatic char **last_environ;
8060484Sobrien
8160484Sobrien
8260484Sobrienint
83218822Sdimsetenv (const char *name, const char *value, int replace)
8460484Sobrien{
8577298Sobrien  register char **ep = 0;
8660484Sobrien  register size_t size;
8760484Sobrien  const size_t namelen = strlen (name);
8860484Sobrien  const size_t vallen = strlen (value) + 1;
8960484Sobrien
9060484Sobrien  LOCK;
9160484Sobrien
9260484Sobrien  size = 0;
9360484Sobrien  if (__environ != NULL)
9477298Sobrien    {
9577298Sobrien      for (ep = __environ; *ep != NULL; ++ep)
9677298Sobrien	if (!strncmp (*ep, name, namelen) && (*ep)[namelen] == '=')
9777298Sobrien	  break;
9877298Sobrien	else
9977298Sobrien	  ++size;
10077298Sobrien    }
10160484Sobrien
10260484Sobrien  if (__environ == NULL || *ep == NULL)
10360484Sobrien    {
10460484Sobrien      char **new_environ;
10560484Sobrien      if (__environ == last_environ && __environ != NULL)
10660484Sobrien	/* We allocated this space; we can extend it.  */
10760484Sobrien	new_environ = (char **) realloc (last_environ,
10860484Sobrien					 (size + 2) * sizeof (char *));
10960484Sobrien      else
11060484Sobrien	new_environ = (char **) malloc ((size + 2) * sizeof (char *));
11160484Sobrien
11260484Sobrien      if (new_environ == NULL)
11360484Sobrien	{
11460484Sobrien	  UNLOCK;
11560484Sobrien	  return -1;
11660484Sobrien	}
11760484Sobrien
118218822Sdim      new_environ[size] = (char *) malloc (namelen + 1 + vallen);
11960484Sobrien      if (new_environ[size] == NULL)
12060484Sobrien	{
12160484Sobrien	  free ((char *) new_environ);
12260484Sobrien	  __set_errno (ENOMEM);
12360484Sobrien	  UNLOCK;
12460484Sobrien	  return -1;
12560484Sobrien	}
12660484Sobrien
12760484Sobrien      if (__environ != last_environ)
12860484Sobrien	memcpy ((char *) new_environ, (char *) __environ,
12960484Sobrien		size * sizeof (char *));
13060484Sobrien
13160484Sobrien      memcpy (new_environ[size], name, namelen);
13260484Sobrien      new_environ[size][namelen] = '=';
13360484Sobrien      memcpy (&new_environ[size][namelen + 1], value, vallen);
13460484Sobrien
13560484Sobrien      new_environ[size + 1] = NULL;
13660484Sobrien
13760484Sobrien      last_environ = __environ = new_environ;
13860484Sobrien    }
13960484Sobrien  else if (replace)
14060484Sobrien    {
14160484Sobrien      size_t len = strlen (*ep);
14260484Sobrien      if (len + 1 < namelen + 1 + vallen)
14360484Sobrien	{
14460484Sobrien	  /* The existing string is too short; malloc a new one.  */
145218822Sdim	  char *new_string = (char *) malloc (namelen + 1 + vallen);
146218822Sdim	  if (new_string == NULL)
14760484Sobrien	    {
14860484Sobrien	      UNLOCK;
14960484Sobrien	      return -1;
15060484Sobrien	    }
151218822Sdim	  *ep = new_string;
15260484Sobrien	}
15360484Sobrien      memcpy (*ep, name, namelen);
15460484Sobrien      (*ep)[namelen] = '=';
15560484Sobrien      memcpy (&(*ep)[namelen + 1], value, vallen);
15660484Sobrien    }
15760484Sobrien
15860484Sobrien  UNLOCK;
15960484Sobrien
16060484Sobrien  return 0;
16160484Sobrien}
16260484Sobrien
16360484Sobrienvoid
164218822Sdimunsetenv (const char *name)
16560484Sobrien{
16660484Sobrien  const size_t len = strlen (name);
16760484Sobrien  char **ep;
16860484Sobrien
16960484Sobrien  LOCK;
17060484Sobrien
17160484Sobrien  for (ep = __environ; *ep; ++ep)
17260484Sobrien    if (!strncmp (*ep, name, len) && (*ep)[len] == '=')
17360484Sobrien      {
17460484Sobrien	/* Found it.  Remove this pointer by moving later ones back.  */
17560484Sobrien	char **dp = ep;
17660484Sobrien	do
17760484Sobrien	  dp[0] = dp[1];
17860484Sobrien	while (*dp++);
17960484Sobrien	/* Continue the loop in case NAME appears again.  */
18060484Sobrien      }
18160484Sobrien
18260484Sobrien  UNLOCK;
18360484Sobrien}
184