mirror of https://github.com/mgba-emu/mgba.git
Scripting: Add "console" logger bridge
This commit is contained in:
parent
e3758597f8
commit
17d2373975
|
@ -56,6 +56,9 @@ int mLogFilterLevels(const struct mLogFilter*, int category);
|
|||
ATTRIBUTE_FORMAT(printf, 3, 4)
|
||||
void mLog(int category, enum mLogLevel level, const char* format, ...);
|
||||
|
||||
ATTRIBUTE_FORMAT(printf, 4, 5)
|
||||
void mLogExplicit(struct mLogger*, int category, enum mLogLevel level, const char* format, ...);
|
||||
|
||||
#define mLOG(CATEGORY, LEVEL, ...) mLog(_mLOG_CAT_ ## CATEGORY, mLOG_ ## LEVEL, __VA_ARGS__)
|
||||
|
||||
#define mLOG_DECLARE_CATEGORY(CATEGORY) extern int _mLOG_CAT_ ## CATEGORY;
|
||||
|
|
|
@ -10,13 +10,18 @@
|
|||
|
||||
CXX_GUARD_START
|
||||
|
||||
#include <mgba/core/log.h>
|
||||
#ifdef USE_DEBUGGERS
|
||||
#include <mgba/debugger/debugger.h>
|
||||
#endif
|
||||
#include <mgba/script/types.h>
|
||||
|
||||
mLOG_DECLARE_CATEGORY(SCRIPT);
|
||||
|
||||
struct mCore;
|
||||
struct mLogger;
|
||||
mSCRIPT_DECLARE_STRUCT(mCore);
|
||||
mSCRIPT_DECLARE_STRUCT(mLogger);
|
||||
|
||||
struct mScriptBridge;
|
||||
struct VFile;
|
||||
|
@ -52,10 +57,12 @@ bool mScriptBridgeLoadScript(struct mScriptBridge*, const char* name);
|
|||
bool mScriptBridgeLookupSymbol(struct mScriptBridge*, const char* name, int32_t* out);
|
||||
|
||||
struct mScriptContext;
|
||||
struct mCore;
|
||||
void mScriptContextAttachCore(struct mScriptContext*, struct mCore*);
|
||||
void mScriptContextDetachCore(struct mScriptContext*);
|
||||
|
||||
void mScriptContextAttachLogger(struct mScriptContext*, struct mLogger*);
|
||||
void mScriptContextDetachLogger(struct mScriptContext*);
|
||||
|
||||
CXX_GUARD_END
|
||||
|
||||
#endif
|
||||
|
|
|
@ -80,6 +80,14 @@ void mLog(int category, enum mLogLevel level, const char* format, ...) {
|
|||
va_end(args);
|
||||
}
|
||||
|
||||
void mLogExplicit(struct mLogger* context, int category, enum mLogLevel level, const char* format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
if (!context->filter || mLogFilterTest(context->filter, category, level)) {
|
||||
context->log(context, category, level, format, args);
|
||||
}
|
||||
}
|
||||
|
||||
void mLogFilterInit(struct mLogFilter* filter) {
|
||||
HashTableInit(&filter->categories, 8, NULL);
|
||||
TableInit(&filter->levels, 8, NULL);
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
#include <mgba-util/table.h>
|
||||
#include <mgba-util/vfs.h>
|
||||
|
||||
mLOG_DEFINE_CATEGORY(SCRIPT, "Scripting", "script");
|
||||
|
||||
struct mScriptBridge {
|
||||
struct Table engines;
|
||||
struct mDebugger* debugger;
|
||||
|
@ -196,3 +198,36 @@ void mScriptContextAttachCore(struct mScriptContext* context, struct mCore* core
|
|||
void mScriptContextDetachCore(struct mScriptContext* context) {
|
||||
mScriptContextRemoveGlobal(context, "emu");
|
||||
}
|
||||
|
||||
void mScriptLog(struct mLogger* logger, struct mScriptString* msg) {
|
||||
mLogExplicit(logger, _mLOG_CAT_SCRIPT, mLOG_INFO, "%s", msg->buffer);
|
||||
}
|
||||
|
||||
void mScriptWarn(struct mLogger* logger, struct mScriptString* msg) {
|
||||
mLogExplicit(logger, _mLOG_CAT_SCRIPT, mLOG_WARN, "%s", msg->buffer);
|
||||
}
|
||||
|
||||
void mScriptError(struct mLogger* logger, struct mScriptString* msg) {
|
||||
mLogExplicit(logger, _mLOG_CAT_SCRIPT, mLOG_ERROR, "%s", msg->buffer);
|
||||
}
|
||||
|
||||
mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mLogger, log, mScriptLog, 1, STR, msg);
|
||||
mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mLogger, warn, mScriptWarn, 1, STR, msg);
|
||||
mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mLogger, error, mScriptError, 1, STR, msg);
|
||||
|
||||
mSCRIPT_DEFINE_STRUCT(mLogger)
|
||||
mSCRIPT_DEFINE_STRUCT_METHOD(mLogger, log)
|
||||
mSCRIPT_DEFINE_STRUCT_METHOD(mLogger, warn)
|
||||
mSCRIPT_DEFINE_STRUCT_METHOD(mLogger, error)
|
||||
mSCRIPT_DEFINE_END;
|
||||
|
||||
void mScriptContextAttachLogger(struct mScriptContext* context, struct mLogger* logger) {
|
||||
struct mScriptValue* value = mScriptValueAlloc(mSCRIPT_TYPE_MS_S(mLogger));
|
||||
value->value.opaque = logger;
|
||||
mScriptContextSetGlobal(context, "console", value);
|
||||
mScriptValueDeref(value);
|
||||
}
|
||||
|
||||
void mScriptContextDetachLogger(struct mScriptContext* context) {
|
||||
mScriptContextRemoveGlobal(context, "console");
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "util/test/suite.h"
|
||||
|
||||
#include <mgba/core/core.h>
|
||||
#include <mgba/core/log.h>
|
||||
#include <mgba/core/scripting.h>
|
||||
#include <mgba/internal/script/lua.h>
|
||||
#include <mgba/script/context.h>
|
||||
|
@ -23,6 +24,13 @@
|
|||
#error "Need a valid platform for testing"
|
||||
#endif
|
||||
|
||||
struct mScriptTestLogger {
|
||||
struct mLogger d;
|
||||
char* log;
|
||||
char* warn;
|
||||
char* error;
|
||||
};
|
||||
|
||||
static const uint8_t _fakeGBROM[0x4000] = {
|
||||
[0x100] = 0x18, // Loop forever
|
||||
[0x101] = 0xFE, // jr, $-2
|
||||
|
@ -76,6 +84,59 @@ static const uint8_t _fakeGBROM[0x4000] = {
|
|||
mScriptValueDeref(global); \
|
||||
} while(0)
|
||||
|
||||
static void _mScriptTestLog(struct mLogger* log, int category, enum mLogLevel level, const char* format, va_list args) {
|
||||
UNUSED(category);
|
||||
struct mScriptTestLogger* logger = (struct mScriptTestLogger*) log;
|
||||
|
||||
char* message;
|
||||
#ifdef HAVE_VASPRINTF
|
||||
vasprintf(&message, format, args);
|
||||
#else
|
||||
char messageBuf[64];
|
||||
vsnprintf(messageBuf, format, args);
|
||||
message = strdup(messageBuf);
|
||||
#endif
|
||||
switch (level) {
|
||||
case mLOG_INFO:
|
||||
if (logger->log) {
|
||||
free(logger->log);
|
||||
}
|
||||
logger->log = message;
|
||||
break;
|
||||
case mLOG_WARN:
|
||||
if (logger->warn) {
|
||||
free(logger->warn);
|
||||
}
|
||||
logger->warn = message;
|
||||
break;
|
||||
case mLOG_ERROR:
|
||||
if (logger->error) {
|
||||
free(logger->error);
|
||||
}
|
||||
logger->error = message;
|
||||
break;
|
||||
default:
|
||||
free(message);
|
||||
}
|
||||
}
|
||||
|
||||
static void mScriptTestLoggerInit(struct mScriptTestLogger* logger) {
|
||||
memset(logger, 0, sizeof(*logger));
|
||||
logger->d.log = _mScriptTestLog;
|
||||
}
|
||||
|
||||
static void mScriptTestLoggerDeinit(struct mScriptTestLogger* logger) {
|
||||
if (logger->log) {
|
||||
free(logger->log);
|
||||
}
|
||||
if (logger->warn) {
|
||||
free(logger->warn);
|
||||
}
|
||||
if (logger->error) {
|
||||
free(logger->error);
|
||||
}
|
||||
}
|
||||
|
||||
M_TEST_SUITE_SETUP(mScriptCore) {
|
||||
if (mSCRIPT_ENGINE_LUA->init) {
|
||||
mSCRIPT_ENGINE_LUA->init(mSCRIPT_ENGINE_LUA);
|
||||
|
@ -230,6 +291,45 @@ M_TEST_DEFINE(memoryWrite) {
|
|||
mScriptContextDeinit(&context);
|
||||
}
|
||||
|
||||
M_TEST_DEFINE(logging) {
|
||||
SETUP_LUA;
|
||||
struct mScriptTestLogger logger;
|
||||
mScriptTestLoggerInit(&logger);
|
||||
|
||||
mScriptContextAttachLogger(&context, &logger.d);
|
||||
|
||||
LOAD_PROGRAM(
|
||||
"assert(console)\n"
|
||||
"console:log(\"log\")\n"
|
||||
"console:warn(\"warn\")\n"
|
||||
"console:error(\"error\")\n"
|
||||
"a = console\n"
|
||||
);
|
||||
|
||||
assert_true(lua->run(lua));
|
||||
assert_non_null(logger.log);
|
||||
assert_non_null(logger.warn);
|
||||
assert_non_null(logger.error);
|
||||
assert_string_equal(logger.log, "log");
|
||||
assert_string_equal(logger.warn, "warn");
|
||||
assert_string_equal(logger.error, "error");
|
||||
|
||||
mScriptContextDetachLogger(&context);
|
||||
|
||||
LOAD_PROGRAM(
|
||||
"assert(not console)\n"
|
||||
);
|
||||
assert_true(lua->run(lua));
|
||||
|
||||
LOAD_PROGRAM(
|
||||
"a:log(\"l2\")\n"
|
||||
);
|
||||
assert_false(lua->run(lua));
|
||||
|
||||
mScriptTestLoggerDeinit(&logger);
|
||||
mScriptContextDeinit(&context);
|
||||
}
|
||||
|
||||
M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(mScriptCore,
|
||||
cmocka_unit_test(globals),
|
||||
cmocka_unit_test(infoFuncs),
|
||||
|
@ -237,4 +337,5 @@ M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(mScriptCore,
|
|||
cmocka_unit_test(runFrame),
|
||||
cmocka_unit_test(memoryRead),
|
||||
cmocka_unit_test(memoryWrite),
|
||||
cmocka_unit_test(logging),
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue