e47789f1a7a088025ac798804e288a96e02fe500
[debian/tar] / gnu / msvc-inval.h
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-2013 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 */