Prevent memory leaks from rb_raise

rb_raise calls longjmp, which bypasses C++ destructors, and also keeps the error for catch blocks from being unallocated if passed by reference, which we do for exceptions.

Some of the calls I left can still jump out of try blocks, which you're not supposed to do, but there shouldn't be any objects with destructors initialized at those points so it's probably fine.
This commit is contained in:
Wayward Heart 2024-06-11 17:44:02 -05:00
parent 1462dc9623
commit a73f9ccc1f
18 changed files with 529 additions and 390 deletions

View file

@ -25,17 +25,18 @@
#include "exception.h"
#define DEF_PLAY_STOP_POS(entity) \
RB_METHOD(audio_##entity##Play) \
RB_METHOD_GUARD(audio_##entity##Play) \
{ \
RB_UNUSED_PARAM; \
const char *filename; \
int volume = 100; \
int pitch = 100; \
double pos = 0.0; \
rb_get_args(argc, argv, "z|iif", &filename, &volume, &pitch, &pos RB_ARG_END); \
GUARD_EXC( shState->audio().entity##Play(filename, volume, pitch, pos); ) \
rb_get_args(argc, argv, "z|iif", &filename, &volume, &pitch, &pos RB_ARG_END); \
shState->audio().entity##Play(filename, volume, pitch, pos); \
return Qnil; \
} \
RB_METHOD_GUARD_END \
RB_METHOD(audio_##entity##Stop) \
{ \
RB_UNUSED_PARAM; \
@ -49,16 +50,17 @@
}
#define DEF_PLAY_STOP(entity) \
RB_METHOD(audio_##entity##Play) \
RB_METHOD_GUARD(audio_##entity##Play) \
{ \
RB_UNUSED_PARAM; \
const char *filename; \
int volume = 100; \
int pitch = 100; \
rb_get_args(argc, argv, "z|ii", &filename, &volume, &pitch RB_ARG_END); \
GUARD_EXC( shState->audio().entity##Play(filename, volume, pitch); ) \
shState->audio().entity##Play(filename, volume, pitch); \
return Qnil; \
} \
RB_METHOD_GUARD_END \
RB_METHOD(audio_##entity##Stop) \
{ \
RB_UNUSED_PARAM; \
@ -87,7 +89,7 @@ RB_METHOD(audio_##entity##Fade) \
#define MAYBE_NIL_TRACK(t) t == Qnil ? -127 : NUM2INT(t)
RB_METHOD(audio_bgmPlay)
RB_METHOD_GUARD(audio_bgmPlay)
{
RB_UNUSED_PARAM;
const char *filename;
@ -96,9 +98,10 @@ RB_METHOD(audio_bgmPlay)
double pos = 0.0;
VALUE track = Qnil;
rb_get_args(argc, argv, "z|iifo", &filename, &volume, &pitch, &pos, &track RB_ARG_END);
GUARD_EXC( shState->audio().bgmPlay(filename, volume, pitch, pos, MAYBE_NIL_TRACK(track)); )
shState->audio().bgmPlay(filename, volume, pitch, pos, MAYBE_NIL_TRACK(track));
return Qnil;
}
RB_METHOD_GUARD_END
RB_METHOD(audio_bgmStop)
{
@ -117,25 +120,27 @@ RB_METHOD(audio_bgmPos)
return rb_float_new(shState->audio().bgmPos(MAYBE_NIL_TRACK(track)));
}
RB_METHOD(audio_bgmGetVolume)
RB_METHOD_GUARD(audio_bgmGetVolume)
{
RB_UNUSED_PARAM;
VALUE track = Qnil;
rb_get_args(argc, argv, "|o", &track RB_ARG_END);
int ret = 0;
GUARD_EXC( ret = shState->audio().bgmGetVolume(MAYBE_NIL_TRACK(track)); )
ret = shState->audio().bgmGetVolume(MAYBE_NIL_TRACK(track));
return rb_fix_new(ret);
}
RB_METHOD_GUARD_END
RB_METHOD(audio_bgmSetVolume)
RB_METHOD_GUARD(audio_bgmSetVolume)
{
RB_UNUSED_PARAM;
int volume;
VALUE track = Qnil;
rb_get_args(argc, argv, "i|o", &volume, &track RB_ARG_END);
GUARD_EXC( shState->audio().bgmSetVolume(volume, MAYBE_NIL_TRACK(track)); )
shState->audio().bgmSetVolume(volume, MAYBE_NIL_TRACK(track));
return Qnil;
}
RB_METHOD_GUARD_END
DEF_PLAY_STOP_POS( bgs )

View file

@ -528,14 +528,15 @@ RB_METHOD(mkxpSystemMemory) {
return INT2NUM(SDL_GetSystemRAM());
}
RB_METHOD(mkxpReloadPathCache) {
RB_METHOD_GUARD(mkxpReloadPathCache) {
RB_UNUSED_PARAM;
GUARD_EXC(shState->fileSystem().reloadPathCache(););
shState->fileSystem().reloadPathCache();
return Qnil;
}
RB_METHOD_GUARD_END
RB_METHOD(mkxpAddPath) {
RB_METHOD_GUARD(mkxpAddPath) {
RB_UNUSED_PARAM;
VALUE path, mountpoint, reload;
@ -545,36 +546,32 @@ RB_METHOD(mkxpAddPath) {
const char *mp = (mountpoint == Qnil) ? 0 : RSTRING_PTR(mountpoint);
try {
bool rl = true;
if (reload != Qnil)
rb_bool_arg(reload, &rl);
shState->fileSystem().addPath(RSTRING_PTR(path), mp, rl);
} catch (Exception &e) {
raiseRbExc(e);
}
bool rl = true;
if (reload != Qnil)
rb_bool_arg(reload, &rl);
shState->fileSystem().addPath(RSTRING_PTR(path), mp, rl);
return path;
}
RB_METHOD_GUARD_END
RB_METHOD(mkxpRemovePath) {
RB_METHOD_GUARD(mkxpRemovePath) {
RB_UNUSED_PARAM;
VALUE path, reload;
rb_scan_args(argc, argv, "11", &path, &reload);
SafeStringValue(path);
try {
bool rl = true;
if (reload != Qnil)
rb_bool_arg(reload, &rl);
shState->fileSystem().removePath(RSTRING_PTR(path), rl);
} catch (Exception &e) {
raiseRbExc(e);
}
bool rl = true;
if (reload != Qnil)
rb_bool_arg(reload, &rl);
shState->fileSystem().removePath(RSTRING_PTR(path), rl);
return path;
}
RB_METHOD_GUARD_END
RB_METHOD(mkxpFileExists) {
RB_UNUSED_PARAM;
@ -601,24 +598,25 @@ RB_METHOD(mkxpSetDefaultFontFamily) {
return Qnil;
}
RB_METHOD(mkxpStringToUTF8) {
RB_METHOD_GUARD(mkxpStringToUTF8) {
RB_UNUSED_PARAM;
rb_check_argc(argc, 0);
std::string ret(RSTRING_PTR(self), RSTRING_LEN(self));
GUARD_EXC(ret = Encoding::convertString(ret); );
ret = Encoding::convertString(ret);
return rb_utf8_str_new(ret.c_str(), ret.length());
}
RB_METHOD_GUARD_END
RB_METHOD(mkxpStringToUTF8Bang) {
RB_METHOD_GUARD(mkxpStringToUTF8Bang) {
RB_UNUSED_PARAM;
rb_check_argc(argc, 0);
std::string ret(RSTRING_PTR(self), RSTRING_LEN(self));
GUARD_EXC(ret = Encoding::convertString(ret); );
ret = Encoding::convertString(ret);
rb_str_resize(self, ret.length());
memcpy(RSTRING_PTR(self), ret.c_str(), RSTRING_LEN(self));
@ -629,6 +627,7 @@ RB_METHOD(mkxpStringToUTF8Bang) {
return self;
}
RB_METHOD_GUARD_END
#ifdef __APPLE__
#define OPENCMD "open "
@ -641,7 +640,7 @@ RB_METHOD(mkxpStringToUTF8Bang) {
#define OPENARGS ""
#endif
RB_METHOD(mkxpLaunch) {
RB_METHOD_GUARD(mkxpLaunch) {
RB_UNUSED_PARAM;
VALUE cmdname, args;
@ -674,11 +673,12 @@ RB_METHOD(mkxpLaunch) {
}
if (std::system(command.c_str()) != 0) {
raiseRbExc(Exception(Exception::MKXPError, "Failed to launch \"%s\"", RSTRING_PTR(cmdname)));
throw Exception(Exception::MKXPError, "Failed to launch \"%s\"", RSTRING_PTR(cmdname));
}
return RUBY_Qnil;
}
RB_METHOD_GUARD_END
json5pp::value loadUserSettings() {
json5pp::value ret;
@ -722,7 +722,7 @@ RB_METHOD(mkxpGetJSONSetting) {
}
RB_METHOD(mkxpSetJSONSetting) {
RB_METHOD_GUARD(mkxpSetJSONSetting) {
RB_UNUSED_PARAM;
VALUE sname, svalue;
@ -736,6 +736,7 @@ RB_METHOD(mkxpSetJSONSetting) {
return Qnil;
}
RB_METHOD_GUARD_END
RB_METHOD(mkxpGetAllJSONSettings) {
RB_UNUSED_PARAM;

View file

@ -50,28 +50,35 @@ RbData::RbData() {
exc[IOError] = rb_eIOError;
exc[TypeError] = rb_eTypeError;
exc[ArgumentError] = rb_eArgError;
exc[SystemExit] = rb_eSystemExit;
exc[RuntimeError] = rb_eRuntimeError;
}
RbData::~RbData() {}
/* Indexed with Exception::Type */
static const RbException excToRbExc[] = {
const RbException excToRbExc[] = {
RGSS, /* RGSSError */
ErrnoENOENT, /* NoFileError */
IOError,
TypeError, ArgumentError,
TypeError, ArgumentError, SystemExit, RuntimeError,
PHYSFS, /* PHYSFSError */
SDL, /* SDLError */
MKXP /* MKXPError */
};
void raiseRbExc(const Exception &exc) {
VALUE excToRbClass(const Exception &exc) {
RbData *data = getRbData();
return data->exc[excToRbExc[exc.type]];
}
void raiseRbExc(Exception exc) {
RbData *data = getRbData();
VALUE excClass = data->exc[excToRbExc[exc.type]];
rb_raise(excClass, "%s", exc.msg.c_str());
rb_raise(excClass, "%s", exc.msg);
}
void raiseDisposedAccess(VALUE self) {
@ -89,207 +96,224 @@ void raiseDisposedAccess(VALUE self) {
}
int rb_get_args(int argc, VALUE *argv, const char *format, ...) {
char c;
VALUE *arg = argv;
va_list ap;
bool opt = false;
int argI = 0;
Exception *exc = 0;
try{
char c;
VALUE *arg = argv;
va_list ap;
bool opt = false;
int argI = 0;
va_start(ap, format);
va_start(ap, format);
while ((c = *format++)) {
switch (c) {
case '|':
break;
default:
// FIXME print num of needed args vs provided
if (argc <= argI && !opt)
rb_raise(rb_eArgError, "wrong number of arguments");
while ((c = *format++)) {
switch (c) {
case '|':
break;
default:
// FIXME print num of needed args vs provided
if (argc <= argI && !opt)
rb_raise(rb_eArgError, "wrong number of arguments");
break;
}
break;
}
if (argI >= argc)
break;
switch (c) {
case 'o': {
if (argI >= argc)
break;
VALUE *obj = va_arg(ap, VALUE *);
switch (c) {
case 'o': {
if (argI >= argc)
break;
*obj = *arg++;
++argI;
VALUE *obj = va_arg(ap, VALUE *);
break;
}
*obj = *arg++;
++argI;
case 'S': {
if (argI >= argc)
break;
}
case 'S': {
if (argI >= argc)
break;
VALUE *str = va_arg(ap, VALUE *);
VALUE tmp = *arg;
if (!RB_TYPE_P(tmp, RUBY_T_STRING))
rb_raise(rb_eTypeError, "Argument %d: Expected string", argI);
*str = tmp;
++argI;
break;
}
case 's': {
if (argI >= argc)
break;
const char **s = va_arg(ap, const char **);
int *len = va_arg(ap, int *);
VALUE tmp = *arg;
if (!RB_TYPE_P(tmp, RUBY_T_STRING))
rb_raise(rb_eTypeError, "Argument %d: Expected string", argI);
*s = RSTRING_PTR(tmp);
*len = RSTRING_LEN(tmp);
++argI;
break;
}
case 'z': {
if (argI >= argc)
break;
const char **s = va_arg(ap, const char **);
VALUE tmp = *arg++;
if (!RB_TYPE_P(tmp, RUBY_T_STRING))
rb_raise(rb_eTypeError, "Argument %d: Expected string", argI);
*s = RSTRING_PTR(tmp);
++argI;
break;
}
case 'f': {
if (argI >= argc)
break;
double *f = va_arg(ap, double *);
VALUE fVal = *arg++;
rb_float_arg(fVal, f, argI);
++argI;
break;
}
case 'i': {
if (argI >= argc)
break;
int *i = va_arg(ap, int *);
VALUE iVal = *arg++;
rb_int_arg(iVal, i, argI);
++argI;
break;
}
case 'b': {
if (argI >= argc)
break;
bool *b = va_arg(ap, bool *);
VALUE bVal = *arg++;
rb_bool_arg(bVal, b, argI);
++argI;
break;
}
case 'n': {
if (argI >= argc)
break;
ID *sym = va_arg(ap, ID *);
VALUE symVal = *arg++;
if (!SYMBOL_P(symVal))
rb_raise(rb_eTypeError, "Argument %d: Expected symbol", argI);
*sym = SYM2ID(symVal);
++argI;
break;
}
case '|':
opt = true;
break;
VALUE *str = va_arg(ap, VALUE *);
VALUE tmp = *arg;
if (!RB_TYPE_P(tmp, RUBY_T_STRING))
rb_raise(rb_eTypeError, "Argument %d: Expected string", argI);
*str = tmp;
++argI;
break;
default:
rb_raise(rb_eFatal, "invalid argument specifier %c", c);
}
}
case 's': {
if (argI >= argc)
break;
const char **s = va_arg(ap, const char **);
int *len = va_arg(ap, int *);
VALUE tmp = *arg;
if (!RB_TYPE_P(tmp, RUBY_T_STRING))
rb_raise(rb_eTypeError, "Argument %d: Expected string", argI);
*s = RSTRING_PTR(tmp);
*len = RSTRING_LEN(tmp);
++argI;
break;
}
case 'z': {
if (argI >= argc)
break;
const char **s = va_arg(ap, const char **);
VALUE tmp = *arg++;
if (!RB_TYPE_P(tmp, RUBY_T_STRING))
rb_raise(rb_eTypeError, "Argument %d: Expected string", argI);
*s = RSTRING_PTR(tmp);
++argI;
break;
}
case 'f': {
if (argI >= argc)
break;
double *f = va_arg(ap, double *);
VALUE fVal = *arg++;
rb_float_arg(fVal, f, argI);
++argI;
break;
}
case 'i': {
if (argI >= argc)
break;
int *i = va_arg(ap, int *);
VALUE iVal = *arg++;
rb_int_arg(iVal, i, argI);
++argI;
break;
}
case 'b': {
if (argI >= argc)
break;
bool *b = va_arg(ap, bool *);
VALUE bVal = *arg++;
rb_bool_arg(bVal, b, argI);
++argI;
break;
}
case 'n': {
if (argI >= argc)
break;
ID *sym = va_arg(ap, ID *);
VALUE symVal = *arg++;
if (!SYMBOL_P(symVal))
rb_raise(rb_eTypeError, "Argument %d: Expected symbol", argI);
*sym = SYM2ID(symVal);
++argI;
break;
}
case '|':
opt = true;
break;
default:
rb_raise(rb_eFatal, "invalid argument specifier %c", c);
}
}
#ifndef NDEBUG
/* Pop remaining arg pointers off
* the stack to check for RB_ARG_END */
format--;
/* Pop remaining arg pointers off
* the stack to check for RB_ARG_END */
format--;
while ((c = *format++)) {
switch (c) {
case 'o':
case 'S':
va_arg(ap, VALUE *);
break;
while ((c = *format++)) {
switch (c) {
case 'o':
case 'S':
va_arg(ap, VALUE *);
break;
case 's':
va_arg(ap, const char **);
va_arg(ap, int *);
break;
case 's':
va_arg(ap, const char **);
va_arg(ap, int *);
break;
case 'z':
va_arg(ap, const char **);
break;
case 'z':
va_arg(ap, const char **);
break;
case 'f':
va_arg(ap, double *);
break;
case 'f':
va_arg(ap, double *);
break;
case 'i':
va_arg(ap, int *);
break;
case 'i':
va_arg(ap, int *);
break;
case 'b':
va_arg(ap, bool *);
break;
case 'b':
va_arg(ap, bool *);
break;
}
}
}
// FIXME print num of needed args vs provided
if (!c && argc > argI)
rb_raise(rb_eArgError, "wrong number of arguments");
// FIXME print num of needed args vs provided
if (!c && argc > argI)
rb_raise(rb_eArgError, "wrong number of arguments");
/* Verify correct termination */
void *argEnd = va_arg(ap, void *);
(void)argEnd;
assert(argEnd == RB_ARG_END_VAL);
/* Verify correct termination */
void *argEnd = va_arg(ap, void *);
(void)argEnd;
assert(argEnd == RB_ARG_END_VAL);
#endif
va_end(ap);
va_end(ap);
return argI;
return argI;
} catch (const Exception &e) {
exc = new Exception(e);
}
/* This should always be true if we reach here */
if (exc) {
/* Raising here is probably fine, right?
* If any methods allocate something with a destructor before
* calling this then they can probably be fixed to not do that. */
Exception e(*exc);
delete exc;
rb_raise(excToRbClass(e), "%s", e.msg);
}
return 0;
}

View file

@ -55,6 +55,8 @@ enum RbException {
TypeError,
ArgumentError,
SystemExit,
RuntimeError,
RbExceptionsMax
};
@ -73,7 +75,8 @@ RbData *getRbData();
struct Exception;
void raiseRbExc(const Exception &exc);
VALUE excToRbClass(const Exception &exc);
void raiseRbExc(Exception exc);
#if RAPI_FULL > 187
#define DECL_TYPE(Klass) extern rb_data_type_t Klass##Type
@ -315,16 +318,16 @@ raiseRbExc(exc); \
} \
}
#define GFX_GUARD_EXC(exp) \
{\
GFX_LOCK; \
try {\
#define GFX_GUARD_EXC(exp) \
{ \
GFX_LOCK; \
try { \
exp \
} catch (const Exception &exc) {\
GFX_UNLOCK; \
raiseRbExc(exc); \
}\
GFX_UNLOCK;\
} catch (const Exception &exc) { \
GFX_UNLOCK; \
throw exc; \
} \
GFX_UNLOCK; \
}
@ -338,7 +341,7 @@ static inline VALUE objectLoad(int argc, VALUE *argv, VALUE self) {
C *c = 0;
GUARD_EXC(c = C::deserialize(data, dataLen););
c = C::deserialize(data, dataLen);
setPrivateData(obj, c);
@ -358,7 +361,7 @@ inline void rb_float_arg(VALUE arg, double *out, int argPos = 0) {
break;
default:
rb_raise(rb_eTypeError, "Argument %d: Expected float", argPos);
throw Exception(Exception::TypeError, "Argument %d: Expected float", argPos);
}
}
@ -374,7 +377,7 @@ inline void rb_int_arg(VALUE arg, int *out, int argPos = 0) {
break;
default:
rb_raise(rb_eTypeError, "Argument %d: Expected fixnum", argPos);
throw Exception(Exception::TypeError, "Argument %d: Expected fixnum", argPos);
}
}
@ -390,10 +393,13 @@ inline void rb_bool_arg(VALUE arg, bool *out, int argPos = 0) {
break;
default:
rb_raise(rb_eTypeError, "Argument %d: Expected bool", argPos);
throw Exception(Exception::TypeError, "Argument %d: Expected bool", argPos);
}
}
/* rb_check_argc and rb_error_arity are both
* consistently called before any C++ objects are allocated,
* so we can just call rb_raise directly in them */
inline void rb_check_argc(int actual, int expected) {
if (actual != expected)
rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", actual,
@ -431,21 +437,41 @@ static inline VALUE rb_file_open_str(VALUE filename, const char *mode) {
(void)self; \
}
/* Calling rb_raise inside the catch block
* leaks memory even if we catch by value */
#define RB_METHOD_GUARD(name) RB_METHOD(name) \
{ \
Exception *exc = 0; \
try{ \
#define RB_METHOD_GUARD_END \
} catch (const Exception &e) { \
exc = new Exception(e); \
} \
if (exc) { \
Exception e(*exc); \
delete exc; \
rb_raise(excToRbClass(e), "%s", e.msg); \
} \
return Qnil; \
}
#define MARSH_LOAD_FUN(Typ) \
RB_METHOD(Typ##Load) { return objectLoad<Typ>(argc, argv, self); }
RB_METHOD_GUARD(Typ##Load) { return objectLoad<Typ>(argc, argv, self); } RB_METHOD_GUARD_END
#define INITCOPY_FUN(Klass) \
RB_METHOD(Klass##InitializeCopy) { \
RB_METHOD_GUARD(Klass##InitializeCopy) { \
VALUE origObj; \
rb_get_args(argc, argv, "o", &origObj RB_ARG_END); \
if (!OBJ_INIT_COPY(self, origObj)) /* When would this fail??*/ \
return self; \
Klass *orig = getPrivateData<Klass>(origObj); \
Klass *k = 0; \
GUARD_EXC(k = new Klass(*orig);) \
k = new Klass(*orig); \
setPrivateData(self, k); \
return self; \
}
} \
RB_METHOD_GUARD_END
/* Object property which is copied by reference, with allowed NIL
* FIXME: Getter assumes prop is disposable,
@ -461,7 +487,7 @@ RB_METHOD(Klass##Get##PropName) { \
RB_UNUSED_PARAM; \
return rb_iv_get(self, prop_iv); \
} \
RB_METHOD(Klass##Set##PropName) { \
RB_METHOD_GUARD(Klass##Set##PropName) { \
RB_UNUSED_PARAM; \
rb_check_argc(argc, 1); \
Klass *k = getPrivateData<Klass>(self); \
@ -471,17 +497,18 @@ if (NIL_P(propObj)) \
prop = 0; \
else \
prop = getPrivateDataCheck<PropKlass>(propObj, PropKlass##Type); \
GUARD_EXC(k->set##PropName(prop);) \
k->set##PropName(prop) \
rb_iv_set(self, prop_iv, propObj); \
return propObj; \
}
} \
RB_METHOD_GUARD_END
#else
#define DEF_PROP_OBJ_REF(Klass, PropKlass, PropName, prop_iv) \
RB_METHOD(Klass##Get##PropName) { \
RB_UNUSED_PARAM; \
return rb_iv_get(self, prop_iv); \
} \
RB_METHOD(Klass##Set##PropName) { \
RB_METHOD_GUARD(Klass##Set##PropName) { \
RB_UNUSED_PARAM; \
rb_check_argc(argc, 1); \
Klass *k = getPrivateData<Klass>(self); \
@ -491,10 +518,11 @@ if (NIL_P(propObj)) \
prop = 0; \
else \
prop = getPrivateDataCheck<PropKlass>(propObj, #PropKlass); \
GUARD_EXC(k->set##PropName(prop);) \
k->set##PropName(prop) \
rb_iv_set(self, prop_iv, propObj); \
return propObj; \
}
} \
RB_METHOD_GUARD_END
#endif
/* Object property which is copied by value, not reference */
@ -505,15 +533,16 @@ RB_UNUSED_PARAM; \
checkDisposed<Klass>(self); \
return rb_iv_get(self, prop_iv); \
} \
RB_METHOD(Klass##Set##PropName) { \
RB_METHOD_GUARD(Klass##Set##PropName) { \
rb_check_argc(argc, 1); \
Klass *k = getPrivateData<Klass>(self); \
VALUE propObj = *argv; \
PropKlass *prop; \
prop = getPrivateDataCheck<PropKlass>(propObj, PropKlass##Type); \
GUARD_EXC(k->set##PropName(*prop);) \
k->set##PropName(*prop); \
return propObj; \
}
} \
RB_METHOD_GUARD_END
#else
#define DEF_PROP_OBJ_VAL(Klass, PropKlass, PropName, prop_iv) \
RB_METHOD(Klass##Get##PropName) { \
@ -521,33 +550,36 @@ RB_UNUSED_PARAM; \
checkDisposed<Klass>(self); \
return rb_iv_get(self, prop_iv); \
} \
RB_METHOD(Klass##Set##PropName) { \
RB_METHOD_GUARD(Klass##Set##PropName) { \
rb_check_argc(argc, 1); \
Klass *k = getPrivateData<Klass>(self); \
VALUE propObj = *argv; \
PropKlass *prop; \
prop = getPrivateDataCheck<PropKlass>(propObj, #PropKlass); \
GUARD_EXC(k->set##PropName(*prop);) \
k->set##PropName(*prop); \
return propObj; \
}
} \
RB_METHOD_GUARD_END
#endif
#define DEF_PROP(Klass, type, PropName, arg_fun, value_fun) \
RB_METHOD(Klass##Get##PropName) { \
#define DEF_PROP(Klass, type, PropName, arg_fun, value_fun) \
RB_METHOD_GUARD(Klass##Get##PropName) { \
RB_UNUSED_PARAM; \
Klass *k = getPrivateData<Klass>(self); \
type value = 0; \
GUARD_EXC(value = k->get##PropName();) \
value = k->get##PropName(); \
return value_fun(value); \
} \
RB_METHOD(Klass##Set##PropName) { \
} \
RB_METHOD_GUARD_END \
RB_METHOD_GUARD(Klass##Set##PropName) { \
rb_check_argc(argc, 1); \
Klass *k = getPrivateData<Klass>(self); \
type value; \
rb_##arg_fun##_arg(*argv, &value); \
GUARD_EXC(k->set##PropName(value);) \
k->set##PropName(value); \
return *argv; \
}
} \
RB_METHOD_GUARD_END
#define DEF_PROP_I(Klass, PropName) \
DEF_PROP(Klass, int, PropName, int, rb_fix_new)
@ -573,7 +605,7 @@ RB_METHOD(Klass##Get##PropName) { \
RB_UNUSED_PARAM; \
return rb_iv_get(self, prop_iv); \
} \
RB_METHOD(Klass##Set##PropName) { \
RB_METHOD_GUARD(Klass##Set##PropName) { \
RB_UNUSED_PARAM; \
rb_check_argc(argc, 1); \
Klass *k = getPrivateData<Klass>(self); \
@ -586,7 +618,8 @@ prop = getPrivateDataCheck<PropKlass>(propObj, PropKlass##Type); \
GFX_GUARD_EXC(k->set##PropName(prop);) \
rb_iv_set(self, prop_iv, propObj); \
return propObj; \
}
} \
RB_METHOD_GUARD_END
#else
#define DEF_GFX_PROP_OBJ_REF(Klass, PropKlass, PropName, prop_iv) \
DEF_PROP_OBJ_REF(Klass, PropKlass, PropName, prop_iv)
@ -600,7 +633,7 @@ RB_UNUSED_PARAM; \
checkDisposed<Klass>(self); \
return rb_iv_get(self, prop_iv); \
} \
RB_METHOD(Klass##Set##PropName) { \
RB_METHOD_GUARD(Klass##Set##PropName) { \
rb_check_argc(argc, 1); \
Klass *k = getPrivateData<Klass>(self); \
VALUE propObj = *argv; \
@ -608,28 +641,31 @@ PropKlass *prop; \
prop = getPrivateDataCheck<PropKlass>(propObj, PropKlass##Type); \
GFX_GUARD_EXC(k->set##PropName(*prop);) \
return propObj; \
}
} \
RB_METHOD_GUARD_END
#else
#define DEF_GFX_PROP_OBJ_VAL(Klass, PropKlass, PropName, prop_iv) \
DEF_PROP_OBJ_VAL(Klass, PropKlass, PropName, prop_iv)
#endif
#define DEF_GFX_PROP(Klass, type, PropName, arg_fun, value_fun) \
RB_METHOD(Klass##Get##PropName) { \
#define DEF_GFX_PROP(Klass, type, PropName, arg_fun, value_fun) \
RB_METHOD_GUARD(Klass##Get##PropName) { \
RB_UNUSED_PARAM; \
Klass *k = getPrivateData<Klass>(self); \
type value = 0; \
GUARD_EXC(value = k->get##PropName();) \
value = k->get##PropName(); \
return value_fun(value); \
} \
RB_METHOD(Klass##Set##PropName) { \
RB_METHOD_GUARD_END \
RB_METHOD_GUARD(Klass##Set##PropName) { \
rb_check_argc(argc, 1); \
Klass *k = getPrivateData<Klass>(self); \
type value; \
rb_##arg_fun##_arg(*argv, &value); \
GFX_GUARD_EXC(k->set##PropName(value);) \
return *argv; \
}
} \
RB_METHOD_GUARD_END
#define DEF_GFX_PROP_I(Klass, PropName) \
DEF_GFX_PROP(Klass, int, PropName, int, rb_fix_new)

View file

@ -64,7 +64,7 @@ void bitmapInitProps(Bitmap *b, VALUE self) {
b->setInitFont(font);
}
RB_METHOD(bitmapInitialize) {
RB_METHOD_GUARD(bitmapInitialize) {
Bitmap *b = 0;
if (argc == 1) {
@ -84,45 +84,49 @@ RB_METHOD(bitmapInitialize) {
return self;
}
RB_METHOD_GUARD_END
RB_METHOD(bitmapWidth) {
RB_METHOD_GUARD(bitmapWidth) {
RB_UNUSED_PARAM;
Bitmap *b = getPrivateData<Bitmap>(self);
int value = 0;
GUARD_EXC(value = b->width(););
value = b->width();
return INT2FIX(value);
}
RB_METHOD_GUARD_END
RB_METHOD(bitmapHeight) {
RB_METHOD_GUARD(bitmapHeight) {
RB_UNUSED_PARAM;
Bitmap *b = getPrivateData<Bitmap>(self);
int value = 0;
GUARD_EXC(value = b->height(););
value = b->height();
return INT2FIX(value);
}
RB_METHOD_GUARD_END
DEF_GFX_PROP_OBJ_REF(Bitmap, Bitmap, Hires, "hires")
RB_METHOD(bitmapRect) {
RB_METHOD_GUARD(bitmapRect) {
RB_UNUSED_PARAM;
Bitmap *b = getPrivateData<Bitmap>(self);
IntRect rect;
GUARD_EXC(rect = b->rect(););
rect = b->rect();
Rect *r = new Rect(rect);
return wrapObject(r, RectType);
}
RB_METHOD_GUARD_END
RB_METHOD(bitmapBlt) {
RB_METHOD_GUARD(bitmapBlt) {
Bitmap *b = getPrivateData<Bitmap>(self);
int x, y;
@ -143,8 +147,9 @@ RB_METHOD(bitmapBlt) {
return self;
}
RB_METHOD_GUARD_END
RB_METHOD(bitmapStretchBlt) {
RB_METHOD_GUARD(bitmapStretchBlt) {
Bitmap *b = getPrivateData<Bitmap>(self);
VALUE destRectObj;
@ -167,8 +172,9 @@ RB_METHOD(bitmapStretchBlt) {
return self;
}
RB_METHOD_GUARD_END
RB_METHOD(bitmapFillRect) {
RB_METHOD_GUARD(bitmapFillRect) {
Bitmap *b = getPrivateData<Bitmap>(self);
VALUE colorObj;
@ -197,8 +203,9 @@ RB_METHOD(bitmapFillRect) {
return self;
}
RB_METHOD_GUARD_END
RB_METHOD(bitmapClear) {
RB_METHOD_GUARD(bitmapClear) {
RB_UNUSED_PARAM;
Bitmap *b = getPrivateData<Bitmap>(self);
@ -207,8 +214,9 @@ RB_METHOD(bitmapClear) {
return self;
}
RB_METHOD_GUARD_END
RB_METHOD(bitmapGetPixel) {
RB_METHOD_GUARD(bitmapGetPixel) {
Bitmap *b = getPrivateData<Bitmap>(self);
int x, y;
@ -216,14 +224,18 @@ RB_METHOD(bitmapGetPixel) {
rb_get_args(argc, argv, "ii", &x, &y RB_ARG_END);
Color value;
GUARD_EXC(value = b->getPixel(x, y););
if (b->surface() || b->megaSurface())
value = b->getPixel(x, y);
else
GFX_GUARD_EXC(value = b->getPixel(x, y););
Color *color = new Color(value);
return wrapObject(color, ColorType);
}
RB_METHOD_GUARD_END
RB_METHOD(bitmapSetPixel) {
RB_METHOD_GUARD(bitmapSetPixel) {
Bitmap *b = getPrivateData<Bitmap>(self);
int x, y;
@ -239,8 +251,9 @@ RB_METHOD(bitmapSetPixel) {
return self;
}
RB_METHOD_GUARD_END
RB_METHOD(bitmapHueChange) {
RB_METHOD_GUARD(bitmapHueChange) {
Bitmap *b = getPrivateData<Bitmap>(self);
int hue;
@ -251,8 +264,9 @@ RB_METHOD(bitmapHueChange) {
return self;
}
RB_METHOD_GUARD_END
RB_METHOD(bitmapDrawText) {
RB_METHOD_GUARD(bitmapDrawText) {
Bitmap *b = getPrivateData<Bitmap>(self);
const char *str;
@ -293,8 +307,9 @@ RB_METHOD(bitmapDrawText) {
return self;
}
RB_METHOD_GUARD_END
RB_METHOD(bitmapTextSize) {
RB_METHOD_GUARD(bitmapTextSize) {
Bitmap *b = getPrivateData<Bitmap>(self);
const char *str;
@ -309,16 +324,17 @@ RB_METHOD(bitmapTextSize) {
}
IntRect value;
GUARD_EXC(value = b->textSize(str););
value = b->textSize(str);
Rect *rect = new Rect(value);
return wrapObject(rect, RectType);
}
RB_METHOD_GUARD_END
DEF_GFX_PROP_OBJ_VAL(Bitmap, Font, Font, "font")
RB_METHOD(bitmapGradientFillRect) {
RB_METHOD_GUARD(bitmapGradientFillRect) {
Bitmap *b = getPrivateData<Bitmap>(self);
VALUE color1Obj, color2Obj;
@ -353,8 +369,9 @@ RB_METHOD(bitmapGradientFillRect) {
return self;
}
RB_METHOD_GUARD_END
RB_METHOD(bitmapClearRect) {
RB_METHOD_GUARD(bitmapClearRect) {
Bitmap *b = getPrivateData<Bitmap>(self);
if (argc == 1) {
@ -376,33 +393,32 @@ RB_METHOD(bitmapClearRect) {
return self;
}
RB_METHOD_GUARD_END
RB_METHOD(bitmapBlur) {
RB_METHOD_GUARD(bitmapBlur) {
RB_UNUSED_PARAM;
Bitmap *b = getPrivateData<Bitmap>(self);
GFX_LOCK;
b->blur();
GFX_UNLOCK;
GFX_GUARD_EXC( b->blur(); );
return Qnil;
}
RB_METHOD_GUARD_END
RB_METHOD(bitmapRadialBlur) {
RB_METHOD_GUARD(bitmapRadialBlur) {
Bitmap *b = getPrivateData<Bitmap>(self);
int angle, divisions;
rb_get_args(argc, argv, "ii", &angle, &divisions RB_ARG_END);
GFX_LOCK;
b->radialBlur(angle, divisions);
GFX_UNLOCK;
GFX_GUARD_EXC( b->radialBlur(angle, divisions); );
return Qnil;
}
RB_METHOD_GUARD_END
RB_METHOD(bitmapGetRawData) {
RB_METHOD_GUARD(bitmapGetRawData) {
RB_UNUSED_PARAM;
Bitmap *b = getPrivateData<Bitmap>(self);
@ -413,8 +429,9 @@ RB_METHOD(bitmapGetRawData) {
return ret;
}
RB_METHOD_GUARD_END
RB_METHOD(bitmapSetRawData) {
RB_METHOD_GUARD(bitmapSetRawData) {
RB_UNUSED_PARAM;
VALUE str;
@ -427,8 +444,9 @@ RB_METHOD(bitmapSetRawData) {
return self;
}
RB_METHOD_GUARD_END
RB_METHOD(bitmapSaveToFile) {
RB_METHOD_GUARD(bitmapSaveToFile) {
RB_UNUSED_PARAM;
VALUE str;
@ -441,8 +459,9 @@ RB_METHOD(bitmapSaveToFile) {
return RUBY_Qnil;
}
RB_METHOD_GUARD_END
RB_METHOD(bitmapGetMega){
RB_METHOD_GUARD(bitmapGetMega){
RB_UNUSED_PARAM;
rb_check_argc(argc, 0);
@ -455,8 +474,9 @@ RB_METHOD(bitmapGetMega){
return ret;
}
RB_METHOD_GUARD_END
RB_METHOD(bitmapGetAnimated){
RB_METHOD_GUARD(bitmapGetAnimated){
RB_UNUSED_PARAM;
rb_check_argc(argc, 0);
@ -469,8 +489,9 @@ RB_METHOD(bitmapGetAnimated){
return ret;
}
RB_METHOD_GUARD_END
RB_METHOD(bitmapGetPlaying){
RB_METHOD_GUARD(bitmapGetPlaying){
RB_UNUSED_PARAM;
rb_check_argc(argc, 0);
@ -479,8 +500,9 @@ RB_METHOD(bitmapGetPlaying){
return rb_bool_new(b->isPlaying());
}
RB_METHOD_GUARD_END
RB_METHOD(bitmapSetPlaying){
RB_METHOD_GUARD(bitmapSetPlaying){
RB_UNUSED_PARAM;
bool play;
@ -493,8 +515,9 @@ RB_METHOD(bitmapSetPlaying){
return RUBY_Qnil;
}
RB_METHOD_GUARD_END
RB_METHOD(bitmapPlay){
RB_METHOD_GUARD(bitmapPlay){
RB_UNUSED_PARAM;
rb_check_argc(argc, 0);
@ -504,8 +527,9 @@ RB_METHOD(bitmapPlay){
return RUBY_Qnil;
}
RB_METHOD_GUARD_END
RB_METHOD(bitmapStop){
RB_METHOD_GUARD(bitmapStop){
RB_UNUSED_PARAM;
rb_check_argc(argc, 0);
@ -515,8 +539,9 @@ RB_METHOD(bitmapStop){
return RUBY_Qnil;
}
RB_METHOD_GUARD_END
RB_METHOD(bitmapGotoStop){
RB_METHOD_GUARD(bitmapGotoStop){
RB_UNUSED_PARAM;
int frame;
@ -529,8 +554,9 @@ RB_METHOD(bitmapGotoStop){
return RUBY_Qnil;
}
RB_METHOD_GUARD_END
RB_METHOD(bitmapGotoPlay){
RB_METHOD_GUARD(bitmapGotoPlay){
RB_UNUSED_PARAM;
int frame;
@ -543,8 +569,9 @@ RB_METHOD(bitmapGotoPlay){
return RUBY_Qnil;
}
RB_METHOD_GUARD_END
RB_METHOD(bitmapFrames){
RB_METHOD_GUARD(bitmapFrames){
RB_UNUSED_PARAM;
rb_check_argc(argc, 0);
@ -553,8 +580,9 @@ RB_METHOD(bitmapFrames){
return INT2NUM(b->numFrames());
}
RB_METHOD_GUARD_END
RB_METHOD(bitmapCurrentFrame){
RB_METHOD_GUARD(bitmapCurrentFrame){
RB_UNUSED_PARAM;
rb_check_argc(argc, 0);
@ -563,8 +591,9 @@ RB_METHOD(bitmapCurrentFrame){
return INT2NUM(b->currentFrameI());
}
RB_METHOD_GUARD_END
RB_METHOD(bitmapAddFrame){
RB_METHOD_GUARD(bitmapAddFrame){
RB_UNUSED_PARAM;
VALUE srcBitmap;
@ -588,8 +617,9 @@ RB_METHOD(bitmapAddFrame){
return INT2NUM(ret);
}
RB_METHOD_GUARD_END
RB_METHOD(bitmapRemoveFrame){
RB_METHOD_GUARD(bitmapRemoveFrame){
RB_UNUSED_PARAM;
VALUE position;
@ -608,8 +638,9 @@ RB_METHOD(bitmapRemoveFrame){
return RUBY_Qnil;
}
RB_METHOD_GUARD_END
RB_METHOD(bitmapNextFrame){
RB_METHOD_GUARD(bitmapNextFrame){
RB_UNUSED_PARAM;
rb_check_argc(argc, 0);
@ -620,8 +651,9 @@ RB_METHOD(bitmapNextFrame){
return INT2NUM(b->currentFrameI());
}
RB_METHOD_GUARD_END
RB_METHOD(bitmapPreviousFrame){
RB_METHOD_GUARD(bitmapPreviousFrame){
RB_UNUSED_PARAM;
rb_check_argc(argc, 0);
@ -632,8 +664,9 @@ RB_METHOD(bitmapPreviousFrame){
return INT2NUM(b->currentFrameI());
}
RB_METHOD_GUARD_END
RB_METHOD(bitmapSetFPS){
RB_METHOD_GUARD(bitmapSetFPS){
RB_UNUSED_PARAM;
VALUE fps;
@ -652,8 +685,9 @@ RB_METHOD(bitmapSetFPS){
return RUBY_Qnil;
}
RB_METHOD_GUARD_END
RB_METHOD(bitmapGetFPS){
RB_METHOD_GUARD(bitmapGetFPS){
RB_UNUSED_PARAM;
rb_check_argc(argc, 0);
@ -662,12 +696,13 @@ RB_METHOD(bitmapGetFPS){
float ret;
GUARD_EXC(ret = b->getAnimationFPS(););
ret = b->getAnimationFPS();
return rb_float_new(ret);
}
RB_METHOD_GUARD_END
RB_METHOD(bitmapSetLooping){
RB_METHOD_GUARD(bitmapSetLooping){
RB_UNUSED_PARAM;
bool loop;
@ -679,8 +714,9 @@ RB_METHOD(bitmapSetLooping){
return rb_bool_new(loop);
}
RB_METHOD_GUARD_END
RB_METHOD(bitmapGetLooping){
RB_METHOD_GUARD(bitmapGetLooping){
RB_UNUSED_PARAM;
rb_check_argc(argc, 0);
@ -688,12 +724,13 @@ RB_METHOD(bitmapGetLooping){
Bitmap *b = getPrivateData<Bitmap>(self);
bool ret;
GUARD_EXC(ret = b->getLooping(););
ret = b->getLooping();
return rb_bool_new(ret);
}
RB_METHOD_GUARD_END
// Captures the Bitmap's current frame data to a new Bitmap
RB_METHOD(bitmapSnapToBitmap) {
RB_METHOD_GUARD(bitmapSnapToBitmap) {
RB_UNUSED_PARAM;
VALUE position;
@ -713,6 +750,7 @@ RB_METHOD(bitmapSnapToBitmap) {
return ret;
}
RB_METHOD_GUARD_END
RB_METHOD(bitmapGetMaxSize){
RB_UNUSED_PARAM;
@ -722,7 +760,7 @@ RB_METHOD(bitmapGetMaxSize){
return INT2NUM(Bitmap::maxSize());
}
RB_METHOD(bitmapInitializeCopy) {
RB_METHOD_GUARD(bitmapInitializeCopy) {
rb_check_argc(argc, 1);
VALUE origObj = argv[0];
@ -740,6 +778,7 @@ RB_METHOD(bitmapInitializeCopy) {
return self;
}
RB_METHOD_GUARD_END
void bitmapBindingInit() {
VALUE klass = rb_define_class("Bitmap", rb_cObject);

View file

@ -32,7 +32,7 @@
} \
}
RB_METHOD(CUSLSetStat) {
RB_METHOD_GUARD(CUSLSetStat) {
RB_UNUSED_PARAM;
VALUE name, stat;
@ -47,11 +47,12 @@ RB_METHOD(CUSLSetStat) {
STEAMSHIM_setStatI(RSTRING_PTR(name), (int)NUM2INT(stat));
STEAMSHIM_GET_OK(SHIMEVENT_SETSTATI, ret);
} else {
rb_raise(rb_eTypeError,
throw Exception(Exception::TypeError,
"Statistic value must be either an integer or float.");
}
return rb_bool_new(ret);
}
RB_METHOD_GUARD_END
RB_METHOD(CUSLGetStatI) {
RB_UNUSED_PARAM;

View file

@ -52,6 +52,10 @@ DEF_ALLOCFUNC_CUSTOMFREE(FileInt, fileIntFreeInstance);
#endif
static VALUE fileIntForPath(const char *path, bool rubyExc) {
VALUE klass = rb_const_get(rb_cObject, rb_intern("FileInt"));
VALUE obj = rb_obj_alloc(klass);
SDL_RWops *ops = SDL_AllocRW();
try {
@ -59,16 +63,9 @@ static VALUE fileIntForPath(const char *path, bool rubyExc) {
} catch (const Exception &e) {
SDL_FreeRW(ops);
if (rubyExc)
raiseRbExc(e);
else
throw e;
throw e;
}
VALUE klass = rb_const_get(rb_cObject, rb_intern("FileInt"));
VALUE obj = rb_obj_alloc(klass);
setPrivateData(obj, ops);
return obj;
@ -183,7 +180,7 @@ kernelLoadDataInt(const char *filename, bool rubyExc, bool raw) {
return result;
}
RB_METHOD(kernelLoadData) {
RB_METHOD_GUARD(kernelLoadData) {
RB_UNUSED_PARAM;
VALUE filename;
@ -195,6 +192,7 @@ RB_METHOD(kernelLoadData) {
rb_bool_arg(raw, &rawv);
return kernelLoadDataInt(RSTRING_PTR(filename), true, rawv);
}
RB_METHOD_GUARD_END
RB_METHOD(kernelSaveData) {
RB_UNUSED_PARAM;

View file

@ -74,7 +74,7 @@ RB_METHOD(graphicsFreeze)
return Qnil;
}
RB_METHOD(graphicsTransition)
RB_METHOD_GUARD(graphicsTransition)
{
RB_UNUSED_PARAM;
@ -88,6 +88,7 @@ RB_METHOD(graphicsTransition)
return Qnil;
}
RB_METHOD_GUARD_END
RB_METHOD(graphicsFrameReset)
{
@ -228,7 +229,7 @@ RB_METHOD(graphicsFadein)
void bitmapInitProps(Bitmap *b, VALUE self);
RB_METHOD(graphicsSnapToBitmap)
RB_METHOD_GUARD(graphicsSnapToBitmap)
{
RB_UNUSED_PARAM;
@ -241,6 +242,7 @@ RB_METHOD(graphicsSnapToBitmap)
return obj;
}
RB_METHOD_GUARD_END
RB_METHOD(graphicsResizeScreen)
{

View file

@ -87,7 +87,7 @@ void* httpGetInternal(void *req) {
}
#endif
RB_METHOD(httpGet) {
RB_METHOD_GUARD(httpGet) {
RB_UNUSED_PARAM;
VALUE path, rheaders, redirect;
@ -107,6 +107,7 @@ RB_METHOD(httpGet) {
return (VALUE)httpGetInternal(&req);
#endif
}
RB_METHOD_GUARD_END
#if RAPI_MAJOR >= 2
@ -130,7 +131,7 @@ void* httpPostInternal(void *args) {
}
#endif
RB_METHOD(httpPost) {
RB_METHOD_GUARD(httpPost) {
RB_UNUSED_PARAM;
VALUE path, postDataHash, rheaders, redirect;
@ -153,6 +154,7 @@ RB_METHOD(httpPost) {
return httpPostInternal(&args);
#endif
}
RB_METHOD_GUARD_END
#if RAPI_MAJOR >= 2
typedef struct {
@ -280,13 +282,13 @@ json5pp::value rb2json(VALUE v) {
return ret_value;
}
raiseRbExc(Exception(Exception::MKXPError, "Invalid value for JSON: %s", RSTRING_PTR(rb_inspect(v))));
throw Exception(Exception::MKXPError, "Invalid value for JSON: %s", RSTRING_PTR(rb_inspect(v)));
// This should be unreachable
return json5pp::value(0);
}
RB_METHOD(httpJsonParse) {
RB_METHOD_GUARD(httpJsonParse) {
RB_UNUSED_PARAM;
VALUE jsonv;
@ -298,13 +300,14 @@ RB_METHOD(httpJsonParse) {
v = json5pp::parse5(RSTRING_PTR(jsonv));
}
catch (const std::exception &e) {
raiseRbExc(Exception(Exception::MKXPError, "Failed to parse JSON: %s", e.what()));
throw Exception(Exception::MKXPError, "Failed to parse JSON: %s", e.what());
}
return json2rb(v);
}
RB_METHOD_GUARD_END
RB_METHOD(httpJsonStringify) {
RB_METHOD_GUARD(httpJsonStringify) {
RB_UNUSED_PARAM;
VALUE obj;
@ -313,6 +316,7 @@ RB_METHOD(httpJsonStringify) {
json5pp::value v = rb2json(obj);
return rb_utf8_str_new_cstr(v.stringify5(json5pp::rule::space_indent<>()).c_str());
}
RB_METHOD_GUARD_END
void httpBindingInit() {
VALUE mNet = rb_define_module("HTTPLite");

View file

@ -76,7 +76,7 @@ static int getScancodeArg(VALUE *argv) {
try {
code = strToScancode[scancode];
} catch (...) {
rb_raise(rb_eRuntimeError, "%s is not a valid name of an SDL scancode.", scancode);
throw Exception(Exception::RuntimeError, "%s is not a valid name of an SDL scancode.", scancode);
}
return code;
@ -88,7 +88,7 @@ static int getControllerButtonArg(VALUE *argv) {
try {
btn = strToGCButton[button];
} catch (...) {
rb_raise(rb_eRuntimeError, "%s is not a valid name of an SDL Controller button.", button);
throw Exception(Exception::RuntimeError, "%s is not a valid name of an SDL Controller button.", button);
}
return btn;
@ -172,7 +172,7 @@ RB_METHOD(inputRepeatTime) {
return rb_float_new(shState->input().repeatTime(num));
}
RB_METHOD(inputPressEx) {
RB_METHOD_GUARD(inputPressEx) {
RB_UNUSED_PARAM;
VALUE button;
@ -185,8 +185,9 @@ RB_METHOD(inputPressEx) {
return rb_bool_new(shState->input().isPressedEx(NUM2INT(button), 1));
}
RB_METHOD_GUARD_END
RB_METHOD(inputTriggerEx) {
RB_METHOD_GUARD(inputTriggerEx) {
RB_UNUSED_PARAM;
VALUE button;
@ -199,8 +200,9 @@ RB_METHOD(inputTriggerEx) {
return rb_bool_new(shState->input().isTriggeredEx(NUM2INT(button), 1));
}
RB_METHOD_GUARD_END
RB_METHOD(inputRepeatEx) {
RB_METHOD_GUARD(inputRepeatEx) {
RB_UNUSED_PARAM;
VALUE button;
@ -213,8 +215,9 @@ RB_METHOD(inputRepeatEx) {
return rb_bool_new(shState->input().isRepeatedEx(NUM2INT(button), 1));
}
RB_METHOD_GUARD_END
RB_METHOD(inputReleaseEx) {
RB_METHOD_GUARD(inputReleaseEx) {
RB_UNUSED_PARAM;
VALUE button;
@ -227,8 +230,9 @@ RB_METHOD(inputReleaseEx) {
return rb_bool_new(shState->input().isReleasedEx(NUM2INT(button), 1));
}
RB_METHOD_GUARD_END
RB_METHOD(inputCountEx) {
RB_METHOD_GUARD(inputCountEx) {
RB_UNUSED_PARAM;
VALUE button;
@ -241,8 +245,9 @@ RB_METHOD(inputCountEx) {
return UINT2NUM(shState->input().repeatcount(NUM2INT(button), 1));
}
RB_METHOD_GUARD_END
RB_METHOD(inputRepeatTimeEx) {
RB_METHOD_GUARD(inputRepeatTimeEx) {
RB_UNUSED_PARAM;
VALUE button;
@ -255,6 +260,7 @@ RB_METHOD(inputRepeatTimeEx) {
return rb_float_new(shState->input().repeatTimeEx(NUM2INT(button), 1));
}
RB_METHOD_GUARD_END
RB_METHOD(inputDir4) {
RB_UNUSED_PARAM;
@ -370,7 +376,7 @@ AXISFUNC(Trigger, TRIGGERLEFT, TRIGGERRIGHT);
#undef POWERCASE
#undef M_SYMBOL
RB_METHOD(inputControllerPressEx) {
RB_METHOD_GUARD(inputControllerPressEx) {
RB_UNUSED_PARAM;
VALUE button;
@ -383,8 +389,9 @@ RB_METHOD(inputControllerPressEx) {
return rb_bool_new(shState->input().controllerIsPressedEx(NUM2INT(button)));
}
RB_METHOD_GUARD_END
RB_METHOD(inputControllerTriggerEx) {
RB_METHOD_GUARD(inputControllerTriggerEx) {
RB_UNUSED_PARAM;
VALUE button;
@ -397,8 +404,9 @@ RB_METHOD(inputControllerTriggerEx) {
return rb_bool_new(shState->input().controllerIsTriggeredEx(NUM2INT(button)));
}
RB_METHOD_GUARD_END
RB_METHOD(inputControllerRepeatEx) {
RB_METHOD_GUARD(inputControllerRepeatEx) {
RB_UNUSED_PARAM;
VALUE button;
@ -411,8 +419,9 @@ RB_METHOD(inputControllerRepeatEx) {
return rb_bool_new(shState->input().controllerIsRepeatedEx(NUM2INT(button)));
}
RB_METHOD_GUARD_END
RB_METHOD(inputControllerReleaseEx) {
RB_METHOD_GUARD(inputControllerReleaseEx) {
RB_UNUSED_PARAM;
VALUE button;
@ -425,8 +434,9 @@ RB_METHOD(inputControllerReleaseEx) {
return rb_bool_new(shState->input().controllerIsReleasedEx(NUM2INT(button)));
}
RB_METHOD_GUARD_END
RB_METHOD(inputControllerCountEx) {
RB_METHOD_GUARD(inputControllerCountEx) {
RB_UNUSED_PARAM;
VALUE button;
@ -439,8 +449,9 @@ RB_METHOD(inputControllerCountEx) {
return rb_bool_new(shState->input().controllerRepeatcount(NUM2INT(button)));
}
RB_METHOD_GUARD_END
RB_METHOD(inputControllerRepeatTimeEx) {
RB_METHOD_GUARD(inputControllerRepeatTimeEx) {
RB_UNUSED_PARAM;
VALUE button;
@ -453,6 +464,7 @@ RB_METHOD(inputControllerRepeatTimeEx) {
return rb_float_new(shState->input().controllerRepeatTimeEx(NUM2INT(button)));
}
RB_METHOD_GUARD_END
RB_METHOD(inputControllerRawButtonStates) {
RB_UNUSED_PARAM;
@ -504,18 +516,13 @@ RB_METHOD(inputGets) {
return ret;
}
RB_METHOD(inputGetClipboard) {
RB_METHOD_GUARD(inputGetClipboard) {
RB_UNUSED_PARAM;
VALUE ret;
try {
ret = rb_utf8_str_new_cstr(shState->input().getClipboardText());
} catch (const Exception &e) {
raiseRbExc(e);
}
return ret;
return rb_utf8_str_new_cstr(shState->input().getClipboardText());
}
RB_METHOD_GUARD_END
RB_METHOD(inputSetClipboard) {
RB_METHOD_GUARD(inputSetClipboard) {
RB_UNUSED_PARAM;
VALUE str;
@ -523,13 +530,11 @@ RB_METHOD(inputSetClipboard) {
SafeStringValue(str);
try {
shState->input().setClipboardText(RSTRING_PTR(str));
} catch (const Exception &e) {
raiseRbExc(e);
}
shState->input().setClipboardText(RSTRING_PTR(str));
return str;
}
RB_METHOD_GUARD_END
struct {
const char *str;

View file

@ -46,7 +46,7 @@ static void *MiniFFI_GetFunctionHandle(void *libhandle, const char *func) {
// MiniFFI.new(library, function[, imports[, exports]])
// Yields itself in blocks
RB_METHOD(MiniFFI_initialize) {
RB_METHOD_GUARD(MiniFFI_initialize) {
VALUE libname, func, imports, exports;
rb_scan_args(argc, argv, "22", &libname, &func, &imports, &exports);
SafeStringValue(libname);
@ -66,7 +66,7 @@ RB_METHOD(MiniFFI_initialize) {
}
#endif
if (!hfunc)
rb_raise(rb_eRuntimeError, "%s", SDL_GetError());
throw Exception(Exception::RuntimeError, "%s", SDL_GetError());
rb_iv_set(self, "_func", MVAL2RB((mffi_value)hfunc));
rb_iv_set(self, "_funcname", func);
@ -138,7 +138,7 @@ RB_METHOD(MiniFFI_initialize) {
}
if (MINIFFI_MAX_ARGS < RARRAY_LEN(ary_imports))
rb_raise(rb_eRuntimeError, "too many parameters: %ld/%ld\n",
throw Exception(Exception::RuntimeError, "too many parameters: %ld/%ld\n",
RARRAY_LEN(ary_imports), MINIFFI_MAX_ARGS);
rb_iv_set(self, "_imports", ary_imports);
@ -181,6 +181,7 @@ RB_METHOD(MiniFFI_initialize) {
rb_yield(self);
return Qnil;
}
RB_METHOD_GUARD_END
#if RAPI_MAJOR >= 2
typedef struct {
@ -195,7 +196,7 @@ void* miniffi_call_cb(void *args) {
}
#endif
RB_METHOD(MiniFFI_call) {
RB_METHOD_GUARD(MiniFFI_call) {
MiniFFIFuncArgs param;
#define params param.params
VALUE func = rb_iv_get(self, "_func");
@ -206,7 +207,7 @@ RB_METHOD(MiniFFI_call) {
int items = rb_scan_args(argc, argv, "0*", &args);
int nimport = RARRAY_LEN(own_imports);
if (items != nimport)
rb_raise(rb_eRuntimeError,
throw Exception(Exception::RuntimeError,
"wrong number of parameters: expected %d, got %d", nimport, items);
for (int i = 0; i < nimport; i++) {
@ -264,6 +265,7 @@ RB_METHOD(MiniFFI_call) {
return MVAL2RB(0);
}
}
RB_METHOD_GUARD_END
void MiniFFIBindingInit() {
VALUE cMiniFFI = rb_define_class("MiniFFI", rb_cObject);

View file

@ -27,20 +27,21 @@
#include "graphics.h"
template<class C>
RB_METHOD(sceneElementGetZ)
RB_METHOD_GUARD(sceneElementGetZ)
{
RB_UNUSED_PARAM;
SceneElement *se = getPrivateData<C>(self);
int value = 0;
GUARD_EXC( value = se->getZ(); );
value = se->getZ();
return rb_fix_new(value);
}
RB_METHOD_GUARD_END
template<class C>
RB_METHOD(sceneElementSetZ)
RB_METHOD_GUARD(sceneElementSetZ)
{
SceneElement *se = getPrivateData<C>(self);
@ -51,22 +52,24 @@ RB_METHOD(sceneElementSetZ)
return rb_fix_new(z);
}
RB_METHOD_GUARD_END
template<class C>
RB_METHOD(sceneElementGetVisible)
RB_METHOD_GUARD(sceneElementGetVisible)
{
RB_UNUSED_PARAM;
SceneElement *se = getPrivateData<C>(self);
bool value = false;
GUARD_EXC( value = se->getVisible(); );
value = se->getVisible();
return rb_bool_new(value);
}
RB_METHOD_GUARD_END
template<class C>
RB_METHOD(sceneElementSetVisible)
RB_METHOD_GUARD(sceneElementSetVisible)
{
SceneElement *se = getPrivateData<C>(self);
@ -75,8 +78,9 @@ RB_METHOD(sceneElementSetVisible)
GFX_GUARD_EXC( se->setVisible(visible); );
return rb_bool_new(visible);
return rb_bool_new(visible);
}
RB_METHOD_GUARD_END
template<class C>
void

View file

@ -36,7 +36,18 @@ serializableDump(int, VALUE *, VALUE self)
VALUE data = rb_str_new(0, dataSize);
GUARD_EXC( s->serialize(RSTRING_PTR(data)); );
Exception *exc = 0;
try{
s->serialize(RSTRING_PTR(data));
} catch (const Exception &e) {
exc = new Exception(e);
}
if (exc) {
Exception e(exc->type, exc->msg);
delete exc;
rb_raise(excToRbClass(e), "%s", e.msg);
}
return data;
}

View file

@ -84,27 +84,29 @@ DEF_GFX_PROP_B(Sprite, Mirror)
DEF_GFX_PROP_B(Sprite, PatternTile)
DEF_GFX_PROP_B(Sprite, Invert)
RB_METHOD(spriteWidth) {
RB_METHOD_GUARD(spriteWidth) {
RB_UNUSED_PARAM;
Sprite *s = getPrivateData<Sprite>(self);
int value = 0;
GUARD_EXC(value = s->getWidth();)
value = s->getWidth();
return rb_fix_new(value);
}
RB_METHOD_GUARD_END
RB_METHOD(spriteHeight) {
RB_METHOD_GUARD(spriteHeight) {
RB_UNUSED_PARAM;
Sprite *s = getPrivateData<Sprite>(self);
int value = 0;
GUARD_EXC(value = s->getHeight();)
value = s->getHeight();
return rb_fix_new(value);
}
RB_METHOD_GUARD_END
void spriteBindingInit() {
VALUE klass = rb_define_class("Sprite", rb_cObject);

View file

@ -86,7 +86,7 @@ TABLE_SIZE(x, X)
TABLE_SIZE(y, Y)
TABLE_SIZE(z, Z)
RB_METHOD(tableGetAt) {
RB_METHOD_GUARD(tableGetAt) {
Table *t = getPrivateData<Table>(self);
int x, y, z;
@ -99,7 +99,7 @@ RB_METHOD(tableGetAt) {
z = NUM2INT(argv[2]);
if (argc > 3)
rb_raise(rb_eArgError, "wrong number of arguments");
throw Exception(Exception::ArgumentError, "wrong number of arguments");
if (x < 0 || x >= t->xSize() || y < 0 || y >= t->ySize() || z < 0 ||
z >= t->zSize()) {
@ -110,15 +110,16 @@ RB_METHOD(tableGetAt) {
return INT2FIX(result); /* short always fits in a Fixnum */
}
RB_METHOD_GUARD_END
RB_METHOD(tableSetAt) {
RB_METHOD_GUARD(tableSetAt) {
Table *t = getPrivateData<Table>(self);
int x, y, z, value;
x = y = z = 0;
if (argc < 2)
rb_raise(rb_eArgError, "wrong number of arguments");
throw Exception(Exception::ArgumentError, "wrong number of arguments");
switch (argc) {
default:
@ -146,6 +147,7 @@ RB_METHOD(tableSetAt) {
return argv[argc - 1];
}
RB_METHOD_GUARD_END
MARSH_LOAD_FUN(Table)
INITCOPY_FUN(Table)

View file

@ -42,7 +42,7 @@ RB_METHOD(viewportElementGetViewport)
}
template<class C>
RB_METHOD(viewportElementSetViewport)
RB_METHOD_GUARD(viewportElementSetViewport)
{
RB_UNUSED_PARAM;
@ -62,6 +62,7 @@ RB_METHOD(viewportElementSetViewport)
return viewportObj;
}
RB_METHOD_GUARD_END
template<class C>
static C *

View file

@ -44,7 +44,7 @@ RB_METHOD(windowInitialize) {
return self;
}
RB_METHOD(windowUpdate) {
RB_METHOD_GUARD(windowUpdate) {
RB_UNUSED_PARAM;
Window *w = getPrivateData<Window>(self);
@ -53,6 +53,7 @@ RB_METHOD(windowUpdate) {
return Qnil;
}
RB_METHOD_GUARD_END
DEF_GFX_PROP_OBJ_REF(Window, Bitmap, Windowskin, "windowskin")
DEF_GFX_PROP_OBJ_REF(Window, Bitmap, Contents, "contents")

View file

@ -37,6 +37,8 @@ struct Exception
/* Already defined by ruby */
TypeError,
ArgumentError,
SystemExit,
RuntimeError,
/* New types introduced in mkxp */
PHYSFSError,
@ -45,7 +47,7 @@ struct Exception
};
Type type;
std::string msg;
char msg[512];
Exception(Type type, const char *format, ...)
: type(type)
@ -53,8 +55,7 @@ struct Exception
va_list ap;
va_start(ap, format);
msg.resize(512);
vsnprintf(&msg[0], msg.size(), format, ap);
vsnprintf(msg, sizeof(msg), format, ap);
va_end(ap);
}