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 
11 struct mScriptBridge {
12 	struct Table engines;
13 	struct mDebugger* debugger;
14 };
15 
16 struct mScriptInfo {
17 	const char* name;
18 	struct VFile* vf;
19 	bool success;
20 };
21 
22 struct mScriptSymbol {
23 	const char* name;
24 	int32_t* out;
25 	bool success;
26 };
27 
_seDeinit(void * value)28 static void _seDeinit(void* value) {
29 	struct mScriptEngine* se = value;
30 	se->deinit(se);
31 }
32 
_seTryLoad(const char * key,void * value,void * user)33 static 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 
_seLookupSymbol(const char * key,void * value,void * user)42 static 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 
_seRun(const char * key,void * value,void * user)51 static 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
59 struct mScriptDebuggerEntry {
60 	enum mDebuggerEntryReason reason;
61 	struct mDebuggerEntryInfo* info;
62 };
63 
_seDebuggerEnter(const char * key,void * value,void * user)64 static 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 
mScriptBridgeCreate(void)72 struct 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 
mScriptBridgeDestroy(struct mScriptBridge * sb)79 void mScriptBridgeDestroy(struct mScriptBridge* sb) {
80 	HashTableDeinit(&sb->engines);
81 	free(sb);
82 }
83 
mScriptBridgeInstallEngine(struct mScriptBridge * sb,struct mScriptEngine * se)84 void 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
mScriptBridgeSetDebugger(struct mScriptBridge * sb,struct mDebugger * debugger)93 void mScriptBridgeSetDebugger(struct mScriptBridge* sb, struct mDebugger* debugger) {
94 	sb->debugger = debugger;
95 	debugger->bridge = sb;
96 }
97 
mScriptBridgeGetDebugger(struct mScriptBridge * sb)98 struct mDebugger* mScriptBridgeGetDebugger(struct mScriptBridge* sb) {
99 	return sb->debugger;
100 }
101 
mScriptBridgeDebuggerEntered(struct mScriptBridge * sb,enum mDebuggerEntryReason reason,struct mDebuggerEntryInfo * info)102 void 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 
mScriptBridgeRun(struct mScriptBridge * sb)111 void mScriptBridgeRun(struct mScriptBridge* sb) {
112 	HashTableEnumerate(&sb->engines, _seRun, NULL);
113 }
114 
mScriptBridgeLoadScript(struct mScriptBridge * sb,const char * name)115 bool 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 
mScriptBridgeLookupSymbol(struct mScriptBridge * sb,const char * name,int32_t * out)130 bool 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 }
139