Blame gl/msvc-inval.h

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