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