Blame lib/msvc-inval.h

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