Exceptions & Try/Catch
This commit is contained in:
17
README.md
17
README.md
@@ -17,12 +17,23 @@ but I hope to improve it overtime.
|
||||
* [License](#license)
|
||||
|
||||
## Features
|
||||
- [x] Basic Window (Win32 & Linux)
|
||||
|
||||
`Currently finished a basic window platform layer. The focus is going to be code
|
||||
for CLI tools but, I wanted to be able to open a simple window. It is a great
|
||||
example case too as the OS API's are slightly different, so a platform layer
|
||||
is a great fix.
|
||||
`
|
||||
- [x] Exceptions & Try/Catch
|
||||
|
||||
` Finished adding Exceptions and Try/Catch. This was the worst example for a
|
||||
platform layers as these are just clever macros. From what I can read, this
|
||||
approach to error handling is generally frowned upon due to debugging isssues.`
|
||||
|
||||
## Todos
|
||||
- [ ] Better makefile
|
||||
|
||||
- [?] Better makefile
|
||||
- [ ] Better Usage Examples
|
||||
- [ ] Basic Window
|
||||
- [ ] Exceptions & Try/Catch
|
||||
- [ ] Memory Allocator
|
||||
- [ ] Arena Allocator
|
||||
- [ ] Arrays
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#ifndef CI2_INCLUDED
|
||||
#define CI2_INCLUDED
|
||||
|
||||
extern void ci2_printf()
|
||||
|
||||
#endif
|
||||
|
||||
107
include/ci2_exception.h
Normal file
107
include/ci2_exception.h
Normal file
@@ -0,0 +1,107 @@
|
||||
#ifndef CI2_EXCEPTION_H
|
||||
#define CI2_EXCEPTION_H
|
||||
|
||||
#include <setjmp.h>
|
||||
#include <assert.h>
|
||||
|
||||
struct Exception {
|
||||
const char *reason;
|
||||
};
|
||||
typedef struct Exception Exception;
|
||||
|
||||
struct Except_Frame {
|
||||
struct Except_Frame *prev;
|
||||
jmp_buf env;
|
||||
const char *file;
|
||||
int line;
|
||||
const struct Exception *exception;
|
||||
};
|
||||
typedef struct Except_Frame Except_Frame;
|
||||
|
||||
enum { EXCEPT_STATE_ENTERED=0,
|
||||
EXCEPT_STATE_RAISED,
|
||||
EXCEPT_STATE_HANDLED,
|
||||
EXCEPT_STATE_FINALIZED,
|
||||
EXCEPT_STATE_COUNT
|
||||
};
|
||||
|
||||
extern struct Except_Frame *except_stack;
|
||||
extern const struct Exception assertion_failed;
|
||||
extern void except_raise(const struct Exception *e, const char *file, int line);
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
extern DWORD except_index;
|
||||
extern void except_init(void);
|
||||
extern void except_push(Except_Frame *fp);
|
||||
extern void except_pop(void);
|
||||
|
||||
#define RAISE(e) except_raise(&(e), __FILE__, __LINE__)
|
||||
#define RERAISE except_raise(except_frame.exception, \
|
||||
except_frame.file, except_frame.line)
|
||||
#define RETURN switch (except_pop(),0) default: return
|
||||
#define TRY do { \
|
||||
volatile int except_flag; \
|
||||
Except_Frame except_frame; \
|
||||
if (except_index == TLS_OUT_OF_INDEXES) \
|
||||
except_init(); \
|
||||
except_push(&except_frame); \
|
||||
except_flag = setjmp(except_frame.env); \
|
||||
if (except_flag == EXCEPT_STATE_ENTERED) {
|
||||
#define EXCEPT(e) \
|
||||
if (except_flag == EXCEPT_STATE_ENTERED) except_pop(); \
|
||||
} else if (except_frame.exception == &(e)) { \
|
||||
except_flag = EXCEPT_STATE_HANDLED;
|
||||
#define ELSE \
|
||||
if (except_flag == EXCEPT_STATE_ENTERED) except_pop(); \
|
||||
} else { \
|
||||
except_flag = EXCEPT_STATE_HANDLED;
|
||||
#define FINALLY \
|
||||
if (except_flag == EXCEPT_STATE_ENTERED) except_pop(); \
|
||||
} { \
|
||||
if (except_flag == EXCEPT_STATE_ENTERED) \
|
||||
except_flag = EXCEPT_STATE_FINALIZED;
|
||||
#define END_TRY \
|
||||
if (except_flag == EXCEPT_STATE_ENTERED) except_pop(); \
|
||||
} if (except_flag == EXCEPT_STATE_RAISED) RERAISE; \
|
||||
} while (0)
|
||||
#else
|
||||
#define RAISE(e) except_raise(&(e), __FILE__, __LINE__)
|
||||
#define RERAISE except_raise(except_frame.exception, \
|
||||
except_frame.file, except_frame.line)
|
||||
#define RETURN switch (except_stack = except_stack->prev,0) default: return
|
||||
#define TRY do { \
|
||||
volatile int except_flag; \
|
||||
Except_Frame except_frame; \
|
||||
except_frame.prev = except_stack; \
|
||||
except_stack = &except_frame; \
|
||||
except_flag = setjmp(except_frame.env); \
|
||||
if (except_flag == EXCEPT_STATE_ENTERED) {
|
||||
#define EXCEPT(e) \
|
||||
if (except_flag == EXCEPT_STATE_ENTERED) except_stack = except_stack->prev; \
|
||||
} else if (except_frame.exception == &(e)) { \
|
||||
except_flag = EXCEPT_STATE_HANDLED;
|
||||
#define ELSE \
|
||||
if (except_flag == EXCEPT_STATE_ENTERED) except_stack = except_stack->prev; \
|
||||
} else { \
|
||||
except_flag = EXCEPT_STATE_HANDLED;
|
||||
#define FINALLY \
|
||||
if (except_flag == EXCEPT_STATE_ENTERED) except_stack = except_stack->prev; \
|
||||
} { \
|
||||
if (except_flag == EXCEPT_STATE_ENTERED) \
|
||||
except_flag = EXCEPT_STATE_FINALIZED;
|
||||
#define END_TRY \
|
||||
if (except_flag == EXCEPT_STATE_ENTERED) except_stack = except_stack->prev; \
|
||||
} if (except_flag == EXCEPT_STATE_RAISED) RERAISE; \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#undef assert
|
||||
#ifdef NDEBUG
|
||||
#define assert(e) ((void)0)
|
||||
#else
|
||||
extern void ci2_assert(int e);
|
||||
#define assert(e) ((void)((e)||(RAISE(assertion_failed),0)))
|
||||
#endif
|
||||
|
||||
#endif // CI2_EXCEPTION_H
|
||||
37
src/linux_exception.c
Normal file
37
src/linux_exception.c
Normal file
@@ -0,0 +1,37 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "../include/ci2_exception.h"
|
||||
|
||||
struct Except_Frame *except_stack = NULL;
|
||||
const struct Exception assertion_failed = { "Assertion failed" };
|
||||
void ci2_assert(int e){
|
||||
if(!e){
|
||||
RAISE(assertion_failed);
|
||||
}
|
||||
}
|
||||
|
||||
void except_raise(const struct Exception *e, const char *file,int line){
|
||||
|
||||
struct Except_Frame *p = except_stack;
|
||||
ci2_assert(e != NULL);
|
||||
|
||||
if (p == NULL) {
|
||||
fprintf(stderr, "Uncaught exception");
|
||||
if (e->reason)
|
||||
fprintf(stderr, " %s", e->reason);
|
||||
else
|
||||
fprintf(stderr, " at 0x%p", (void*)e);
|
||||
if (file && line > 0)
|
||||
fprintf(stderr, " raised at %s:%d\n", file, line);
|
||||
fprintf(stderr, "aborting...\n");
|
||||
fflush(stderr);
|
||||
abort();
|
||||
}
|
||||
|
||||
p->exception = e;
|
||||
p->file = file;
|
||||
p->line = line;
|
||||
except_stack = except_stack->prev;
|
||||
|
||||
longjmp(p->env, EXCEPT_STATE_RAISED);
|
||||
}
|
||||
69
src/win32_exception.c
Normal file
69
src/win32_exception.c
Normal file
@@ -0,0 +1,69 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "../include/win32_exception.h"
|
||||
|
||||
DWORD except_index = -1;
|
||||
|
||||
const struct Exception assertion_failed = { "Assertion failed" };
|
||||
void ci2_assert(int e){
|
||||
if(!e){
|
||||
RAISE(assertion_failed);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
_CRTIMP void __cdecl _assert(void *, void *, unsigned);
|
||||
#undef assert
|
||||
#define ci2_assert(e) ((e) || (_assert(#e, __FILE__, __LINE__), 0))
|
||||
#endif
|
||||
|
||||
void except_raise(const struct Exception *e, const char *file,int line){
|
||||
Except_Frame *p;
|
||||
|
||||
if (except_index == TLS_OUT_OF_INDEXES)
|
||||
except_init();
|
||||
p = TlsGetValue(except_index);
|
||||
ci2_assert(e != NULL);
|
||||
if (p == NULL) {
|
||||
fprintf(stderr, "Uncaught exception");
|
||||
if (e->reason)
|
||||
fprintf(stderr, " %s", e->reason);
|
||||
else
|
||||
fprintf(stderr, " at 0x%p", (void*)e);
|
||||
if (file && line > 0)
|
||||
fprintf(stderr, " raised at %s:%d\n", file, line);
|
||||
fprintf(stderr, "aborting...\n");
|
||||
fflush(stderr);
|
||||
abort();
|
||||
}
|
||||
|
||||
p->exception = e;
|
||||
p->file = file;
|
||||
p->line = line;
|
||||
|
||||
except_pop();
|
||||
|
||||
longjmp(p->env, EXCEPT_STATE_RAISED);
|
||||
}
|
||||
void except_init(void) {
|
||||
BOOL cond;
|
||||
except_index = TlsAlloc();
|
||||
assert(except_index != TLS_OUT_OF_INDEXES);
|
||||
cond = TlsSetValue(except_index, NULL);
|
||||
assert(cond == TRUE);
|
||||
}
|
||||
void except_push(Except_Frame *fp) {
|
||||
BOOL cond;
|
||||
|
||||
fp->prev = TlsGetValue(except_index);
|
||||
cond = TlsSetValue(except_index, fp);
|
||||
assert(cond == TRUE);
|
||||
}
|
||||
void except_pop(void) {
|
||||
BOOL cond;
|
||||
Except_Frame *tos = TlsGetValue(except_index);
|
||||
|
||||
cond = TlsSetValue(except_index, tos->prev);
|
||||
assert(cond == TRUE);
|
||||
}
|
||||
|
||||
13
tests/01_sanity.c
Normal file
13
tests/01_sanity.c
Normal file
@@ -0,0 +1,13 @@
|
||||
#define DEBUG
|
||||
#include "../include/ci2_exception.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void){
|
||||
printf("\n\n");
|
||||
printf("Assertion sanity test.\n");
|
||||
ci2_assert(0);
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
}
|
||||
14
tests/02_uncaught.c
Normal file
14
tests/02_uncaught.c
Normal file
@@ -0,0 +1,14 @@
|
||||
#define DEBUG
|
||||
#include "../include/ci2_exception.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void){
|
||||
printf("\n\n");
|
||||
printf("Uncaught exceptions sanity test.\n");
|
||||
struct Exception uncaught = {NULL};
|
||||
RAISE(uncaught);
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user