Support catching CFC exceptions from C

Needed to fix CLOWNFISH-14.


Project: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/commit/5d0a3efe
Tree: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/tree/5d0a3efe
Diff: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/diff/5d0a3efe

Branch: refs/heads/master
Commit: 5d0a3efefc68ae1ea81564a0184d70273db75623
Parents: 65387c4
Author: Nick Wellnhofer <wellnho...@aevum.de>
Authored: Fri Mar 4 17:58:28 2016 +0100
Committer: Nick Wellnhofer <wellnho...@aevum.de>
Committed: Sat Mar 5 17:51:27 2016 +0100

----------------------------------------------------------------------
 compiler/src/CFCUtil.c | 71 +++++++++++++++++++++++++++++++++++++++++----
 compiler/src/CFCUtil.h | 23 +++++++++++++++
 2 files changed, 88 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/5d0a3efe/compiler/src/CFCUtil.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCUtil.c b/compiler/src/CFCUtil.c
index da546af..a2a0993 100644
--- a/compiler/src/CFCUtil.c
+++ b/compiler/src/CFCUtil.c
@@ -23,6 +23,7 @@
 #include <stdarg.h>
 #include <errno.h>
 #include <sys/stat.h>
+#include <setjmp.h>
 
 // For mkdir.
 #ifdef CHY_HAS_DIRECT_H
@@ -36,6 +37,9 @@
 
 #include "CFCUtil.h"
 
+static char    *thrown_error;
+static jmp_buf *current_env;
+
 void
 CFCUtil_null_check(const void *arg, const char *name, const char *file,
                    int line) {
@@ -594,6 +598,21 @@ CFCUtil_closedir(void *dirhandle, const char *dir) {
 
 /***************************************************************************/
 
+jmp_buf*
+CFCUtil_try_start(jmp_buf *env) {
+    jmp_buf *prev_env = current_env;
+    current_env = env;
+    return prev_env;
+}
+
+char*
+CFCUtil_try_end(jmp_buf *prev_env) {
+    current_env = prev_env;
+    char *error = thrown_error;
+    thrown_error = NULL;
+    return error;
+}
+
 #ifdef CFCPERL
 
 #include "EXTERN.h"
@@ -605,8 +624,27 @@ void
 CFCUtil_die(const char* format, ...) {
     va_list args;
     va_start(args, format);
-    vcroak(format, &args);
-    va_end(args);
+
+    if (current_env) {
+        thrown_error = CFCUtil_vsprintf(format, args);
+        va_end(args);
+        longjmp(*current_env, 1);
+    }
+    else {
+        vcroak(format, &args);
+        va_end(args);
+    }
+}
+
+void
+CFCUtil_rethrow(char *error) {
+    if (current_env) {
+        thrown_error = error;
+        longjmp(*current_env, 1);
+    }
+    else {
+        croak("%s", error);
+    }
 }
 
 void
@@ -623,10 +661,31 @@ void
 CFCUtil_die(const char* format, ...) {
     va_list args;
     va_start(args, format);
-    vfprintf(stderr, format, args);
-    va_end(args);
-    fprintf(stderr, "\n");
-    exit(1);
+
+    if (current_env) {
+        thrown_error = CFCUtil_vsprintf(format, args);
+        va_end(args);
+        longjmp(*current_env, 1);
+    }
+    else {
+        vfprintf(stderr, format, args);
+        va_end(args);
+        fprintf(stderr, "\n");
+        abort();
+    }
+}
+
+void
+CFCUtil_rethrow(char *error) {
+    if (current_env) {
+        thrown_error = error;
+        longjmp(*current_env, 1);
+    }
+    else {
+        fprintf(stderr, "%s\n", error);
+        FREEMEM(error);
+        abort();
+    }
 }
 
 void

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/5d0a3efe/compiler/src/CFCUtil.h
----------------------------------------------------------------------
diff --git a/compiler/src/CFCUtil.h b/compiler/src/CFCUtil.h
index 3e06b03..73286ef 100644
--- a/compiler/src/CFCUtil.h
+++ b/compiler/src/CFCUtil.h
@@ -29,6 +29,18 @@ extern "C" {
 
 #include <stdarg.h>
 #include <stddef.h>
+#include <setjmp.h>
+
+#define CFCUTIL_TRY                                   \
+    do {                                              \
+        jmp_buf env;                                  \
+        jmp_buf *prev_env = CFCUtil_try_start(&env);  \
+        if (!setjmp(env))
+
+#define CFCUTIL_CATCH(error)                          \
+        error = CFCUtil_try_end(prev_env);            \
+    } while (0)
+
 
 /** Create an inner Perl object with a refcount of 1.  For use in actual
  * Perl-space, it is necessary to wrap this inner object in an RV.
@@ -223,11 +235,22 @@ CFCUtil_free_string_array(char **strings);
 void
 CFCUtil_die(const char *format, ...);
 
+/* Rethrow an error.
+ */
+void
+CFCUtil_rethrow(char *error);
+
 /* Print an error message to stderr.
  */
 void
 CFCUtil_warn(const char *format, ...);
 
+jmp_buf*
+CFCUtil_try_start(jmp_buf *env);
+
+char*
+CFCUtil_try_end(jmp_buf *prev_env);
+
 #ifdef __cplusplus
 }
 #endif

Reply via email to