mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
mruby-exit.c: make exit() to raise SystemExit exception.
Now it allows error handlers to work, unlike `exit!`.
This commit is contained in:
@@ -21,6 +21,14 @@ struct RException {
|
||||
struct RObject *backtrace; // NULL, RArray or RData
|
||||
};
|
||||
|
||||
/* error that should terminate execution */
|
||||
#define MRB_EXC_EXIT 65536
|
||||
#define MRB_EXC_EXIT_P(e) ((e)->flags & MRB_EXC_EXIT)
|
||||
/* retrieve status value from exc; need <mruby/variable.h> and <mruby/presym.h> */
|
||||
#define MRB_EXC_EXIT_STATUS(mrb,e) ((int)mrb_as_int((mrb),mrb_obj_iv_get((mrb),(e),MRB_SYM(status))))
|
||||
/* exit with SystemExit status */
|
||||
#define MRB_EXC_CHECK_EXIT(mrb,e) do {if (MRB_EXC_EXIT_P(e)) exit(MRB_EXC_EXIT_STATUS((mrb),(e)));} while (0)
|
||||
|
||||
#define mrb_exc_ptr(v) ((struct RException*)mrb_ptr(v))
|
||||
|
||||
MRB_API mrb_noreturn void mrb_sys_fail(mrb_state *mrb, const char *mesg);
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <mruby/dump.h>
|
||||
#include <mruby/string.h>
|
||||
#include <mruby/variable.h>
|
||||
#include <mruby/error.h>
|
||||
#include <mruby/presym.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
@@ -674,6 +675,7 @@ main(int argc, char **argv)
|
||||
stack_keep = proc->body.irep->nlocals;
|
||||
/* did an exception occur? */
|
||||
if (mrb->exc) {
|
||||
MRB_EXC_CHECK_EXIT(mrb, mrb->exc);
|
||||
p(mrb, mrb_obj_value(mrb->exc), 0);
|
||||
mrb->exc = 0;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
#include <mruby/dump.h>
|
||||
#include <mruby/variable.h>
|
||||
#include <mruby/proc.h>
|
||||
#include <mruby/error.h>
|
||||
#include <mruby/presym.h>
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
# include <io.h> /* for setmode */
|
||||
@@ -366,6 +368,7 @@ main(int argc, char **argv)
|
||||
mrb_gc_arena_restore(mrb, ai);
|
||||
mrbc_context_free(mrb, c);
|
||||
if (mrb->exc) {
|
||||
MRB_EXC_CHECK_EXIT(mrb, mrb->exc);
|
||||
if (!mrb_undef_p(v)) {
|
||||
mrb_print_error(mrb);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <mruby.h>
|
||||
#include <mruby/error.h>
|
||||
#include <mruby/variable.h>
|
||||
#include <mruby/presym.h>
|
||||
|
||||
#ifndef EXIT_SUCCESS
|
||||
# define EXIT_SUCCESS 0
|
||||
@@ -9,48 +12,69 @@
|
||||
# define EXIT_FAILURE 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* exit(status=false)
|
||||
*
|
||||
* Exits the process immediately. No exit handlers are run currently.
|
||||
* <em>status</em> is returned to the underlying system as the
|
||||
* exit status.
|
||||
*
|
||||
* exit(true)
|
||||
*/
|
||||
static int
|
||||
get_status(mrb_state *mrb)
|
||||
{
|
||||
mrb_value status = mrb_true_value();
|
||||
|
||||
mrb_get_args(mrb, "|o", &status);
|
||||
if (mrb_true_p(status)) return EXIT_SUCCESS;
|
||||
if (mrb_false_p(status)) return EXIT_FAILURE;
|
||||
return (int)mrb_as_int(mrb, status);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* exit!(status=false)
|
||||
* exit(status=true)
|
||||
*
|
||||
* Initiates the termination of the Ruby script by raising the
|
||||
* SystemExit exception. This exception may be caught. The
|
||||
* optional parameter is used to return a status code to the invoking
|
||||
* environment.
|
||||
*
|
||||
* +true+ and +false+ of _status_ means success and failure
|
||||
* respectively. The interpretation of other integer values are
|
||||
* system dependent.
|
||||
*
|
||||
* exit(0)
|
||||
*/
|
||||
static mrb_value
|
||||
f_exit(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
int status = get_status(mrb);
|
||||
mrb_value exc = mrb_obj_new(mrb, mrb_exc_get_id(mrb, MRB_SYM(SystemExit)), 0, NULL);
|
||||
struct RException *e = mrb_exc_ptr(exc);
|
||||
e->flags |= MRB_EXC_EXIT;
|
||||
mrb_iv_set(mrb, exc, MRB_SYM(status), mrb_int_value(mrb, (mrb_int)status));
|
||||
mrb_exc_raise(mrb, exc);
|
||||
/* not reached */
|
||||
return mrb_nil_value();
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* exit!(status=true)
|
||||
*
|
||||
* Exits the process immediately. No exit handlers are run.
|
||||
* <em>status</em> is returned to the underlying system as the
|
||||
* exit status.
|
||||
*
|
||||
* exit!(true)
|
||||
* exit!(0)
|
||||
*/
|
||||
static mrb_value
|
||||
f_exit_bang(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
mrb_value status = mrb_true_value();
|
||||
int istatus;
|
||||
|
||||
mrb_get_args(mrb, "|o", &status);
|
||||
istatus = mrb_true_p(status) ? EXIT_SUCCESS :
|
||||
mrb_false_p(status) ? EXIT_FAILURE :
|
||||
(int)mrb_int(mrb, status);
|
||||
exit(istatus);
|
||||
|
||||
exit(get_status(mrb));
|
||||
/* not reached */
|
||||
return status;
|
||||
return mrb_nil_value();
|
||||
}
|
||||
|
||||
void
|
||||
mrb_mruby_exit_gem_init(mrb_state* mrb)
|
||||
{
|
||||
mrb_define_method(mrb, mrb->kernel_module, "exit", f_exit_bang, MRB_ARGS_OPT(1));
|
||||
mrb_define_method(mrb, mrb->kernel_module, "exit!", f_exit_bang, MRB_ARGS_OPT(1));
|
||||
mrb_define_class_id(mrb, MRB_SYM(SystemExit), mrb->eException_class);
|
||||
mrb_define_method_id(mrb, mrb->kernel_module, MRB_SYM(exit), f_exit, MRB_ARGS_OPT(1));
|
||||
mrb_define_method_id(mrb, mrb->kernel_module, MRB_SYM_B(exit), f_exit_bang, MRB_ARGS_OPT(1));
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
Reference in New Issue
Block a user