Blame gl/msvc-inval.h

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