Move files around a lot
[lsnes.git] / src / core / lua.cpp
blob92a83da11ac15d3dbef636c8e898deaf1739fd19
1 #include "core/lua.hpp"
3 #ifdef NO_LUA
4 struct lua_State { int x; };
5 lua_function::lua_function(const std::string& name) throw(std::bad_alloc) {}
6 lua_function::~lua_function() throw() {}
7 void lua_callback_do_paint(struct lua_render_context* ctx) throw() {}
8 void lua_callback_do_video(struct lua_render_context* ctx) throw() {}
9 void lua_callback_do_input(controls_t& data, bool subframe) throw() {}
10 void lua_callback_do_reset() throw() {}
11 void lua_callback_do_readwrite() throw() {}
12 void lua_callback_startup() throw() {}
13 void lua_callback_pre_load(const std::string& name) throw() {}
14 void lua_callback_err_load(const std::string& name) throw() {}
15 void lua_callback_post_load(const std::string& name, bool was_state) throw() {}
16 void lua_callback_pre_save(const std::string& name, bool is_state) throw() {}
17 void lua_callback_err_save(const std::string& name) throw() {}
18 void lua_callback_post_save(const std::string& name, bool is_state) throw() {}
19 void lua_callback_snoop_input(uint32_t port, uint32_t controller, uint32_t index, short value) throw() {}
20 void lua_callback_quit() throw() {}
21 void init_lua() throw() {}
22 bool lua_requests_repaint = false;
23 bool lua_requests_subframe_paint = false;
24 bool lua_supported = false;
25 #else
27 #include "core/command.hpp"
28 #include "core/globalwrap.hpp"
29 #include "core/lua-int.hpp"
30 #include "core/mainloop.hpp"
31 #include "core/memorymanip.hpp"
32 #include "core/misc.hpp"
34 #include <map>
35 #include <cstring>
36 #include <string>
37 #include <iostream>
38 extern "C" {
39 #include <lua.h>
40 #include <lualib.h>
43 namespace
45 globalwrap<std::map<std::string, lua_function*>> functions;
46 lua_State* lua_initialized;
47 int lua_trampoline_function(lua_State* L)
49 void* ptr = lua_touserdata(L, lua_upvalueindex(1));
50 lua_function* f = reinterpret_cast<lua_function*>(ptr);
51 return f->invoke(L);
54 //Pushes given table to top of stack, creating if needed.
55 void recursive_lookup_table(lua_State* L, const std::string& tab)
57 if(tab == "") {
58 lua_pushvalue(L, LUA_GLOBALSINDEX);
59 return;
61 std::string u = tab;
62 size_t split = u.find_last_of(".");
63 std::string u1;
64 std::string u2 = u;
65 if(split < u.length()) {
66 u1 = u.substr(0, split);
67 u2 = u.substr(split + 1);
69 recursive_lookup_table(L, u1);
70 lua_getfield(L, -1, u2.c_str());
71 if(lua_type(L, -1) != LUA_TTABLE) {
72 //Not a table, create a table.
73 lua_pop(L, 1);
74 lua_newtable(L);
75 lua_setfield(L, -2, u2.c_str());
76 lua_getfield(L, -1, u2.c_str());
78 //Get rid of previous table.
79 lua_insert(L, -2);
80 lua_pop(L, 1);
83 void register_lua_function(lua_State* L, const std::string& fun)
85 std::string u = fun;
86 size_t split = u.find_last_of(".");
87 std::string u1;
88 std::string u2 = u;
89 if(split < u.length()) {
90 u1 = u.substr(0, split);
91 u2 = u.substr(split + 1);
93 recursive_lookup_table(L, u1);
94 void* ptr = reinterpret_cast<void*>(functions()[fun]);
95 lua_pushlightuserdata(L, ptr);
96 lua_pushcclosure(L, lua_trampoline_function, 1);
97 lua_setfield(L, -2, u2.c_str());
98 lua_pop(L, 1);
101 void register_lua_functions(lua_State* L)
103 for(auto i : functions())
104 register_lua_function(L, i.first);
105 lua_initialized = L;
109 lua_function::lua_function(const std::string& name) throw(std::bad_alloc)
111 functions()[fname = name] = this;
112 if(lua_initialized)
113 register_lua_function(lua_initialized, fname);
116 lua_function::~lua_function() throw()
118 functions().erase(fname);
121 std::string get_string_argument(lua_State* LS, unsigned argindex, const char* fname)
123 if(lua_isnone(LS, argindex)) {
124 char buffer[1024];
125 sprintf(buffer, "argument #%i to %s must be string", argindex, fname);
126 lua_pushstring(LS, buffer);
127 lua_error(LS);
129 size_t len;
130 const char* f = lua_tolstring(LS, argindex, &len);
131 if(!f) {
132 char buffer[1024];
133 sprintf(buffer, "argument #%i to %s must be string", argindex, fname);
134 lua_pushstring(LS, buffer);
135 lua_error(LS);
137 return std::string(f, f + len);
140 bool get_boolean_argument(lua_State* LS, unsigned argindex, const char* fname)
142 if(lua_isnone(LS, argindex) || !lua_isboolean(LS, argindex)) {
143 char buffer[1024];
144 sprintf(buffer, "argument #%i to %s must be boolean", argindex, fname);
145 lua_pushstring(LS, buffer);
146 lua_error(LS);
148 return (lua_toboolean(LS, argindex) != 0);
151 lua_render_context* lua_render_ctx = NULL;
152 controls_t* lua_input_controllerdata = NULL;
154 namespace
156 lua_State* L;
157 bool recursive_flag = false;
158 const char* luareader_fragment = NULL;
160 const char* read_lua_fragment(lua_State* LS, void* dummy, size_t* size)
162 if(luareader_fragment) {
163 const char* ret = luareader_fragment;
164 *size = strlen(luareader_fragment);
165 luareader_fragment = NULL;
166 return ret;
167 } else {
168 *size = 0;
169 return NULL;
173 void* alloc(void* user, void* old, size_t olds, size_t news)
175 if(news) {
176 void* m = realloc(old, news);
177 if(!m)
178 OOM_panic();
179 return m;
180 } else
181 free(old);
182 return NULL;
185 bool callback_exists(const char* name)
187 if(recursive_flag)
188 return false;
189 lua_getglobal(L, name);
190 int t = lua_type(L, -1);
191 if(t != LUA_TFUNCTION)
192 lua_pop(L, 1);
193 return (t == LUA_TFUNCTION);
196 void push_string(const std::string& s)
198 lua_pushlstring(L, s.c_str(), s.length());
201 void push_boolean(bool b)
203 lua_pushboolean(L, b ? 1 : 0);
206 #define TEMPORARY "LUAINTERP_INTERNAL_COMMAND_TEMPORARY"
208 const char* eval_lua_lua = "loadstring(" TEMPORARY ")();";
209 const char* run_lua_lua = "dofile(" TEMPORARY ");";
211 void run_lua_fragment() throw(std::bad_alloc)
213 if(recursive_flag)
214 return;
215 int t = lua_load(L, read_lua_fragment, NULL, "run_lua_fragment");
216 if(t == LUA_ERRSYNTAX) {
217 messages << "Can't run Lua: Internal syntax error: " << lua_tostring(L, -1) << std::endl;
218 lua_pop(L, 1);
219 return;
221 if(t == LUA_ERRMEM) {
222 messages << "Can't run Lua: Out of memory" << std::endl;
223 lua_pop(L, 1);
224 return;
226 recursive_flag = true;
227 int r = lua_pcall(L, 0, 0, 0);
228 recursive_flag = false;
229 if(r == LUA_ERRRUN) {
230 messages << "Error running Lua hunk: " << lua_tostring(L, -1) << std::endl;
231 lua_pop(L, 1);
233 if(r == LUA_ERRMEM) {
234 messages << "Error running Lua hunk: Out of memory" << std::endl;
235 lua_pop(L, 1);
237 if(r == LUA_ERRERR) {
238 messages << "Error running Lua hunk: Double Fault???" << std::endl;
239 lua_pop(L, 1);
241 if(lua_requests_repaint) {
242 lua_requests_repaint = false;
243 command::invokeC("repaint");
247 void do_eval_lua(const std::string& c) throw(std::bad_alloc)
249 push_string(c);
250 lua_setglobal(L, TEMPORARY);
251 luareader_fragment = eval_lua_lua;
252 run_lua_fragment();
255 void do_run_lua(const std::string& c) throw(std::bad_alloc)
257 push_string(c);
258 lua_setglobal(L, TEMPORARY);
259 luareader_fragment = run_lua_lua;
260 run_lua_fragment();
263 void run_lua_cb(int args) throw()
265 recursive_flag = true;
266 int r = lua_pcall(L, args, 0, 0);
267 recursive_flag = false;
268 if(r == LUA_ERRRUN) {
269 messages << "Error running Lua callback: " << lua_tostring(L, -1) << std::endl;
270 lua_pop(L, 1);
272 if(r == LUA_ERRMEM) {
273 messages << "Error running Lua callback: Out of memory" << std::endl;
274 lua_pop(L, 1);
276 if(r == LUA_ERRERR) {
277 messages << "Error running Lua callback: Double Fault???" << std::endl;
278 lua_pop(L, 1);
280 if(lua_requests_repaint) {
281 lua_requests_repaint = false;
282 command::invokeC("repaint");
287 void lua_callback_do_paint(struct lua_render_context* ctx) throw()
289 if(!callback_exists("on_paint"))
290 return;
291 lua_render_ctx = ctx;
292 run_lua_cb(0);
293 lua_render_ctx = NULL;
296 void lua_callback_do_video(struct lua_render_context* ctx) throw()
298 if(!callback_exists("on_video"))
299 return;
300 lua_render_ctx = ctx;
301 run_lua_cb(0);
302 lua_render_ctx = NULL;
305 void lua_callback_do_reset() throw()
307 if(!callback_exists("on_reset"))
308 return;
309 run_lua_cb(0);
312 void lua_callback_do_readwrite() throw()
314 if(!callback_exists("on_readwrite"))
315 return;
316 run_lua_cb(0);
319 void lua_callback_startup() throw()
321 if(!callback_exists("on_startup"))
322 return;
323 run_lua_cb(0);
326 void lua_callback_pre_load(const std::string& name) throw()
328 if(!callback_exists("on_pre_load"))
329 return;
330 push_string(name);
331 run_lua_cb(1);
334 void lua_callback_err_load(const std::string& name) throw()
336 if(!callback_exists("on_err_load"))
337 return;
338 push_string(name);
339 run_lua_cb(1);
342 void lua_callback_post_load(const std::string& name, bool was_state) throw()
344 if(!callback_exists("on_post_load"))
345 return;
346 push_string(name);
347 push_boolean(was_state);
348 run_lua_cb(2);
351 void lua_callback_pre_save(const std::string& name, bool is_state) throw()
353 if(!callback_exists("on_pre_save"))
354 return;
355 push_string(name);
356 push_boolean(is_state);
357 run_lua_cb(2);
360 void lua_callback_err_save(const std::string& name) throw()
362 if(!callback_exists("on_err_save"))
363 return;
364 push_string(name);
365 run_lua_cb(1);
368 void lua_callback_post_save(const std::string& name, bool is_state) throw()
370 if(!callback_exists("on_post_save"))
371 return;
372 push_string(name);
373 push_boolean(is_state);
374 run_lua_cb(2);
377 void lua_callback_do_input(controls_t& data, bool subframe) throw()
379 if(!callback_exists("on_input"))
380 return;
381 lua_input_controllerdata = &data;
382 push_boolean(subframe);
383 run_lua_cb(1);
384 lua_input_controllerdata = NULL;
387 void lua_callback_snoop_input(uint32_t port, uint32_t controller, uint32_t index, short value) throw()
389 if(!callback_exists("on_snoop"))
390 return;
391 lua_pushnumber(L, port);
392 lua_pushnumber(L, controller);
393 lua_pushnumber(L, index);
394 lua_pushnumber(L, value);
395 run_lua_cb(4);
398 namespace
400 function_ptr_command<const std::string&> evaluate_lua("evaluate-lua", "Evaluate expression in Lua VM",
401 "Syntax: evaluate-lua <expression>\nEvaluates <expression> in Lua VM.\n",
402 [](const std::string& args) throw(std::bad_alloc, std::runtime_error) {
403 if(args == "")
404 throw std::runtime_error("Expected expression to evaluate");
405 do_eval_lua(args);
408 function_ptr_command<arg_filename> run_lua("run-lua", "Run Lua script in Lua VM",
409 "Syntax: run-lua <file>\nRuns <file> in Lua VM.\n",
410 [](arg_filename args) throw(std::bad_alloc, std::runtime_error)
412 do_run_lua(args);
416 void lua_callback_quit() throw()
418 if(!callback_exists("on_quit"))
419 return;
420 run_lua_cb(0);
423 void init_lua() throw()
425 L = lua_newstate(alloc, NULL);
426 if(!L) {
427 messages << "Can't initialize Lua." << std::endl;
428 fatal_error();
430 luaL_openlibs(L);
432 register_lua_functions(L);
435 bool lua_requests_repaint = false;
436 bool lua_requests_subframe_paint = false;
437 bool lua_supported = true;
438 #endif