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