Exceptions in C!
This commit is contained in:
parent
e8bea8924b
commit
26179d76aa
6 changed files with 134 additions and 0 deletions
|
@ -20,3 +20,4 @@ add_subdirectory(./BinaryTree)
|
|||
add_subdirectory(./Subprocess)
|
||||
add_subdirectory(./TracingHeap)
|
||||
add_subdirectory(./Complex)
|
||||
add_subdirectory(./ExceptionalScope)
|
||||
|
|
1
src/ExceptionalScope/CMakeLists.txt
Normal file
1
src/ExceptionalScope/CMakeLists.txt
Normal file
|
@ -0,0 +1 @@
|
|||
add_library(ExceptionalScope STATIC ExceptionalScope.c)
|
51
src/ExceptionalScope/ExceptionalScope.c
Normal file
51
src/ExceptionalScope/ExceptionalScope.c
Normal file
|
@ -0,0 +1,51 @@
|
|||
#include "ExceptionalScope.h"
|
||||
#include "../errorcodes.h"
|
||||
|
||||
#include <setjmp.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
int ExceptionalScope_Create(ExceptionalScope* self)
|
||||
{
|
||||
memset(self, 0, sizeof(*self));
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
void ExceptionalScope_ActivateCleaners(ExceptionalScope* self)
|
||||
{
|
||||
while (self->cleaners != NULL) {
|
||||
self->cleaners->action(self->cleaners->arg);
|
||||
self->cleaners = self->cleaners->next;
|
||||
}
|
||||
}
|
||||
|
||||
void ExceptionalScope_Destroy(ExceptionalScope* self)
|
||||
{
|
||||
ExceptionalScope_ActivateCleaners(self);
|
||||
}
|
||||
|
||||
void ExceptionalScope_PushCleaner(ExceptionalScope* self, ExceptionalScopeCleaner* cleaner)
|
||||
{
|
||||
cleaner->next = self->cleaners;
|
||||
self->cleaners = cleaner;
|
||||
}
|
||||
|
||||
int ExceptionalScope_PopCleaner(ExceptionalScope* self, ExceptionalScopeCleaner* cleaner)
|
||||
{
|
||||
if (self->cleaners != cleaner) return ENOTFOUND;
|
||||
|
||||
self->cleaners = self->cleaners->next;
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
[[noreturn]] void ExceptionalScope_Throw(ExceptionalScope* self, void* exception)
|
||||
{
|
||||
self->exception = exception;
|
||||
|
||||
ExceptionalScope_ActivateCleaners(self);
|
||||
|
||||
longjmp(self->handler, 1);
|
||||
}
|
33
src/ExceptionalScope/ExceptionalScope.h
Normal file
33
src/ExceptionalScope/ExceptionalScope.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
#ifndef UTILITIEC_EXCEPTIONALSCOPE_H
|
||||
#define UTILITIEC_EXCEPTIONALSCOPE_H
|
||||
|
||||
#include <setjmp.h>
|
||||
|
||||
#define withScopedCleaner(scope, cleaner) for (int __cleanerDone##cleaner = (ExceptionalScope_PushCleaner(scope, &cleaner), 1); __cleanerDone##cleaner--; ExceptionalScope_PopCleaner(scope, &cleaner))
|
||||
#define try(scope) if (setjmp((scope)->handler) == 0)
|
||||
#define catch else
|
||||
|
||||
typedef void (*ExceptionalScopeCleanerFunction) (void* arg);
|
||||
|
||||
typedef struct ExceptionalScopeCleaner_s {
|
||||
ExceptionalScopeCleanerFunction action;
|
||||
void* arg;
|
||||
|
||||
struct ExceptionalScopeCleaner_s* next;
|
||||
} ExceptionalScopeCleaner;
|
||||
|
||||
typedef struct ExceptionalScope_s {
|
||||
jmp_buf handler; // jump here when the exception is thrown
|
||||
ExceptionalScopeCleaner* cleaners; // execute all these before the jumping to the handler
|
||||
void* exception;
|
||||
} ExceptionalScope;
|
||||
|
||||
int ExceptionalScope_Create(ExceptionalScope* self);
|
||||
void ExceptionalScope_Destroy(ExceptionalScope* self);
|
||||
|
||||
void ExceptionalScope_PushCleaner(ExceptionalScope* self, ExceptionalScopeCleaner* cleaner);
|
||||
int ExceptionalScope_PopCleaner(ExceptionalScope* self, ExceptionalScopeCleaner* cleaner);
|
||||
|
||||
[[noreturn]] void ExceptionalScope_Throw(ExceptionalScope* self, void* exception);
|
||||
|
||||
#endif
|
|
@ -60,4 +60,8 @@ target_link_libraries(QuadTree-test
|
|||
rand
|
||||
pointers
|
||||
allocator-interface
|
||||
|
||||
add_executable(ExceptionalScope-test ExceptionalScope.test.c)
|
||||
target_link_libraries(ExceptionalScope-test
|
||||
ExceptionalScope
|
||||
)
|
||||
|
|
44
tests/ExceptionalScope.test.c
Normal file
44
tests/ExceptionalScope.test.c
Normal file
|
@ -0,0 +1,44 @@
|
|||
#include "../src/ExceptionalScope/ExceptionalScope.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#define unsafe
|
||||
|
||||
void print(const char* s)
|
||||
{
|
||||
unsafe {
|
||||
puts(s);
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
ExceptionalScope scope;
|
||||
ExceptionalScope_Create(&scope);
|
||||
scope.exception = (void*) 0xCAFEBABE;
|
||||
|
||||
try(&scope) {
|
||||
ExceptionalScopeCleaner outerCleaner = {
|
||||
.next = NULL,
|
||||
.arg = "Unwinding the cleaner stack #2",
|
||||
.action = (ExceptionalScopeCleanerFunction) print,
|
||||
};
|
||||
withScopedCleaner(&scope, outerCleaner) {
|
||||
ExceptionalScopeCleaner innerCleaner = {
|
||||
.next = NULL,
|
||||
.arg = "Unwinding the cleaner stack #1",
|
||||
.action = (ExceptionalScopeCleanerFunction) print,
|
||||
};
|
||||
|
||||
withScopedCleaner(&scope, innerCleaner) {
|
||||
|
||||
ExceptionalScope_Throw(&scope, (void*) 0xDEADBEEF);
|
||||
puts("After the throw");
|
||||
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
printf("Caught an exception: %p\n", scope.exception);
|
||||
}
|
||||
|
||||
ExceptionalScope_Destroy(&scope);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue