Add start paused option
[lsnes.git] / src / lua / lua.cpp
blob2aa251641a796dbf71202eac3d8fdd57ec71eb43
1 #include "core/command.hpp"
2 #include "core/globalwrap.hpp"
3 #include "lua/internal.hpp"
4 #include "lua/lua.hpp"
5 #include "core/mainloop.hpp"
6 #include "core/memorymanip.hpp"
7 #include "core/misc.hpp"
9 #include <map>
10 #include <cstring>
11 #include <string>
12 #include <iostream>
13 extern "C" {
14 #include <lua.h>
15 #include <lualib.h>
18 uint64_t lua_idle_hook_time = 0x7EFFFFFFFFFFFFFFULL;
19 uint64_t lua_timer_hook_time = 0x7EFFFFFFFFFFFFFFULL;
21 namespace
23 globalwrap<std::map<std::string, lua_function*>> functions;
24 lua_State* lua_initialized;
25 int lua_trampoline_function(lua_State* L)
27 void* ptr = lua_touserdata(L, lua_upvalueindex(1));
28 lua_function* f = reinterpret_cast<lua_function*>(ptr);
29 try {
30 return f->invoke(L);
31 } catch(std::exception& e) {
32 lua_pushfstring(L, "Error in internal function: %s", e.what());
33 lua_error(L);
37 //Pushes given table to top of stack, creating if needed.
38 void recursive_lookup_table(lua_State* L, const std::string& tab)
40 if(tab == "") {
41 lua_getglobal(L, "_G");
42 return;
44 std::string u = tab;
45 size_t split = u.find_last_of(".");
46 std::string u1;
47 std::string u2 = u;
48 if(split < u.length()) {
49 u1 = u.substr(0, split);
50 u2 = u.substr(split + 1);
52 recursive_lookup_table(L, u1);
53 lua_getfield(L, -1, u2.c_str());
54 if(lua_type(L, -1) != LUA_TTABLE) {
55 //Not a table, create a table.
56 lua_pop(L, 1);
57 lua_newtable(L);
58 lua_setfield(L, -2, u2.c_str());
59 lua_getfield(L, -1, u2.c_str());
61 //Get rid of previous table.
62 lua_insert(L, -2);
63 lua_pop(L, 1);
66 void register_lua_function(lua_State* L, const std::string& fun)
68 std::string u = fun;
69 size_t split = u.find_last_of(".");
70 std::string u1;
71 std::string u2 = u;
72 if(split < u.length()) {
73 u1 = u.substr(0, split);
74 u2 = u.substr(split + 1);
76 recursive_lookup_table(L, u1);
77 void* ptr = reinterpret_cast<void*>(functions()[fun]);
78 lua_pushlightuserdata(L, ptr);
79 lua_pushcclosure(L, lua_trampoline_function, 1);
80 lua_setfield(L, -2, u2.c_str());
81 lua_pop(L, 1);
84 void register_lua_functions(lua_State* L)
86 for(auto i : functions())
87 register_lua_function(L, i.first);
88 lua_initialized = L;
92 lua_function::lua_function(const std::string& name) throw(std::bad_alloc)
94 functions()[fname = name] = this;
95 if(lua_initialized)
96 register_lua_function(lua_initialized, fname);
99 lua_function::~lua_function() throw()
101 functions().erase(fname);
104 std::string get_string_argument(lua_State* LS, unsigned argindex, const char* fname)
106 if(lua_isnone(LS, argindex)) {
107 char buffer[1024];
108 sprintf(buffer, "argument #%i to %s must be string", argindex, fname);
109 lua_pushstring(LS, buffer);
110 lua_error(LS);
112 size_t len;
113 const char* f = lua_tolstring(LS, argindex, &len);
114 if(!f) {
115 char buffer[1024];
116 sprintf(buffer, "argument #%i to %s must be string", argindex, fname);
117 lua_pushstring(LS, buffer);
118 lua_error(LS);
120 return std::string(f, f + len);
123 bool get_boolean_argument(lua_State* LS, unsigned argindex, const char* fname)
125 if(lua_isnone(LS, argindex) || !lua_isboolean(LS, argindex)) {
126 char buffer[1024];
127 sprintf(buffer, "argument #%i to %s must be boolean", argindex, fname);
128 lua_pushstring(LS, buffer);
129 lua_error(LS);
131 return (lua_toboolean(LS, argindex) != 0);
134 void push_keygroup_parameters(lua_State* LS, const struct keygroup::parameters& p)
136 lua_newtable(LS);
137 lua_pushstring(LS, "last_rawval");
138 lua_pushnumber(LS, p.last_rawval);
139 lua_settable(LS, -3);
140 lua_pushstring(LS, "cal_left");
141 lua_pushnumber(LS, p.cal_left);
142 lua_settable(LS, -3);
143 lua_pushstring(LS, "cal_center");
144 lua_pushnumber(LS, p.cal_center);
145 lua_settable(LS, -3);
146 lua_pushstring(LS, "cal_right");
147 lua_pushnumber(LS, p.cal_right);
148 lua_settable(LS, -3);
149 lua_pushstring(LS, "cal_tolerance");
150 lua_pushnumber(LS, p.cal_tolerance);
151 lua_settable(LS, -3);
152 lua_pushstring(LS, "ktype");
153 switch(p.ktype) {
154 case keygroup::KT_DISABLED: lua_pushstring(LS, "disabled"); break;
155 case keygroup::KT_KEY: lua_pushstring(LS, "key"); break;
156 case keygroup::KT_AXIS_PAIR: lua_pushstring(LS, "axis"); break;
157 case keygroup::KT_AXIS_PAIR_INVERSE: lua_pushstring(LS, "axis-inverse"); break;
158 case keygroup::KT_HAT: lua_pushstring(LS, "hat"); break;
159 case keygroup::KT_MOUSE: lua_pushstring(LS, "mouse"); break;
160 case keygroup::KT_PRESSURE_PM: lua_pushstring(LS, "pressure-pm"); break;
161 case keygroup::KT_PRESSURE_P0: lua_pushstring(LS, "pressure-p0"); break;
162 case keygroup::KT_PRESSURE_0M: lua_pushstring(LS, "pressure-0m"); break;
163 case keygroup::KT_PRESSURE_0P: lua_pushstring(LS, "pressure-0p"); break;
164 case keygroup::KT_PRESSURE_M0: lua_pushstring(LS, "pressure-m0"); break;
165 case keygroup::KT_PRESSURE_MP: lua_pushstring(LS, "pressure-mp"); break;
167 lua_settable(LS, -3);
170 lua_render_context* lua_render_ctx = NULL;
171 controller_frame* lua_input_controllerdata = NULL;
172 bool lua_booted_flag = false;
174 namespace
176 lua_State* L;
177 bool recursive_flag = false;
178 const char* luareader_fragment = NULL;
180 const char* read_lua_fragment(lua_State* LS, void* dummy, size_t* size)
182 if(luareader_fragment) {
183 const char* ret = luareader_fragment;
184 *size = strlen(luareader_fragment);
185 luareader_fragment = NULL;
186 return ret;
187 } else {
188 *size = 0;
189 return NULL;
193 void* alloc(void* user, void* old, size_t olds, size_t news)
195 if(news) {
196 void* m = realloc(old, news);
197 if(!m)
198 OOM_panic();
199 return m;
200 } else
201 free(old);
202 return NULL;
205 bool callback_exists(const char* name)
207 if(recursive_flag)
208 return false;
209 lua_getglobal(L, name);
210 int t = lua_type(L, -1);
211 if(t != LUA_TFUNCTION)
212 lua_pop(L, 1);
213 return (t == LUA_TFUNCTION);
216 void push_string(const std::string& s)
218 lua_pushlstring(L, s.c_str(), s.length());
221 void push_boolean(bool b)
223 lua_pushboolean(L, b ? 1 : 0);
226 #define TEMPORARY "LUAINTERP_INTERNAL_COMMAND_TEMPORARY"
228 const char* eval_lua_lua = "loadstring(" TEMPORARY ")();";
229 const char* run_lua_lua = "dofile(" TEMPORARY ");";
231 void run_lua_fragment() throw(std::bad_alloc)
233 if(recursive_flag)
234 return;
235 #if LUA_VERSION_NUM == 501
236 int t = lua_load(L, read_lua_fragment, NULL, "run_lua_fragment");
237 #endif
238 #if LUA_VERSION_NUM == 502
239 int t = lua_load(L, read_lua_fragment, NULL, "run_lua_fragment", "bt");
240 #endif
241 if(t == LUA_ERRSYNTAX) {
242 messages << "Can't run Lua: Internal syntax error: " << lua_tostring(L, -1) << std::endl;
243 lua_pop(L, 1);
244 return;
246 if(t == LUA_ERRMEM) {
247 messages << "Can't run Lua: Out of memory" << std::endl;
248 lua_pop(L, 1);
249 return;
251 recursive_flag = true;
252 int r = lua_pcall(L, 0, 0, 0);
253 recursive_flag = false;
254 if(r == LUA_ERRRUN) {
255 messages << "Error running Lua hunk: " << lua_tostring(L, -1) << std::endl;
256 lua_pop(L, 1);
258 if(r == LUA_ERRMEM) {
259 messages << "Error running Lua hunk: Out of memory" << std::endl;
260 lua_pop(L, 1);
262 if(r == LUA_ERRERR) {
263 messages << "Error running Lua hunk: Double Fault???" << std::endl;
264 lua_pop(L, 1);
266 if(lua_requests_repaint) {
267 lua_requests_repaint = false;
268 command::invokeC("repaint");
272 void do_eval_lua(const std::string& c) throw(std::bad_alloc)
274 push_string(c);
275 lua_setglobal(L, TEMPORARY);
276 luareader_fragment = eval_lua_lua;
277 run_lua_fragment();
280 void do_run_lua(const std::string& c) throw(std::bad_alloc)
282 push_string(c);
283 lua_setglobal(L, TEMPORARY);
284 luareader_fragment = run_lua_lua;
285 run_lua_fragment();
288 void run_lua_cb(int args) throw()
290 recursive_flag = true;
291 int r = lua_pcall(L, args, 0, 0);
292 recursive_flag = false;
293 if(r == LUA_ERRRUN) {
294 messages << "Error running Lua callback: " << lua_tostring(L, -1) << std::endl;
295 lua_pop(L, 1);
297 if(r == LUA_ERRMEM) {
298 messages << "Error running Lua callback: Out of memory" << std::endl;
299 lua_pop(L, 1);
301 if(r == LUA_ERRERR) {
302 messages << "Error running Lua callback: Double Fault???" << std::endl;
303 lua_pop(L, 1);
305 if(lua_requests_repaint) {
306 lua_requests_repaint = false;
307 command::invokeC("repaint");
311 int system_write_error(lua_State* L)
313 lua_pushstring(L, "_SYSTEM is write-protected");
314 lua_error(L);
315 return 0;
318 void copy_system_tables(lua_State* L)
320 lua_getglobal(L, "_G");
321 lua_newtable(L);
322 lua_pushnil(L);
323 while(lua_next(L, -3)) {
324 //Stack: _SYSTEM, KEY, VALUE
325 lua_pushvalue(L, -2);
326 lua_pushvalue(L, -2);
327 //Stack: _SYSTEM, KEY, VALUE, KEY, VALUE
328 lua_rawset(L, -5);
329 //Stack: _SYSTEM, KEY, VALUE
330 lua_pop(L, 1);
331 //Stack: _SYSTEM, KEY
333 lua_newtable(L);
334 lua_pushcfunction(L, system_write_error);
335 lua_setfield(L, -2, "__newindex");
336 lua_setmetatable(L, -2);
337 lua_setglobal(L, "_SYSTEM");
341 void lua_callback_do_paint(struct lua_render_context* ctx, bool non_synthetic) throw()
343 if(!callback_exists("on_paint"))
344 return;
345 lua_render_ctx = ctx;
346 push_boolean(non_synthetic);
347 run_lua_cb(1);
348 lua_render_ctx = NULL;
351 void lua_callback_do_video(struct lua_render_context* ctx) throw()
353 if(!callback_exists("on_video"))
354 return;
355 lua_render_ctx = ctx;
356 run_lua_cb(0);
357 lua_render_ctx = NULL;
360 void lua_callback_do_reset() throw()
362 if(!callback_exists("on_reset"))
363 return;
364 run_lua_cb(0);
367 void lua_callback_do_frame() throw()
369 if(!callback_exists("on_frame"))
370 return;
371 run_lua_cb(0);
374 void lua_callback_do_rewind() throw()
376 if(!callback_exists("on_rewind"))
377 return;
378 run_lua_cb(0);
381 void lua_callback_do_idle() throw()
383 lua_idle_hook_time = 0x7EFFFFFFFFFFFFFFULL;
384 if(!callback_exists("on_idle"))
385 return;
386 run_lua_cb(0);
389 void lua_callback_do_timer() throw()
391 lua_timer_hook_time = 0x7EFFFFFFFFFFFFFFULL;
392 if(!callback_exists("on_timer"))
393 return;
394 run_lua_cb(0);
397 void lua_callback_do_frame_emulated() throw()
399 if(!callback_exists("on_frame_emulated"))
400 return;
401 run_lua_cb(0);
404 void lua_callback_do_readwrite() throw()
406 if(!callback_exists("on_readwrite"))
407 return;
408 run_lua_cb(0);
411 void lua_callback_startup() throw()
413 lua_booted_flag = true;
414 if(!callback_exists("on_startup"))
415 return;
416 run_lua_cb(0);
419 void lua_callback_pre_load(const std::string& name) throw()
421 if(!callback_exists("on_pre_load"))
422 return;
423 push_string(name);
424 run_lua_cb(1);
427 void lua_callback_err_load(const std::string& name) throw()
429 if(!callback_exists("on_err_load"))
430 return;
431 push_string(name);
432 run_lua_cb(1);
435 void lua_callback_post_load(const std::string& name, bool was_state) throw()
437 if(!callback_exists("on_post_load"))
438 return;
439 push_string(name);
440 push_boolean(was_state);
441 run_lua_cb(2);
444 void lua_callback_pre_save(const std::string& name, bool is_state) throw()
446 if(!callback_exists("on_pre_save"))
447 return;
448 push_string(name);
449 push_boolean(is_state);
450 run_lua_cb(2);
453 void lua_callback_err_save(const std::string& name) throw()
455 if(!callback_exists("on_err_save"))
456 return;
457 push_string(name);
458 run_lua_cb(1);
461 void lua_callback_post_save(const std::string& name, bool is_state) throw()
463 if(!callback_exists("on_post_save"))
464 return;
465 push_string(name);
466 push_boolean(is_state);
467 run_lua_cb(2);
470 void lua_callback_do_input(controller_frame& data, bool subframe) throw()
472 if(!callback_exists("on_input"))
473 return;
474 lua_input_controllerdata = &data;
475 push_boolean(subframe);
476 run_lua_cb(1);
477 lua_input_controllerdata = NULL;
480 void lua_callback_snoop_input(uint32_t port, uint32_t controller, uint32_t index, short value) throw()
482 if(!callback_exists("on_snoop"))
483 return;
484 lua_pushnumber(L, port);
485 lua_pushnumber(L, controller);
486 lua_pushnumber(L, index);
487 lua_pushnumber(L, value);
488 run_lua_cb(4);
491 namespace
493 function_ptr_command<const std::string&> evaluate_lua("evaluate-lua", "Evaluate expression in Lua VM",
494 "Syntax: evaluate-lua <expression>\nEvaluates <expression> in Lua VM.\n",
495 [](const std::string& args) throw(std::bad_alloc, std::runtime_error) {
496 if(args == "")
497 throw std::runtime_error("Expected expression to evaluate");
498 do_eval_lua(args);
501 function_ptr_command<arg_filename> run_lua("run-lua", "Run Lua script in Lua VM",
502 "Syntax: run-lua <file>\nRuns <file> in Lua VM.\n",
503 [](arg_filename args) throw(std::bad_alloc, std::runtime_error)
505 do_run_lua(args);
509 void lua_callback_quit() throw()
511 if(!callback_exists("on_quit"))
512 return;
513 run_lua_cb(0);
516 void lua_callback_keyhook(const std::string& key, const struct keygroup::parameters& p) throw()
518 if(!callback_exists("on_keyhook"))
519 return;
520 lua_pushstring(L, key.c_str());
521 push_keygroup_parameters(L, p);
522 run_lua_cb(2);
525 void init_lua() throw()
527 L = lua_newstate(alloc, NULL);
528 if(!L) {
529 messages << "Can't initialize Lua." << std::endl;
530 fatal_error();
532 luaL_openlibs(L);
534 register_lua_functions(L);
535 copy_system_tables(L);
538 void quit_lua() throw()
540 if(lua_initialized)
541 lua_close(lua_initialized);
545 #define LUA_TIMED_HOOK_IDLE 0
546 #define LUA_TIMED_HOOK_TIMER 1
548 uint64_t lua_timed_hook(int timer) throw()
550 switch(timer) {
551 case LUA_TIMED_HOOK_IDLE:
552 return lua_idle_hook_time;
553 case LUA_TIMED_HOOK_TIMER:
554 return lua_timer_hook_time;
559 bool lua_requests_repaint = false;
560 bool lua_requests_subframe_paint = false;
561 bool lua_supported = true;