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)
|
ATTRIBUTE_FORMAT(printf, 3, 4)
|
||||||
void mLog(int category, enum mLogLevel level, const char* format, ...);
|
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(CATEGORY, LEVEL, ...) mLog(_mLOG_CAT_ ## CATEGORY, mLOG_ ## LEVEL, __VA_ARGS__)
|
||||||
|
|
||||||
#define mLOG_DECLARE_CATEGORY(CATEGORY) extern int _mLOG_CAT_ ## CATEGORY;
|
#define mLOG_DECLARE_CATEGORY(CATEGORY) extern int _mLOG_CAT_ ## CATEGORY;
|
||||||
|
|
|
@ -10,13 +10,18 @@
|
||||||
|
|
||||||
CXX_GUARD_START
|
CXX_GUARD_START
|
||||||
|
|
||||||
|
#include <mgba/core/log.h>
|
||||||
#ifdef USE_DEBUGGERS
|
#ifdef USE_DEBUGGERS
|
||||||
#include <mgba/debugger/debugger.h>
|
#include <mgba/debugger/debugger.h>
|
||||||
#endif
|
#endif
|
||||||
#include <mgba/script/types.h>
|
#include <mgba/script/types.h>
|
||||||
|
|
||||||
|
mLOG_DECLARE_CATEGORY(SCRIPT);
|
||||||
|
|
||||||
struct mCore;
|
struct mCore;
|
||||||
|
struct mLogger;
|
||||||
mSCRIPT_DECLARE_STRUCT(mCore);
|
mSCRIPT_DECLARE_STRUCT(mCore);
|
||||||
|
mSCRIPT_DECLARE_STRUCT(mLogger);
|
||||||
|
|
||||||
struct mScriptBridge;
|
struct mScriptBridge;
|
||||||
struct VFile;
|
struct VFile;
|
||||||
|
@ -52,10 +57,12 @@ bool mScriptBridgeLoadScript(struct mScriptBridge*, const char* name);
|
||||||
bool mScriptBridgeLookupSymbol(struct mScriptBridge*, const char* name, int32_t* out);
|
bool mScriptBridgeLookupSymbol(struct mScriptBridge*, const char* name, int32_t* out);
|
||||||
|
|
||||||
struct mScriptContext;
|
struct mScriptContext;
|
||||||
struct mCore;
|
|
||||||
void mScriptContextAttachCore(struct mScriptContext*, struct mCore*);
|
void mScriptContextAttachCore(struct mScriptContext*, struct mCore*);
|
||||||
void mScriptContextDetachCore(struct mScriptContext*);
|
void mScriptContextDetachCore(struct mScriptContext*);
|
||||||
|
|
||||||
|
void mScriptContextAttachLogger(struct mScriptContext*, struct mLogger*);
|
||||||
|
void mScriptContextDetachLogger(struct mScriptContext*);
|
||||||
|
|
||||||
CXX_GUARD_END
|
CXX_GUARD_END
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -80,6 +80,14 @@ void mLog(int category, enum mLogLevel level, const char* format, ...) {
|
||||||
va_end(args);
|
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) {
|
void mLogFilterInit(struct mLogFilter* filter) {
|
||||||
HashTableInit(&filter->categories, 8, NULL);
|
HashTableInit(&filter->categories, 8, NULL);
|
||||||
TableInit(&filter->levels, 8, NULL);
|
TableInit(&filter->levels, 8, NULL);
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
#include <mgba-util/table.h>
|
#include <mgba-util/table.h>
|
||||||
#include <mgba-util/vfs.h>
|
#include <mgba-util/vfs.h>
|
||||||
|
|
||||||
|
mLOG_DEFINE_CATEGORY(SCRIPT, "Scripting", "script");
|
||||||
|
|
||||||
struct mScriptBridge {
|
struct mScriptBridge {
|
||||||
struct Table engines;
|
struct Table engines;
|
||||||
struct mDebugger* debugger;
|
struct mDebugger* debugger;
|
||||||
|
@ -196,3 +198,36 @@ void mScriptContextAttachCore(struct mScriptContext* context, struct mCore* core
|
||||||
void mScriptContextDetachCore(struct mScriptContext* context) {
|
void mScriptContextDetachCore(struct mScriptContext* context) {
|
||||||
mScriptContextRemoveGlobal(context, "emu");
|
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 "util/test/suite.h"
|
||||||
|
|
||||||
#include <mgba/core/core.h>
|
#include <mgba/core/core.h>
|
||||||
|
#include <mgba/core/log.h>
|
||||||
#include <mgba/core/scripting.h>
|
#include <mgba/core/scripting.h>
|
||||||
#include <mgba/internal/script/lua.h>
|
#include <mgba/internal/script/lua.h>
|
||||||
#include <mgba/script/context.h>
|
#include <mgba/script/context.h>
|
||||||
|
@ -23,6 +24,13 @@
|
||||||
#error "Need a valid platform for testing"
|
#error "Need a valid platform for testing"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct mScriptTestLogger {
|
||||||
|
struct mLogger d;
|
||||||
|
char* log;
|
||||||
|
char* warn;
|
||||||
|
char* error;
|
||||||
|
};
|
||||||
|
|
||||||
static const uint8_t _fakeGBROM[0x4000] = {
|
static const uint8_t _fakeGBROM[0x4000] = {
|
||||||
[0x100] = 0x18, // Loop forever
|
[0x100] = 0x18, // Loop forever
|
||||||
[0x101] = 0xFE, // jr, $-2
|
[0x101] = 0xFE, // jr, $-2
|
||||||
|
@ -76,6 +84,59 @@ static const uint8_t _fakeGBROM[0x4000] = {
|
||||||
mScriptValueDeref(global); \
|
mScriptValueDeref(global); \
|
||||||
} while(0)
|
} 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) {
|
M_TEST_SUITE_SETUP(mScriptCore) {
|
||||||
if (mSCRIPT_ENGINE_LUA->init) {
|
if (mSCRIPT_ENGINE_LUA->init) {
|
||||||
mSCRIPT_ENGINE_LUA->init(mSCRIPT_ENGINE_LUA);
|
mSCRIPT_ENGINE_LUA->init(mSCRIPT_ENGINE_LUA);
|
||||||
|
@ -230,6 +291,45 @@ M_TEST_DEFINE(memoryWrite) {
|
||||||
mScriptContextDeinit(&context);
|
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,
|
M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(mScriptCore,
|
||||||
cmocka_unit_test(globals),
|
cmocka_unit_test(globals),
|
||||||
cmocka_unit_test(infoFuncs),
|
cmocka_unit_test(infoFuncs),
|
||||||
|
@ -237,4 +337,5 @@ M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(mScriptCore,
|
||||||
cmocka_unit_test(runFrame),
|
cmocka_unit_test(runFrame),
|
||||||
cmocka_unit_test(memoryRead),
|
cmocka_unit_test(memoryRead),
|
||||||
cmocka_unit_test(memoryWrite),
|
cmocka_unit_test(memoryWrite),
|
||||||
|
cmocka_unit_test(logging),
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in New Issue