Make git diff --check happy
[lsnes.git] / lua.cpp
blob74d7ce3833509d2a379a83a4c139c566e3aaff2b
1 #include "lua.hpp"
2 #include "lua-int.hpp"
3 #include "command.hpp"
4 #include "misc.hpp"
5 #include "memorymanip.hpp"
6 #include "mainloop.hpp"
7 #include <map>
8 #include <string>
9 extern "C" {
10 #include <lua.h>
11 #include <lualib.h>
13 #include <iostream>
14 #include "fieldsplit.hpp"
16 namespace
18 std::map<std::string, lua_function*>* functions;
19 lua_State* lua_initialized;
20 window* tmp_win;
22 int lua_trampoline_function(lua_State* L)
24 void* ptr = lua_touserdata(L, lua_upvalueindex(1));
25 lua_function* f = reinterpret_cast<lua_function*>(ptr);
26 return f->invoke(L, tmp_win);
29 //Pushes given table to top of stack, creating if needed.
30 void recursive_lookup_table(lua_State* L, const std::string& tab)
32 if(tab == "") {
33 lua_pushvalue(L, LUA_GLOBALSINDEX);
34 return;
36 std::string u = tab;
37 size_t split = u.find_last_of(".");
38 std::string u1;
39 std::string u2 = u;
40 if(split < u.length()) {
41 u1 = u.substr(0, split);
42 u2 = u.substr(split + 1);
44 recursive_lookup_table(L, u1);
45 lua_getfield(L, -1, u2.c_str());
46 if(lua_type(L, -1) != LUA_TTABLE) {
47 //Not a table, create a table.
48 lua_pop(L, 1);
49 lua_newtable(L);
50 lua_setfield(L, -2, u2.c_str());
51 lua_getfield(L, -1, u2.c_str());
53 //Get rid of previous table.
54 lua_insert(L, -2);
55 lua_pop(L, 1);
58 void register_lua_function(lua_State* L, const std::string& fun)
60 std::string u = fun;
61 size_t split = u.find_last_of(".");
62 std::string u1;
63 std::string u2 = u;
64 if(split < u.length()) {
65 u1 = u.substr(0, split);
66 u2 = u.substr(split + 1);
68 recursive_lookup_table(L, u1);
69 void* ptr = reinterpret_cast<void*>((*functions)[fun]);
70 lua_pushlightuserdata(L, ptr);
71 lua_pushcclosure(L, lua_trampoline_function, 1);
72 lua_setfield(L, -2, u2.c_str());
73 lua_pop(L, 1);
76 void register_lua_functions(lua_State* L)
78 if(functions)
79 for(auto i = functions->begin(); i != functions->end(); i++)
80 register_lua_function(L, i->first);
81 lua_initialized = L;
85 lua_function::lua_function(const std::string& name) throw(std::bad_alloc)
87 if(!functions)
88 functions = new std::map<std::string, lua_function*>();
89 (*functions)[fname = name] = this;
90 if(lua_initialized)
91 register_lua_function(lua_initialized, fname);
94 lua_function::~lua_function() throw()
96 if(!functions)
97 return;
98 functions->erase(fname);
101 std::string get_string_argument(lua_State* LS, unsigned argindex, const char* fname)
103 if(lua_isnone(LS, argindex)) {
104 lua_pushfstring(LS, "argument #%i to %s must be string", argindex, fname);
105 lua_error(LS);
107 size_t len;
108 const char* f = lua_tolstring(LS, argindex, &len);
109 if(!f) {
110 lua_pushfstring(LS, "argument #%i to %s must be string", argindex, fname);
111 lua_error(LS);
113 return std::string(f, f + len);
116 bool get_boolean_argument(lua_State* LS, unsigned argindex, const char* fname)
118 if(lua_isnone(LS, argindex) || !lua_isboolean(LS, argindex)) {
119 lua_pushfstring(LS, "argument #%i to %s must be boolean", argindex, fname);
120 lua_error(LS);
122 return (lua_toboolean(LS, argindex) != 0);
125 lua_render_context* lua_render_ctx = NULL;
126 controls_t* lua_input_controllerdata = NULL;
128 namespace
130 lua_State* L;
131 bool recursive_flag = false;
132 const char* luareader_fragment = NULL;
134 const char* read_lua_fragment(lua_State* LS, void* dummy, size_t* size)
136 if(luareader_fragment) {
137 const char* ret = luareader_fragment;
138 *size = strlen(luareader_fragment);
139 luareader_fragment = NULL;
140 return ret;
141 } else {
142 *size = 0;
143 return NULL;
147 void* alloc(void* user, void* old, size_t olds, size_t news)
149 if(news)
150 return realloc(old, news);
151 else
152 free(old);
153 return NULL;
156 bool callback_exists(const char* name)
158 if(recursive_flag)
159 return false;
160 lua_getglobal(L, name);
161 int t = lua_type(L, -1);
162 if(t != LUA_TFUNCTION)
163 lua_pop(L, 1);
164 return (t == LUA_TFUNCTION);
167 void push_string(const std::string& s)
169 lua_pushlstring(L, s.c_str(), s.length());
172 void push_boolean(bool b)
174 lua_pushboolean(L, b ? 1 : 0);
177 #define TEMPORARY "LUAINTERP_INTERNAL_COMMAND_TEMPORARY"
179 const char* eval_lua_lua = "loadstring(" TEMPORARY ")();";
180 const char* run_lua_lua = "dofile(" TEMPORARY ");";
182 void run_lua_fragment(window* win) throw(std::bad_alloc)
184 if(recursive_flag)
185 return;
186 int t = lua_load(L, read_lua_fragment, NULL, "run_lua_fragment");
187 if(t == LUA_ERRSYNTAX) {
188 out(win) << "Can't run Lua: Internal syntax error: " << lua_tostring(L, -1) << std::endl;
189 lua_pop(L, 1);
190 return;
192 if(t == LUA_ERRMEM) {
193 out(win) << "Can't run Lua: Out of memory" << std::endl;
194 lua_pop(L, 1);
195 return;
197 recursive_flag = true;
198 tmp_win = win;
199 int r = lua_pcall(L, 0, 0, 0);
200 recursive_flag = false;
201 if(r == LUA_ERRRUN) {
202 out(win) << "Error running Lua hunk: " << lua_tostring(L, -1) << std::endl;
203 lua_pop(L, 1);
205 if(r == LUA_ERRMEM) {
206 out(win) << "Error running Lua hunk: Out of memory" << std::endl;
207 lua_pop(L, 1);
209 if(r == LUA_ERRERR) {
210 out(win) << "Error running Lua hunk: Double Fault???" << std::endl;
211 lua_pop(L, 1);
213 if(lua_requests_repaint) {
214 lua_requests_repaint = false;
215 command::invokeC("repaint", win);
219 void do_eval_lua(const std::string& c, window* win) throw(std::bad_alloc)
221 push_string(c);
222 lua_setglobal(L, TEMPORARY);
223 luareader_fragment = eval_lua_lua;
224 run_lua_fragment(win);
227 void do_run_lua(const std::string& c, window* win) throw(std::bad_alloc)
229 push_string(c);
230 lua_setglobal(L, TEMPORARY);
231 luareader_fragment = run_lua_lua;
232 run_lua_fragment(win);
235 void run_lua_cb(int args, window* win) throw()
237 recursive_flag = true;
238 tmp_win = win;
239 int r = lua_pcall(L, args, 0, 0);
240 recursive_flag = false;
241 if(r == LUA_ERRRUN) {
242 out(win) << "Error running Lua callback: " << lua_tostring(L, -1) << std::endl;
243 lua_pop(L, 1);
245 if(r == LUA_ERRMEM) {
246 out(win) << "Error running Lua callback: Out of memory" << std::endl;
247 lua_pop(L, 1);
249 if(r == LUA_ERRERR) {
250 out(win) << "Error running Lua callback: Double Fault???" << std::endl;
251 lua_pop(L, 1);
253 if(lua_requests_repaint) {
254 lua_requests_repaint = false;
255 command::invokeC("repaint", win);
260 void lua_callback_do_paint(struct lua_render_context* ctx, window* win) throw()
262 if(!callback_exists("on_paint"))
263 return;
264 lua_render_ctx = ctx;
265 run_lua_cb(0, win);
266 lua_render_ctx = NULL;
269 void lua_callback_do_video(struct lua_render_context* ctx, window* win) throw()
271 if(!callback_exists("on_video"))
272 return;
273 lua_render_ctx = ctx;
274 run_lua_cb(0, win);
275 lua_render_ctx = NULL;
278 void lua_callback_do_reset(window* win) throw()
280 if(!callback_exists("on_reset"))
281 return;
282 run_lua_cb(0, win);
285 void lua_callback_do_readwrite(window* win) throw()
287 if(!callback_exists("on_readwrite"))
288 return;
289 run_lua_cb(0, win);
292 void lua_callback_startup(window* win) throw()
294 if(!callback_exists("on_startup"))
295 return;
296 run_lua_cb(0, win);
299 void lua_callback_pre_load(const std::string& name, window* win) throw()
301 if(!callback_exists("on_pre_load"))
302 return;
303 push_string(name);
304 run_lua_cb(1, win);
307 void lua_callback_err_load(const std::string& name, window* win) throw()
309 if(!callback_exists("on_err_load"))
310 return;
311 push_string(name);
312 run_lua_cb(1, win);
315 void lua_callback_post_load(const std::string& name, bool was_state, window* win) throw()
317 if(!callback_exists("on_post_load"))
318 return;
319 push_string(name);
320 push_boolean(was_state);
321 run_lua_cb(2, win);
324 void lua_callback_pre_save(const std::string& name, bool is_state, window* win) throw()
326 if(!callback_exists("on_pre_save"))
327 return;
328 push_string(name);
329 push_boolean(is_state);
330 run_lua_cb(2, win);
333 void lua_callback_err_save(const std::string& name, window* win) throw()
335 if(!callback_exists("on_err_save"))
336 return;
337 push_string(name);
338 run_lua_cb(1, win);
341 void lua_callback_post_save(const std::string& name, bool is_state, window* win) throw()
343 if(!callback_exists("on_post_save"))
344 return;
345 push_string(name);
346 push_boolean(is_state);
347 run_lua_cb(2, win);
350 void lua_callback_do_input(controls_t& data, bool subframe, window* win) throw()
352 if(!callback_exists("on_input"))
353 return;
354 lua_input_controllerdata = &data;
355 push_boolean(subframe);
356 run_lua_cb(1, win);
357 lua_input_controllerdata = NULL;
360 void lua_callback_snoop_input(uint32_t port, uint32_t controller, uint32_t index, short value, window* win) throw()
362 if(!callback_exists("on_snoop"))
363 return;
364 lua_pushnumber(L, port);
365 lua_pushnumber(L, controller);
366 lua_pushnumber(L, index);
367 lua_pushnumber(L, value);
368 run_lua_cb(4, win);
371 namespace
373 class evallua : public command
375 public:
376 evallua() throw(std::bad_alloc) : command("evaluate-lua") {}
377 void invoke(const std::string& args, window* win) throw(std::bad_alloc, std::runtime_error)
379 if(args == "")
380 throw std::runtime_error("Expected expression to evaluate");
381 do_eval_lua(args, win);
383 std::string get_short_help() throw(std::bad_alloc) { return "Evaluate expression in Lua VM"; }
384 std::string get_long_help() throw(std::bad_alloc)
386 return "Syntax: evaluate-lua <expression>\n"
387 "Evaluates <expression> in Lua VM.\n";
389 } evallua_o;
391 class runlua : public command
393 public:
394 runlua() throw(std::bad_alloc) : command("run-lua") {}
395 void invoke(const std::string& args, window* win) throw(std::bad_alloc, std::runtime_error)
397 if(args == "")
398 throw std::runtime_error("Expected script to run");
399 do_run_lua(args, win);
401 std::string get_short_help() throw(std::bad_alloc) { return "Run Lua script in Lua VM"; }
402 std::string get_long_help() throw(std::bad_alloc)
404 return "Syntax: run-lua <file>\n"
405 "Runs <file> in Lua VM.\n";
407 } runlua_o;
410 void lua_callback_quit(window* win) throw()
412 if(!callback_exists("on_quit"))
413 return;
414 run_lua_cb(0, win);
417 void init_lua(window* win) throw()
419 L = lua_newstate(alloc, NULL);
420 if(!L) {
421 out(win) << "Can't initialize Lua." << std::endl;
422 fatal_error(win);
424 luaL_openlibs(L);
426 register_lua_functions(L);
429 bool lua_requests_repaint = false;
430 bool lua_requests_subframe_paint = false;