all repos — mgba @ 1093849ad5f6103d8eb1817e9b913255a3218eb9

mGBA Game Boy Advance Emulator

src/core/scripting.c (view raw)

  1/* Copyright (c) 2013-2017 Jeffrey Pfau
  2 *
  3 * This Source Code Form is subject to the terms of the Mozilla Public
  4 * License, v. 2.0. If a copy of the MPL was not distributed with this
  5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  6#include <mgba/core/scripting.h>
  7
  8#include <mgba-util/table.h>
  9#include <mgba-util/vfs.h>
 10
 11struct mScriptBridge {
 12	struct Table engines;
 13	struct mDebugger* debugger;
 14};
 15
 16struct mScriptInfo {
 17	const char* name;
 18	struct VFile* vf;
 19	bool success;
 20};
 21
 22struct mScriptSymbol {
 23	const char* name;
 24	int32_t* out;
 25	bool success;
 26};
 27
 28static void _seDeinit(void* value) {
 29	struct mScriptEngine* se = value;
 30	se->deinit(se);
 31}
 32
 33static void _seTryLoad(const char* key, void* value, void* user) {
 34	UNUSED(key);
 35	struct mScriptEngine* se = value;
 36	struct mScriptInfo* si = user;
 37	if (!si->success && se->isScript(se, si->name, si->vf)) {
 38		si->success = se->loadScript(se, si->name, si->vf);
 39	}
 40}
 41
 42static void _seLookupSymbol(const char* key, void* value, void* user) {
 43	UNUSED(key);
 44	struct mScriptEngine* se = value;
 45	struct mScriptSymbol* si = user;
 46	if (!si->success) {
 47		si->success = se->lookupSymbol(se, si->name, si->out);
 48	}
 49}
 50
 51static void _seRun(const char* key, void* value, void* user) {
 52	UNUSED(key);
 53	UNUSED(user);
 54	struct mScriptEngine* se = value;
 55	se->run(se);
 56}
 57
 58#ifdef USE_DEBUGGERS
 59struct mScriptDebuggerEntry {
 60	enum mDebuggerEntryReason reason;
 61	struct mDebuggerEntryInfo* info;
 62};
 63
 64static void _seDebuggerEnter(const char* key, void* value, void* user) {
 65	UNUSED(key);
 66	struct mScriptEngine* se = value;
 67	struct mScriptDebuggerEntry* entry = user;
 68	se->debuggerEntered(se, entry->reason, entry->info);
 69}
 70#endif
 71
 72struct mScriptBridge* mScriptBridgeCreate(void) {
 73	struct mScriptBridge* sb = malloc(sizeof(*sb));
 74	HashTableInit(&sb->engines, 0, _seDeinit);
 75	sb->debugger = NULL;
 76	return sb;
 77}
 78
 79void mScriptBridgeDestroy(struct mScriptBridge* sb) {
 80	HashTableDeinit(&sb->engines);
 81	free(sb);
 82}
 83
 84void mScriptBridgeInstallEngine(struct mScriptBridge* sb, struct mScriptEngine* se) {
 85	if (!se->init(se, sb)) {
 86		return;
 87	}
 88	const char* name = se->name(se);
 89	HashTableInsert(&sb->engines, name, se);
 90}
 91
 92#ifdef USE_DEBUGGERS
 93void mScriptBridgeSetDebugger(struct mScriptBridge* sb, struct mDebugger* debugger) {
 94	sb->debugger = debugger;
 95	debugger->bridge = sb;
 96}
 97
 98struct mDebugger* mScriptBridgeGetDebugger(struct mScriptBridge* sb) {
 99	return sb->debugger;
100}
101
102void mScriptBridgeDebuggerEntered(struct mScriptBridge* sb, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) {
103	struct mScriptDebuggerEntry entry = {
104		.reason = reason,
105		.info = info
106	};
107	HashTableEnumerate(&sb->engines, _seDebuggerEnter, &entry);
108}
109#endif
110
111void mScriptBridgeRun(struct mScriptBridge* sb) {
112	HashTableEnumerate(&sb->engines, _seRun, NULL);
113}
114
115bool mScriptBridgeLoadScript(struct mScriptBridge* sb, const char* name) {
116	struct VFile* vf = VFileOpen(name, O_RDONLY);
117	if (!vf) {
118		return false;
119	}
120	struct mScriptInfo info = {
121		.name = name,
122		.vf = vf,
123		.success = false
124	};
125	HashTableEnumerate(&sb->engines, _seTryLoad, &info);
126	vf->close(vf);
127	return info.success;
128}
129
130bool mScriptBridgeLookupSymbol(struct mScriptBridge* sb, const char* name, int32_t* out) {
131	struct mScriptSymbol info = {
132		.name = name,
133		.out = out,
134		.success = false
135	};
136	HashTableEnumerate(&sb->engines, _seLookupSymbol, &info);
137	return info.success;
138}