OSDN Git Service

Implement POSIX.1 compatible setenv() and unsetenv() functions.
authorKeith Marshall <keithmarshall@users.sourceforge.net>
Mon, 28 Nov 2016 14:14:48 +0000 (14:14 +0000)
committerKeith Marshall <keithmarshall@users.sourceforge.net>
Mon, 28 Nov 2016 14:14:48 +0000 (14:14 +0000)
mingwrt/ChangeLog
mingwrt/Makefile.in
mingwrt/include/stdlib.h
mingwrt/mingwex/setenv.c [new file with mode: 0644]

index d902839..df2e26e 100644 (file)
@@ -1,3 +1,17 @@
+2016-11-28  Keith Marshall  <keithmarshall@users.sourceforge.net>
+
+       Implement POSIX.1 compatible setenv() and unsetenv() functions.
+
+       * mingwex/setenv.c: New file; it implements...
+       (__mingw_setenv): ...this function, providing common code for...
+       * include/stdlib.h [_POSIX_C_SOURCE >= 200112L] (setenv, unsetenv):
+       ...these user visible functions, implemented as __CRT_ALIAS inlines;
+       qualify them as __JMPSTUB__ and __LIBIMPL__ respectively, so ensuring
+       that their corresponding external representations are automatically
+       added to libmingwex.a
+
+       * Makefile.in (libmingwex.a): Add setenv.$OBJEXT
+
 2016-11-27  Keith Marshall  <keithmarshall@users.sourceforge.net>
 
        Work around another C++11 compliance issue; fix bug [#2321].
index c95d788..0a3e5c3 100644 (file)
@@ -491,7 +491,7 @@ $(addsuffix fmt.$(OBJEXT),varo crto geto seto crtn getn setn): %.$(OBJEXT): ofmt
 #
 libmingwex.a: $(addsuffix .$(OBJEXT), mingw-aligned-malloc mingw-fseek)
 libmingwex.a: $(addsuffix .$(OBJEXT), glob getopt basename dirname nsleep)
-libmingwex.a: $(addsuffix .$(OBJEXT), mkstemp mkdtemp cryptnam)
+libmingwex.a: $(addsuffix .$(OBJEXT), mkstemp mkdtemp cryptnam setenv)
 
 libmingwex.a: $(addsuffix .$(OBJEXT), tdelete tfind tsearch twalk)
 
index e4b98f6..7ca7eb7 100644 (file)
@@ -824,6 +824,24 @@ __cdecl __MINGW_NOTHROW  char *mkdtemp (char *__dirname_template)
 { return __mingw_mkdtemp( __dirname_template ); }
 
 #endif /* _POSIX_C_SOURCE >= 200809L (for mkdtemp()) */
+
+#if _POSIX_C_SOURCE >= 200112L
+/* setenv() and unsetenv() are also available, from POSIX.1-2001 onwards.
+ */
+__cdecl __MINGW_NOTHROW  int setenv( const char *, const char *, int );
+__cdecl __MINGW_NOTHROW  int unsetenv( const char * );
+
+__cdecl __MINGW_NOTHROW  int __mingw_setenv( const char *, const char *, int );
+
+__CRT_ALIAS __JMPSTUB__(( FUNCTION = setenv ))
+__cdecl __MINGW_NOTHROW  int setenv( const char *__n, const char *__v, int __f )
+{ return __mingw_setenv( __n, __v, __f ); }
+
+__CRT_ALIAS __LIBIMPL__(( FUNCTION = unsetenv ))
+__cdecl __MINGW_NOTHROW  int unsetenv( const char *__name )
+{ return __mingw_setenv( __name, NULL, 1 ); }
+
+#endif /* _POSIX_C_SOURCE >= 200112L (for setenv()) */
 #endif /* _STDLIB_H */
 
 _END_C_DECLS
diff --git a/mingwrt/mingwex/setenv.c b/mingwrt/mingwex/setenv.c
new file mode 100644 (file)
index 0000000..57b804d
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * setenv.c
+ *
+ * Implementation of POSIX standard IEEE 1003.1-2001 setenv() function;
+ * may also be invoked inline, as "retval = setenv( varname, NULL, 1 )",
+ * to implement the complementary unsetenv() function.
+ *
+ * $Id$
+ *
+ * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
+ * Copyright (C) 2016, MinGW.org Project
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+#define _POSIX_C_SOURCE 200112L
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+int __mingw_setenv( const char *var, const char *value, int overwrite )
+{
+  /* Core implementation for both setenv() and unsetenv() functions;
+   * at the outset, assume that the requested operation may fail.
+   */
+  int retval = -1;
+
+  /* The specified "var" name MUST be non-NULL, not a zero-length
+   * string, and must not include any '=' character.
+   */
+  if( var && *var && (strchr( var, '=' ) == NULL) )
+  {
+    /* A properly named variable may be added to, removed from,
+     * or modified within the environment, ONLY if "overwrite"
+     * mode is enabled, OR if the named variable does not yet
+     * exist...
+     */
+    if( overwrite || getenv( var ) == NULL )
+    {
+      /* ... in which cases, we convert the specified name and
+       * value into the appropriate form for use with putenv(),
+       * (noting that we accept a NULL "value" as equivalent to
+       * a zero-length string, which renders putenv() as the
+       * equivalent of unsetenv()).
+       */
+      const char *fmt = "%s=%s";
+      const char *val = value ? value : "";
+      char buf[1 + snprintf( NULL, 0, fmt, var, val )];
+      snprintf( buf, sizeof( buf ), fmt, var, val );
+
+      /* "buf" is now formatted as "var=value", in the form
+       * required by putenv(), but it exists only within our
+       * volatile stack-frame space.  POSIX.1 suggests that we
+       * should copy it to more persistent storage, before it
+       * is passed to putenv(), to associate an environment
+       * pointer with it.  However, we note that Microsoft's
+       * putenv() implementation appears to make such a copy
+       * in any case, so we do not do so; (in fact, if we did
+       * strdup() it (say), then we would leak memory).
+       */
+      if( (retval = putenv( buf )) != 0 )
+       /*
+        * If putenv() returns non-zero, indicating failure, the
+        * most probable explanation is that there wasn't enough
+        * free memory; ensure that errno is set accordingly.
+        */
+        errno = ENOMEM;
+    }
+    else
+      /* The named variable already exists, and overwrite mode
+       * was not enabled; there is nothing to be done.
+       */
+      retval = 0;
+  }
+  else
+    /* The specified environment variable name was invalid.
+     */
+    errno = EINVAL;
+
+  /* Succeed or fail, "retval" has now been set to indicate the
+   * appropriate status for return.
+   */
+  return retval;
+}
+
+/* $RCSfile$: end of file */