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

View file

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

View file

@ -50,28 +50,35 @@ RbData::RbData() {
exc[IOError] = rb_eIOError; exc[IOError] = rb_eIOError;
exc[TypeError] = rb_eTypeError; exc[TypeError] = rb_eTypeError;
exc[ArgumentError] = rb_eArgError; exc[ArgumentError] = rb_eArgError;
exc[SystemExit] = rb_eSystemExit;
exc[RuntimeError] = rb_eRuntimeError;
} }
RbData::~RbData() {} RbData::~RbData() {}
/* Indexed with Exception::Type */ /* Indexed with Exception::Type */
static const RbException excToRbExc[] = { const RbException excToRbExc[] = {
RGSS, /* RGSSError */ RGSS, /* RGSSError */
ErrnoENOENT, /* NoFileError */ ErrnoENOENT, /* NoFileError */
IOError, IOError,
TypeError, ArgumentError, TypeError, ArgumentError, SystemExit, RuntimeError,
PHYSFS, /* PHYSFSError */ PHYSFS, /* PHYSFSError */
SDL, /* SDLError */ SDL, /* SDLError */
MKXP /* MKXPError */ 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(); RbData *data = getRbData();
VALUE excClass = data->exc[excToRbExc[exc.type]]; 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) { void raiseDisposedAccess(VALUE self) {
@ -89,207 +96,224 @@ void raiseDisposedAccess(VALUE self) {
} }
int rb_get_args(int argc, VALUE *argv, const char *format, ...) { int rb_get_args(int argc, VALUE *argv, const char *format, ...) {
char c; Exception *exc = 0;
VALUE *arg = argv; try{
va_list ap; char c;
bool opt = false; VALUE *arg = argv;
int argI = 0; va_list ap;
bool opt = false;
int argI = 0;
va_start(ap, format); va_start(ap, format);
while ((c = *format++)) { while ((c = *format++)) {
switch (c) { switch (c) {
case '|': case '|':
break; break;
default: default:
// FIXME print num of needed args vs provided // FIXME print num of needed args vs provided
if (argc <= argI && !opt) if (argc <= argI && !opt)
rb_raise(rb_eArgError, "wrong number of arguments"); rb_raise(rb_eArgError, "wrong number of arguments");
break; break;
} }
if (argI >= argc)
break;
switch (c) {
case 'o': {
if (argI >= argc) if (argI >= argc)
break; break;
VALUE *obj = va_arg(ap, VALUE *); switch (c) {
case 'o': {
if (argI >= argc)
break;
*obj = *arg++; VALUE *obj = va_arg(ap, VALUE *);
++argI;
break; *obj = *arg++;
} ++argI;
case 'S': { break;
if (argI >= argc) }
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; break;
VALUE *str = va_arg(ap, VALUE *); default:
VALUE tmp = *arg; rb_raise(rb_eFatal, "invalid argument specifier %c", c);
}
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;
default:
rb_raise(rb_eFatal, "invalid argument specifier %c", c);
}
}
#ifndef NDEBUG #ifndef NDEBUG
/* Pop remaining arg pointers off /* Pop remaining arg pointers off
* the stack to check for RB_ARG_END */ * the stack to check for RB_ARG_END */
format--; format--;
while ((c = *format++)) { while ((c = *format++)) {
switch (c) { switch (c) {
case 'o': case 'o':
case 'S': case 'S':
va_arg(ap, VALUE *); va_arg(ap, VALUE *);
break; break;
case 's': case 's':
va_arg(ap, const char **); va_arg(ap, const char **);
va_arg(ap, int *); va_arg(ap, int *);
break; break;
case 'z': case 'z':
va_arg(ap, const char **); va_arg(ap, const char **);
break; break;
case 'f': case 'f':
va_arg(ap, double *); va_arg(ap, double *);
break; break;
case 'i': case 'i':
va_arg(ap, int *); va_arg(ap, int *);
break; break;
case 'b': case 'b':
va_arg(ap, bool *); va_arg(ap, bool *);
break; break;
}
} }
}
// FIXME print num of needed args vs provided // FIXME print num of needed args vs provided
if (!c && argc > argI) if (!c && argc > argI)
rb_raise(rb_eArgError, "wrong number of arguments"); rb_raise(rb_eArgError, "wrong number of arguments");
/* Verify correct termination */ /* Verify correct termination */
void *argEnd = va_arg(ap, void *); void *argEnd = va_arg(ap, void *);
(void)argEnd; (void)argEnd;
assert(argEnd == RB_ARG_END_VAL); assert(argEnd == RB_ARG_END_VAL);
#endif #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, TypeError,
ArgumentError, ArgumentError,
SystemExit,
RuntimeError,
RbExceptionsMax RbExceptionsMax
}; };
@ -73,7 +75,8 @@ RbData *getRbData();
struct Exception; struct Exception;
void raiseRbExc(const Exception &exc); VALUE excToRbClass(const Exception &exc);
void raiseRbExc(Exception exc);
#if RAPI_FULL > 187 #if RAPI_FULL > 187
#define DECL_TYPE(Klass) extern rb_data_type_t Klass##Type #define DECL_TYPE(Klass) extern rb_data_type_t Klass##Type
@ -315,16 +318,16 @@ raiseRbExc(exc); \
} \ } \
} }
#define GFX_GUARD_EXC(exp) \ #define GFX_GUARD_EXC(exp) \
{\ { \
GFX_LOCK; \ GFX_LOCK; \
try {\ try { \
exp \ exp \
} catch (const Exception &exc) {\ } catch (const Exception &exc) { \
GFX_UNLOCK; \ GFX_UNLOCK; \
raiseRbExc(exc); \ throw exc; \
}\ } \
GFX_UNLOCK;\ GFX_UNLOCK; \
} }
@ -338,7 +341,7 @@ static inline VALUE objectLoad(int argc, VALUE *argv, VALUE self) {
C *c = 0; C *c = 0;
GUARD_EXC(c = C::deserialize(data, dataLen);); c = C::deserialize(data, dataLen);
setPrivateData(obj, c); setPrivateData(obj, c);
@ -358,7 +361,7 @@ inline void rb_float_arg(VALUE arg, double *out, int argPos = 0) {
break; break;
default: 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; break;
default: 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; break;
default: 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) { inline void rb_check_argc(int actual, int expected) {
if (actual != expected) if (actual != expected)
rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", actual, 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; \ (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) \ #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) \ #define INITCOPY_FUN(Klass) \
RB_METHOD(Klass##InitializeCopy) { \ RB_METHOD_GUARD(Klass##InitializeCopy) { \
VALUE origObj; \ VALUE origObj; \
rb_get_args(argc, argv, "o", &origObj RB_ARG_END); \ rb_get_args(argc, argv, "o", &origObj RB_ARG_END); \
if (!OBJ_INIT_COPY(self, origObj)) /* When would this fail??*/ \ if (!OBJ_INIT_COPY(self, origObj)) /* When would this fail??*/ \
return self; \ return self; \
Klass *orig = getPrivateData<Klass>(origObj); \ Klass *orig = getPrivateData<Klass>(origObj); \
Klass *k = 0; \ Klass *k = 0; \
GUARD_EXC(k = new Klass(*orig);) \ k = new Klass(*orig); \
setPrivateData(self, k); \ setPrivateData(self, k); \
return self; \ return self; \
} } \
RB_METHOD_GUARD_END
/* Object property which is copied by reference, with allowed NIL /* Object property which is copied by reference, with allowed NIL
* FIXME: Getter assumes prop is disposable, * FIXME: Getter assumes prop is disposable,
@ -461,7 +487,7 @@ RB_METHOD(Klass##Get##PropName) { \
RB_UNUSED_PARAM; \ RB_UNUSED_PARAM; \
return rb_iv_get(self, prop_iv); \ return rb_iv_get(self, prop_iv); \
} \ } \
RB_METHOD(Klass##Set##PropName) { \ RB_METHOD_GUARD(Klass##Set##PropName) { \
RB_UNUSED_PARAM; \ RB_UNUSED_PARAM; \
rb_check_argc(argc, 1); \ rb_check_argc(argc, 1); \
Klass *k = getPrivateData<Klass>(self); \ Klass *k = getPrivateData<Klass>(self); \
@ -471,17 +497,18 @@ if (NIL_P(propObj)) \
prop = 0; \ prop = 0; \
else \ else \
prop = getPrivateDataCheck<PropKlass>(propObj, PropKlass##Type); \ prop = getPrivateDataCheck<PropKlass>(propObj, PropKlass##Type); \
GUARD_EXC(k->set##PropName(prop);) \ k->set##PropName(prop) \
rb_iv_set(self, prop_iv, propObj); \ rb_iv_set(self, prop_iv, propObj); \
return propObj; \ return propObj; \
} } \
RB_METHOD_GUARD_END
#else #else
#define DEF_PROP_OBJ_REF(Klass, PropKlass, PropName, prop_iv) \ #define DEF_PROP_OBJ_REF(Klass, PropKlass, PropName, prop_iv) \
RB_METHOD(Klass##Get##PropName) { \ RB_METHOD(Klass##Get##PropName) { \
RB_UNUSED_PARAM; \ RB_UNUSED_PARAM; \
return rb_iv_get(self, prop_iv); \ return rb_iv_get(self, prop_iv); \
} \ } \
RB_METHOD(Klass##Set##PropName) { \ RB_METHOD_GUARD(Klass##Set##PropName) { \
RB_UNUSED_PARAM; \ RB_UNUSED_PARAM; \
rb_check_argc(argc, 1); \ rb_check_argc(argc, 1); \
Klass *k = getPrivateData<Klass>(self); \ Klass *k = getPrivateData<Klass>(self); \
@ -491,10 +518,11 @@ if (NIL_P(propObj)) \
prop = 0; \ prop = 0; \
else \ else \
prop = getPrivateDataCheck<PropKlass>(propObj, #PropKlass); \ prop = getPrivateDataCheck<PropKlass>(propObj, #PropKlass); \
GUARD_EXC(k->set##PropName(prop);) \ k->set##PropName(prop) \
rb_iv_set(self, prop_iv, propObj); \ rb_iv_set(self, prop_iv, propObj); \
return propObj; \ return propObj; \
} } \
RB_METHOD_GUARD_END
#endif #endif
/* Object property which is copied by value, not reference */ /* Object property which is copied by value, not reference */
@ -505,15 +533,16 @@ RB_UNUSED_PARAM; \
checkDisposed<Klass>(self); \ checkDisposed<Klass>(self); \
return rb_iv_get(self, prop_iv); \ return rb_iv_get(self, prop_iv); \
} \ } \
RB_METHOD(Klass##Set##PropName) { \ RB_METHOD_GUARD(Klass##Set##PropName) { \
rb_check_argc(argc, 1); \ rb_check_argc(argc, 1); \
Klass *k = getPrivateData<Klass>(self); \ Klass *k = getPrivateData<Klass>(self); \
VALUE propObj = *argv; \ VALUE propObj = *argv; \
PropKlass *prop; \ PropKlass *prop; \
prop = getPrivateDataCheck<PropKlass>(propObj, PropKlass##Type); \ prop = getPrivateDataCheck<PropKlass>(propObj, PropKlass##Type); \
GUARD_EXC(k->set##PropName(*prop);) \ k->set##PropName(*prop); \
return propObj; \ return propObj; \
} } \
RB_METHOD_GUARD_END
#else #else
#define DEF_PROP_OBJ_VAL(Klass, PropKlass, PropName, prop_iv) \ #define DEF_PROP_OBJ_VAL(Klass, PropKlass, PropName, prop_iv) \
RB_METHOD(Klass##Get##PropName) { \ RB_METHOD(Klass##Get##PropName) { \
@ -521,33 +550,36 @@ RB_UNUSED_PARAM; \
checkDisposed<Klass>(self); \ checkDisposed<Klass>(self); \
return rb_iv_get(self, prop_iv); \ return rb_iv_get(self, prop_iv); \
} \ } \
RB_METHOD(Klass##Set##PropName) { \ RB_METHOD_GUARD(Klass##Set##PropName) { \
rb_check_argc(argc, 1); \ rb_check_argc(argc, 1); \
Klass *k = getPrivateData<Klass>(self); \ Klass *k = getPrivateData<Klass>(self); \
VALUE propObj = *argv; \ VALUE propObj = *argv; \
PropKlass *prop; \ PropKlass *prop; \
prop = getPrivateDataCheck<PropKlass>(propObj, #PropKlass); \ prop = getPrivateDataCheck<PropKlass>(propObj, #PropKlass); \
GUARD_EXC(k->set##PropName(*prop);) \ k->set##PropName(*prop); \
return propObj; \ return propObj; \
} } \
RB_METHOD_GUARD_END
#endif #endif
#define DEF_PROP(Klass, type, PropName, arg_fun, value_fun) \ #define DEF_PROP(Klass, type, PropName, arg_fun, value_fun) \
RB_METHOD(Klass##Get##PropName) { \ RB_METHOD_GUARD(Klass##Get##PropName) { \
RB_UNUSED_PARAM; \ RB_UNUSED_PARAM; \
Klass *k = getPrivateData<Klass>(self); \ Klass *k = getPrivateData<Klass>(self); \
type value = 0; \ type value = 0; \
GUARD_EXC(value = k->get##PropName();) \ value = k->get##PropName(); \
return value_fun(value); \ return value_fun(value); \
} \ } \
RB_METHOD(Klass##Set##PropName) { \ RB_METHOD_GUARD_END \
RB_METHOD_GUARD(Klass##Set##PropName) { \
rb_check_argc(argc, 1); \ rb_check_argc(argc, 1); \
Klass *k = getPrivateData<Klass>(self); \ Klass *k = getPrivateData<Klass>(self); \
type value; \ type value; \
rb_##arg_fun##_arg(*argv, &value); \ rb_##arg_fun##_arg(*argv, &value); \
GUARD_EXC(k->set##PropName(value);) \ k->set##PropName(value); \
return *argv; \ return *argv; \
} } \
RB_METHOD_GUARD_END
#define DEF_PROP_I(Klass, PropName) \ #define DEF_PROP_I(Klass, PropName) \
DEF_PROP(Klass, int, PropName, int, rb_fix_new) DEF_PROP(Klass, int, PropName, int, rb_fix_new)
@ -573,7 +605,7 @@ RB_METHOD(Klass##Get##PropName) { \
RB_UNUSED_PARAM; \ RB_UNUSED_PARAM; \
return rb_iv_get(self, prop_iv); \ return rb_iv_get(self, prop_iv); \
} \ } \
RB_METHOD(Klass##Set##PropName) { \ RB_METHOD_GUARD(Klass##Set##PropName) { \
RB_UNUSED_PARAM; \ RB_UNUSED_PARAM; \
rb_check_argc(argc, 1); \ rb_check_argc(argc, 1); \
Klass *k = getPrivateData<Klass>(self); \ Klass *k = getPrivateData<Klass>(self); \
@ -586,7 +618,8 @@ prop = getPrivateDataCheck<PropKlass>(propObj, PropKlass##Type); \
GFX_GUARD_EXC(k->set##PropName(prop);) \ GFX_GUARD_EXC(k->set##PropName(prop);) \
rb_iv_set(self, prop_iv, propObj); \ rb_iv_set(self, prop_iv, propObj); \
return propObj; \ return propObj; \
} } \
RB_METHOD_GUARD_END
#else #else
#define DEF_GFX_PROP_OBJ_REF(Klass, PropKlass, PropName, prop_iv) \ #define DEF_GFX_PROP_OBJ_REF(Klass, PropKlass, PropName, prop_iv) \
DEF_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); \ checkDisposed<Klass>(self); \
return rb_iv_get(self, prop_iv); \ return rb_iv_get(self, prop_iv); \
} \ } \
RB_METHOD(Klass##Set##PropName) { \ RB_METHOD_GUARD(Klass##Set##PropName) { \
rb_check_argc(argc, 1); \ rb_check_argc(argc, 1); \
Klass *k = getPrivateData<Klass>(self); \ Klass *k = getPrivateData<Klass>(self); \
VALUE propObj = *argv; \ VALUE propObj = *argv; \
@ -608,28 +641,31 @@ PropKlass *prop; \
prop = getPrivateDataCheck<PropKlass>(propObj, PropKlass##Type); \ prop = getPrivateDataCheck<PropKlass>(propObj, PropKlass##Type); \
GFX_GUARD_EXC(k->set##PropName(*prop);) \ GFX_GUARD_EXC(k->set##PropName(*prop);) \
return propObj; \ return propObj; \
} } \
RB_METHOD_GUARD_END
#else #else
#define DEF_GFX_PROP_OBJ_VAL(Klass, PropKlass, PropName, prop_iv) \ #define DEF_GFX_PROP_OBJ_VAL(Klass, PropKlass, PropName, prop_iv) \
DEF_PROP_OBJ_VAL(Klass, PropKlass, PropName, prop_iv) DEF_PROP_OBJ_VAL(Klass, PropKlass, PropName, prop_iv)
#endif #endif
#define DEF_GFX_PROP(Klass, type, PropName, arg_fun, value_fun) \ #define DEF_GFX_PROP(Klass, type, PropName, arg_fun, value_fun) \
RB_METHOD(Klass##Get##PropName) { \ RB_METHOD_GUARD(Klass##Get##PropName) { \
RB_UNUSED_PARAM; \ RB_UNUSED_PARAM; \
Klass *k = getPrivateData<Klass>(self); \ Klass *k = getPrivateData<Klass>(self); \
type value = 0; \ type value = 0; \
GUARD_EXC(value = k->get##PropName();) \ value = k->get##PropName(); \
return value_fun(value); \ return value_fun(value); \
} \ } \
RB_METHOD(Klass##Set##PropName) { \ RB_METHOD_GUARD_END \
RB_METHOD_GUARD(Klass##Set##PropName) { \
rb_check_argc(argc, 1); \ rb_check_argc(argc, 1); \
Klass *k = getPrivateData<Klass>(self); \ Klass *k = getPrivateData<Klass>(self); \
type value; \ type value; \
rb_##arg_fun##_arg(*argv, &value); \ rb_##arg_fun##_arg(*argv, &value); \
GFX_GUARD_EXC(k->set##PropName(value);) \ GFX_GUARD_EXC(k->set##PropName(value);) \
return *argv; \ return *argv; \
} } \
RB_METHOD_GUARD_END
#define DEF_GFX_PROP_I(Klass, PropName) \ #define DEF_GFX_PROP_I(Klass, PropName) \
DEF_GFX_PROP(Klass, int, PropName, int, rb_fix_new) 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); b->setInitFont(font);
} }
RB_METHOD(bitmapInitialize) { RB_METHOD_GUARD(bitmapInitialize) {
Bitmap *b = 0; Bitmap *b = 0;
if (argc == 1) { if (argc == 1) {
@ -84,45 +84,49 @@ RB_METHOD(bitmapInitialize) {
return self; return self;
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapWidth) { RB_METHOD_GUARD(bitmapWidth) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
Bitmap *b = getPrivateData<Bitmap>(self); Bitmap *b = getPrivateData<Bitmap>(self);
int value = 0; int value = 0;
GUARD_EXC(value = b->width();); value = b->width();
return INT2FIX(value); return INT2FIX(value);
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapHeight) { RB_METHOD_GUARD(bitmapHeight) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
Bitmap *b = getPrivateData<Bitmap>(self); Bitmap *b = getPrivateData<Bitmap>(self);
int value = 0; int value = 0;
GUARD_EXC(value = b->height();); value = b->height();
return INT2FIX(value); return INT2FIX(value);
} }
RB_METHOD_GUARD_END
DEF_GFX_PROP_OBJ_REF(Bitmap, Bitmap, Hires, "hires") DEF_GFX_PROP_OBJ_REF(Bitmap, Bitmap, Hires, "hires")
RB_METHOD(bitmapRect) { RB_METHOD_GUARD(bitmapRect) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
Bitmap *b = getPrivateData<Bitmap>(self); Bitmap *b = getPrivateData<Bitmap>(self);
IntRect rect; IntRect rect;
GUARD_EXC(rect = b->rect();); rect = b->rect();
Rect *r = new Rect(rect); Rect *r = new Rect(rect);
return wrapObject(r, RectType); return wrapObject(r, RectType);
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapBlt) { RB_METHOD_GUARD(bitmapBlt) {
Bitmap *b = getPrivateData<Bitmap>(self); Bitmap *b = getPrivateData<Bitmap>(self);
int x, y; int x, y;
@ -143,8 +147,9 @@ RB_METHOD(bitmapBlt) {
return self; return self;
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapStretchBlt) { RB_METHOD_GUARD(bitmapStretchBlt) {
Bitmap *b = getPrivateData<Bitmap>(self); Bitmap *b = getPrivateData<Bitmap>(self);
VALUE destRectObj; VALUE destRectObj;
@ -167,8 +172,9 @@ RB_METHOD(bitmapStretchBlt) {
return self; return self;
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapFillRect) { RB_METHOD_GUARD(bitmapFillRect) {
Bitmap *b = getPrivateData<Bitmap>(self); Bitmap *b = getPrivateData<Bitmap>(self);
VALUE colorObj; VALUE colorObj;
@ -197,8 +203,9 @@ RB_METHOD(bitmapFillRect) {
return self; return self;
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapClear) { RB_METHOD_GUARD(bitmapClear) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
Bitmap *b = getPrivateData<Bitmap>(self); Bitmap *b = getPrivateData<Bitmap>(self);
@ -207,8 +214,9 @@ RB_METHOD(bitmapClear) {
return self; return self;
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapGetPixel) { RB_METHOD_GUARD(bitmapGetPixel) {
Bitmap *b = getPrivateData<Bitmap>(self); Bitmap *b = getPrivateData<Bitmap>(self);
int x, y; int x, y;
@ -216,14 +224,18 @@ RB_METHOD(bitmapGetPixel) {
rb_get_args(argc, argv, "ii", &x, &y RB_ARG_END); rb_get_args(argc, argv, "ii", &x, &y RB_ARG_END);
Color value; 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); Color *color = new Color(value);
return wrapObject(color, ColorType); return wrapObject(color, ColorType);
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapSetPixel) { RB_METHOD_GUARD(bitmapSetPixel) {
Bitmap *b = getPrivateData<Bitmap>(self); Bitmap *b = getPrivateData<Bitmap>(self);
int x, y; int x, y;
@ -239,8 +251,9 @@ RB_METHOD(bitmapSetPixel) {
return self; return self;
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapHueChange) { RB_METHOD_GUARD(bitmapHueChange) {
Bitmap *b = getPrivateData<Bitmap>(self); Bitmap *b = getPrivateData<Bitmap>(self);
int hue; int hue;
@ -251,8 +264,9 @@ RB_METHOD(bitmapHueChange) {
return self; return self;
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapDrawText) { RB_METHOD_GUARD(bitmapDrawText) {
Bitmap *b = getPrivateData<Bitmap>(self); Bitmap *b = getPrivateData<Bitmap>(self);
const char *str; const char *str;
@ -293,8 +307,9 @@ RB_METHOD(bitmapDrawText) {
return self; return self;
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapTextSize) { RB_METHOD_GUARD(bitmapTextSize) {
Bitmap *b = getPrivateData<Bitmap>(self); Bitmap *b = getPrivateData<Bitmap>(self);
const char *str; const char *str;
@ -309,16 +324,17 @@ RB_METHOD(bitmapTextSize) {
} }
IntRect value; IntRect value;
GUARD_EXC(value = b->textSize(str);); value = b->textSize(str);
Rect *rect = new Rect(value); Rect *rect = new Rect(value);
return wrapObject(rect, RectType); return wrapObject(rect, RectType);
} }
RB_METHOD_GUARD_END
DEF_GFX_PROP_OBJ_VAL(Bitmap, Font, Font, "font") DEF_GFX_PROP_OBJ_VAL(Bitmap, Font, Font, "font")
RB_METHOD(bitmapGradientFillRect) { RB_METHOD_GUARD(bitmapGradientFillRect) {
Bitmap *b = getPrivateData<Bitmap>(self); Bitmap *b = getPrivateData<Bitmap>(self);
VALUE color1Obj, color2Obj; VALUE color1Obj, color2Obj;
@ -353,8 +369,9 @@ RB_METHOD(bitmapGradientFillRect) {
return self; return self;
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapClearRect) { RB_METHOD_GUARD(bitmapClearRect) {
Bitmap *b = getPrivateData<Bitmap>(self); Bitmap *b = getPrivateData<Bitmap>(self);
if (argc == 1) { if (argc == 1) {
@ -376,33 +393,32 @@ RB_METHOD(bitmapClearRect) {
return self; return self;
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapBlur) { RB_METHOD_GUARD(bitmapBlur) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
Bitmap *b = getPrivateData<Bitmap>(self); Bitmap *b = getPrivateData<Bitmap>(self);
GFX_LOCK; GFX_GUARD_EXC( b->blur(); );
b->blur();
GFX_UNLOCK;
return Qnil; return Qnil;
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapRadialBlur) { RB_METHOD_GUARD(bitmapRadialBlur) {
Bitmap *b = getPrivateData<Bitmap>(self); Bitmap *b = getPrivateData<Bitmap>(self);
int angle, divisions; int angle, divisions;
rb_get_args(argc, argv, "ii", &angle, &divisions RB_ARG_END); rb_get_args(argc, argv, "ii", &angle, &divisions RB_ARG_END);
GFX_LOCK; GFX_GUARD_EXC( b->radialBlur(angle, divisions); );
b->radialBlur(angle, divisions);
GFX_UNLOCK;
return Qnil; return Qnil;
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapGetRawData) { RB_METHOD_GUARD(bitmapGetRawData) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
Bitmap *b = getPrivateData<Bitmap>(self); Bitmap *b = getPrivateData<Bitmap>(self);
@ -413,8 +429,9 @@ RB_METHOD(bitmapGetRawData) {
return ret; return ret;
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapSetRawData) { RB_METHOD_GUARD(bitmapSetRawData) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
VALUE str; VALUE str;
@ -427,8 +444,9 @@ RB_METHOD(bitmapSetRawData) {
return self; return self;
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapSaveToFile) { RB_METHOD_GUARD(bitmapSaveToFile) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
VALUE str; VALUE str;
@ -441,8 +459,9 @@ RB_METHOD(bitmapSaveToFile) {
return RUBY_Qnil; return RUBY_Qnil;
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapGetMega){ RB_METHOD_GUARD(bitmapGetMega){
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
rb_check_argc(argc, 0); rb_check_argc(argc, 0);
@ -455,8 +474,9 @@ RB_METHOD(bitmapGetMega){
return ret; return ret;
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapGetAnimated){ RB_METHOD_GUARD(bitmapGetAnimated){
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
rb_check_argc(argc, 0); rb_check_argc(argc, 0);
@ -469,8 +489,9 @@ RB_METHOD(bitmapGetAnimated){
return ret; return ret;
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapGetPlaying){ RB_METHOD_GUARD(bitmapGetPlaying){
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
rb_check_argc(argc, 0); rb_check_argc(argc, 0);
@ -479,8 +500,9 @@ RB_METHOD(bitmapGetPlaying){
return rb_bool_new(b->isPlaying()); return rb_bool_new(b->isPlaying());
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapSetPlaying){ RB_METHOD_GUARD(bitmapSetPlaying){
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
bool play; bool play;
@ -493,8 +515,9 @@ RB_METHOD(bitmapSetPlaying){
return RUBY_Qnil; return RUBY_Qnil;
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapPlay){ RB_METHOD_GUARD(bitmapPlay){
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
rb_check_argc(argc, 0); rb_check_argc(argc, 0);
@ -504,8 +527,9 @@ RB_METHOD(bitmapPlay){
return RUBY_Qnil; return RUBY_Qnil;
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapStop){ RB_METHOD_GUARD(bitmapStop){
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
rb_check_argc(argc, 0); rb_check_argc(argc, 0);
@ -515,8 +539,9 @@ RB_METHOD(bitmapStop){
return RUBY_Qnil; return RUBY_Qnil;
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapGotoStop){ RB_METHOD_GUARD(bitmapGotoStop){
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
int frame; int frame;
@ -529,8 +554,9 @@ RB_METHOD(bitmapGotoStop){
return RUBY_Qnil; return RUBY_Qnil;
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapGotoPlay){ RB_METHOD_GUARD(bitmapGotoPlay){
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
int frame; int frame;
@ -543,8 +569,9 @@ RB_METHOD(bitmapGotoPlay){
return RUBY_Qnil; return RUBY_Qnil;
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapFrames){ RB_METHOD_GUARD(bitmapFrames){
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
rb_check_argc(argc, 0); rb_check_argc(argc, 0);
@ -553,8 +580,9 @@ RB_METHOD(bitmapFrames){
return INT2NUM(b->numFrames()); return INT2NUM(b->numFrames());
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapCurrentFrame){ RB_METHOD_GUARD(bitmapCurrentFrame){
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
rb_check_argc(argc, 0); rb_check_argc(argc, 0);
@ -563,8 +591,9 @@ RB_METHOD(bitmapCurrentFrame){
return INT2NUM(b->currentFrameI()); return INT2NUM(b->currentFrameI());
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapAddFrame){ RB_METHOD_GUARD(bitmapAddFrame){
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
VALUE srcBitmap; VALUE srcBitmap;
@ -588,8 +617,9 @@ RB_METHOD(bitmapAddFrame){
return INT2NUM(ret); return INT2NUM(ret);
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapRemoveFrame){ RB_METHOD_GUARD(bitmapRemoveFrame){
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
VALUE position; VALUE position;
@ -608,8 +638,9 @@ RB_METHOD(bitmapRemoveFrame){
return RUBY_Qnil; return RUBY_Qnil;
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapNextFrame){ RB_METHOD_GUARD(bitmapNextFrame){
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
rb_check_argc(argc, 0); rb_check_argc(argc, 0);
@ -620,8 +651,9 @@ RB_METHOD(bitmapNextFrame){
return INT2NUM(b->currentFrameI()); return INT2NUM(b->currentFrameI());
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapPreviousFrame){ RB_METHOD_GUARD(bitmapPreviousFrame){
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
rb_check_argc(argc, 0); rb_check_argc(argc, 0);
@ -632,8 +664,9 @@ RB_METHOD(bitmapPreviousFrame){
return INT2NUM(b->currentFrameI()); return INT2NUM(b->currentFrameI());
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapSetFPS){ RB_METHOD_GUARD(bitmapSetFPS){
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
VALUE fps; VALUE fps;
@ -652,8 +685,9 @@ RB_METHOD(bitmapSetFPS){
return RUBY_Qnil; return RUBY_Qnil;
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapGetFPS){ RB_METHOD_GUARD(bitmapGetFPS){
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
rb_check_argc(argc, 0); rb_check_argc(argc, 0);
@ -662,12 +696,13 @@ RB_METHOD(bitmapGetFPS){
float ret; float ret;
GUARD_EXC(ret = b->getAnimationFPS();); ret = b->getAnimationFPS();
return rb_float_new(ret); return rb_float_new(ret);
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapSetLooping){ RB_METHOD_GUARD(bitmapSetLooping){
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
bool loop; bool loop;
@ -679,8 +714,9 @@ RB_METHOD(bitmapSetLooping){
return rb_bool_new(loop); return rb_bool_new(loop);
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapGetLooping){ RB_METHOD_GUARD(bitmapGetLooping){
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
rb_check_argc(argc, 0); rb_check_argc(argc, 0);
@ -688,12 +724,13 @@ RB_METHOD(bitmapGetLooping){
Bitmap *b = getPrivateData<Bitmap>(self); Bitmap *b = getPrivateData<Bitmap>(self);
bool ret; bool ret;
GUARD_EXC(ret = b->getLooping();); ret = b->getLooping();
return rb_bool_new(ret); return rb_bool_new(ret);
} }
RB_METHOD_GUARD_END
// Captures the Bitmap's current frame data to a new Bitmap // Captures the Bitmap's current frame data to a new Bitmap
RB_METHOD(bitmapSnapToBitmap) { RB_METHOD_GUARD(bitmapSnapToBitmap) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
VALUE position; VALUE position;
@ -713,6 +750,7 @@ RB_METHOD(bitmapSnapToBitmap) {
return ret; return ret;
} }
RB_METHOD_GUARD_END
RB_METHOD(bitmapGetMaxSize){ RB_METHOD(bitmapGetMaxSize){
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
@ -722,7 +760,7 @@ RB_METHOD(bitmapGetMaxSize){
return INT2NUM(Bitmap::maxSize()); return INT2NUM(Bitmap::maxSize());
} }
RB_METHOD(bitmapInitializeCopy) { RB_METHOD_GUARD(bitmapInitializeCopy) {
rb_check_argc(argc, 1); rb_check_argc(argc, 1);
VALUE origObj = argv[0]; VALUE origObj = argv[0];
@ -740,6 +778,7 @@ RB_METHOD(bitmapInitializeCopy) {
return self; return self;
} }
RB_METHOD_GUARD_END
void bitmapBindingInit() { void bitmapBindingInit() {
VALUE klass = rb_define_class("Bitmap", rb_cObject); VALUE klass = rb_define_class("Bitmap", rb_cObject);

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -36,7 +36,18 @@ serializableDump(int, VALUE *, VALUE self)
VALUE data = rb_str_new(0, dataSize); 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; 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, PatternTile)
DEF_GFX_PROP_B(Sprite, Invert) DEF_GFX_PROP_B(Sprite, Invert)
RB_METHOD(spriteWidth) { RB_METHOD_GUARD(spriteWidth) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
Sprite *s = getPrivateData<Sprite>(self); Sprite *s = getPrivateData<Sprite>(self);
int value = 0; int value = 0;
GUARD_EXC(value = s->getWidth();) value = s->getWidth();
return rb_fix_new(value); return rb_fix_new(value);
} }
RB_METHOD_GUARD_END
RB_METHOD(spriteHeight) { RB_METHOD_GUARD(spriteHeight) {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
Sprite *s = getPrivateData<Sprite>(self); Sprite *s = getPrivateData<Sprite>(self);
int value = 0; int value = 0;
GUARD_EXC(value = s->getHeight();) value = s->getHeight();
return rb_fix_new(value); return rb_fix_new(value);
} }
RB_METHOD_GUARD_END
void spriteBindingInit() { void spriteBindingInit() {
VALUE klass = rb_define_class("Sprite", rb_cObject); VALUE klass = rb_define_class("Sprite", rb_cObject);

View file

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

View file

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

View file

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

View file

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