--- /dev/null
+/* Invalid parameter handler for MSVC runtime libraries.
+ Copyright (C) 2011 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#include <config.h>
+
+/* Specification. */
+#include "msvc-inval.h"
+
+#if HAVE_MSVC_INVALID_PARAMETER_HANDLER
+
+# ifdef STATUS_GNULIB_INVALID_PARAMETER
+
+/* Get declarations of the Win32 API functions. */
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+
+static void cdecl
+gl_msvc_invalid_parameter_handler (const wchar_t *expression,
+ const wchar_t *function,
+ const wchar_t *file,
+ unsigned int line,
+ uintptr_t dummy)
+{
+ RaiseException (STATUS_GNULIB_INVALID_PARAMETER, 0, 0, NULL);
+}
+
+static int gl_msvc_inval_initialized /* = 0 */;
+
+void
+gl_msvc_inval_ensure_handler (void)
+{
+ if (gl_msvc_inval_initialized == 0)
+ {
+ _set_invalid_parameter_handler (gl_msvc_invalid_parameter_handler);
+ gl_msvc_inval_initialized = 1;
+ }
+}
+
+# else
+
+jmp_buf gl_msvc_inval_restart;
+
+void cdecl
+gl_msvc_invalid_parameter_handler (const wchar_t *expression,
+ const wchar_t *function,
+ const wchar_t *file,
+ unsigned int line,
+ uintptr_t dummy)
+{
+ longjmp (gl_msvc_inval_restart, 1);
+}
+
+# endif
+
+#endif
--- /dev/null
+/* Invalid parameter handler for MSVC runtime libraries.
+ Copyright (C) 2011 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef _MSVC_INVAL_H
+#define _MSVC_INVAL_H
+
+/* With MSVC runtime libraries with the "invalid parameter handler" concept,
+ functions like fprintf(), dup2(), or close() crash when the caller passes
+ an invalid argument. But POSIX wants error codes (such as EINVAL or EBADF)
+ instead.
+ This file defines macros that turn such an invalid parameter notification
+ into a non-local exit. An error code can then be produced at the target
+ of this exit. You can thus write code like
+
+ TRY_MSVC_INVAL
+ {
+ <Code that can trigger an invalid parameter notification
+ but does not do 'return', 'break', nor 'goto'.>
+ }
+ CATCH_MSVC_INVAL
+ {
+ <Code that handles an invalid parameter notification
+ but does not do 'return', 'break', nor 'goto'.>
+ }
+ DONE_MSVC_INVAL
+ */
+
+#if HAVE_MSVC_INVALID_PARAMETER_HANDLER
+/* A native Windows platform with the "invalid parameter handler" concept. */
+
+/* Get _invalid_parameter_handler type and _set_invalid_parameter_handler
+ declaration. */
+#include <stdlib.h>
+
+# if defined _MSC_VER
+/* A compiler that supports __try/__except, as described in the page
+ "try-except statement" on microsoft.com
+ <http://msdn.microsoft.com/en-us/library/s58ftw19.aspx>.
+ With __try/__except, we can use the multithread-safe exception handling. */
+
+/* Gnulib can define its own status codes, as described in the page
+ "Raising Software Exceptions" on microsoft.com
+ <http://msdn.microsoft.com/en-us/library/het71c37.aspx>.
+ Our status codes are composed of
+ - 0xE0000000, mandatory for all user-defined status codes,
+ - 0x474E550, a API identifier ("GNU"),
+ - 0, 1, 2, ..., used to distinguish different status codes from the
+ same API. */
+# define STATUS_GNULIB_INVALID_PARAMETER (0xE0000000 + 0x474E550 + 0)
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+/* Ensure that the invalid parameter handler in installed that raises a
+ software exception with code STATUS_GNULIB_INVALID_PARAMETER.
+ Because we assume no other part of the program installs a different
+ invalid parameter handler, this solution is multithread-safe. */
+extern void gl_msvc_inval_ensure_handler (void);
+
+# ifdef __cplusplus
+}
+# endif
+
+# define TRY_MSVC_INVAL \
+ gl_msvc_inval_ensure_handler (); \
+ __try
+# define CATCH_MSVC_INVAL \
+ __except (GetExceptionCode () == STATUS_GNULIB_INVALID_PARAMETER \
+ ? EXCEPTION_EXECUTE_HANDLER \
+ : EXCEPTION_CONTINUE_SEARCH)
+# define DONE_MSVC_INVAL
+
+# else
+/* Any compiler.
+ We can only use setjmp/longjmp.
+ Unfortunately, this is *not* multithread-safe. */
+
+# include <setjmp.h>
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+/* The restart that will resume execution at the code between
+ CATCH_MSVC_INVAL and DONE_MSVC_INVAL. It is enabled only between
+ TRY_MSVC_INVAL and CATCH_MSVC_INVAL. */
+extern jmp_buf gl_msvc_inval_restart;
+
+/* The invalid parameter handler that unwinds the stack up to the
+ gl_msvc_inval_restart. It is enabled only between TRY_MSVC_INVAL
+ and CATCH_MSVC_INVAL. */
+extern void cdecl gl_msvc_invalid_parameter_handler (const wchar_t *expression,
+ const wchar_t *function,
+ const wchar_t *file,
+ unsigned int line,
+ uintptr_t dummy);
+
+# ifdef __cplusplus
+}
+# endif
+
+# define TRY_MSVC_INVAL \
+ { \
+ _invalid_parameter_handler orig_handler; \
+ /* First, initialize gl_msvc_inval_restart. */ \
+ if (setjmp (gl_msvc_inval_restart) == 0) \
+ { \
+ /* Then, enable gl_msvc_invalid_parameter_handler. */ \
+ orig_handler = \
+ _set_invalid_parameter_handler (gl_msvc_invalid_parameter_handler);
+# define CATCH_MSVC_INVAL \
+ /* Execution completed. \
+ Disable gl_msvc_invalid_parameter_handler. */ \
+ _set_invalid_parameter_handler (orig_handler); \
+ } \
+ else \
+ { \
+ /* Execution triggered an invalid parameter notification. \
+ Disable gl_msvc_invalid_parameter_handler. */ \
+ _set_invalid_parameter_handler (orig_handler);
+# define DONE_MSVC_INVAL \
+ } \
+ }
+
+# endif
+
+#else
+
+# define TRY_MSVC_INVAL if (1)
+# define CATCH_MSVC_INVAL else
+# define DONE_MSVC_INVAL
+
+#endif
+
+#endif /* _MSVC_INVAL_H */