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)
|
* [License](#license)
|
||||||
|
|
||||||
## Features
|
## 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
|
## Todos
|
||||||
- [ ] Better makefile
|
|
||||||
|
- [?] Better makefile
|
||||||
- [ ] Better Usage Examples
|
- [ ] Better Usage Examples
|
||||||
- [ ] Basic Window
|
|
||||||
- [ ] Exceptions & Try/Catch
|
|
||||||
- [ ] Memory Allocator
|
- [ ] Memory Allocator
|
||||||
- [ ] Arena Allocator
|
- [ ] Arena Allocator
|
||||||
- [ ] Arrays
|
- [ ] Arrays
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#ifndef CI2_INCLUDED
|
#ifndef CI2_INCLUDED
|
||||||
#define CI2_INCLUDED
|
#define CI2_INCLUDED
|
||||||
|
|
||||||
extern void ci2_printf()
|
|
||||||
|
|
||||||
#endif
|
#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