Pack movie data in memory
[lsnes.git] / src / core / lua.cpp
blobbd4f3212983e37509f57083ed79345b9a97ab8d1
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(controller_frame& data, bool subframe) throw() {}
10 void lua_callback_do_reset() throw() {}
11 void lua_callback_do_frame() throw() {}
12 void lua_callback_do_readwrite() throw() {}
13 void lua_callback_startup() throw() {}
14 void lua_callback_pre_load(const std::string& name) throw() {}
15 void lua_callback_err_load(const std::string& name) throw() {}
16 void lua_callback_post_load(const std::string& name, bool was_state) throw() {}
17 void lua_callback_pre_save(const std::string& name, bool is_state) throw() {}
18 void lua_callback_err_save(const std::string& name) throw() {}
19 void lua_callback_post_save(const std::string& name, bool is_state) throw() {}
20 void lua_callback_snoop_input(uint32_t port, uint32_t controller, uint32_t index, short value) throw() {}
21 void lua_callback_quit() throw() {}
22 void init_lua() throw() {}
23 void quit_lua() throw() {}
24 bool lua_requests_repaint = false;
25 bool lua_requests_subframe_paint = false;
26 bool lua_supported = false;
27 #else
29 #include "core/command.hpp"
30 #include "core/globalwrap.hpp"
31 #include "core/lua-int.hpp"
32 #include "core/mainloop.hpp"
33 #include "core/memorymanip.hpp"
34 #include "core/misc.hpp"
36 #include <map>
37 #include <cstring>
38 #include <string>
39 #include <iostream>
40 extern "C" {
41 #include <lua.h>
42 #include <lualib.h>
45 namespace
47 globalwrap<std::map<std::string, lua_function*>> functions;
48 lua_State* lua_initialized;
49 int lua_trampoline_function(lua_State* L)
51 void* ptr = lua_touserdata(L, lua_upvalueindex(1));
52 lua_function* f = reinterpret_cast<lua_function*>(ptr);
53 return f->invoke(L);
56 //Pushes given table to top of stack, creating if needed.
57 void recursive_lookup_table(lua_State* L, const std::string& tab)
59 if(tab == "") {
60 lua_pushvalue(L, LUA_GLOBALSINDEX);
61 return;
63 std::string u = tab;
64 size_t split = u.find_last_of(".");
65 std::string u1;
66 std::string u2 = u;
67 if(split < u.length()) {
68 u1 = u.substr(0, split);
69 u2 = u.substr(split + 1);
71 recursive_lookup_table(L, u1);
72 lua_getfield(L, -1, u2.c_str());
73 if(lua_type(L, -1) != LUA_TTABLE) {
74 //Not a table, create a table.
75 lua_pop(L, 1);
76 lua_newtable(L);
77 lua_setfield(L, -2, u2.c_str());
78 lua_getfield(L, -1, u2.c_str());
80 //Get rid of previous table.
81 lua_insert(L, -2);
82 lua_pop(L, 1);
85 void register_lua_function(lua_State* L, const std::string& fun)
87 std::string u = fun;
88 size_t split = u.find_last_of(".");
89 std::string u1;
90 std::string u2 = u;
91 if(split < u.length()) {
92 u1 = u.substr(0, split);
93 u2 = u.substr(split + 1);
95 recursive_lookup_table(L, u1);
96 void* ptr = reinterpret_cast<void*>(functions()[fun]);
97 lua_pushlightuserdata(L, ptr);
98 lua_pushcclosure(L, lua_trampoline_function, 1);
99 lua_setfield(L, -2, u2.c_str());
100 lua_pop(L, 1);
103 void register_lua_functions(lua_State* L)
105 for(auto i : functions())
106 register_lua_function(L, i.first);
107 lua_initialized = L;
111 lua_function::lua_function(const std::string& name) throw(std::bad_alloc)
113 functions()[fname = name] = this;
114 if(lua_initialized)
115 register_lua_function(lua_initialized, fname);
118 lua_function::~lua_function() throw()
120 functions().erase(fname);
123 std::string get_string_argument(lua_State* LS, unsigned argindex, const char* fname)
125 if(lua_isnone(LS, argindex)) {
126 char buffer[1024];
127 sprintf(buffer, "argument #%i to %s must be string", argindex, fname);
128 lua_pushstring(LS, buffer);
129 lua_error(LS);
131 size_t len;
132 const char* f = lua_tolstring(LS, argindex, &len);
133 if(!f) {
134 char buffer[1024];
135 sprintf(buffer, "argument #%i to %s must be string", argindex, fname);
136 lua_pushstring(LS, buffer);
137 lua_error(LS);
139 return std::string(f, f + len);
142 bool get_boolean_argument(lua_State* LS, unsigned argindex, const char* fname)
144 if(lua_isnone(LS, argindex) || !lua_isboolean(LS, argindex)) {
145 char buffer[1024];
146 sprintf(buffer, "argument #%i to %s must be boolean", argindex, fname);
147 lua_pushstring(LS, buffer);
148 lua_error(LS);
150 return (lua_toboolean(LS, argindex) != 0);
153 lua_render_context* lua_render_ctx = NULL;
154 controller_frame* lua_input_controllerdata = NULL;
156 namespace
158 lua_State* L;
159 bool recursive_flag = false;
160 const char* luareader_fragment = NULL;
162 const char* read_lua_fragment(lua_State* LS, void* dummy, size_t* size)
164 if(luareader_fragment) {
165 const char* ret = luareader_fragment;
166 *size = strlen(luareader_fragment);
167 luareader_fragment = NULL;
168 return ret;
169 } else {
170 *size = 0;
171 return NULL;
175 void* alloc(void* user, void* old, size_t olds, size_t news)
177 if(news) {
178 void* m = realloc(old, news);
179 if(!m)
180 OOM_panic();
181 return m;
182 } else
183 free(old);
184 return NULL;
187 bool callback_exists(const char* name)
189 if(recursive_flag)
190 return false;
191 lua_getglobal(L, name);
192 int t = lua_type(L, -1);
193 if(t != LUA_TFUNCTION)
194 lua_pop(L, 1);
195 return (t == LUA_TFUNCTION);
198 void push_string(const std::string& s)
200 lua_pushlstring(L, s.c_str(), s.length());
203 void push_boolean(bool b)
205 lua_pushboolean(L, b ? 1 : 0);
208 #define TEMPORARY "LUAINTERP_INTERNAL_COMMAND_TEMPORARY"
210 const char* eval_lua_lua = "loadstring(" TEMPORARY ")();";
211 const char* run_lua_lua = "dofile(" TEMPORARY ");";
213 void run_lua_fragment() throw(std::bad_alloc)
215 if(recursive_flag)
216 return;
217 int t = lua_load(L, read_lua_fragment, NULL, "run_lua_fragment");
218 if(t == LUA_ERRSYNTAX) {
219 messages << "Can't run Lua: Internal syntax error: " << lua_tostring(L, -1) << std::endl;
220 lua_pop(L, 1);
221 return;
223 if(t == LUA_ERRMEM) {
224 messages << "Can't run Lua: Out of memory" << std::endl;
225 lua_pop(L, 1);
226 return;
228 recursive_flag = true;
229 int r = lua_pcall(L, 0, 0, 0);
230 recursive_flag = false;
231 if(r == LUA_ERRRUN) {
232 messages << "Error running Lua hunk: " << lua_tostring(L, -1) << std::endl;
233 lua_pop(L, 1);
235 if(r == LUA_ERRMEM) {
236 messages << "Error running Lua hunk: Out of memory" << std::endl;
237 lua_pop(L, 1);
239 if(r == LUA_ERRERR) {
240 messages << "Error running Lua hunk: Double Fault???" << std::endl;
241 lua_pop(L, 1);
243 if(lua_requests_repaint) {
244 lua_requests_repaint = false;
245 command::invokeC("repaint");
249 void do_eval_lua(const std::string& c) throw(std::bad_alloc)
251 push_string(c);
252 lua_setglobal(L, TEMPORARY);
253 luareader_fragment = eval_lua_lua;
254 run_lua_fragment();
257 void do_run_lua(const std::string& c) throw(std::bad_alloc)
259 push_string(c);
260 lua_setglobal(L, TEMPORARY);
261 luareader_fragment = run_lua_lua;
262 run_lua_fragment();
265 void run_lua_cb(int args) throw()
267 recursive_flag = true;
268 int r = lua_pcall(L, args, 0, 0);
269 recursive_flag = false;
270 if(r == LUA_ERRRUN) {
271 messages << "Error running Lua callback: " << lua_tostring(L, -1) << std::endl;
272 lua_pop(L, 1);
274 if(r == LUA_ERRMEM) {
275 messages << "Error running Lua callback: Out of memory" << std::endl;
276 lua_pop(L, 1);
278 if(r == LUA_ERRERR) {
279 messages << "Error running Lua callback: Double Fault???" << std::endl;
280 lua_pop(L, 1);
282 if(lua_requests_repaint) {
283 lua_requests_repaint = false;
284 command::invokeC("repaint");
288 int system_write_error(lua_State* L)
290 lua_pushstring(L, "_SYSTEM is write-protected");
291 lua_error(L);
292 return 0;
295 void copy_system_tables(lua_State* L)
297 lua_newtable(L);
298 lua_pushnil(L);
299 while(lua_next(L, LUA_GLOBALSINDEX)) {
300 //Stack: _SYSTEM, KEY, VALUE
301 lua_pushvalue(L, -2);
302 lua_pushvalue(L, -2);
303 //Stack: _SYSTEM, KEY, VALUE, KEY, VALUE
304 lua_rawset(L, -5);
305 //Stack: _SYSTEM, KEY, VALUE
306 lua_pop(L, 1);
307 //Stack: _SYSTEM, KEY
309 lua_newtable(L);
310 lua_pushcfunction(L, system_write_error);
311 lua_setfield(L, -2, "__newindex");
312 lua_setmetatable(L, -2);
313 lua_setglobal(L, "_SYSTEM");
317 void lua_callback_do_paint(struct lua_render_context* ctx) throw()
319 if(!callback_exists("on_paint"))
320 return;
321 lua_render_ctx = ctx;
322 run_lua_cb(0);
323 lua_render_ctx = NULL;
326 void lua_callback_do_video(struct lua_render_context* ctx) throw()
328 if(!callback_exists("on_video"))
329 return;
330 lua_render_ctx = ctx;
331 run_lua_cb(0);
332 lua_render_ctx = NULL;
335 void lua_callback_do_reset() throw()
337 if(!callback_exists("on_reset"))
338 return;
339 run_lua_cb(0);
342 void lua_callback_do_frame() throw()
344 if(!callback_exists("on_frame"))
345 return;
346 run_lua_cb(0);
349 void lua_callback_do_readwrite() throw()
351 if(!callback_exists("on_readwrite"))
352 return;
353 run_lua_cb(0);
356 void lua_callback_startup() throw()
358 if(!callback_exists("on_startup"))
359 return;
360 run_lua_cb(0);
363 void lua_callback_pre_load(const std::string& name) throw()
365 if(!callback_exists("on_pre_load"))
366 return;
367 push_string(name);
368 run_lua_cb(1);
371 void lua_callback_err_load(const std::string& name) throw()
373 if(!callback_exists("on_err_load"))
374 return;
375 push_string(name);
376 run_lua_cb(1);
379 void lua_callback_post_load(const std::string& name, bool was_state) throw()
381 if(!callback_exists("on_post_load"))
382 return;
383 push_string(name);
384 push_boolean(was_state);
385 run_lua_cb(2);
388 void lua_callback_pre_save(const std::string& name, bool is_state) throw()
390 if(!callback_exists("on_pre_save"))
391 return;
392 push_string(name);
393 push_boolean(is_state);
394 run_lua_cb(2);
397 void lua_callback_err_save(const std::string& name) throw()
399 if(!callback_exists("on_err_save"))
400 return;
401 push_string(name);
402 run_lua_cb(1);
405 void lua_callback_post_save(const std::string& name, bool is_state) throw()
407 if(!callback_exists("on_post_save"))
408 return;
409 push_string(name);
410 push_boolean(is_state);
411 run_lua_cb(2);
414 void lua_callback_do_input(controller_frame& data, bool subframe) throw()
416 if(!callback_exists("on_input"))
417 return;
418 lua_input_controllerdata = &data;
419 push_boolean(subframe);
420 run_lua_cb(1);
421 lua_input_controllerdata = NULL;
424 void lua_callback_snoop_input(uint32_t port, uint32_t controller, uint32_t index, short value) throw()
426 if(!callback_exists("on_snoop"))
427 return;
428 lua_pushnumber(L, port);
429 lua_pushnumber(L, controller);
430 lua_pushnumber(L, index);
431 lua_pushnumber(L, value);
432 run_lua_cb(4);
435 namespace
437 function_ptr_command<const std::string&> evaluate_lua("evaluate-lua", "Evaluate expression in Lua VM",
438 "Syntax: evaluate-lua <expression>\nEvaluates <expression> in Lua VM.\n",
439 [](const std::string& args) throw(std::bad_alloc, std::runtime_error) {
440 if(args == "")
441 throw std::runtime_error("Expected expression to evaluate");
442 do_eval_lua(args);
445 function_ptr_command<arg_filename> run_lua("run-lua", "Run Lua script in Lua VM",
446 "Syntax: run-lua <file>\nRuns <file> in Lua VM.\n",
447 [](arg_filename args) throw(std::bad_alloc, std::runtime_error)
449 do_run_lua(args);
453 void lua_callback_quit() throw()
455 if(!callback_exists("on_quit"))
456 return;
457 run_lua_cb(0);
460 void init_lua() throw()
462 L = lua_newstate(alloc, NULL);
463 if(!L) {
464 messages << "Can't initialize Lua." << std::endl;
465 fatal_error();
467 luaL_openlibs(L);
469 register_lua_functions(L);
470 copy_system_tables(L);
473 void quit_lua() throw()
475 if(lua_initialized)
476 lua_close(lua_initialized);
479 bool lua_requests_repaint = false;
480 bool lua_requests_subframe_paint = false;
481 bool lua_supported = true;
482 #endif