msvcrt: Added _strdate_s and _wstrdate_s implementation.
[wine] / include / wine / exception.h
1 /*
2  * Wine exception handling
3  *
4  * Copyright (c) 1999 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library 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 GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #ifndef __WINE_WINE_EXCEPTION_H
22 #define __WINE_WINE_EXCEPTION_H
23
24 #include <setjmp.h>
25 #include <windef.h>
26 #include <excpt.h>
27
28 #ifdef __cplusplus
29 extern "C" {
30 #endif
31
32 /* The following definitions allow using exceptions in Wine and Winelib code
33  *
34  * They should be used like this:
35  *
36  * __TRY
37  * {
38  *     do some stuff that can raise an exception
39  * }
40  * __EXCEPT(filter_func)
41  * {
42  *     handle the exception here
43  * }
44  * __ENDTRY
45  *
46  * or
47  *
48  * __TRY
49  * {
50  *     do some stuff that can raise an exception
51  * }
52  * __FINALLY(finally_func)
53  *
54  * The filter_func and finally_func functions must be defined like this:
55  *
56  * LONG CALLBACK filter_func( PEXCEPTION_POINTERS __eptr ) { ... }
57  *
58  * void CALLBACK finally_func( BOOL __normal ) { ... }
59  *
60  * The filter function must return one of the EXCEPTION_* code; it can
61  * use GetExceptionInformation() and GetExceptionCode() to retrieve the
62  * exception info.
63  *
64  * Warning: inside a __TRY or __EXCEPT block, 'break' or 'continue' statements
65  *          break out of the current block. You cannot use 'return', 'goto'
66  *          or 'longjmp' to leave a __TRY block, as this will surely crash.
67  *          You can use them to leave a __EXCEPT block though.
68  *
69  * -- AJ
70  */
71
72 /* Define this if you want to use your compiler built-in __try/__except support.
73  * This is only useful when compiling to a native Windows binary, as the built-in
74  * compiler exceptions will most certainly not work under Winelib.
75  */
76 #ifdef USE_COMPILER_EXCEPTIONS
77
78 #define __TRY __try
79 #define __EXCEPT(func) __except((func)(GetExceptionInformation()))
80 #define __FINALLY(func) __finally { (func)(!AbnormalTermination()); }
81 #define __ENDTRY /*nothing*/
82 #define __EXCEPT_PAGE_FAULT __except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
83 #define __EXCEPT_ALL __except(EXCEPTION_EXECUTE_HANDLER)
84
85 #else  /* USE_COMPILER_EXCEPTIONS */
86
87 #ifndef __GNUC__
88 #define __attribute__(x) /* nothing */
89 #endif
90
91 #if defined(__MINGW32__) || defined(__CYGWIN__)
92 #define sigjmp_buf jmp_buf
93 #define sigsetjmp(buf,sigs) setjmp(buf)
94 #define siglongjmp(buf,val) longjmp(buf,val)
95 #endif
96
97 extern void __wine_rtl_unwind( EXCEPTION_REGISTRATION_RECORD* frame, EXCEPTION_RECORD *record,
98                                void (*target)(void) ) DECLSPEC_HIDDEN DECLSPEC_NORETURN;
99 extern DWORD __wine_exception_handler( EXCEPTION_RECORD *record,
100                                        EXCEPTION_REGISTRATION_RECORD *frame,
101                                        CONTEXT *context,
102                                        EXCEPTION_REGISTRATION_RECORD **pdispatcher ) DECLSPEC_HIDDEN;
103 extern DWORD __wine_exception_handler_page_fault( EXCEPTION_RECORD *record,
104                                                   EXCEPTION_REGISTRATION_RECORD *frame,
105                                                   CONTEXT *context,
106                                                   EXCEPTION_REGISTRATION_RECORD **pdispatcher ) DECLSPEC_HIDDEN;
107 extern DWORD __wine_exception_handler_all( EXCEPTION_RECORD *record,
108                                            EXCEPTION_REGISTRATION_RECORD *frame,
109                                            CONTEXT *context,
110                                            EXCEPTION_REGISTRATION_RECORD **pdispatcher ) DECLSPEC_HIDDEN;
111 extern DWORD __wine_finally_handler( EXCEPTION_RECORD *record,
112                                      EXCEPTION_REGISTRATION_RECORD *frame,
113                                      CONTEXT *context,
114                                      EXCEPTION_REGISTRATION_RECORD **pdispatcher ) DECLSPEC_HIDDEN;
115
116 #define __TRY \
117     do { __WINE_FRAME __f; \
118          int __first = 1; \
119          for (;;) if (!__first) \
120          { \
121              do {
122
123 #define __EXCEPT(func) \
124              } while(0); \
125              __wine_pop_frame( &__f.frame ); \
126              break; \
127          } else { \
128              __f.frame.Handler = __wine_exception_handler; \
129              __f.u.filter = (func); \
130              if (sigsetjmp( __f.jmp, 0 )) { \
131                  const __WINE_FRAME * const __eptr __attribute__((unused)) = &__f; \
132                  do {
133
134 /* convenience handler for page fault exceptions */
135 #define __EXCEPT_PAGE_FAULT \
136              } while(0); \
137              __wine_pop_frame( &__f.frame ); \
138              break; \
139          } else { \
140              __f.frame.Handler = __wine_exception_handler_page_fault; \
141              if (sigsetjmp( __f.jmp, 0 )) { \
142                  const __WINE_FRAME * const __eptr __attribute__((unused)) = &__f; \
143                  do {
144
145 /* convenience handler for all exception */
146 #define __EXCEPT_ALL \
147              } while(0); \
148              __wine_pop_frame( &__f.frame ); \
149              break; \
150          } else { \
151              __f.frame.Handler = __wine_exception_handler_all; \
152              if (sigsetjmp( __f.jmp, 0 )) { \
153                  const __WINE_FRAME * const __eptr __attribute__((unused)) = &__f; \
154                  do {
155
156 #define __ENDTRY \
157                  } while (0); \
158                  break; \
159              } \
160              __wine_push_frame( &__f.frame ); \
161              __first = 0; \
162          } \
163     } while (0);
164
165 #define __FINALLY(func) \
166              } while(0); \
167              __wine_pop_frame( &__f.frame ); \
168              (func)(1); \
169              break; \
170          } else { \
171              __f.frame.Handler = __wine_finally_handler; \
172              __f.u.finally_func = (func); \
173              __wine_push_frame( &__f.frame ); \
174              __first = 0; \
175          } \
176     } while (0);
177
178
179 typedef LONG (CALLBACK *__WINE_FILTER)(PEXCEPTION_POINTERS);
180 typedef void (CALLBACK *__WINE_FINALLY)(BOOL);
181
182 #define GetExceptionInformation() (__eptr)
183 #define GetExceptionCode()        (__eptr->ExceptionRecord->ExceptionCode)
184 #define AbnormalTermination()     (!__normal)
185
186 typedef struct __tagWINE_FRAME
187 {
188     EXCEPTION_REGISTRATION_RECORD frame;
189     union
190     {
191         /* exception data */
192         __WINE_FILTER filter;
193         /* finally data */
194         __WINE_FINALLY finally_func;
195     } u;
196     sigjmp_buf jmp;
197     /* hack to make GetExceptionCode() work in handler */
198     DWORD ExceptionCode;
199     const struct __tagWINE_FRAME *ExceptionRecord;
200 } __WINE_FRAME;
201
202 #endif /* USE_COMPILER_EXCEPTIONS */
203
204 static inline EXCEPTION_REGISTRATION_RECORD *__wine_push_frame( EXCEPTION_REGISTRATION_RECORD *frame )
205 {
206 #if defined(__GNUC__) && defined(__i386__)
207     EXCEPTION_REGISTRATION_RECORD *prev;
208     __asm__ __volatile__(".byte 0x64\n\tmovl (0),%0"
209                          "\n\tmovl %0,(%1)"
210                          "\n\t.byte 0x64\n\tmovl %1,(0)"
211                          : "=&r" (prev) : "r" (frame) : "memory" );
212     return prev;
213 #else
214     NT_TIB *teb = (NT_TIB *)NtCurrentTeb();
215     frame->Prev = teb->ExceptionList;
216     teb->ExceptionList = frame;
217     return frame->Prev;
218 #endif
219 }
220
221 static inline EXCEPTION_REGISTRATION_RECORD *__wine_pop_frame( EXCEPTION_REGISTRATION_RECORD *frame )
222 {
223 #if defined(__GNUC__) && defined(__i386__)
224     __asm__ __volatile__(".byte 0x64\n\tmovl %0,(0)"
225                          : : "r" (frame->Prev) : "memory" );
226     return frame->Prev;
227
228 #else
229     NT_TIB *teb = (NT_TIB *)NtCurrentTeb();
230     teb->ExceptionList = frame->Prev;
231     return frame->Prev;
232 #endif
233 }
234
235 static inline EXCEPTION_REGISTRATION_RECORD *__wine_get_frame(void)
236 {
237 #if defined(__GNUC__) && defined(__i386__)
238     EXCEPTION_REGISTRATION_RECORD *ret;
239     __asm__ __volatile__(".byte 0x64\n\tmovl (0),%0" : "=r" (ret) );
240     return ret;
241 #else
242     NT_TIB *teb = (NT_TIB *)NtCurrentTeb();
243     return teb->ExceptionList;
244 #endif
245 }
246
247 /* Exception handling flags - from OS/2 2.0 exception handling */
248
249 /* Win32 seems to use the same flags as ExceptionFlags in an EXCEPTION_RECORD */
250 #define EH_NONCONTINUABLE   0x01
251 #define EH_UNWINDING        0x02
252 #define EH_EXIT_UNWIND      0x04
253 #define EH_STACK_INVALID    0x08
254 #define EH_NESTED_CALL      0x10
255
256 /* Wine-specific exceptions codes */
257
258 #define EXCEPTION_WINE_STUB       0x80000100  /* stub entry point called */
259 #define EXCEPTION_WINE_ASSERTION  0x80000101  /* assertion failed */
260
261 /* unhandled return status from vm86 mode */
262 #define EXCEPTION_VM86_INTx       0x80000110
263 #define EXCEPTION_VM86_STI        0x80000111
264 #define EXCEPTION_VM86_PICRETURN  0x80000112
265
266 extern void __wine_enter_vm86( CONTEXT *context );
267
268 #ifdef __cplusplus
269 }
270 #endif
271
272 #endif  /* __WINE_WINE_EXCEPTION_H */