msvc-inval: Allow three invalid parameter handling modes.
authorBruno Haible <bruno@clisp.org>
Sun, 25 Sep 2011 21:08:45 +0000 (23:08 +0200)
committerBruno Haible <bruno@clisp.org>
Sun, 25 Sep 2011 21:08:45 +0000 (23:08 +0200)
* lib/msvc-inval.h: Don't include <stdlib.h> here.
(DEFAULT_HANDLING, HAIRY_LIBRARY_HANDLING, SANE_LIBRARY_HANDLING): New
macros.
(gl_msvc_inval_ensure_handler, TRY_MSVC_INVAL, CATCH_MSVC_INVAL,
DONE_MSVC_INVAL): Implement DEFAULT_HANDLING. Treat
SANE_LIBRARY_HANDLING as a no-op.
* lib/msvc-inval.c: Treat SANE_LIBRARY_HANDLING as a no-op. Include
<stdlib.h>.
(gl_msvc_invalid_parameter_handler): Implement DEFAULT_HANDLING.

ChangeLog
lib/msvc-inval.c
lib/msvc-inval.h

index 4b51d08..0bea9c5 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,18 @@
 2011-09-25  Bruno Haible  <bruno@clisp.org>
 
+       msvc-inval: Allow three invalid parameter handling modes.
+       * lib/msvc-inval.h: Don't include <stdlib.h> here.
+       (DEFAULT_HANDLING, HAIRY_LIBRARY_HANDLING, SANE_LIBRARY_HANDLING): New
+       macros.
+       (gl_msvc_inval_ensure_handler, TRY_MSVC_INVAL, CATCH_MSVC_INVAL,
+       DONE_MSVC_INVAL): Implement DEFAULT_HANDLING. Treat
+       SANE_LIBRARY_HANDLING as a no-op.
+       * lib/msvc-inval.c: Treat SANE_LIBRARY_HANDLING as a no-op. Include
+       <stdlib.h>.
+       (gl_msvc_invalid_parameter_handler): Implement DEFAULT_HANDLING.
+
+2011-09-25  Bruno Haible  <bruno@clisp.org>
+
        msvc-inval: Make handler multithread-safe.
        * lib/msvc-inval.h (struct gl_msvc_inval_per_thread): New type.
        (gl_msvc_inval_restart, gl_msvc_inval_restart_valid): Remove
index ba3c799..31dbeea 100644 (file)
 /* Specification.  */
 #include "msvc-inval.h"
 
-#if HAVE_MSVC_INVALID_PARAMETER_HANDLER
+#if HAVE_MSVC_INVALID_PARAMETER_HANDLER \
+    && !(MSVC_INVALID_PARAMETER_HANDLING == SANE_LIBRARY_HANDLING)
+
+/* Get _invalid_parameter_handler type and _set_invalid_parameter_handler
+   declaration.  */
+# include <stdlib.h>
+
+# if MSVC_INVALID_PARAMETER_HANDLING == DEFAULT_HANDLING
+
+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)
+{
+}
+
+# else
 
 /* Get declarations of the Win32 API functions.  */
-# define WIN32_LEAN_AND_MEAN
-# include <windows.h>
+#  define WIN32_LEAN_AND_MEAN
+#  include <windows.h>
 
-# if defined _MSC_VER
+#  if defined _MSC_VER
 
 static void cdecl
 gl_msvc_invalid_parameter_handler (const wchar_t *expression,
@@ -38,7 +56,7 @@ gl_msvc_invalid_parameter_handler (const wchar_t *expression,
   RaiseException (STATUS_GNULIB_INVALID_PARAMETER, 0, 0, NULL);
 }
 
-# else
+#  else
 
 /* An index to thread-local storage.  */
 static DWORD tls_index;
@@ -93,6 +111,8 @@ gl_msvc_invalid_parameter_handler (const wchar_t *expression,
     RaiseException (STATUS_GNULIB_INVALID_PARAMETER, 0, 0, NULL);
 }
 
+#  endif
+
 # endif
 
 static int gl_msvc_inval_initialized /* = 0 */;
index 5f2e446..5ebc29f 100644 (file)
      DONE_MSVC_INVAL;
 
    This entire block expands to a single statement.
- */
 
-#if HAVE_MSVC_INVALID_PARAMETER_HANDLER
-/* A native Windows platform with the "invalid parameter handler" concept.  */
+   The handling of invalid parameters can be done in three ways:
 
-/* Get _invalid_parameter_handler type and _set_invalid_parameter_handler
-   declaration.  */
-# include <stdlib.h>
-# include <excpt.h>
+     * The default way, which is reasonable for programs (not libraries):
+       AC_DEFINE([MSVC_INVALID_PARAMETER_HANDLING], [DEFAULT_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)
+     * The way for libraries that make "hairy" calls (like close(-1), or
+       fclose(fp) where fileno(fp) is closed, or simply getdtablesize()):
+       AC_DEFINE([MSVC_INVALID_PARAMETER_HANDLING], [HAIRY_LIBRARY_HANDLING])
 
-# 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.  */
+     * The way for libraries that make no "hairy" calls:
+       AC_DEFINE([MSVC_INVALID_PARAMETER_HANDLING], [SANE_LIBRARY_HANDLING])
+ */
+
+#define DEFAULT_HANDLING       0
+#define HAIRY_LIBRARY_HANDLING 1
+#define SANE_LIBRARY_HANDLING  2
+
+#if HAVE_MSVC_INVALID_PARAMETER_HANDLER \
+    && !(MSVC_INVALID_PARAMETER_HANDLING == SANE_LIBRARY_HANDLING)
+/* A native Windows platform with the "invalid parameter handler" concept,
+   and either DEFAULT_HANDLING or HAIRY_LIBRARY_HANDLING.  */
+
+# if MSVC_INVALID_PARAMETER_HANDLING == DEFAULT_HANDLING
+/* Default handling.  */
 
 #  ifdef __cplusplus
 extern "C" {
 #  endif
 
-/* Ensure that the invalid parameter handler in installed that raises a
-   software exception with code STATUS_GNULIB_INVALID_PARAMETER.
+/* Ensure that the invalid parameter handler in installed that just returns.
    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);
@@ -83,24 +82,70 @@ extern void gl_msvc_inval_ensure_handler (void);
      do                                                                        \
        {                                                                       \
          gl_msvc_inval_ensure_handler ();                                      \
-         __try
+         if (1)
 #  define CATCH_MSVC_INVAL \
-         __except (GetExceptionCode () == STATUS_GNULIB_INVALID_PARAMETER      \
-                   ? EXCEPTION_EXECUTE_HANDLER                                 \
-                   : EXCEPTION_CONTINUE_SEARCH)
+         else
 #  define DONE_MSVC_INVAL \
        }                                                                       \
      while (0)
 
 # else
+/* Handling for hairy libraries.  */
+
+#  include <excpt.h>
+
+/* 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)
+
+#  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.  */
+
+#   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 \
+      do                                                                       \
+        {                                                                      \
+          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 \
+        }                                                                      \
+      while (0)
+
+#  else
 /* Any compiler.
    We can only use setjmp/longjmp.  */
 
-#  include <setjmp.h>
+#   include <setjmp.h>
 
-#  ifdef __cplusplus
+#   ifdef __cplusplus
 extern "C" {
-#  endif
+#   endif
 
 struct gl_msvc_inval_per_thread
 {
@@ -123,40 +168,43 @@ extern void gl_msvc_inval_ensure_handler (void);
 /* Return a pointer to the per-thread data for the current thread.  */
 extern struct gl_msvc_inval_per_thread *gl_msvc_inval_current (void);
 
-#  ifdef __cplusplus
+#   ifdef __cplusplus
 }
-#  endif
+#   endif
+
+#   define TRY_MSVC_INVAL \
+      do                                                                       \
+        {                                                                      \
+          struct gl_msvc_inval_per_thread *msvc_inval_current;                 \
+          gl_msvc_inval_ensure_handler ();                                     \
+          msvc_inval_current = gl_msvc_inval_current ();                       \
+          /* First, initialize gl_msvc_inval_restart.  */                      \
+          if (setjmp (msvc_inval_current->restart) == 0)                       \
+            {                                                                  \
+              /* Then, mark it as valid.  */                                   \
+              msvc_inval_current->restart_valid = 1;
+#   define CATCH_MSVC_INVAL \
+              /* Execution completed.                                          \
+                 Mark gl_msvc_inval_restart as invalid.  */                    \
+              msvc_inval_current->restart_valid = 0;                           \
+            }                                                                  \
+          else                                                                 \
+            {                                                                  \
+              /* Execution triggered an invalid parameter notification.        \
+                 Mark gl_msvc_inval_restart as invalid.  */                    \
+              msvc_inval_current->restart_valid = 0;
+#   define DONE_MSVC_INVAL \
+            }                                                                  \
+        }                                                                      \
+      while (0)
 
-#  define TRY_MSVC_INVAL \
-     do                                                                        \
-       {                                                                       \
-         struct gl_msvc_inval_per_thread *msvc_inval_current;                  \
-         gl_msvc_inval_ensure_handler ();                                      \
-         msvc_inval_current = gl_msvc_inval_current ();                        \
-         /* First, initialize gl_msvc_inval_restart.  */                       \
-         if (setjmp (msvc_inval_current->restart) == 0)                        \
-           {                                                                   \
-             /* Then, mark it as valid.  */                                    \
-             msvc_inval_current->restart_valid = 1;
-#  define CATCH_MSVC_INVAL \
-             /* Execution completed.                                           \
-                Mark gl_msvc_inval_restart as invalid.  */                     \
-             msvc_inval_current->restart_valid = 0;                            \
-           }                                                                   \
-         else                                                                  \
-           {                                                                   \
-             /* Execution triggered an invalid parameter notification.         \
-                Mark gl_msvc_inval_restart as invalid.  */                     \
-             msvc_inval_current->restart_valid = 0;
-#  define DONE_MSVC_INVAL \
-           }                                                                   \
-       }                                                                       \
-     while (0)
+#  endif
 
 # endif
 
 #else
-/* A platform that does not need to the invalid parameter handler.  */
+/* A platform that does not need to the invalid parameter handler,
+   or when SANE_LIBRARY_HANDLING is desired.  */
 
 /* The braces here avoid GCC warnings like
    "warning: suggest explicit braces to avoid ambiguous `else'".  */