File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libiconv / srclib / msvc-inval.h
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Mar 17 13:38:46 2021 UTC (3 years, 3 months ago) by misho
Branches: libiconv, MAIN
CVS tags: v1_16p0, HEAD
libiconv 1.16

    1: /* Invalid parameter handler for MSVC runtime libraries.
    2:    Copyright (C) 2011-2019 Free Software Foundation, Inc.
    3: 
    4:    This program is free software; you can redistribute it and/or modify
    5:    it under the terms of the GNU General Public License as published by
    6:    the Free Software Foundation; either version 3, or (at your option)
    7:    any later version.
    8: 
    9:    This program is distributed in the hope that it will be useful,
   10:    but WITHOUT ANY WARRANTY; without even the implied warranty of
   11:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   12:    GNU General Public License for more details.
   13: 
   14:    You should have received a copy of the GNU General Public License along
   15:    with this program; if not, see <https://www.gnu.org/licenses/>.  */
   16: 
   17: #ifndef _MSVC_INVAL_H
   18: #define _MSVC_INVAL_H
   19: 
   20: /* With MSVC runtime libraries with the "invalid parameter handler" concept,
   21:    functions like fprintf(), dup2(), or close() crash when the caller passes
   22:    an invalid argument.  But POSIX wants error codes (such as EINVAL or EBADF)
   23:    instead.
   24:    This file defines macros that turn such an invalid parameter notification
   25:    into a non-local exit.  An error code can then be produced at the target
   26:    of this exit.  You can thus write code like
   27: 
   28:      TRY_MSVC_INVAL
   29:        {
   30:          <Code that can trigger an invalid parameter notification
   31:           but does not do 'return', 'break', 'continue', nor 'goto'.>
   32:        }
   33:      CATCH_MSVC_INVAL
   34:        {
   35:          <Code that handles an invalid parameter notification
   36:           but does not do 'return', 'break', 'continue', nor 'goto'.>
   37:        }
   38:      DONE_MSVC_INVAL;
   39: 
   40:    This entire block expands to a single statement.
   41: 
   42:    The handling of invalid parameters can be done in three ways:
   43: 
   44:      * The default way, which is reasonable for programs (not libraries):
   45:        AC_DEFINE([MSVC_INVALID_PARAMETER_HANDLING], [DEFAULT_HANDLING])
   46: 
   47:      * The way for libraries that make "hairy" calls (like close(-1), or
   48:        fclose(fp) where fileno(fp) is closed, or simply getdtablesize()):
   49:        AC_DEFINE([MSVC_INVALID_PARAMETER_HANDLING], [HAIRY_LIBRARY_HANDLING])
   50: 
   51:      * The way for libraries that make no "hairy" calls:
   52:        AC_DEFINE([MSVC_INVALID_PARAMETER_HANDLING], [SANE_LIBRARY_HANDLING])
   53:  */
   54: 
   55: #define DEFAULT_HANDLING       0
   56: #define HAIRY_LIBRARY_HANDLING 1
   57: #define SANE_LIBRARY_HANDLING  2
   58: 
   59: #if HAVE_MSVC_INVALID_PARAMETER_HANDLER \
   60:     && !(MSVC_INVALID_PARAMETER_HANDLING == SANE_LIBRARY_HANDLING)
   61: /* A native Windows platform with the "invalid parameter handler" concept,
   62:    and either DEFAULT_HANDLING or HAIRY_LIBRARY_HANDLING.  */
   63: 
   64: # if MSVC_INVALID_PARAMETER_HANDLING == DEFAULT_HANDLING
   65: /* Default handling.  */
   66: 
   67: #  ifdef __cplusplus
   68: extern "C" {
   69: #  endif
   70: 
   71: /* Ensure that the invalid parameter handler in installed that just returns.
   72:    Because we assume no other part of the program installs a different
   73:    invalid parameter handler, this solution is multithread-safe.  */
   74: extern void gl_msvc_inval_ensure_handler (void);
   75: 
   76: #  ifdef __cplusplus
   77: }
   78: #  endif
   79: 
   80: #  define TRY_MSVC_INVAL \
   81:      do                                                                        \
   82:        {                                                                       \
   83:          gl_msvc_inval_ensure_handler ();                                      \
   84:          if (1)
   85: #  define CATCH_MSVC_INVAL \
   86:          else
   87: #  define DONE_MSVC_INVAL \
   88:        }                                                                       \
   89:      while (0)
   90: 
   91: # else
   92: /* Handling for hairy libraries.  */
   93: 
   94: #  include <excpt.h>
   95: 
   96: /* Gnulib can define its own status codes, as described in the page
   97:    "Raising Software Exceptions" on microsoft.com
   98:    <https://docs.microsoft.com/en-us/cpp/cpp/raising-software-exceptions>.
   99:    Our status codes are composed of
  100:      - 0xE0000000, mandatory for all user-defined status codes,
  101:      - 0x474E550, a API identifier ("GNU"),
  102:      - 0, 1, 2, ..., used to distinguish different status codes from the
  103:        same API.  */
  104: #  define STATUS_GNULIB_INVALID_PARAMETER (0xE0000000 + 0x474E550 + 0)
  105: 
  106: #  if defined _MSC_VER
  107: /* A compiler that supports __try/__except, as described in the page
  108:    "try-except statement" on microsoft.com
  109:    <https://docs.microsoft.com/en-us/cpp/cpp/try-except-statement>.
  110:    With __try/__except, we can use the multithread-safe exception handling.  */
  111: 
  112: #   ifdef __cplusplus
  113: extern "C" {
  114: #   endif
  115: 
  116: /* Ensure that the invalid parameter handler in installed that raises a
  117:    software exception with code STATUS_GNULIB_INVALID_PARAMETER.
  118:    Because we assume no other part of the program installs a different
  119:    invalid parameter handler, this solution is multithread-safe.  */
  120: extern void gl_msvc_inval_ensure_handler (void);
  121: 
  122: #   ifdef __cplusplus
  123: }
  124: #   endif
  125: 
  126: #   define TRY_MSVC_INVAL \
  127:       do                                                                       \
  128:         {                                                                      \
  129:           gl_msvc_inval_ensure_handler ();                                     \
  130:           __try
  131: #   define CATCH_MSVC_INVAL \
  132:           __except (GetExceptionCode () == STATUS_GNULIB_INVALID_PARAMETER     \
  133:                     ? EXCEPTION_EXECUTE_HANDLER                                \
  134:                     : EXCEPTION_CONTINUE_SEARCH)
  135: #   define DONE_MSVC_INVAL \
  136:         }                                                                      \
  137:       while (0)
  138: 
  139: #  else
  140: /* Any compiler.
  141:    We can only use setjmp/longjmp.  */
  142: 
  143: #   include <setjmp.h>
  144: 
  145: #   ifdef __cplusplus
  146: extern "C" {
  147: #   endif
  148: 
  149: struct gl_msvc_inval_per_thread
  150: {
  151:   /* The restart that will resume execution at the code between
  152:      CATCH_MSVC_INVAL and DONE_MSVC_INVAL.  It is enabled only between
  153:      TRY_MSVC_INVAL and CATCH_MSVC_INVAL.  */
  154:   jmp_buf restart;
  155: 
  156:   /* Tells whether the contents of restart is valid.  */
  157:   int restart_valid;
  158: };
  159: 
  160: /* Ensure that the invalid parameter handler in installed that passes
  161:    control to the gl_msvc_inval_restart if it is valid, or raises a
  162:    software exception with code STATUS_GNULIB_INVALID_PARAMETER otherwise.
  163:    Because we assume no other part of the program installs a different
  164:    invalid parameter handler, this solution is multithread-safe.  */
  165: extern void gl_msvc_inval_ensure_handler (void);
  166: 
  167: /* Return a pointer to the per-thread data for the current thread.  */
  168: extern struct gl_msvc_inval_per_thread *gl_msvc_inval_current (void);
  169: 
  170: #   ifdef __cplusplus
  171: }
  172: #   endif
  173: 
  174: #   define TRY_MSVC_INVAL \
  175:       do                                                                       \
  176:         {                                                                      \
  177:           struct gl_msvc_inval_per_thread *msvc_inval_current;                 \
  178:           gl_msvc_inval_ensure_handler ();                                     \
  179:           msvc_inval_current = gl_msvc_inval_current ();                       \
  180:           /* First, initialize gl_msvc_inval_restart.  */                      \
  181:           if (setjmp (msvc_inval_current->restart) == 0)                       \
  182:             {                                                                  \
  183:               /* Then, mark it as valid.  */                                   \
  184:               msvc_inval_current->restart_valid = 1;
  185: #   define CATCH_MSVC_INVAL \
  186:               /* Execution completed.                                          \
  187:                  Mark gl_msvc_inval_restart as invalid.  */                    \
  188:               msvc_inval_current->restart_valid = 0;                           \
  189:             }                                                                  \
  190:           else                                                                 \
  191:             {                                                                  \
  192:               /* Execution triggered an invalid parameter notification.        \
  193:                  Mark gl_msvc_inval_restart as invalid.  */                    \
  194:               msvc_inval_current->restart_valid = 0;
  195: #   define DONE_MSVC_INVAL \
  196:             }                                                                  \
  197:         }                                                                      \
  198:       while (0)
  199: 
  200: #  endif
  201: 
  202: # endif
  203: 
  204: #else
  205: /* A platform that does not need to the invalid parameter handler,
  206:    or when SANE_LIBRARY_HANDLING is desired.  */
  207: 
  208: /* The braces here avoid GCC warnings like
  209:    "warning: suggest explicit braces to avoid ambiguous 'else'".  */
  210: # define TRY_MSVC_INVAL \
  211:     do                                                                         \
  212:       {                                                                        \
  213:         if (1)
  214: # define CATCH_MSVC_INVAL \
  215:         else
  216: # define DONE_MSVC_INVAL \
  217:       }                                                                        \
  218:     while (0)
  219: 
  220: #endif
  221: 
  222: #endif /* _MSVC_INVAL_H */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>