-
Notifications
You must be signed in to change notification settings - Fork 0
/
cex.h
115 lines (95 loc) · 3.13 KB
/
cex.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#ifndef CEX_H
#define CEX_H
#ifdef __cplusplus
extern "C" {
#endif
#include <setjmp.h>
#include <stdlib.h>
/*
Payload types for macros
*/
typedef const char *CEX_STRING_TYPE;
typedef int CEX_INT_TYPE;
typedef void *CEX_VOID_PTR_TYPE;
/**
\brief Stores one of many possible exception payloads
*/
#define CEX_DECLARE_PAYLOAD(T) T##_TYPE T##_VAL;
union cex_payload
{
CEX_DECLARE_PAYLOAD( CEX_STRING );
CEX_DECLARE_PAYLOAD( CEX_INT );
CEX_DECLARE_PAYLOAD( CEX_VOID_PTR );
};
#undef CEX_DECLARE_PAYLOAD
/**
\brief Exception payload types
*/
enum cex_type
{
CEX_STRING,
CEX_INT,
CEX_VOID_PTR
};
/**
\brief A wrapper for jmp_buf so it's more implementation
independent and easier to use.
*/
struct cex_jmp_buf_wrapper
{
jmp_buf jbuf;
};
/**
\brief Possible error values handled by the
*/
enum cex_error
{
CEX_NO_ERROR = 0, //!< Indicates no error
CEX_ALLOC_ERROR, //!< Memory allocation error
CEX_STACK_UNDERFLOW, //!< pop/top called on empty jump stack
CEX_STACK_OVERFLOW, //!< Jump location stack overlflow
CEX_UNCAUGHT //!< Exception uncaught and jump stack is empty
};
/**
\brief The status struct.
This struct contains a stack of try-catch block jump locations and stores
currently processed exception.
*/
struct cex_status
{
// The jump location stack
unsigned char stack_allocated; //!< Was the stack allocated with malloc
size_t max_stack_size; //!< Max stack size
struct cex_jmp_buf_wrapper *bp; //!< Stack base pointer
struct cex_jmp_buf_wrapper *sp; //!< Stack pointer
// The exception
union cex_payload ex_payload;
enum cex_type ex_type;
unsigned char ex_caught;
//! Error handler function - shall be set after init by user
void ( *error_callback )( struct cex_status *st, enum cex_error err );
};
// CEX status management
extern enum cex_error cex_init_alloc( struct cex_status *st, size_t size );
extern enum cex_error cex_init_fixed( struct cex_status *st, struct cex_jmp_buf_wrapper *array, size_t size );
extern void cex_delete( struct cex_status *st );
// Jump location stack access
extern size_t cex_stack_size( struct cex_status *st );
extern void cex_push( struct cex_status *st );
extern struct cex_jmp_buf_wrapper *cex_top( struct cex_status *st );
extern struct cex_jmp_buf_wrapper cex_pop( struct cex_status *st );
// Exception throwing and propagation
extern void cex_generic_throw( struct cex_status *st, union cex_payload payload, enum cex_type type );
extern void cex_propagate( struct cex_status *st );
// Throw
#define cex_throw(st, T, value) { union cex_payload p = {.T##_VAL = value}; cex_generic_throw( &(st), p, (T) ); }
// Try and catch blocks
#define cex_try_block(st) cex_push( &(st) ); if ( !setjmp( cex_top( &(st) )->jbuf ) ) {
#define cex_catch_block(st) cex_pop( &(st) ); } else for ( cex_pop( &(st) ); !(st).ex_caught; cex_propagate( &(st) ) )
// Catchers
#define cex_catch_case(st, T) for ( T##_TYPE cex_what; !(st).ex_caught && (st).ex_type == (T) && ( cex_what = (st).ex_payload. T##_VAL, (st).ex_caught = 1, 1 ); )
#define cex_catch_all(st) if ( !(st).ex_caught && ( ( (st).ex_caught = 1 ), 1 ) )
#ifdef __cplusplus
}
#endif
#endif