1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-04-30 03:40:34 +02:00

Import Gnulib's `setenv' module, for MinGW.

Reported by Eli Zaretskii <eliz@gnu.org>.

* m4/gnulib-cache.m4 (gl_MODULES): Add `setenv'.
This commit is contained in:
Ludovic Courtès 2012-01-25 22:35:29 +01:00
parent 68fcf71189
commit 40fb4e317b
5 changed files with 550 additions and 2 deletions

View file

@ -21,7 +21,7 @@
# the same distribution terms as the rest of that program. # the same distribution terms as the rest of that program.
# #
# Generated by gnulib-tool. # Generated by gnulib-tool.
# Reproduce by: gnulib-tool --import --dir=. --local-dir=gnulib-local --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --lgpl=3 --no-conditional-dependencies --libtool --macro-prefix=gl --no-vc-files accept alignof alloca-opt announce-gen autobuild bind byteswap canonicalize-lgpl ceil close connect dirfd duplocale environ extensions flock floor fpieee frexp full-read full-write func gendocs getaddrinfo getpeername getsockname getsockopt git-version-gen gitlog-to-changelog gnu-web-doc-update gnupload havelib iconv_open-utf inet_ntop inet_pton isinf isnan ldexp lib-symbol-versions lib-symbol-visibility libunistring listen localcharset locale log1p maintainer-makefile malloc-gnu malloca nproc open pipe2 putenv recv recvfrom rename send sendto setsockopt shutdown socket stat-time stdlib strftime striconveh string sys_stat trunc verify vsnprintf warnings wchar # Reproduce by: gnulib-tool --import --dir=. --local-dir=gnulib-local --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --lgpl=3 --no-conditional-dependencies --libtool --macro-prefix=gl --no-vc-files accept alignof alloca-opt announce-gen autobuild bind byteswap canonicalize-lgpl ceil close connect dirfd duplocale environ extensions flock floor fpieee frexp full-read full-write func gendocs getaddrinfo getpeername getsockname getsockopt git-version-gen gitlog-to-changelog gnu-web-doc-update gnupload havelib iconv_open-utf inet_ntop inet_pton isinf isnan ldexp lib-symbol-versions lib-symbol-visibility libunistring listen localcharset locale log1p maintainer-makefile malloc-gnu malloca nproc open pipe2 putenv recv recvfrom rename send sendto setenv setsockopt shutdown socket stat-time stdlib strftime striconveh string sys_stat trunc verify vsnprintf warnings wchar
AUTOMAKE_OPTIONS = 1.5 gnits subdir-objects AUTOMAKE_OPTIONS = 1.5 gnits subdir-objects
@ -1343,6 +1343,15 @@ EXTRA_libgnu_la_SOURCES += sendto.c
## end gnulib module sendto ## end gnulib module sendto
## begin gnulib module setenv
EXTRA_DIST += setenv.c
EXTRA_libgnu_la_SOURCES += setenv.c
## end gnulib module setenv
## begin gnulib module setsockopt ## begin gnulib module setsockopt

390
lib/setenv.c Normal file
View file

@ -0,0 +1,390 @@
/* Copyright (C) 1992, 1995-2003, 2005-2012 Free Software Foundation, Inc.
This file is part of the GNU C Library.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#if !_LIBC
# define _GL_USE_STDLIB_ALLOC 1
# include <config.h>
#endif
/* Don't use __attribute__ __nonnull__ in this compilation unit. Otherwise gcc
optimizes away the name == NULL test below. */
#define _GL_ARG_NONNULL(params)
#include <alloca.h>
/* Specification. */
#include <stdlib.h>
#include <errno.h>
#ifndef __set_errno
# define __set_errno(ev) ((errno) = (ev))
#endif
#include <string.h>
#if _LIBC || HAVE_UNISTD_H
# include <unistd.h>
#endif
#if !_LIBC
# include "malloca.h"
#endif
#if _LIBC || !HAVE_SETENV
#if !_LIBC
# define __environ environ
#endif
#if _LIBC
/* This lock protects against simultaneous modifications of 'environ'. */
# include <bits/libc-lock.h>
__libc_lock_define_initialized (static, envlock)
# define LOCK __libc_lock_lock (envlock)
# define UNLOCK __libc_lock_unlock (envlock)
#else
# define LOCK
# define UNLOCK
#endif
/* In the GNU C library we must keep the namespace clean. */
#ifdef _LIBC
# define setenv __setenv
# define clearenv __clearenv
# define tfind __tfind
# define tsearch __tsearch
#endif
/* In the GNU C library implementation we try to be more clever and
allow arbitrarily many changes of the environment given that the used
values are from a small set. Outside glibc this will eat up all
memory after a while. */
#if defined _LIBC || (defined HAVE_SEARCH_H && defined HAVE_TSEARCH \
&& defined __GNUC__)
# define USE_TSEARCH 1
# include <search.h>
typedef int (*compar_fn_t) (const void *, const void *);
/* This is a pointer to the root of the search tree with the known
values. */
static void *known_values;
# define KNOWN_VALUE(Str) \
({ \
void *value = tfind (Str, &known_values, (compar_fn_t) strcmp); \
value != NULL ? *(char **) value : NULL; \
})
# define STORE_VALUE(Str) \
tsearch (Str, &known_values, (compar_fn_t) strcmp)
#else
# undef USE_TSEARCH
# define KNOWN_VALUE(Str) NULL
# define STORE_VALUE(Str) do { } while (0)
#endif
/* If this variable is not a null pointer we allocated the current
environment. */
static char **last_environ;
/* This function is used by 'setenv' and 'putenv'. The difference between
the two functions is that for the former must create a new string which
is then placed in the environment, while the argument of 'putenv'
must be used directly. This is all complicated by the fact that we try
to reuse values once generated for a 'setenv' call since we can never
free the strings. */
int
__add_to_environ (const char *name, const char *value, const char *combined,
int replace)
{
char **ep;
size_t size;
const size_t namelen = strlen (name);
const size_t vallen = value != NULL ? strlen (value) + 1 : 0;
LOCK;
/* We have to get the pointer now that we have the lock and not earlier
since another thread might have created a new environment. */
ep = __environ;
size = 0;
if (ep != NULL)
{
for (; *ep != NULL; ++ep)
if (!strncmp (*ep, name, namelen) && (*ep)[namelen] == '=')
break;
else
++size;
}
if (ep == NULL || *ep == NULL)
{
char **new_environ;
#ifdef USE_TSEARCH
char *new_value;
#endif
/* We allocated this space; we can extend it. */
new_environ =
(char **) (last_environ == NULL
? malloc ((size + 2) * sizeof (char *))
: realloc (last_environ, (size + 2) * sizeof (char *)));
if (new_environ == NULL)
{
/* It's easier to set errno to ENOMEM than to rely on the
'malloc-posix' and 'realloc-posix' gnulib modules. */
__set_errno (ENOMEM);
UNLOCK;
return -1;
}
/* If the whole entry is given add it. */
if (combined != NULL)
/* We must not add the string to the search tree since it belongs
to the user. */
new_environ[size] = (char *) combined;
else
{
/* See whether the value is already known. */
#ifdef USE_TSEARCH
# ifdef _LIBC
new_value = (char *) alloca (namelen + 1 + vallen);
__mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1),
value, vallen);
# else
new_value = (char *) malloca (namelen + 1 + vallen);
if (new_value == NULL)
{
__set_errno (ENOMEM);
UNLOCK;
return -1;
}
memcpy (new_value, name, namelen);
new_value[namelen] = '=';
memcpy (&new_value[namelen + 1], value, vallen);
# endif
new_environ[size] = KNOWN_VALUE (new_value);
if (new_environ[size] == NULL)
#endif
{
new_environ[size] = (char *) malloc (namelen + 1 + vallen);
if (new_environ[size] == NULL)
{
#if defined USE_TSEARCH && !defined _LIBC
freea (new_value);
#endif
__set_errno (ENOMEM);
UNLOCK;
return -1;
}
#ifdef USE_TSEARCH
memcpy (new_environ[size], new_value, namelen + 1 + vallen);
#else
memcpy (new_environ[size], name, namelen);
new_environ[size][namelen] = '=';
memcpy (&new_environ[size][namelen + 1], value, vallen);
#endif
/* And save the value now. We cannot do this when we remove
the string since then we cannot decide whether it is a
user string or not. */
STORE_VALUE (new_environ[size]);
}
#if defined USE_TSEARCH && !defined _LIBC
freea (new_value);
#endif
}
if (__environ != last_environ)
memcpy ((char *) new_environ, (char *) __environ,
size * sizeof (char *));
new_environ[size + 1] = NULL;
last_environ = __environ = new_environ;
}
else if (replace)
{
char *np;
/* Use the user string if given. */
if (combined != NULL)
np = (char *) combined;
else
{
#ifdef USE_TSEARCH
char *new_value;
# ifdef _LIBC
new_value = alloca (namelen + 1 + vallen);
__mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1),
value, vallen);
# else
new_value = malloca (namelen + 1 + vallen);
if (new_value == NULL)
{
__set_errno (ENOMEM);
UNLOCK;
return -1;
}
memcpy (new_value, name, namelen);
new_value[namelen] = '=';
memcpy (&new_value[namelen + 1], value, vallen);
# endif
np = KNOWN_VALUE (new_value);
if (np == NULL)
#endif
{
np = (char *) malloc (namelen + 1 + vallen);
if (np == NULL)
{
#if defined USE_TSEARCH && !defined _LIBC
freea (new_value);
#endif
__set_errno (ENOMEM);
UNLOCK;
return -1;
}
#ifdef USE_TSEARCH
memcpy (np, new_value, namelen + 1 + vallen);
#else
memcpy (np, name, namelen);
np[namelen] = '=';
memcpy (&np[namelen + 1], value, vallen);
#endif
/* And remember the value. */
STORE_VALUE (np);
}
#if defined USE_TSEARCH && !defined _LIBC
freea (new_value);
#endif
}
*ep = np;
}
UNLOCK;
return 0;
}
int
setenv (const char *name, const char *value, int replace)
{
if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
{
__set_errno (EINVAL);
return -1;
}
return __add_to_environ (name, value, NULL, replace);
}
/* The 'clearenv' was planned to be added to POSIX.1 but probably
never made it. Nevertheless the POSIX.9 standard (POSIX bindings
for Fortran 77) requires this function. */
int
clearenv (void)
{
LOCK;
if (__environ == last_environ && __environ != NULL)
{
/* We allocated this environment so we can free it. */
free (__environ);
last_environ = NULL;
}
/* Clear the environment pointer removes the whole environment. */
__environ = NULL;
UNLOCK;
return 0;
}
#ifdef _LIBC
static void
free_mem (void)
{
/* Remove all traces. */
clearenv ();
/* Now remove the search tree. */
__tdestroy (known_values, free);
known_values = NULL;
}
text_set_element (__libc_subfreeres, free_mem);
# undef setenv
# undef clearenv
weak_alias (__setenv, setenv)
weak_alias (__clearenv, clearenv)
#endif
#endif /* _LIBC || !HAVE_SETENV */
/* The rest of this file is called into use when replacing an existing
but buggy setenv. Known bugs include failure to diagnose invalid
name, and consuming a leading '=' from value. */
#if HAVE_SETENV
# undef setenv
# if !HAVE_DECL_SETENV
extern int setenv (const char *, const char *, int);
# endif
# define STREQ(a, b) (strcmp (a, b) == 0)
int
rpl_setenv (const char *name, const char *value, int replace)
{
int result;
if (!name || !*name || strchr (name, '='))
{
errno = EINVAL;
return -1;
}
/* Call the real setenv even if replace is 0, in case implementation
has underlying data to update, such as when environ changes. */
result = setenv (name, value, replace);
if (result == 0 && replace && *value == '=')
{
char *tmp = getenv (name);
if (!STREQ (tmp, value))
{
int saved_errno;
size_t len = strlen (value);
tmp = malloca (len + 2);
/* Since leading '=' is eaten, double it up. */
*tmp = '=';
memcpy (tmp + 1, value, len + 1);
result = setenv (name, tmp, replace);
saved_errno = errno;
freea (tmp);
errno = saved_errno;
}
}
return result;
}
#endif /* HAVE_SETENV */

View file

@ -27,7 +27,7 @@
# Specification in the form of a command-line invocation: # Specification in the form of a command-line invocation:
# gnulib-tool --import --dir=. --local-dir=gnulib-local --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --lgpl=3 --no-conditional-dependencies --libtool --macro-prefix=gl --no-vc-files accept alignof alloca-opt announce-gen autobuild bind byteswap canonicalize-lgpl ceil close connect dirfd duplocale environ extensions flock floor fpieee frexp full-read full-write func gendocs getaddrinfo getpeername getsockname getsockopt git-version-gen gitlog-to-changelog gnu-web-doc-update gnupload havelib iconv_open-utf inet_ntop inet_pton isinf isnan ldexp lib-symbol-versions lib-symbol-visibility libunistring listen localcharset locale log1p maintainer-makefile malloc-gnu malloca nproc open pipe2 putenv recv recvfrom rename send sendto setsockopt shutdown socket stat-time stdlib strftime striconveh string sys_stat trunc verify vsnprintf warnings wchar # gnulib-tool --import --dir=. --local-dir=gnulib-local --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --lgpl=3 --no-conditional-dependencies --libtool --macro-prefix=gl --no-vc-files accept alignof alloca-opt announce-gen autobuild bind byteswap canonicalize-lgpl ceil close connect dirfd duplocale environ extensions flock floor fpieee frexp full-read full-write func gendocs getaddrinfo getpeername getsockname getsockopt git-version-gen gitlog-to-changelog gnu-web-doc-update gnupload havelib iconv_open-utf inet_ntop inet_pton isinf isnan ldexp lib-symbol-versions lib-symbol-visibility libunistring listen localcharset locale log1p maintainer-makefile malloc-gnu malloca nproc open pipe2 putenv recv recvfrom rename send sendto setenv setsockopt shutdown socket stat-time stdlib strftime striconveh string sys_stat trunc verify vsnprintf warnings wchar
# Specification in the form of a few gnulib-tool.m4 macro invocations: # Specification in the form of a few gnulib-tool.m4 macro invocations:
gl_LOCAL_DIR([gnulib-local]) gl_LOCAL_DIR([gnulib-local])
@ -89,6 +89,7 @@ gl_MODULES([
rename rename
send send
sendto sendto
setenv
setsockopt setsockopt
shutdown shutdown
socket socket

View file

@ -149,6 +149,7 @@ AC_DEFUN([gl_EARLY],
# Code from module send: # Code from module send:
# Code from module sendto: # Code from module sendto:
# Code from module servent: # Code from module servent:
# Code from module setenv:
# Code from module setsockopt: # Code from module setsockopt:
# Code from module shutdown: # Code from module shutdown:
# Code from module signal-h: # Code from module signal-h:
@ -523,6 +524,11 @@ if test "$ac_cv_header_winsock2_h" = yes; then
fi fi
gl_SYS_SOCKET_MODULE_INDICATOR([sendto]) gl_SYS_SOCKET_MODULE_INDICATOR([sendto])
gl_SERVENT gl_SERVENT
gl_FUNC_SETENV
if test $HAVE_SETENV = 0 || test $REPLACE_SETENV = 1; then
AC_LIBOBJ([setenv])
fi
gl_STDLIB_MODULE_INDICATOR([setenv])
AC_REQUIRE([gl_HEADER_SYS_SOCKET]) AC_REQUIRE([gl_HEADER_SYS_SOCKET])
if test "$ac_cv_header_winsock2_h" = yes; then if test "$ac_cv_header_winsock2_h" = yes; then
AC_LIBOBJ([setsockopt]) AC_LIBOBJ([setsockopt])
@ -886,6 +892,7 @@ AC_DEFUN([gl_FILE_LIST], [
lib/same-inode.h lib/same-inode.h
lib/send.c lib/send.c
lib/sendto.c lib/sendto.c
lib/setenv.c
lib/setsockopt.c lib/setsockopt.c
lib/shutdown.c lib/shutdown.c
lib/signal.in.h lib/signal.in.h
@ -1027,6 +1034,7 @@ AC_DEFUN([gl_FILE_LIST], [
m4/safe-read.m4 m4/safe-read.m4
m4/safe-write.m4 m4/safe-write.m4
m4/servent.m4 m4/servent.m4
m4/setenv.m4
m4/signal_h.m4 m4/signal_h.m4
m4/size_max.m4 m4/size_max.m4
m4/snprintf.m4 m4/snprintf.m4

140
m4/setenv.m4 Normal file
View file

@ -0,0 +1,140 @@
# setenv.m4 serial 25
dnl Copyright (C) 2001-2004, 2006-2012 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
dnl with or without modifications, as long as this notice is preserved.
AC_DEFUN([gl_FUNC_SETENV],
[
AC_REQUIRE([gl_FUNC_SETENV_SEPARATE])
if test $ac_cv_func_setenv = no; then
HAVE_SETENV=0
else
AC_CACHE_CHECK([whether setenv validates arguments],
[gl_cv_func_setenv_works],
[AC_RUN_IFELSE([AC_LANG_PROGRAM([[
#include <stdlib.h>
#include <errno.h>
#include <string.h>
]], [[
int result = 0;
{
if (setenv ("", "", 0) != -1)
result |= 1;
else if (errno != EINVAL)
result |= 2;
}
{
if (setenv ("a", "=", 1) != 0)
result |= 4;
else if (strcmp (getenv ("a"), "=") != 0)
result |= 8;
}
return result;
]])],
[gl_cv_func_setenv_works=yes], [gl_cv_func_setenv_works=no],
[gl_cv_func_setenv_works="guessing no"])])
if test "$gl_cv_func_setenv_works" != yes; then
REPLACE_SETENV=1
fi
fi
])
# Like gl_FUNC_SETENV, except prepare for separate compilation
# (no REPLACE_SETENV, no AC_LIBOBJ).
AC_DEFUN([gl_FUNC_SETENV_SEPARATE],
[
AC_REQUIRE([gl_STDLIB_H_DEFAULTS])
AC_CHECK_DECLS_ONCE([setenv])
if test $ac_cv_have_decl_setenv = no; then
HAVE_DECL_SETENV=0
fi
AC_CHECK_FUNCS_ONCE([setenv])
gl_PREREQ_SETENV
])
AC_DEFUN([gl_FUNC_UNSETENV],
[
AC_REQUIRE([gl_STDLIB_H_DEFAULTS])
AC_CHECK_DECLS_ONCE([unsetenv])
if test $ac_cv_have_decl_unsetenv = no; then
HAVE_DECL_UNSETENV=0
fi
AC_CHECK_FUNCS([unsetenv])
if test $ac_cv_func_unsetenv = no; then
HAVE_UNSETENV=0
else
HAVE_UNSETENV=1
dnl Some BSDs return void, failing to do error checking.
AC_CACHE_CHECK([for unsetenv() return type], [gt_cv_func_unsetenv_ret],
[AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM(
[[
#undef _BSD
#define _BSD 1 /* unhide unsetenv declaration in OSF/1 5.1 <stdlib.h> */
#include <stdlib.h>
extern
#ifdef __cplusplus
"C"
#endif
int unsetenv (const char *name);
]],
[[]])],
[gt_cv_func_unsetenv_ret='int'],
[gt_cv_func_unsetenv_ret='void'])])
if test $gt_cv_func_unsetenv_ret = 'void'; then
AC_DEFINE([VOID_UNSETENV], [1], [Define to 1 if unsetenv returns void
instead of int.])
REPLACE_UNSETENV=1
fi
dnl Solaris 10 unsetenv does not remove all copies of a name.
dnl Haiku alpha 2 unsetenv gets confused by assignment to environ.
dnl OpenBSD 4.7 unsetenv("") does not fail.
AC_CACHE_CHECK([whether unsetenv obeys POSIX],
[gl_cv_func_unsetenv_works],
[AC_RUN_IFELSE([AC_LANG_PROGRAM([[
#include <stdlib.h>
#include <errno.h>
extern char **environ;
]], [[
char entry1[] = "a=1";
char entry2[] = "b=2";
char *env[] = { entry1, entry2, NULL };
if (putenv ((char *) "a=1")) return 1;
if (putenv (entry2)) return 2;
entry2[0] = 'a';
unsetenv ("a");
if (getenv ("a")) return 3;
if (!unsetenv ("") || errno != EINVAL) return 4;
entry2[0] = 'b';
environ = env;
if (!getenv ("a")) return 5;
entry2[0] = 'a';
unsetenv ("a");
if (getenv ("a")) return 6;
]])],
[gl_cv_func_unsetenv_works=yes], [gl_cv_func_unsetenv_works=no],
[gl_cv_func_unsetenv_works="guessing no"])])
if test "$gl_cv_func_unsetenv_works" != yes; then
REPLACE_UNSETENV=1
fi
fi
])
# Prerequisites of lib/setenv.c.
AC_DEFUN([gl_PREREQ_SETENV],
[
AC_REQUIRE([AC_FUNC_ALLOCA])
AC_REQUIRE([gl_ENVIRON])
AC_CHECK_HEADERS_ONCE([unistd.h])
AC_CHECK_HEADERS([search.h])
AC_CHECK_FUNCS([tsearch])
])
# Prerequisites of lib/unsetenv.c.
AC_DEFUN([gl_PREREQ_UNSETENV],
[
AC_REQUIRE([gl_ENVIRON])
AC_CHECK_HEADERS_ONCE([unistd.h])
])