Fix number of compile errors and warnings with GCC 14
[lsnes.git] / src / lua / lua.cpp
blob5b3ff46b9b90e6ea902d59fb358c4a4e5ed61fed
1 #include "cmdhelp/lua.hpp"
2 #include "core/command.hpp"
3 #include "core/misc.hpp"
4 #include "library/globalwrap.hpp"
5 #include "library/keyboard.hpp"
6 #include "library/memtracker.hpp"
7 #include "lua/internal.hpp"
8 #include "lua/lua.hpp"
9 #include "lua/unsaferewind.hpp"
10 #include "core/instance.hpp"
11 #include "core/mainloop.hpp"
12 #include "core/messages.hpp"
13 #include "core/memorymanip.hpp"
14 #include "core/moviedata.hpp"
15 #include "core/misc.hpp"
17 #include <map>
18 #include <cstring>
19 #include <string>
20 #include <iostream>
21 extern "C" {
22 #include <lualib.h>
25 extern const char* lua_sysrc_script;
27 lua::function_group lua_func_bit;
28 lua::function_group lua_func_misc;
29 lua::function_group lua_func_load;
30 lua::function_group lua_func_zip;
32 lua::class_group lua_class_callback;
33 lua::class_group lua_class_gui;
34 lua::class_group lua_class_bind;
35 lua::class_group lua_class_pure;
36 lua::class_group lua_class_movie;
37 lua::class_group lua_class_memory;
38 lua::class_group lua_class_fileio;
40 namespace
42 const char* lua_vm_id = "Lua VM";
43 typedef settingvar::model_int<32,1024> mb_model;
44 settingvar::supervariable<mb_model> SET_lua_maxmem(lsnes_setgrp, "lua-maxmem",
45 "Lua‣Maximum memory use (MB)", 128);
47 void pushpair(lua::state& L, std::string key, double value)
49 L.pushstring(key.c_str());
50 L.pushnumber(value);
51 L.settable(-3);
54 void pushpair(lua::state& L, std::string key, std::string value)
56 L.pushstring(key.c_str());
57 L.pushstring(value.c_str());
58 L.settable(-3);
61 std::string get_mode_str(int mode)
63 if(mode < 0)
64 return "disabled";
65 else if(mode > 0)
66 return "axis";
67 return "pressure0+";
71 void push_keygroup_parameters(lua::state& L, keyboard::key& p)
73 keyboard::mouse_calibration p2;
74 int mode;
75 L.newtable();
76 switch(p.get_type()) {
77 case keyboard::KBD_KEYTYPE_KEY:
78 pushpair(L, "value", p.get_state());
79 pushpair(L, "type", "key");
80 break;
81 case keyboard::KBD_KEYTYPE_HAT:
82 pushpair(L, "value", p.get_state());
83 pushpair(L, "type", "hat");
84 break;
85 case keyboard::KBD_KEYTYPE_MOUSE:
86 p2 = p.cast_mouse()->get_calibration();
87 pushpair(L, "value", p.get_state());
88 pushpair(L, "type", "mouse");
89 break;
90 case keyboard::KBD_KEYTYPE_AXIS:
91 mode = p.cast_axis()->get_mode();
92 pushpair(L, "value", p.get_state());
93 pushpair(L, "type", get_mode_str(mode));
94 break;
99 namespace
101 void soft_oom(int status)
103 if(status == 0)
104 messages << "Lua: Memory limit exceeded, attempting to free memory..." << std::endl;
105 if(status < 0)
106 messages << "Lua: Memory allocation still failed." << std::endl;
107 if(status > 0)
108 messages << "Lua: Allocation successful after freeing some memory." << std::endl;
111 int push_keygroup_parameters2(lua::state& L, keyboard::key* p)
113 push_keygroup_parameters(L, *p);
114 return 1;
118 const char* read_lua_fragment(lua_State* unused, void* fragment, size_t* size)
120 const char*& luareader_fragment = *reinterpret_cast<const char**>(fragment);
121 if(luareader_fragment) {
122 const char* ret = luareader_fragment;
123 *size = strlen(luareader_fragment);
124 luareader_fragment = NULL;
125 return ret;
126 } else {
127 *size = 0;
128 return NULL;
132 #define TEMPORARY "LUAINTERP_INTERNAL_COMMAND_TEMPORARY"
134 const char* CONST_eval_sysrc_lua = "local fn, err = " LUA_LOAD_CMD "(" TEMPORARY ", \"<built-in>\"); "
135 "if fn then fn(); else print2(\"Parse error in sysrc.lua script: \"..err); end;";
136 const char* CONST_eval_lua_lua = "local fn, err = " LUA_LOAD_CMD "(" TEMPORARY "); if fn then fn(); else "
137 " print(\"Parse error in Lua statement: \"..err); end;";
138 const char* CONST_run_lua_lua = "dofile(" TEMPORARY ");";
140 int system_write_error(lua::state& L)
142 throw std::runtime_error("_SYSTEM is write-protected");
145 void copy_system_tables(lua::state& L)
147 L.pushglobals();
148 L.newtable();
149 L.pushnil();
150 while(L.next(-3)) {
151 //Stack: _SYSTEM, KEY, VALUE
152 L.pushvalue(-2);
153 L.pushvalue(-2);
154 //Stack: _SYSTEM, KEY, VALUE, KEY, VALUE
155 L.rawset(-5);
156 //Stack: _SYSTEM, KEY, VALUE
157 L.pop(1);
158 //Stack: _SYSTEM, KEY
160 L.newtable();
161 L.push_trampoline(system_write_error, 0);
162 L.setfield(-2, "__newindex");
163 L.setmetatable(-2);
164 L.setglobal("_SYSTEM");
168 void lua_state::_listener::on_setting_change(settingvar::group& grp, const settingvar::base& val)
170 if(val.get_iname() == "lua-maxmem")
171 obj.set_memory_limit(dynamic_cast<const settingvar::variable<mb_model>*>(&val)->get());
174 void lua_state::set_memory_limit(size_t limit_mb)
176 L.set_memory_limit(limit_mb << 20);
179 lua_state::lua_state(lua::state& _L, command::group& _command, settingvar::group& settings)
180 : r16m_empty_frame_count(0), r16m_capture(nullptr), L(_L), command(_command),
181 resetcmd(command, CLUA::reset, [this]() { this->do_reset(); }),
182 evalcmd(command, CLUA::eval, [this](const std::string& a) { this->do_eval_lua(a); }),
183 evalcmd2(command, CLUA::eval2, [this](const std::string& a) { this->do_eval_lua(a); }),
184 runcmd(command, CLUA::run, [this](command::arg_filename a) { this->do_run_lua(a); }),
185 listener(settings, *this)
187 memset(r16m_fbuf, 0, 16);
188 requests_repaint = false;
189 requests_subframe_paint = false;
190 render_ctx = NULL;
191 input_controllerdata = NULL;
192 //We can't read the value of lua maxmem setting here (it crashes), so just set default, it will be changed
193 //if needed.
194 L.set_memory_limit(1 << 27);
195 memtracker::singleton()(lua_vm_id, L.get_memory_use());
196 L.set_memory_change_handler([](ssize_t delta) { memtracker::singleton()(lua_vm_id, delta); });
198 idle_hook_time = 0x7EFFFFFFFFFFFFFFULL;
199 timer_hook_time = 0x7EFFFFFFFFFFFFFFULL;
200 frob_output = NULL;
201 veto_flag = NULL;
202 kill_frame = NULL;
203 hscl = NULL;
204 vscl = NULL;
205 synchronous_paint_ctx = NULL;
206 recursive_flag = false;
207 luareader_fragment = NULL;
209 renderq_saved = NULL;
210 renderq_last = NULL;
211 renderq_redirect = false;
213 on_paint = new lua::state::callback_list(L, "paint", "on_paint");
214 on_video = new lua::state::callback_list(L, "video", "on_video");
215 on_reset = new lua::state::callback_list(L, "reset", "on_reset");
216 on_frame = new lua::state::callback_list(L, "frame", "on_frame");
217 on_rewind = new lua::state::callback_list(L, "rewind", "on_rewind");
218 on_idle = new lua::state::callback_list(L, "idle", "on_idle");
219 on_timer = new lua::state::callback_list(L, "timer", "on_timer");
220 on_frame_emulated = new lua::state::callback_list(L, "frame_emulated", "on_frame_emulated");
221 on_readwrite = new lua::state::callback_list(L, "readwrite", "on_readwrite");
222 on_startup = new lua::state::callback_list(L, "startup", "on_startup");
223 on_pre_load = new lua::state::callback_list(L, "pre_load", "on_pre_load");
224 on_post_load = new lua::state::callback_list(L, "post_load", "on_post_load");
225 on_err_load = new lua::state::callback_list(L, "err_load", "on_err_load");
226 on_pre_save = new lua::state::callback_list(L, "pre_save", "on_pre_save");
227 on_post_save = new lua::state::callback_list(L, "post_save", "on_post_save");
228 on_err_save = new lua::state::callback_list(L, "err_save", "on_err_save");
229 on_input = new lua::state::callback_list(L, "input", "on_input");
230 on_snoop = new lua::state::callback_list(L, "snoop", "on_snoop");
231 on_snoop2 = new lua::state::callback_list(L, "snoop2", "on_snoop2");
232 on_button = new lua::state::callback_list(L, "button", "on_button");
233 on_quit = new lua::state::callback_list(L, "quit", "on_quit");
234 on_keyhook = new lua::state::callback_list(L, "keyhook", "on_keyhook");
235 on_movie_lost = new lua::state::callback_list(L, "movie_lost", "on_movie_lost");
236 on_pre_rewind = new lua::state::callback_list(L, "pre_rewind", "on_pre_rewind");
237 on_post_rewind = new lua::state::callback_list(L, "post_rewind", "on_post_rewind");
238 on_set_rewind = new lua::state::callback_list(L, "set_rewind", "on_set_rewind");
239 on_latch = new lua::state::callback_list(L, "latch", "on_latch");
240 on_frob_with_value = new lua::state::callback_list(L, "frob_with_value", "on_frob_with_value");
243 lua_state::~lua_state()
245 delete on_paint;
246 delete on_video;
247 delete on_reset;
248 delete on_frame;
249 delete on_rewind;
250 delete on_idle;
251 delete on_timer;
252 delete on_frame_emulated;
253 delete on_readwrite;
254 delete on_startup;
255 delete on_pre_load;
256 delete on_post_load;
257 delete on_err_load;
258 delete on_pre_save;
259 delete on_post_save;
260 delete on_err_save;
261 delete on_input;
262 delete on_snoop;
263 delete on_snoop2;
264 delete on_button;
265 delete on_quit;
266 delete on_keyhook;
267 delete on_movie_lost;
268 delete on_pre_rewind;
269 delete on_post_rewind;
270 delete on_set_rewind;
271 delete on_latch;
272 delete on_frob_with_value;
275 void lua_state::callback_do_paint(struct lua::render_context* ctx, bool non_synthetic) throw()
277 run_synchronous_paint(ctx);
278 run_callback(*on_paint, lua::state::store_tag(render_ctx, ctx), lua::state::boolean_tag(non_synthetic));
281 void lua_state::callback_do_video(struct lua::render_context* ctx, bool& _kill_frame, uint32_t& _hscl,
282 uint32_t& _vscl) throw()
284 run_callback(*on_video, lua::state::store_tag(render_ctx, ctx), lua::state::store_tag(kill_frame,
285 &_kill_frame), lua::state::store_tag(hscl, &_hscl), lua::state::store_tag(vscl, &_vscl));
288 void lua_state::callback_do_reset() throw()
290 run_callback(*on_reset);
293 void lua_state::callback_do_frame() throw()
295 run_callback(*on_frame);
298 void lua_state::callback_do_rewind() throw()
300 run_callback(*on_rewind);
303 void lua_state::callback_do_idle() throw()
305 idle_hook_time = 0x7EFFFFFFFFFFFFFFULL;
306 run_callback(*on_idle);
309 void lua_state::callback_do_timer() throw()
311 timer_hook_time = 0x7EFFFFFFFFFFFFFFULL;
312 run_callback(*on_timer);
315 void lua_state::callback_do_frame_emulated() throw()
317 run_callback(*on_frame_emulated);
320 void lua_state::callback_do_readwrite() throw()
322 run_callback(*on_readwrite);
325 void lua_state::callback_pre_load(const std::string& name) throw()
327 run_callback(*on_pre_load, lua::state::string_tag(name));
330 void lua_state::callback_err_load(const std::string& name) throw()
332 run_callback(*on_err_load, lua::state::string_tag(name));
335 void lua_state::callback_post_load(const std::string& name, bool was_state) throw()
337 run_callback(*on_post_load, lua::state::string_tag(name), lua::state::boolean_tag(was_state));
340 void lua_state::callback_pre_save(const std::string& name, bool is_state) throw()
342 run_callback(*on_pre_save, lua::state::string_tag(name), lua::state::boolean_tag(is_state));
345 void lua_state::callback_err_save(const std::string& name) throw()
347 run_callback(*on_err_save, lua::state::string_tag(name));
350 void lua_state::callback_post_save(const std::string& name, bool is_state) throw()
352 run_callback(*on_post_save, lua::state::string_tag(name), lua::state::boolean_tag(is_state));
355 void lua_state::callback_do_input(portctrl::frame& data, bool subframe) throw()
357 run_callback(*on_input, lua::state::store_tag(input_controllerdata, &data),
358 lua::state::boolean_tag(subframe));
361 void lua_state::callback_snoop_input(uint32_t port, uint32_t controller, uint32_t index, short value) throw()
363 if(port >= 1 && port <= 2 && controller <= 3 && index <= 15 && r16m_capture) {
364 auto b = port * 8 + controller * 2 + index / 8 - 8;
365 r16m_fbuf[b] |= (value != 0) << (7 - index % 8);
367 if(run_callback(*on_snoop2, lua::state::numeric_tag(port), lua::state::numeric_tag(controller),
368 lua::state::numeric_tag(index), lua::state::numeric_tag(value)))
369 return;
370 run_callback(*on_snoop, lua::state::numeric_tag(port), lua::state::numeric_tag(controller),
371 lua::state::numeric_tag(index), lua::state::numeric_tag(value));
374 bool lua_state::callback_do_button(uint32_t port, uint32_t controller, uint32_t index, const char* type)
376 bool flag = false;
377 run_callback(*on_button, lua::state::store_tag(veto_flag, &flag), lua::state::numeric_tag(port),
378 lua::state::numeric_tag(controller), lua::state::numeric_tag(index), lua::state::string_tag(type));
379 return flag;
382 void lua_state::callback_frob_with_value(unsigned a, unsigned b, unsigned c, short& d)
384 short value = d;
385 run_callback(*on_frob_with_value, lua::state::store_tag(frob_output, &value), lua::state::numeric_tag(a),
386 lua::state::numeric_tag(b), lua::state::numeric_tag(c), lua::state::numeric_tag(d));
387 d = value;
390 namespace
392 lua::_class<lua_unsaferewind> LUA_class_unsaferewind(lua_class_movie, "UNSAFEREWIND", {}, {
393 }, &lua_unsaferewind::print);
396 void lua_state::do_reset()
398 L.reset();
399 luaL_openlibs(L.handle());
401 run_sysrc_lua(true);
402 copy_system_tables(L);
403 messages << "Lua VM reset" << std::endl;
406 void lua_state::do_evaluate(const std::string& a)
408 if(a == "")
409 throw std::runtime_error("Expected expression to evaluate");
410 do_eval_lua(a);
413 void lua_state::callback_quit() throw()
415 run_callback(*on_quit);
418 void lua_state::callback_keyhook(const std::string& key, keyboard::key& p) throw()
420 run_callback(*on_keyhook, lua::state::string_tag(key), lua::state::fnptr_tag(push_keygroup_parameters2, &p));
423 void init_lua(emulator_instance& core) throw()
425 core.lua->set_oom_handler(OOM_panic);
426 core.lua->set_soft_oom_handler(soft_oom);
427 try {
428 core.lua->reset();
429 core.lua->add_function_group(lua_func_bit);
430 core.lua->add_function_group(lua_func_load);
431 core.lua->add_function_group(lua_func_misc);
432 core.lua->add_function_group(lua_func_zip);
433 core.lua->add_class_group(lua_class_callback);
434 core.lua->add_class_group(lua_class_gui);
435 core.lua->add_class_group(lua_class_bind);
436 core.lua->add_class_group(lua_class_pure);
437 core.lua->add_class_group(lua_class_movie);
438 core.lua->add_class_group(lua_class_memory);
439 core.lua->add_class_group(lua_class_fileio);
440 } catch(std::exception& e) {
441 messages << "Can't initialize Lua." << std::endl;
442 fatal_error();
444 luaL_openlibs(core.lua->handle());
445 core.lua2->run_sysrc_lua(false);
446 copy_system_tables(*core.lua);
449 void quit_lua(emulator_instance& core) throw()
451 core.lua->deinit();
455 #define LUA_TIMED_HOOK_IDLE 0
456 #define LUA_TIMED_HOOK_TIMER 1
458 uint64_t lua_state::timed_hook(int timer) throw()
460 switch(timer) {
461 case LUA_TIMED_HOOK_IDLE:
462 return idle_hook_time;
463 case LUA_TIMED_HOOK_TIMER:
464 return timer_hook_time;
466 return 0;
469 void lua_state::callback_do_unsafe_rewind(movie& mov, void* u)
471 auto& core = CORE();
472 if(u) {
473 lua_unsaferewind* u2 = reinterpret_cast<lua::objpin<lua_unsaferewind>*>(u)->object();
474 //Load.
475 try {
476 run_callback(*on_pre_rewind);
477 run_callback(*on_movie_lost, "unsaferewind");
478 mainloop_restore_state(u2->console_state);
479 mov.fast_load(u2->console_state.save_frame, u2->ptr, u2->console_state.lagged_frames,
480 u2->console_state.pollcounters);
481 core.mlogic->get_mfile().dyn = u2->console_state;
482 run_callback(*on_post_rewind);
483 delete reinterpret_cast<lua::objpin<lua_unsaferewind>*>(u);
484 } catch(std::bad_alloc& e) {
485 OOM_panic();
486 } catch(...) {
487 return;
489 } else {
490 //Save
491 run_callback(*on_set_rewind, lua::state::fn_tag([&core, &mov](lua::state& L) ->
492 int {
493 lua_unsaferewind* u2 = lua::_class<lua_unsaferewind>::create(*core.lua);
494 u2->console_state = core.mlogic->get_mfile().dyn;
495 mov.fast_save(u2->console_state.save_frame, u2->ptr, u2->console_state.lagged_frames,
496 u2->console_state.pollcounters);
497 return 1;
498 }));
502 void lua_state::callback_movie_lost(const char* what)
504 run_callback(*on_movie_lost, std::string(what));
507 void flush_r16m_blank_frames(FILE* r16m_capture, uint64_t& r16m_empty_frame_count)
509 uint8_t dummy[16] = {0};
510 while(r16m_empty_frame_count > 0) {
511 if(fwrite(dummy, 16, 1, r16m_capture) < 1) {
512 messages << "Error writing to R16M dump." << std::endl;
514 r16m_empty_frame_count--;
518 void lua_state::set_r16m_dump(FILE* fp)
520 if(r16m_capture) {
521 //Do not flush here, as these are empty frames.
522 fclose(r16m_capture);
523 messages << "Closed R16M dump." << std::endl;
525 r16m_capture = fp;
526 memset(r16m_fbuf, 0, 16);
527 r16m_empty_frame_count = 0;
528 if(fp) {
529 messages << "Ready for R16M dump." << std::endl;
533 void lua_state::callback_do_latch(std::list<std::string>& args)
535 if(r16m_capture) {
536 uint8_t syndrome = 0;
537 for(int i = 0; i < 16; i++) { syndrome |= r16m_fbuf[i]; }
538 if(syndrome != 0) {
539 flush_r16m_blank_frames(r16m_capture, r16m_empty_frame_count);
540 if(fwrite(r16m_fbuf, 16, 1, r16m_capture) < 1) {
541 messages << "Error writing to R16M dump." << std::endl;
543 } else {
544 r16m_empty_frame_count++;
546 memset(r16m_fbuf, 0, 16);
548 run_callback(*on_latch, lua::state::vararg_tag(args));
551 lua_unsaferewind::lua_unsaferewind(lua::state& L)
555 void lua_state::run_startup_scripts()
557 for(auto i : startup_scripts) {
558 messages << "Trying to run Lua script: " << i << std::endl;
559 do_run_lua(i);
563 void lua_state::add_startup_script(const std::string& file)
565 startup_scripts.push_back(file);
568 const std::map<std::string, std::u32string>& lua_state::get_watch_vars()
570 return watch_vars;
573 bool lua_state::run_lua_fragment()
575 bool result = true;
576 if(recursive_flag)
577 return false;
578 int t = L.load(read_lua_fragment, &luareader_fragment, "run_lua_fragment", "t");
579 if(t == LUA_ERRSYNTAX) {
580 messages << "Can't run Lua: Internal syntax error: " << L.as_string(-1) << std::endl;
581 L.pop(1);
582 return false;
584 if(t == LUA_ERRMEM) {
585 messages << "Can't run Lua: Out of memory" << std::endl;
586 L.pop(1);
587 return false;
589 recursive_flag = true;
590 int r = L.pcall(0, 0, 0);
591 recursive_flag = false;
592 if(r == LUA_ERRRUN) {
593 auto msgptr = L.tostring(-1);
594 if(!msgptr) msgptr = "(null)";
595 messages << "Error running Lua hunk: " << L.as_string(-1) << std::endl;
596 L.pop(1);
597 result = false;
599 if(r == LUA_ERRMEM) {
600 messages << "Error running Lua hunk: Out of memory" << std::endl;
601 L.pop(1);
602 result = false;
604 if(r == LUA_ERRERR) {
605 messages << "Error running Lua hunk: Double Fault???" << std::endl;
606 L.pop(1);
607 result = false;
609 #ifdef LUA_ERRGCMM
610 if(r == LUA_ERRGCMM) {
611 messages << "Error running Lua hunk: Fault in garbage collector" << std::endl;
612 L.pop(1);
613 result = false;
615 #endif
616 render_ctx = NULL;
617 if(requests_repaint) {
618 requests_repaint = false;
619 command.invoke("repaint");
621 return result;
624 void lua_state::do_eval_lua(const std::string& c)
626 L.pushlstring(c.c_str(), c.length());
627 L.setglobal(TEMPORARY);
628 luareader_fragment = CONST_eval_lua_lua;
629 run_lua_fragment();
632 void lua_state::do_run_lua(const std::string& c)
634 L.pushlstring(c.c_str(), c.length());
635 L.setglobal(TEMPORARY);
636 luareader_fragment = CONST_run_lua_lua;
637 run_lua_fragment();
640 template<typename... T> bool lua_state::run_callback(lua::state::callback_list& list, T... args)
642 if(recursive_flag)
643 return true;
644 recursive_flag = true;
645 try {
646 if(!list.callback(args...)) {
647 recursive_flag = false;
648 return false;
650 } catch(std::exception& e) {
651 messages << e.what() << std::endl;
653 recursive_flag = false;
654 render_ctx = NULL;
655 if(requests_repaint) {
656 requests_repaint = false;
657 command.invoke("repaint");
659 return true;
662 void lua_state::run_sysrc_lua(bool rerun)
664 L.pushstring(lua_sysrc_script);
665 L.setglobal(TEMPORARY);
666 luareader_fragment = CONST_eval_sysrc_lua;
667 if(!run_lua_fragment() && !rerun) {
668 //run_lua_fragment shows error.
669 //messages << "Failed to run sysrc lua script" << std::endl;
670 fatal_error();
674 void lua_state::run_synchronous_paint(struct lua::render_context* ctx)
676 if(!synchronous_paint_ctx)
677 return;
678 lua_renderq_run(ctx, synchronous_paint_ctx);