Blame gl/msvc-inval.h

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