Blame lib/msvc-inval.h

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