00001 #include "tRuby.h"
00002
00003 #ifdef HAVE_LIBRUBY
00004
00005 #ifdef MACOSX_XCODE
00006 # include "AARuby.h"
00007 #endif
00008
00009 extern "C" {
00010 extern void Init_armagetronad(void);
00011 }
00012
00013 namespace tRuby
00014 {
00015 std::string GetExceptionInfo();
00016 VALUE RequireProtect(VALUE lib);
00017 VALUE LoadProtect(VALUE data);
00018 VALUE EvalProtect(VALUE code);
00019
00020
00021
00022
00023 void InitializeInterpreter()
00024 {
00025 ruby_init();
00026 VALUE load_path = rb_gv_get("$LOAD_PATH");
00027 rb_ary_push(load_path, rb_str_new2("."));
00028 Init_armagetronad();
00029 ruby_script("Armagetron Advanced");
00030 }
00031
00032 void CleanupInterpreter()
00033 {
00034 ruby_finalize();
00035 }
00036
00037 void Require(const char * lib)
00038 {
00039 int status = 0;
00040 rb_protect(RequireProtect, reinterpret_cast<VALUE>(lib), &status);
00041 CheckStatus(status);
00042 }
00043
00044 void Load(const tPath & path, const char * filename, bool w)
00045 {
00046 VALUE wrap = w ? Qtrue : Qfalse;
00047 tString realPath = path.GetReadPath(filename);
00048 if (realPath == "")
00049 return;
00050
00051 VALUE args[] = {rb_str_new2(realPath.c_str()), wrap};
00052 int status = 0;
00053 rb_protect(LoadProtect, reinterpret_cast<VALUE>(args), &status);
00054 CheckStatus(status);
00055 }
00056
00057 VALUE Eval(std::string code)
00058 {
00059 int status = 0;
00060 VALUE result = rb_protect(EvalProtect, reinterpret_cast<VALUE>(code.c_str()), &status);
00061 CheckStatus(status);
00062 return result;
00063 }
00064
00065
00066
00067
00068 std::string GetExceptionInfo()
00069 {
00070 VALUE exception = rb_gv_get("$!");
00071 if (NIL_P(exception))
00072 return std::string("No exception");
00073
00074 VALUE klass = rb_funcall(rb_funcall(exception,
00075 rb_intern("class"),
00076 0),
00077 rb_intern("to_s"),
00078 0);
00079 VALUE to_s = rb_funcall(exception, rb_intern("to_s"), 0);
00080 VALUE backtrace = rb_funcall(rb_funcall(exception,
00081 rb_intern("backtrace"),
00082 0),
00083 rb_intern("join"),
00084 1,
00085 rb_str_new2("\n"));
00086 std::string info;
00087 info += StringValuePtr(klass);
00088 info += ": ";
00089 info += StringValuePtr(to_s);
00090 info += '\n';
00091 info += StringValuePtr(backtrace);
00092 return info;
00093 }
00094
00095 void CheckStatus(int status)
00096 {
00097 if (status)
00098 {
00099 std::runtime_error error(GetExceptionInfo());
00100 throw error;
00101 }
00102 }
00103
00104 VALUE RequireProtect(VALUE lib)
00105 {
00106 rb_require(reinterpret_cast<char *>(lib));
00107 return Qnil;
00108 }
00109
00110 VALUE LoadProtect(VALUE data)
00111 {
00112 VALUE * args = reinterpret_cast<VALUE *>(data);
00113 rb_funcall(rb_mKernel, rb_intern("load"), 1, args[0], args[1]);
00114 return Qnil;
00115 }
00116
00117 VALUE EvalProtect(VALUE code)
00118 {
00119 return rb_eval_string(reinterpret_cast<char *>(code));;
00120 }
00121
00122
00123
00124
00125 Sandbox::Sandbox(float timeout)
00126 {
00127 VALUE options = rb_hash_new();
00128 rb_funcall(options, rb_intern("[]="), 2, ID2SYM(rb_intern("init")), ID2SYM(rb_intern("all")));
00129
00130 if (timeout != 0)
00131 {
00132 rb_funcall(options, rb_intern("[]="), 2, ID2SYM(rb_intern("timeout")), rb_float_new(timeout));
00133 }
00134
00135 VALUE args[] = { rb_cObject, rb_str_new2("Sandbox") };
00136 int status = 0;
00137 VALUE cSandbox = rb_protect(ConstGetProtect, reinterpret_cast<VALUE>(args), &status);
00138 CheckStatus(status);
00139
00140 sandbox_ = rb_funcall(cSandbox,
00141 rb_intern("new"),
00142 1,
00143 options);
00144 }
00145
00146 Sandbox::~Sandbox()
00147 {
00148 }
00149
00150 VALUE Sandbox::Eval(std::string code)
00151 {
00152 int status = 0;
00153 VALUE args[] = { reinterpret_cast<VALUE>(this), rb_str_new2(code.c_str()) };
00154 VALUE val = rb_protect(EvalProtect, reinterpret_cast<VALUE>(args), &status);
00155 CheckStatus(status);
00156 return val;
00157 }
00158
00159 void Sandbox::Import(const char * c)
00160 {
00161 VALUE constants = rb_funcall(rb_str_new2(c), rb_intern("split"), 1, rb_str_new2("::"));
00162 VALUE constant = rb_cObject;
00163 for(int index = 0; index < RARRAY(constants)->len; ++index)
00164 {
00165 int status = 0;
00166 VALUE args[] = {constant, RARRAY(constants)->ptr[index]};
00167 constant = rb_protect(ConstGetProtect, reinterpret_cast<VALUE>(args), &status);
00168 CheckStatus(status);
00169 }
00170 rb_funcall(sandbox_, rb_intern("import"), 1, constant);
00171 }
00172
00173 void Sandbox::Load(const tPath & path, const char * filename)
00174 {
00175 tString realPath = path.GetReadPath(filename);
00176 if (realPath == "")
00177 return;
00178
00179 VALUE args[] = { reinterpret_cast<VALUE>(this), rb_str_new2(realPath.c_str()) };
00180 int status = 0;
00181 rb_protect(LoadProtect, reinterpret_cast<VALUE>(args), &status);
00182 CheckStatus(status);
00183 }
00184
00185
00186
00187
00188 VALUE & Sandbox::GetSandbox()
00189 {
00190 return sandbox_;
00191 }
00192
00193 VALUE Sandbox::EvalProtect(VALUE data)
00194 {
00195 VALUE * args = reinterpret_cast<VALUE *>(data);
00196 Sandbox * sandbox = reinterpret_cast<Sandbox *>(args[0]);
00197 return rb_funcall(sandbox->GetSandbox(), rb_intern("eval"), 1, args[1]);
00198 }
00199
00200 VALUE Sandbox::ConstGetProtect(VALUE data)
00201 {
00202 VALUE * args = reinterpret_cast<VALUE *>(data);
00203 return rb_funcall(args[0], rb_intern("const_get"), 1, args[1]);
00204 }
00205
00206 VALUE Sandbox::LoadProtect(VALUE data)
00207 {
00208 VALUE * args = reinterpret_cast<VALUE *>(data);
00209 Sandbox * sandbox = reinterpret_cast<Sandbox *>(args[0]);
00210 rb_funcall(sandbox->GetSandbox(), rb_intern("load"), 1, args[1]);
00211 return Qnil;
00212 }
00213
00214
00215
00216
00217 Safe::Safe(float timeout)
00218 {
00219 VALUE options = rb_hash_new();
00220
00221 if (timeout != 0)
00222 {
00223 rb_funcall(options, rb_intern("[]="), 2, ID2SYM(rb_intern("timeout")), rb_float_new(timeout));
00224 }
00225
00226 VALUE args[] = { rb_cObject, rb_str_new2("Sandbox") };
00227 int status = 0;
00228 VALUE cSandbox = rb_protect(ConstGetProtect, reinterpret_cast<VALUE>(args), &status);
00229 CheckStatus(status);
00230 status = 0;
00231 VALUE args2[] = { cSandbox, rb_str_new2("Safe") };
00232 VALUE cSafe = rb_protect(ConstGetProtect, reinterpret_cast<VALUE>(args2), &status);
00233 CheckStatus(status);
00234
00235 sandbox_ = rb_funcall(cSafe,
00236 rb_intern("new"),
00237 1,
00238 options);
00239 }
00240
00241 Safe::~Safe()
00242 {
00243 }
00244 }
00245
00246 #endif // HAVE_LIBRUBY