Blame lib/msvc-inval.h

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