Evdev joystick plugin
[lsnes.git] / generic / lua.cpp
blobb9d9673c7b6d1bca4f2b919fcf531edb2a690c9d
1 #include "lua.hpp"
2 #ifdef NO_LUA
3 struct lua_State { int x; };
4 lua_function::lua_function(const std::string& name) throw(std::bad_alloc) {}
5 lua_function::~lua_function() throw() {}
6 void lua_callback_do_paint(struct lua_render_context* ctx) throw() {}
7 void lua_callback_do_video(struct lua_render_context* ctx) throw() {}
8 void lua_callback_do_input(controls_t& data, bool subframe) throw() {}
9 void lua_callback_do_reset() throw() {}
10 void lua_callback_do_readwrite() throw() {}
11 void lua_callback_startup() throw() {}
12 void lua_callback_pre_load(const std::string& name) throw() {}
13 void lua_callback_err_load(const std::string& name) throw() {}
14 void lua_callback_post_load(const std::string& name, bool was_state) throw() {}
15 void lua_callback_pre_save(const std::string& name, bool is_state) throw() {}
16 void lua_callback_err_save(const std::string& name) throw() {}
17 void lua_callback_post_save(const std::string& name, bool is_state) throw() {}
18 void lua_callback_snoop_input(uint32_t port, uint32_t controller, uint32_t index, short value) throw() {}
19 void lua_callback_quit() throw() {}
20 void init_lua() throw() {}
21 bool lua_requests_repaint = false;
22 bool lua_requests_subframe_paint = false;
23 #else
25 #include "lua-int.hpp"
26 #include "command.hpp"
27 #include "misc.hpp"
28 #include "memorymanip.hpp"
29 #include "mainloop.hpp"
30 #include "globalwrap.hpp"
31 #include <map>
32 #include <cstring>
33 #include <string>
34 extern "C" {
35 #include <lua.h>
36 #include <lualib.h>
38 #include <iostream>
40 namespace
42 globalwrap<std::map<std::string, lua_function*>> functions;
43 lua_State* lua_initialized;
44 int lua_trampoline_function(lua_State* L)
46 void* ptr = lua_touserdata(L, lua_upvalueindex(1));
47 lua_function* f = reinterpret_cast<lua_function*>(ptr);
48 return f->invoke(L);
51 //Pushes given table to top of stack, creating if needed.
52 void recursive_lookup_table(lua_State* L, const std::string& tab)
54 if(tab == "") {
55 lua_pushvalue(L, LUA_GLOBALSINDEX);
56 return;
58 std::string u = tab;
59 size_t split = u.find_last_of(".");
60 std::string u1;
61 std::string u2 = u;
62 if(split < u.length()) {
63 u1 = u.substr(0, split);
64 u2 = u.substr(split + 1);
66 recursive_lookup_table(L, u1);
67 lua_getfield(L, -1, u2.c_str());
68 if(lua_type(L, -1) != LUA_TTABLE) {
69 //Not a table, create a table.
70 lua_pop(L, 1);
71 lua_newtable(L);
72 lua_setfield(L, -2, u2.c_str());
73 lua_getfield(L, -1, u2.c_str());
75 //Get rid of previous table.
76 lua_insert(L, -2);
77 lua_pop(L, 1);
80 void register_lua_function(lua_State* L, const std::string& fun)
82 std::string u = fun;
83 size_t split = u.find_last_of(".");
84 std::string u1;
85 std::string u2 = u;
86 if(split < u.length()) {
87 u1 = u.substr(0, split);
88 u2 = u.substr(split + 1);
90 recursive_lookup_table(L, u1);
91 void* ptr = reinterpret_cast<void*>(functions()[fun]);
92 lua_pushlightuserdata(L, ptr);
93 lua_pushcclosure(L, lua_trampoline_function, 1);
94 lua_setfield(L, -2, u2.c_str());
95 lua_pop(L, 1);
98 void register_lua_functions(lua_State* L)
100 for(auto i : functions())
101 register_lua_function(L, i.first);
102 lua_initialized = L;
106 lua_function::lua_function(const std::string& name) throw(std::bad_alloc)
108 functions()[fname = name] = this;
109 if(lua_initialized)
110 register_lua_function(lua_initialized, fname);
113 lua_function::~lua_function() throw()
115 functions().erase(fname);
118 std::string get_string_argument(lua_State* LS, unsigned argindex, const char* fname)
120 if(lua_isnone(LS, argindex)) {
121 char buffer[1024];
122 sprintf(buffer, "argument #%i to %s must be string", argindex, fname);
123 lua_pushstring(LS, buffer);
124 lua_error(LS);
126 size_t len;
127 const char* f = lua_tolstring(LS, argindex, &len);
128 if(!f) {
129 char buffer[1024];
130 sprintf(buffer, "argument #%i to %s must be string", argindex, fname);
131 lua_pushstring(LS, buffer);
132 lua_error(LS);
134 return std::string(f, f + len);
137 bool get_boolean_argument(lua_State* LS, unsigned argindex, const char* fname)
139 if(lua_isnone(LS, argindex) || !lua_isboolean(LS, argindex)) {
140 char buffer[1024];
141 sprintf(buffer, "argument #%i to %s must be boolean", argindex, fname);
142 lua_pushstring(LS, buffer);
143 lua_error(LS);
145 return (lua_toboolean(LS, argindex) != 0);
148 lua_render_context* lua_render_ctx = NULL;
149 controls_t* lua_input_controllerdata = NULL;
151 namespace
153 lua_State* L;
154 bool recursive_flag = false;
155 const char* luareader_fragment = NULL;
157 const char* read_lua_fragment(lua_State* LS, void* dummy, size_t* size)
159 if(luareader_fragment) {
160 const char* ret = luareader_fragment;
161 *size = strlen(luareader_fragment);
162 luareader_fragment = NULL;
163 return ret;
164 } else {
165 *size = 0;
166 return NULL;
170 void* alloc(void* user, void* old, size_t olds, size_t news)
172 if(news) {
173 void* m = realloc(old, news);
174 if(!m)
175 OOM_panic();
176 return m;
177 } else
178 free(old);
179 return NULL;
182 bool callback_exists(const char* name)
184 if(recursive_flag)
185 return false;
186 lua_getglobal(L, name);
187 int t = lua_type(L, -1);
188 if(t != LUA_TFUNCTION)
189 lua_pop(L, 1);
190 return (t == LUA_TFUNCTION);
193 void push_string(const std::string& s)
195 lua_pushlstring(L, s.c_str(), s.length());
198 void push_boolean(bool b)
200 lua_pushboolean(L, b ? 1 : 0);
203 #define TEMPORARY "LUAINTERP_INTERNAL_COMMAND_TEMPORARY"
205 const char* eval_lua_lua = "loadstring(" TEMPORARY ")();";
206 const char* run_lua_lua = "dofile(" TEMPORARY ");";
208 void run_lua_fragment() throw(std::bad_alloc)
210 if(recursive_flag)
211 return;
212 int t = lua_load(L, read_lua_fragment, NULL, "run_lua_fragment");
213 if(t == LUA_ERRSYNTAX) {
214 messages << "Can't run Lua: Internal syntax error: " << lua_tostring(L, -1) << std::endl;
215 lua_pop(L, 1);
216 return;
218 if(t == LUA_ERRMEM) {
219 messages << "Can't run Lua: Out of memory" << std::endl;
220 lua_pop(L, 1);
221 return;
223 recursive_flag = true;
224 int r = lua_pcall(L, 0, 0, 0);
225 recursive_flag = false;
226 if(r == LUA_ERRRUN) {
227 messages << "Error running Lua hunk: " << lua_tostring(L, -1) << std::endl;
228 lua_pop(L, 1);
230 if(r == LUA_ERRMEM) {
231 messages << "Error running Lua hunk: Out of memory" << std::endl;
232 lua_pop(L, 1);
234 if(r == LUA_ERRERR) {
235 messages << "Error running Lua hunk: Double Fault???" << std::endl;
236 lua_pop(L, 1);
238 if(lua_requests_repaint) {
239 lua_requests_repaint = false;
240 command::invokeC("repaint");
244 void do_eval_lua(const std::string& c) throw(std::bad_alloc)
246 push_string(c);
247 lua_setglobal(L, TEMPORARY);
248 luareader_fragment = eval_lua_lua;
249 run_lua_fragment();
252 void do_run_lua(const std::string& c) throw(std::bad_alloc)
254 push_string(c);
255 lua_setglobal(L, TEMPORARY);
256 luareader_fragment = run_lua_lua;
257 run_lua_fragment();
260 void run_lua_cb(int args) throw()
262 recursive_flag = true;
263 int r = lua_pcall(L, args, 0, 0);
264 recursive_flag = false;
265 if(r == LUA_ERRRUN) {
266 messages << "Error running Lua callback: " << lua_tostring(L, -1) << std::endl;
267 lua_pop(L, 1);
269 if(r == LUA_ERRMEM) {
270 messages << "Error running Lua callback: Out of memory" << std::endl;
271 lua_pop(L, 1);
273 if(r == LUA_ERRERR) {
274 messages << "Error running Lua callback: Double Fault???" << std::endl;
275 lua_pop(L, 1);
277 if(lua_requests_repaint) {
278 lua_requests_repaint = false;
279 command::invokeC("repaint");
284 void lua_callback_do_paint(struct lua_render_context* ctx) throw()
286 if(!callback_exists("on_paint"))
287 return;
288 lua_render_ctx = ctx;
289 run_lua_cb(0);
290 lua_render_ctx = NULL;
293 void lua_callback_do_video(struct lua_render_context* ctx) throw()
295 if(!callback_exists("on_video"))
296 return;
297 lua_render_ctx = ctx;
298 run_lua_cb(0);
299 lua_render_ctx = NULL;
302 void lua_callback_do_reset() throw()
304 if(!callback_exists("on_reset"))
305 return;
306 run_lua_cb(0);
309 void lua_callback_do_readwrite() throw()
311 if(!callback_exists("on_readwrite"))
312 return;
313 run_lua_cb(0);
316 void lua_callback_startup() throw()
318 if(!callback_exists("on_startup"))
319 return;
320 run_lua_cb(0);
323 void lua_callback_pre_load(const std::string& name) throw()
325 if(!callback_exists("on_pre_load"))
326 return;
327 push_string(name);
328 run_lua_cb(1);
331 void lua_callback_err_load(const std::string& name) throw()
333 if(!callback_exists("on_err_load"))
334 return;
335 push_string(name);
336 run_lua_cb(1);
339 void lua_callback_post_load(const std::string& name, bool was_state) throw()
341 if(!callback_exists("on_post_load"))
342 return;
343 push_string(name);
344 push_boolean(was_state);
345 run_lua_cb(2);
348 void lua_callback_pre_save(const std::string& name, bool is_state) throw()
350 if(!callback_exists("on_pre_save"))
351 return;
352 push_string(name);
353 push_boolean(is_state);
354 run_lua_cb(2);
357 void lua_callback_err_save(const std::string& name) throw()
359 if(!callback_exists("on_err_save"))
360 return;
361 push_string(name);
362 run_lua_cb(1);
365 void lua_callback_post_save(const std::string& name, bool is_state) throw()
367 if(!callback_exists("on_post_save"))
368 return;
369 push_string(name);
370 push_boolean(is_state);
371 run_lua_cb(2);
374 void lua_callback_do_input(controls_t& data, bool subframe) throw()
376 if(!callback_exists("on_input"))
377 return;
378 lua_input_controllerdata = &data;
379 push_boolean(subframe);
380 run_lua_cb(1);
381 lua_input_controllerdata = NULL;
384 void lua_callback_snoop_input(uint32_t port, uint32_t controller, uint32_t index, short value) throw()
386 if(!callback_exists("on_snoop"))
387 return;
388 lua_pushnumber(L, port);
389 lua_pushnumber(L, controller);
390 lua_pushnumber(L, index);
391 lua_pushnumber(L, value);
392 run_lua_cb(4);
395 namespace
397 function_ptr_command<const std::string&> evaluate_lua("evaluate-lua", "Evaluate expression in Lua VM",
398 "Syntax: evaluate-lua <expression>\nEvaluates <expression> in Lua VM.\n",
399 [](const std::string& args) throw(std::bad_alloc, std::runtime_error) {
400 if(args == "")
401 throw std::runtime_error("Expected expression to evaluate");
402 do_eval_lua(args);
405 function_ptr_command<arg_filename> run_lua("run-lua", "Run Lua script in Lua VM",
406 "Syntax: run-lua <file>\nRuns <file> in Lua VM.\n",
407 [](arg_filename args) throw(std::bad_alloc, std::runtime_error)
409 do_run_lua(args);
413 void lua_callback_quit() throw()
415 if(!callback_exists("on_quit"))
416 return;
417 run_lua_cb(0);
420 void init_lua() throw()
422 L = lua_newstate(alloc, NULL);
423 if(!L) {
424 messages << "Can't initialize Lua." << std::endl;
425 fatal_error();
427 luaL_openlibs(L);
429 register_lua_functions(L);
432 bool lua_requests_repaint = false;
433 bool lua_requests_subframe_paint = false;
434 #endif