CException/lib/CException.h
2024-03-16 22:41:16 -04:00

123 lines
4.4 KiB
C

/* =========================================================================
CException - Simple Exception Handling in C
ThrowTheSwitch.org
Copyright (c) 2007-24 Mark VanderVoord
SPDX-License-Identifier: MIT
========================================================================= */
#ifndef _CEXCEPTION_H
#define _CEXCEPTION_H
#include <setjmp.h>
#ifdef __cplusplus
extern "C"
{
#endif
#define CEXCEPTION_VERSION_MAJOR 1
#define CEXCEPTION_VERSION_MINOR 3
#define CEXCEPTION_VERSION_BUILD 4
#define CEXCEPTION_VERSION ((CEXCEPTION_VERSION_MAJOR << 16) | (CEXCEPTION_VERSION_MINOR << 8) | CEXCEPTION_VERSION_BUILD)
//To Use CException, you have a number of options:
//1. Just include it and run with the defaults
//2. Define any of the following symbols at the command line to override them
//3. Include a header file before CException.h everywhere which defines any of these
//4. Create an Exception.h in your path, and just define EXCEPTION_USE_CONFIG_FILE first
#ifdef CEXCEPTION_USE_CONFIG_FILE
#include "CExceptionConfig.h"
#endif
//This is the value to assign when there isn't an exception
#ifndef CEXCEPTION_NONE
#define CEXCEPTION_NONE (0x5A5A5A5A)
#endif
//This is number of exception stacks to keep track of (one per task)
#ifndef CEXCEPTION_NUM_ID
#define CEXCEPTION_NUM_ID (1) //there is only the one stack by default
#endif
//This is the method of getting the current exception stack index (0 if only one stack)
#ifndef CEXCEPTION_GET_ID
#define CEXCEPTION_GET_ID (0) //use the first index always because there is only one anyway
#endif
//The type to use to store the exception values.
#ifndef CEXCEPTION_T
#define CEXCEPTION_T unsigned int
#endif
//This is an optional special handler for when there is no global Catch
#ifndef CEXCEPTION_NO_CATCH_HANDLER
#define CEXCEPTION_NO_CATCH_HANDLER(id)
#endif
//These hooks allow you to inject custom code into places, particularly useful for saving and restoring additional state
#ifndef CEXCEPTION_HOOK_START_TRY
#define CEXCEPTION_HOOK_START_TRY
#endif
#ifndef CEXCEPTION_HOOK_HAPPY_TRY
#define CEXCEPTION_HOOK_HAPPY_TRY
#endif
#ifndef CEXCEPTION_HOOK_AFTER_TRY
#define CEXCEPTION_HOOK_AFTER_TRY
#endif
#ifndef CEXCEPTION_HOOK_START_CATCH
#define CEXCEPTION_HOOK_START_CATCH
#endif
//exception frame structures
typedef struct {
jmp_buf* pFrame;
CEXCEPTION_T volatile Exception;
} CEXCEPTION_FRAME_T;
//actual root frame storage (only one if single-tasking)
extern volatile CEXCEPTION_FRAME_T CExceptionFrames[];
//Try (see C file for explanation)
#define Try \
{ \
jmp_buf *PrevFrame, NewFrame; \
unsigned int MY_ID = CEXCEPTION_GET_ID; \
PrevFrame = CExceptionFrames[MY_ID].pFrame; \
CExceptionFrames[MY_ID].pFrame = (jmp_buf*)(&NewFrame); \
CExceptionFrames[MY_ID].Exception = CEXCEPTION_NONE; \
CEXCEPTION_HOOK_START_TRY; \
if (setjmp(NewFrame) == 0) { \
if (1)
//Catch (see C file for explanation)
#define Catch(e) \
else { } \
CExceptionFrames[MY_ID].Exception = CEXCEPTION_NONE; \
CEXCEPTION_HOOK_HAPPY_TRY; \
} \
else \
{ \
e = CExceptionFrames[MY_ID].Exception; \
(void)e; \
CEXCEPTION_HOOK_START_CATCH; \
} \
CExceptionFrames[MY_ID].pFrame = PrevFrame; \
CEXCEPTION_HOOK_AFTER_TRY; \
} \
if (CExceptionFrames[CEXCEPTION_GET_ID].Exception != CEXCEPTION_NONE)
//Throw an Error
void Throw(CEXCEPTION_T ExceptionID);
//Just exit the Try block and skip the Catch.
#define ExitTry() Throw(CEXCEPTION_NONE)
#ifdef __cplusplus
} // extern "C"
#endif
#endif // _CEXCEPTION_H