Blame lib/msvc-inval.h

Packit 33f14e
/* Invalid parameter handler for MSVC runtime libraries.
Packit 33f14e
   Copyright (C) 2011-2017 Free Software Foundation, Inc.
Packit 33f14e
Packit 33f14e
   This program is free software; you can redistribute it and/or modify
Packit 33f14e
   it under the terms of the GNU General Public License as published by
Packit 33f14e
   the Free Software Foundation; either version 3, or (at your option)
Packit 33f14e
   any later version.
Packit 33f14e
Packit 33f14e
   This program is distributed in the hope that it will be useful,
Packit 33f14e
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 33f14e
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 33f14e
   GNU General Public License for more details.
Packit 33f14e
Packit 33f14e
   You should have received a copy of the GNU General Public License along
Packit 33f14e
   with this program; if not, see <http://www.gnu.org/licenses/>.  */
Packit 33f14e
Packit 33f14e
#ifndef _MSVC_INVAL_H
Packit 33f14e
#define _MSVC_INVAL_H
Packit 33f14e
Packit 33f14e
/* With MSVC runtime libraries with the "invalid parameter handler" concept,
Packit 33f14e
   functions like fprintf(), dup2(), or close() crash when the caller passes
Packit 33f14e
   an invalid argument.  But POSIX wants error codes (such as EINVAL or EBADF)
Packit 33f14e
   instead.
Packit 33f14e
   This file defines macros that turn such an invalid parameter notification
Packit 33f14e
   into a non-local exit.  An error code can then be produced at the target
Packit 33f14e
   of this exit.  You can thus write code like
Packit 33f14e
Packit 33f14e
     TRY_MSVC_INVAL
Packit 33f14e
       {
Packit 33f14e
         
Packit 33f14e
          but does not do 'return', 'break', 'continue', nor 'goto'.>
Packit 33f14e
       }
Packit 33f14e
     CATCH_MSVC_INVAL
Packit 33f14e
       {
Packit 33f14e
         
Packit 33f14e
          but does not do 'return', 'break', 'continue', nor 'goto'.>
Packit 33f14e
       }
Packit 33f14e
     DONE_MSVC_INVAL;
Packit 33f14e
Packit 33f14e
   This entire block expands to a single statement.
Packit 33f14e
Packit 33f14e
   The handling of invalid parameters can be done in three ways:
Packit 33f14e
Packit 33f14e
     * The default way, which is reasonable for programs (not libraries):
Packit 33f14e
       AC_DEFINE([MSVC_INVALID_PARAMETER_HANDLING], [DEFAULT_HANDLING])
Packit 33f14e
Packit 33f14e
     * The way for libraries that make "hairy" calls (like close(-1), or
Packit 33f14e
       fclose(fp) where fileno(fp) is closed, or simply getdtablesize()):
Packit 33f14e
       AC_DEFINE([MSVC_INVALID_PARAMETER_HANDLING], [HAIRY_LIBRARY_HANDLING])
Packit 33f14e
Packit 33f14e
     * The way for libraries that make no "hairy" calls:
Packit 33f14e
       AC_DEFINE([MSVC_INVALID_PARAMETER_HANDLING], [SANE_LIBRARY_HANDLING])
Packit 33f14e
 */
Packit 33f14e
Packit 33f14e
#define DEFAULT_HANDLING       0
Packit 33f14e
#define HAIRY_LIBRARY_HANDLING 1
Packit 33f14e
#define SANE_LIBRARY_HANDLING  2
Packit 33f14e
Packit 33f14e
#if HAVE_MSVC_INVALID_PARAMETER_HANDLER \
Packit 33f14e
    && !(MSVC_INVALID_PARAMETER_HANDLING == SANE_LIBRARY_HANDLING)
Packit 33f14e
/* A native Windows platform with the "invalid parameter handler" concept,
Packit 33f14e
   and either DEFAULT_HANDLING or HAIRY_LIBRARY_HANDLING.  */
Packit 33f14e
Packit 33f14e
# if MSVC_INVALID_PARAMETER_HANDLING == DEFAULT_HANDLING
Packit 33f14e
/* Default handling.  */
Packit 33f14e
Packit 33f14e
#  ifdef __cplusplus
Packit 33f14e
extern "C" {
Packit 33f14e
#  endif
Packit 33f14e
Packit 33f14e
/* Ensure that the invalid parameter handler in installed that just returns.
Packit 33f14e
   Because we assume no other part of the program installs a different
Packit 33f14e
   invalid parameter handler, this solution is multithread-safe.  */
Packit 33f14e
extern void gl_msvc_inval_ensure_handler (void);
Packit 33f14e
Packit 33f14e
#  ifdef __cplusplus
Packit 33f14e
}
Packit 33f14e
#  endif
Packit 33f14e
Packit 33f14e
#  define TRY_MSVC_INVAL \
Packit 33f14e
     do                                                                        \
Packit 33f14e
       {                                                                       \
Packit 33f14e
         gl_msvc_inval_ensure_handler ();                                      \
Packit 33f14e
         if (1)
Packit 33f14e
#  define CATCH_MSVC_INVAL \
Packit 33f14e
         else
Packit 33f14e
#  define DONE_MSVC_INVAL \
Packit 33f14e
       }                                                                       \
Packit 33f14e
     while (0)
Packit 33f14e
Packit 33f14e
# else
Packit 33f14e
/* Handling for hairy libraries.  */
Packit 33f14e
Packit 33f14e
#  include <excpt.h>
Packit 33f14e
Packit 33f14e
/* Gnulib can define its own status codes, as described in the page
Packit 33f14e
   "Raising Software Exceptions" on microsoft.com
Packit 33f14e
   <http://msdn.microsoft.com/en-us/library/het71c37.aspx>.
Packit 33f14e
   Our status codes are composed of
Packit 33f14e
     - 0xE0000000, mandatory for all user-defined status codes,
Packit 33f14e
     - 0x474E550, a API identifier ("GNU"),
Packit 33f14e
     - 0, 1, 2, ..., used to distinguish different status codes from the
Packit 33f14e
       same API.  */
Packit 33f14e
#  define STATUS_GNULIB_INVALID_PARAMETER (0xE0000000 + 0x474E550 + 0)
Packit 33f14e
Packit 33f14e
#  if defined _MSC_VER
Packit 33f14e
/* A compiler that supports __try/__except, as described in the page
Packit 33f14e
   "try-except statement" on microsoft.com
Packit 33f14e
   <http://msdn.microsoft.com/en-us/library/s58ftw19.aspx>.
Packit 33f14e
   With __try/__except, we can use the multithread-safe exception handling.  */
Packit 33f14e
Packit 33f14e
#   ifdef __cplusplus
Packit 33f14e
extern "C" {
Packit 33f14e
#   endif
Packit 33f14e
Packit 33f14e
/* Ensure that the invalid parameter handler in installed that raises a
Packit 33f14e
   software exception with code STATUS_GNULIB_INVALID_PARAMETER.
Packit 33f14e
   Because we assume no other part of the program installs a different
Packit 33f14e
   invalid parameter handler, this solution is multithread-safe.  */
Packit 33f14e
extern void gl_msvc_inval_ensure_handler (void);
Packit 33f14e
Packit 33f14e
#   ifdef __cplusplus
Packit 33f14e
}
Packit 33f14e
#   endif
Packit 33f14e
Packit 33f14e
#   define TRY_MSVC_INVAL \
Packit 33f14e
      do                                                                       \
Packit 33f14e
        {                                                                      \
Packit 33f14e
          gl_msvc_inval_ensure_handler ();                                     \
Packit 33f14e
          __try
Packit 33f14e
#   define CATCH_MSVC_INVAL \
Packit 33f14e
          __except (GetExceptionCode () == STATUS_GNULIB_INVALID_PARAMETER     \
Packit 33f14e
                    ? EXCEPTION_EXECUTE_HANDLER                                \
Packit 33f14e
                    : EXCEPTION_CONTINUE_SEARCH)
Packit 33f14e
#   define DONE_MSVC_INVAL \
Packit 33f14e
        }                                                                      \
Packit 33f14e
      while (0)
Packit 33f14e
Packit 33f14e
#  else
Packit 33f14e
/* Any compiler.
Packit 33f14e
   We can only use setjmp/longjmp.  */
Packit 33f14e
Packit 33f14e
#   include <setjmp.h>
Packit 33f14e
Packit 33f14e
#   ifdef __cplusplus
Packit 33f14e
extern "C" {
Packit 33f14e
#   endif
Packit 33f14e
Packit 33f14e
struct gl_msvc_inval_per_thread
Packit 33f14e
{
Packit 33f14e
  /* The restart that will resume execution at the code between
Packit 33f14e
     CATCH_MSVC_INVAL and DONE_MSVC_INVAL.  It is enabled only between
Packit 33f14e
     TRY_MSVC_INVAL and CATCH_MSVC_INVAL.  */
Packit 33f14e
  jmp_buf restart;
Packit 33f14e
Packit 33f14e
  /* Tells whether the contents of restart is valid.  */
Packit 33f14e
  int restart_valid;
Packit 33f14e
};
Packit 33f14e
Packit 33f14e
/* Ensure that the invalid parameter handler in installed that passes
Packit 33f14e
   control to the gl_msvc_inval_restart if it is valid, or raises a
Packit 33f14e
   software exception with code STATUS_GNULIB_INVALID_PARAMETER otherwise.
Packit 33f14e
   Because we assume no other part of the program installs a different
Packit 33f14e
   invalid parameter handler, this solution is multithread-safe.  */
Packit 33f14e
extern void gl_msvc_inval_ensure_handler (void);
Packit 33f14e
Packit 33f14e
/* Return a pointer to the per-thread data for the current thread.  */
Packit 33f14e
extern struct gl_msvc_inval_per_thread *gl_msvc_inval_current (void);
Packit 33f14e
Packit 33f14e
#   ifdef __cplusplus
Packit 33f14e
}
Packit 33f14e
#   endif
Packit 33f14e
Packit 33f14e
#   define TRY_MSVC_INVAL \
Packit 33f14e
      do                                                                       \
Packit 33f14e
        {                                                                      \
Packit 33f14e
          struct gl_msvc_inval_per_thread *msvc_inval_current;                 \
Packit 33f14e
          gl_msvc_inval_ensure_handler ();                                     \
Packit 33f14e
          msvc_inval_current = gl_msvc_inval_current ();                       \
Packit 33f14e
          /* First, initialize gl_msvc_inval_restart.  */                      \
Packit 33f14e
          if (setjmp (msvc_inval_current->restart) == 0)                       \
Packit 33f14e
            {                                                                  \
Packit 33f14e
              /* Then, mark it as valid.  */                                   \
Packit 33f14e
              msvc_inval_current->restart_valid = 1;
Packit 33f14e
#   define CATCH_MSVC_INVAL \
Packit 33f14e
              /* Execution completed.                                          \
Packit 33f14e
                 Mark gl_msvc_inval_restart as invalid.  */                    \
Packit 33f14e
              msvc_inval_current->restart_valid = 0;                           \
Packit 33f14e
            }                                                                  \
Packit 33f14e
          else                                                                 \
Packit 33f14e
            {                                                                  \
Packit 33f14e
              /* Execution triggered an invalid parameter notification.        \
Packit 33f14e
                 Mark gl_msvc_inval_restart as invalid.  */                    \
Packit 33f14e
              msvc_inval_current->restart_valid = 0;
Packit 33f14e
#   define DONE_MSVC_INVAL \
Packit 33f14e
            }                                                                  \
Packit 33f14e
        }                                                                      \
Packit 33f14e
      while (0)
Packit 33f14e
Packit 33f14e
#  endif
Packit 33f14e
Packit 33f14e
# endif
Packit 33f14e
Packit 33f14e
#else
Packit 33f14e
/* A platform that does not need to the invalid parameter handler,
Packit 33f14e
   or when SANE_LIBRARY_HANDLING is desired.  */
Packit 33f14e
Packit 33f14e
/* The braces here avoid GCC warnings like
Packit 33f14e
   "warning: suggest explicit braces to avoid ambiguous 'else'".  */
Packit 33f14e
# define TRY_MSVC_INVAL \
Packit 33f14e
    do                                                                         \
Packit 33f14e
      {                                                                        \
Packit 33f14e
        if (1)
Packit 33f14e
# define CATCH_MSVC_INVAL \
Packit 33f14e
        else
Packit 33f14e
# define DONE_MSVC_INVAL \
Packit 33f14e
      }                                                                        \
Packit 33f14e
    while (0)
Packit 33f14e
Packit 33f14e
#endif
Packit 33f14e
Packit 33f14e
#endif /* _MSVC_INVAL_H */