MRI: Fix exception message box script name and display script index

Previously, when the script names in the backtrace were in the form
'SectionXXX'/'{XXXX}' (default RMXP behavior), this same name would
be shown in the error message box, whereas RMXP always displays the
actual script name (eg. 'Scene_Map') instead; only with
useScriptNames=true was mkxp's behavior mostly correct.
Fix this by keeping a backtrace format -> actual script name mapping
and always using the script name in the message box.
The script name and line would also be parsed wrongly if the name
contained any colons, fix this by walking the exception string
back to front instead.

Also prepend the script index to the name when useScriptNames=true;
this is invaluable when debugging projects where multiple scripts
carry the same name. The format is 'XXX:Script_Name'.
This commit is contained in:
Jonas Kulla 2014-09-02 16:35:19 +02:00
parent 7bc07301db
commit 3b7b8657ea
1 changed files with 67 additions and 26 deletions

View File

@ -27,6 +27,7 @@
#include "util.h" #include "util.h"
#include "debugwriter.h" #include "debugwriter.h"
#include "graphics.h" #include "graphics.h"
#include "boost-hash.h"
#include <ruby.h> #include <ruby.h>
#include <ruby/encoding.h> #include <ruby/encoding.h>
@ -303,7 +304,15 @@ static void runCustomScript(const std::string &filename)
VALUE kernelLoadDataInt(const char *filename); VALUE kernelLoadDataInt(const char *filename);
static void runRMXPScripts() struct BacktraceData
{
/* Maps: Ruby visible filename, To: Actual script name */
BoostHash<std::string, std::string> scriptNames;
};
#define SCRIPT_SECTION_FMT (rgssVer >= 3 ? "{%04ld}" : "Section%03ld")
static void runRMXPScripts(BacktraceData &btData)
{ {
const Config &conf = shState->rtData().config; const Config &conf = shState->rtData().config;
const std::string &scriptPack = conf.game.scripts; const std::string &scriptPack = conf.game.scripts;
@ -394,17 +403,17 @@ static void runRMXPScripts()
RSTRING_LEN(scriptDecoded)); RSTRING_LEN(scriptDecoded));
VALUE fname; VALUE fname;
const char *scriptName = RSTRING_PTR(rb_ary_entry(script, 1));
char buf[512];
int len;
if (conf.useScriptNames) if (conf.useScriptNames)
{ len = snprintf(buf, sizeof(buf), "%03ld:%s", i, scriptName);
fname = rb_ary_entry(script, 1);
}
else else
{ len = snprintf(buf, sizeof(buf), SCRIPT_SECTION_FMT, i);
char buf[32];
const char *format = rgssVer >= 3 ? "{%04ld}" : "Section%03ld";
int len = snprintf(buf, sizeof(buf), format, i);
fname = newStringUTF8(buf, len); fname = newStringUTF8(buf, len);
} btData.scriptNames.insert(buf, scriptName);
int state; int state;
evalString(string, fname, &state); evalString(string, fname, &state);
@ -413,9 +422,10 @@ static void runRMXPScripts()
} }
} }
static void showExc(VALUE exc) static void showExc(VALUE exc, const BacktraceData &btData)
{ {
VALUE bt = rb_funcall2(exc, rb_intern("backtrace"), 0, NULL); VALUE bt = rb_funcall2(exc, rb_intern("backtrace"), 0, NULL);
VALUE msg = rb_funcall2(exc, rb_intern("message"), 0, NULL);
VALUE bt0 = rb_ary_entry(bt, 0); VALUE bt0 = rb_ary_entry(bt, 0);
VALUE name = rb_class_path(rb_obj_class(exc)); VALUE name = rb_class_path(rb_obj_class(exc));
@ -426,19 +436,49 @@ static void showExc(VALUE exc)
rb_str_catf(ds, "\n\tfrom %" PRIsVALUE, rb_ary_entry(bt, i)); rb_str_catf(ds, "\n\tfrom %" PRIsVALUE, rb_ary_entry(bt, i));
Debug() << StringValueCStr(ds); Debug() << StringValueCStr(ds);
ID id_index = rb_intern("index"); char *s = RSTRING_PTR(bt0);
/* an "offset" argument is not needed for the first time */
VALUE argv[2] = { rb_str_new_cstr(":") }; char line[16];
long filelen = NUM2LONG(rb_funcall2(bt0, id_index, 1, argv)); std::string file(512, '\0');
argv[1] = LONG2NUM(filelen + 1);
VALUE tmp = rb_funcall2(bt0, id_index, ARRAY_SIZE(argv), argv); char *p = s + strlen(s);
long linelen = NUM2LONG(tmp) - filelen - 1; char *e;
VALUE file = rb_str_subseq(bt0, 0, filelen);
VALUE line = rb_str_subseq(bt0, filelen + 1, linelen); while (p != s)
VALUE ms = rb_sprintf("Script '%" PRIsVALUE "' line %" PRIsVALUE if (*--p == ':')
": %" PRIsVALUE " occured.\n\n%" PRIsVALUE, break;
file, line, name, exc);
showMsg(StringValueCStr(ms)); e = p;
while (p != s)
if (*--p == ':')
break;
/* s p e
* SectionXXX:YY: in 'blabla' */
*e = '\0';
strncpy(line, *p ? p+1 : p, sizeof(line));
line[sizeof(line)-1] = '\0';
*e = ':';
e = p;
/* s e
* SectionXXX:YY: in 'blabla' */
*e = '\0';
strncpy(&file[0], s, file.size());
*e = ':';
/* Shrink to fit */
file.resize(strlen(file.c_str()));
file = btData.scriptNames.value(file, file);
std::string ms(640, '\0');
snprintf(&ms[0], ms.size(), "Script '%s' line %s: %s occured.\n\n%s",
file.c_str(), line, RSTRING_PTR(name), RSTRING_PTR(msg));
showMsg(ms);
} }
static void mriBindingExecute() static void mriBindingExecute()
@ -464,6 +504,7 @@ static void mriBindingExecute()
RbData rbData; RbData rbData;
shState->setBindingData(&rbData); shState->setBindingData(&rbData);
BacktraceData btData;
mriBindingInit(); mriBindingInit();
@ -471,11 +512,11 @@ static void mriBindingExecute()
if (!customScript.empty()) if (!customScript.empty())
runCustomScript(customScript); runCustomScript(customScript);
else else
runRMXPScripts(); runRMXPScripts(btData);
VALUE exc = rb_errinfo(); VALUE exc = rb_errinfo();
if (!NIL_P(exc) && !rb_obj_is_kind_of(exc, rb_eSystemExit)) if (!NIL_P(exc) && !rb_obj_is_kind_of(exc, rb_eSystemExit))
showExc(exc); showExc(exc, btData);
ruby_cleanup(0); ruby_cleanup(0);