Annotation of embedaddon/libiconv/srclib/msvc-inval.h, revision 1.1
1.1 ! misho 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>