| /* | |
| Copyright (c) 2004/2005 KJK::Hyperion | |
| Permission is hereby granted, free of charge, to any person obtaining a | |
| copy of this software and associated documentation files (the "Software"), | |
| to deal in the Software without restriction, including without limitation | |
| the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| and/or sell copies of the Software, and to permit persons to whom the | |
| Software is furnished to do so, subject to the following conditions: | |
| The above copyright notice and this permission notice shall be included in | |
| all copies or substantial portions of the Software. | |
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| DEALINGS IN THE SOFTWARE. | |
| */ | |
| #ifndef KJK_PSEH_FRAMEBASED_H_ | |
| #define KJK_PSEH_FRAMEBASED_H_ | |
| #if ((__GNUC__ > 4) && (__GNUC_MINOR__ > 1)) | |
| /* warning: this will hide uninitialized variable warnings in the following code */ | |
| # pragma GCC diagnostic ignored "-Wuninitialized" | |
| #endif | |
| #include <pseh/framebased/internal.h> | |
| #include <pseh/excpt.h> | |
| #ifndef offsetof | |
| # include <stddef.h> | |
| #endif | |
| #if defined(_SEH_NO_NATIVE_NLG) | |
| # error PSEH setjmp/longjmp fallback is no longer supported | |
| #endif | |
| #if defined(__GNUC__) | |
| # define _SEHLongJmp __builtin_longjmp | |
| # define _SEHSetJmp __builtin_setjmp | |
| typedef void * _SEHJmpBuf_t[5]; | |
| #else | |
| # include <setjmp.h> | |
| # define _SEHLongJmp longjmp | |
| # define _SEHSetJmp setjmp | |
| # define _SEHJmpBuf_t jmp_buf | |
| #endif | |
| #ifdef __cplusplus | |
| # define _SEH_INIT_CONST static const | |
| #else | |
| # define _SEH_INIT_CONST register const | |
| #endif | |
| typedef struct __SEHFrame | |
| { | |
| _SEHPortableFrame_t SEH_Header; | |
| void * volatile SEH_Locals; | |
| } | |
| _SEHFrame_t; | |
| typedef struct __SEHTryLevel | |
| { | |
| _SEHPortableTryLevel_t ST_Header; | |
| _SEHJmpBuf_t ST_JmpBuf; | |
| } | |
| _SEHTryLevel_t; | |
| static __declspec(noreturn) __inline void __stdcall _SEHCompilerSpecificHandler | |
| ( | |
| _SEHPortableTryLevel_t * trylevel | |
| ) | |
| { | |
| _SEHTryLevel_t * mytrylevel; | |
| mytrylevel = _SEH_CONTAINING_RECORD(trylevel, _SEHTryLevel_t, ST_Header); | |
| _SEHLongJmp(mytrylevel->ST_JmpBuf, 1); | |
| } | |
| static const int _SEHScopeKind = 1; | |
| static _SEHPortableFrame_t * const _SEHPortableFrame = 0; | |
| static _SEHPortableTryLevel_t * const _SEHPortableTryLevel = 0; | |
| /* SHARED LOCALS */ | |
| /* Access the locals for the current frame */ | |
| #define _SEH_ACCESS_LOCALS(LOCALS_) \ | |
| _SEH_LOCALS_TYPENAME(LOCALS_) * _SEHPLocals; \ | |
| _SEHPLocals = \ | |
| _SEH_PVOID_CAST \ | |
| ( \ | |
| _SEH_LOCALS_TYPENAME(LOCALS_) *, \ | |
| _SEH_CONTAINING_RECORD(_SEHPortableFrame, _SEHFrame_t, SEH_Header) \ | |
| ->SEH_Locals \ | |
| ); | |
| /* Access local variable VAR_ */ | |
| #define _SEH_VAR(VAR_) _SEHPLocals->VAR_ | |
| /* FILTER FUNCTIONS */ | |
| /* Declares a filter function's prototype */ | |
| #define _SEH_FILTER(NAME_) \ | |
| long __stdcall NAME_ \ | |
| ( \ | |
| struct _EXCEPTION_POINTERS * _SEHExceptionPointers, \ | |
| struct __SEHPortableFrame * _SEHPortableFrame \ | |
| ) | |
| /* Declares a static filter */ | |
| #define __SEH_STATIC_FILTER(ACTION_) ((ACTION_) + 2) | |
| #define _SEH_STATIC_FILTER(ACTION_) ((_SEHFilter_t)(__SEH_STATIC_FILTER(ACTION_))) | |
| /* Declares a PSEH filter wrapping a regular filter function */ | |
| #define _SEH_WRAP_FILTER(WRAPPER_, NAME_) \ | |
| static __inline _SEH_FILTER(WRAPPER_) \ | |
| { \ | |
| return (NAME_)(_SEHExceptionPointers); \ | |
| } | |
| /* FINALLY FUNCTIONS */ | |
| /* Declares a finally function's prototype */ | |
| #define _SEH_FINALLYFUNC(NAME_) \ | |
| void __stdcall NAME_ \ | |
| ( \ | |
| struct __SEHPortableFrame * _SEHPortableFrame \ | |
| ) | |
| /* Declares a PSEH finally function wrapping a regular function */ | |
| #define _SEH_WRAP_FINALLY(WRAPPER_, NAME_) \ | |
| _SEH_WRAP_FINALLY_ARGS(WRAPPER_, NAME_, ()) | |
| #define _SEH_WRAP_FINALLY_ARGS(WRAPPER_, NAME_, ARGS_) \ | |
| static __inline _SEH_FINALLYFUNC(WRAPPER_) \ | |
| { \ | |
| NAME_ ARGS_; \ | |
| } | |
| #define _SEH_WRAP_FINALLY_LOCALS_ARGS(WRAPPER_, LOCALS_, NAME_, ARGS_) \ | |
| static __inline _SEH_FINALLYFUNC(WRAPPER_) \ | |
| { \ | |
| _SEH_ACCESS_LOCALS(LOCALS_); \ | |
| NAME_ ARGS_; \ | |
| } | |
| /* SAFE BLOCKS */ | |
| #ifdef __cplusplus | |
| # define _SEH_DECLARE_HANDLERS(FILTER_, FINALLY_) \ | |
| static const _SEHHandlers_t _SEHHandlers = { (FILTER_), (FINALLY_) }; | |
| #else | |
| # define _SEH_DECLARE_HANDLERS(FILTER_, FINALLY_) \ | |
| _SEHHandlers_t _SEHHandlers = { (0), (0) }; \ | |
| _SEHHandlers.SH_Filter = (FILTER_); \ | |
| _SEHHandlers.SH_Finally = (FINALLY_); | |
| #endif | |
| #define _SEH_SetExceptionCode(CODE_) (_SEHPortableFrame->SPF_Code = (CODE_)) | |
| #define _SEH_GetExceptionCode() (unsigned long)(_SEHPortableFrame->SPF_Code) | |
| #define _SEH_GetExceptionPointers() \ | |
| ((struct _EXCEPTION_POINTERS *)_SEHExceptionPointers) | |
| #define _SEH_AbnormalTermination() (_SEHPortableFrame->SPF_Code != 0) | |
| #define _SEH_LEAVE break | |
| #define _SEH_YIELD(STMT_) \ | |
| for(;;) \ | |
| { \ | |
| if(!_SEHScopeKind) \ | |
| _SEHReturn(); \ | |
| \ | |
| STMT_; \ | |
| } | |
| #ifdef _ARM_ | |
| #define _SEH_TRY \ | |
| for(;;) \ | |
| { \ | |
| \ | |
| { \ | |
| \ | |
| for(;;) \ | |
| { \ | |
| if(1) \ | |
| { \ | |
| for(;;) \ | |
| { \ | |
| { | |
| #define _SEH_EXCEPT(FILTER_) \ | |
| } \ | |
| \ | |
| break; \ | |
| } \ | |
| \ | |
| break; \ | |
| } \ | |
| else \ | |
| { \ | |
| { \ | |
| break; \ | |
| } \ | |
| } \ | |
| \ | |
| break; \ | |
| } \ | |
| \ | |
| \ | |
| if(0) \ | |
| { | |
| #define _SEH_FINALLY(FINALLY_) \ | |
| } \ | |
| \ | |
| break; \ | |
| } \ | |
| \ | |
| break; \ | |
| } \ | |
| else \ | |
| { \ | |
| } \ | |
| \ | |
| break; \ | |
| } \ | |
| \ | |
| (FINALLY_)(&_SEHFrame.SEH_Header); \ | |
| \ | |
| if(0) \ | |
| { | |
| #define _SEH_END \ | |
| } \ | |
| } \ | |
| \ | |
| \ | |
| break; \ | |
| } | |
| #else | |
| #define _SEH_TRY \ | |
| for(;;) \ | |
| { \ | |
| _SEH_INIT_CONST int _SEHTopTryLevel = (_SEHScopeKind != 0); \ | |
| _SEHPortableFrame_t * const _SEHCurPortableFrame = _SEHPortableFrame; \ | |
| _SEHPortableTryLevel_t * const _SEHPrevPortableTryLevel = _SEHPortableTryLevel; \ | |
| \ | |
| { \ | |
| _SEH_INIT_CONST int _SEHScopeKind = 0; \ | |
| register int _SEHState = 0; \ | |
| register int _SEHHandle = 0; \ | |
| _SEHFrame_t _SEHFrame; \ | |
| _SEHTryLevel_t _SEHTryLevel; \ | |
| _SEHPortableFrame_t * const _SEHPortableFrame = \ | |
| _SEHTopTryLevel ? &_SEHFrame.SEH_Header : _SEHCurPortableFrame; \ | |
| _SEHPortableTryLevel_t * const _SEHPortableTryLevel = &_SEHTryLevel.ST_Header; \ | |
| \ | |
| (void)_SEHScopeKind; \ | |
| (void)_SEHPortableFrame; \ | |
| (void)_SEHPortableTryLevel; \ | |
| (void)_SEHHandle; \ | |
| \ | |
| for(;;) \ | |
| { \ | |
| if(_SEHState) \ | |
| { \ | |
| for(;;) \ | |
| { \ | |
| { | |
| #define _SEH_EXCEPT(FILTER_) \ | |
| } \ | |
| \ | |
| break; \ | |
| } \ | |
| \ | |
| break; \ | |
| } \ | |
| else \ | |
| { \ | |
| if((_SEHHandle = _SEHSetJmp(_SEHTryLevel.ST_JmpBuf)) == 0) \ | |
| { \ | |
| _SEHTryLevel.ST_Header.SPT_Handlers.SH_Filter = (FILTER_); \ | |
| _SEHTryLevel.ST_Header.SPT_Handlers.SH_Finally = 0; \ | |
| \ | |
| _SEHTryLevel.ST_Header.SPT_Next = _SEHPrevPortableTryLevel; \ | |
| _SEHFrame.SEH_Header.SPF_TopTryLevel = &_SEHTryLevel.ST_Header; \ | |
| \ | |
| if(_SEHTopTryLevel) \ | |
| { \ | |
| if(&_SEHLocals != _SEHDummyLocals) \ | |
| _SEHFrame.SEH_Locals = &_SEHLocals; \ | |
| \ | |
| _SEH_EnableTracing(_SEH_DO_DEFAULT_TRACING); \ | |
| _SEHFrame.SEH_Header.SPF_Handler = _SEHCompilerSpecificHandler; \ | |
| _SEHEnterFrame(&_SEHFrame.SEH_Header); \ | |
| } \ | |
| \ | |
| ++ _SEHState; \ | |
| continue; \ | |
| } \ | |
| else \ | |
| { \ | |
| break; \ | |
| } \ | |
| } \ | |
| \ | |
| break; \ | |
| } \ | |
| \ | |
| _SEHPortableFrame->SPF_TopTryLevel = _SEHPrevPortableTryLevel; \ | |
| \ | |
| if(_SEHHandle) \ | |
| { | |
| #define _SEH_FINALLY(FINALLY_) \ | |
| } \ | |
| \ | |
| break; \ | |
| } \ | |
| \ | |
| _SEHPortableFrame->SPF_TopTryLevel = _SEHPrevPortableTryLevel; \ | |
| break; \ | |
| } \ | |
| else \ | |
| { \ | |
| _SEHTryLevel.ST_Header.SPT_Handlers.SH_Filter = 0; \ | |
| _SEHTryLevel.ST_Header.SPT_Handlers.SH_Finally = (FINALLY_); \ | |
| \ | |
| _SEHTryLevel.ST_Header.SPT_Next = _SEHPrevPortableTryLevel; \ | |
| _SEHFrame.SEH_Header.SPF_TopTryLevel = &_SEHTryLevel.ST_Header; \ | |
| \ | |
| if(_SEHTopTryLevel) \ | |
| { \ | |
| if(&_SEHLocals != _SEHDummyLocals) \ | |
| _SEHFrame.SEH_Locals = &_SEHLocals; \ | |
| \ | |
| _SEH_EnableTracing(_SEH_DO_DEFAULT_TRACING); \ | |
| _SEHFrame.SEH_Header.SPF_Handler = _SEHCompilerSpecificHandler; \ | |
| _SEHEnterFrame(&_SEHFrame.SEH_Header); \ | |
| } \ | |
| \ | |
| ++ _SEHState; \ | |
| continue; \ | |
| } \ | |
| \ | |
| break; \ | |
| } \ | |
| \ | |
| (FINALLY_)(&_SEHFrame.SEH_Header); \ | |
| \ | |
| if(0) \ | |
| { | |
| #define _SEH_END \ | |
| } \ | |
| } \ | |
| \ | |
| if(_SEHTopTryLevel) \ | |
| _SEHLeaveFrame(); \ | |
| \ | |
| break; \ | |
| } | |
| #endif | |
| #define _SEH_HANDLE _SEH_EXCEPT(_SEH_STATIC_FILTER(_SEH_EXECUTE_HANDLER)) | |
| #define _SEH_EnableTracing(LEVEL_) ((void)(_SEHPortableFrame->SPF_Tracing = (LEVEL_))) | |
| #define _SEH_DisableTracing() ((void)(_SEHPortableFrame->SPF_Tracing = _SEH_DO_TRACE_NONE)) | |
| #endif | |
| /* EOF */ |