Blame gettext-runtime/gnulib-lib/msvc-inval.h

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