Last active
December 20, 2015 01:39
-
-
Save wanabe/6050395 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| diff --git a/src/backtrace.c b/src/backtrace.c | |
| index e05ad43..20ccaa7 100644 | |
| --- a/src/backtrace.c | |
| +++ b/src/backtrace.c | |
| @@ -7,18 +7,65 @@ | |
| #include "mruby.h" | |
| #include "mruby/variable.h" | |
| #include "mruby/proc.h" | |
| +#include "mruby/array.h" | |
| +#include "mruby/string.h" | |
| +#include <stdarg.h> | |
| -void | |
| -mrb_print_backtrace(mrb_state *mrb) | |
| +typedef void (*output_stream_func)(mrb_state*, void*, const char*, ...); | |
| + | |
| +static void | |
| +outputf(mrb_state *mrb, void *stream, const char *format, ...) | |
| +{ | |
| + va_list ap; | |
| + | |
| + va_start(ap, format); | |
| + vfprintf((FILE*)stream, format, ap); | |
| +} | |
| + | |
| +#define MIN_BUFSIZE 127 | |
| + | |
| +static void | |
| +strcatf(mrb_state *mrb, void *stream, const char *format, ...) | |
| +{ | |
| + va_list ap; | |
| + mrb_value ary; | |
| + int len, ai; | |
| + | |
| + ai = mrb_gc_arena_save(mrb); | |
| + ary = mrb_obj_value((struct RArray*)stream); | |
| + va_start(ap, format); | |
| + len = vsnprintf(NULL, 0, format, ap); | |
| + va_end(ap); | |
| + | |
| + if (len < MIN_BUFSIZE) { | |
| + char buf[MIN_BUFSIZE + 1]; | |
| + | |
| + va_start(ap, format); | |
| + vsnprintf(buf, MIN_BUFSIZE, format, ap); | |
| + va_end(ap); | |
| + mrb_ary_push(mrb, ary, mrb_str_new(mrb, buf, len)); | |
| + } | |
| + else { | |
| + char *buf = (char*)mrb_alloca(mrb, len + 1); | |
| + | |
| + va_start(ap, format); | |
| + vsnprintf(buf, len, format, ap); | |
| + va_end(ap); | |
| + mrb_ary_push(mrb, ary, mrb_str_new(mrb, buf, len)); | |
| + } | |
| + mrb_gc_arena_restore(mrb, ai); | |
| +} | |
| + | |
| +static void | |
| +mrb_output_backtrace(mrb_state *mrb, struct RObject *exc, output_stream_func outputfunc, void *stream) | |
| { | |
| -#ifdef ENABLE_STDIO | |
| mrb_callinfo *ci; | |
| mrb_int ciidx; | |
| const char *filename, *method, *sep; | |
| int i, line; | |
| - fputs("trace:\n", stderr); | |
| - ciidx = mrb_fixnum(mrb_obj_iv_get(mrb, mrb->exc, mrb_intern2(mrb, "ciidx", 5))); | |
| + outputfunc(mrb, stream, "trace:\n"); | |
| + ciidx = mrb_fixnum(mrb_obj_iv_get(mrb, exc, mrb_intern2(mrb, "ciidx", 5))); | |
| if (ciidx >= mrb->c->ciend - mrb->c->cibase) | |
| ciidx = 10; /* ciidx is broken... */ | |
| @@ -41,7 +88,7 @@ mrb_print_backtrace(mrb_state *mrb) | |
| pc = mrb->c->cibase[i+1].pc; | |
| } | |
| else { | |
| - pc = (mrb_code*)mrb_voidp(mrb_obj_iv_get(mrb, mrb->exc, mrb_intern2(mrb, "lastpc", 6))); | |
| + pc = (mrb_code*)mrb_voidp(mrb_obj_iv_get(mrb, exc, mrb_intern2(mrb, "lastpc", 6))); | |
| } | |
| if (irep->iseq <= pc && pc < irep->iseq + irep->ilen) { | |
| line = irep->lines[pc - irep->iseq - 1]; | |
| @@ -59,15 +106,33 @@ mrb_print_backtrace(mrb_state *mrb) | |
| const char *cn = mrb_class_name(mrb, ci->proc->target_class); | |
| if (cn) { | |
| - fprintf(stderr, "\t[%d] %s:%d:in %s%s%s\n", i, filename, line, cn, sep, method); | |
| + outputfunc(mrb, stream, "\t[%d] %s:%d:in %s%s%s\n", i, filename, line, cn, sep, method); | |
| } | |
| else { | |
| - fprintf(stderr, "\t[%d] %s:%d:in %s\n", i, filename, line, method); | |
| + outputfunc(mrb, stream, "\t[%d] %s:%d:in %s\n", i, filename, line, method); | |
| } | |
| } | |
| else { | |
| - fprintf(stderr, "\t[%d] %s:%d\n", i, filename, line); | |
| + outputfunc(mrb, stream, "\t[%d] %s:%d\n", i, filename, line); | |
| } | |
| } | |
| +} | |
| + | |
| +void | |
| +mrb_print_backtrace(mrb_state *mrb) | |
| +{ | |
| +#ifdef ENABLE_STDIO | |
| + mrb_output_backtrace(mrb, mrb->exc, outputf, stderr); | |
| #endif | |
| } | |
| + | |
| +mrb_value | |
| +mrb_get_backtrace(mrb_state *mrb, mrb_value self) | |
| +{ | |
| + mrb_value ary; | |
| + | |
| + ary = mrb_ary_new(mrb); | |
| + mrb_output_backtrace(mrb, mrb_obj_ptr(self), strcatf, mrb_ary_ptr(ary)); | |
| + | |
| + return ary; | |
| +} | |
| diff --git a/src/error.c b/src/error.c | |
| index bd3afd2..3a58f98 100644 | |
| --- a/src/error.c | |
| +++ b/src/error.c | |
| @@ -433,6 +433,8 @@ mrb_sys_fail(mrb_state *mrb, const char *mesg) | |
| } | |
| } | |
| +mrb_value mrb_get_backtrace(mrb_state*, mrb_value); | |
| + | |
| void | |
| mrb_init_exception(mrb_state *mrb) | |
| { | |
| @@ -446,6 +448,7 @@ mrb_init_exception(mrb_state *mrb) | |
| mrb_define_method(mrb, e, "to_s", exc_to_s, MRB_ARGS_NONE()); | |
| mrb_define_method(mrb, e, "message", exc_message, MRB_ARGS_NONE()); | |
| mrb_define_method(mrb, e, "inspect", exc_inspect, MRB_ARGS_NONE()); | |
| + mrb_define_method(mrb, e, "backtrace", mrb_get_backtrace, MRB_ARGS_NONE()); | |
| mrb->eStandardError_class = mrb_define_class(mrb, "StandardError", mrb->eException_class); /* 15.2.23 */ | |
| mrb_define_class(mrb, "RuntimeError", mrb->eStandardError_class); /* 15.2.28 */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment