lsnes rr0-β2
[lsnes.git] / lua.cpp
blob766d7d6548b95c7c13a95bc8b97b7f275d948fb1
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 <cstring>
9 #include <string>
10 extern "C" {
11 #include <lua.h>
12 #include <lualib.h>
14 #include <iostream>
16 namespace
18 std::map<std::string, lua_function*>* functions;
19 lua_State* lua_initialized;
20 int lua_trampoline_function(lua_State* L)
22 void* ptr = lua_touserdata(L, lua_upvalueindex(1));
23 lua_function* f = reinterpret_cast<lua_function*>(ptr);
24 return f->invoke(L);
27 //Pushes given table to top of stack, creating if needed.
28 void recursive_lookup_table(lua_State* L, const std::string& tab)
30 if(tab == "") {
31 lua_pushvalue(L, LUA_GLOBALSINDEX);
32 return;
34 std::string u = tab;
35 size_t split = u.find_last_of(".");
36 std::string u1;
37 std::string u2 = u;
38 if(split < u.length()) {
39 u1 = u.substr(0, split);
40 u2 = u.substr(split + 1);
42 recursive_lookup_table(L, u1);
43 lua_getfield(L, -1, u2.c_str());
44 if(lua_type(L, -1) != LUA_TTABLE) {
45 //Not a table, create a table.
46 lua_pop(L, 1);
47 lua_newtable(L);
48 lua_setfield(L, -2, u2.c_str());
49 lua_getfield(L, -1, u2.c_str());
51 //Get rid of previous table.
52 lua_insert(L, -2);
53 lua_pop(L, 1);
56 void register_lua_function(lua_State* L, const std::string& fun)
58 std::string u = fun;
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 void* ptr = reinterpret_cast<void*>((*functions)[fun]);
68 lua_pushlightuserdata(L, ptr);
69 lua_pushcclosure(L, lua_trampoline_function, 1);
70 lua_setfield(L, -2, u2.c_str());
71 lua_pop(L, 1);
74 void register_lua_functions(lua_State* L)
76 if(functions)
77 for(auto i = functions->begin(); i != functions->end(); i++)
78 register_lua_function(L, i->first);
79 lua_initialized = L;
83 lua_function::lua_function(const std::string& name) throw(std::bad_alloc)
85 if(!functions)
86 functions = new std::map<std::string, lua_function*>();
87 (*functions)[fname = name] = this;
88 if(lua_initialized)
89 register_lua_function(lua_initialized, fname);
92 lua_function::~lua_function() throw()
94 if(!functions)
95 return;
96 functions->erase(fname);
99 std::string get_string_argument(lua_State* LS, unsigned argindex, const char* fname)
101 if(lua_isnone(LS, argindex)) {
102 char buffer[1024];
103 sprintf(buffer, "argument #%i to %s must be string", argindex, fname);
104 lua_pushstring(LS, buffer);
105 lua_error(LS);
107 size_t len;
108 const char* f = lua_tolstring(LS, argindex, &len);
109 if(!f) {
110 char buffer[1024];
111 sprintf(buffer, "argument #%i to %s must be string", argindex, fname);
112 lua_pushstring(LS, buffer);
113 lua_error(LS);
115 return std::string(f, f + len);
118 bool get_boolean_argument(lua_State* LS, unsigned argindex, const char* fname)
120 if(lua_isnone(LS, argindex) || !lua_isboolean(LS, argindex)) {
121 char buffer[1024];
122 sprintf(buffer, "argument #%i to %s must be boolean", argindex, fname);
123 lua_pushstring(LS, buffer);
124 lua_error(LS);
126 return (lua_toboolean(LS, argindex) != 0);
129 lua_render_context* lua_render_ctx = NULL;
130 controls_t* lua_input_controllerdata = NULL;
132 namespace
134 lua_State* L;
135 bool recursive_flag = false;
136 const char* luareader_fragment = NULL;
138 const char* read_lua_fragment(lua_State* LS, void* dummy, size_t* size)
140 if(luareader_fragment) {
141 const char* ret = luareader_fragment;
142 *size = strlen(luareader_fragment);
143 luareader_fragment = NULL;
144 return ret;
145 } else {
146 *size = 0;
147 return NULL;
151 void* alloc(void* user, void* old, size_t olds, size_t news)
153 if(news)
154 return realloc(old, news);
155 else
156 free(old);
157 return NULL;
160 bool callback_exists(const char* name)
162 if(recursive_flag)
163 return false;
164 lua_getglobal(L, name);
165 int t = lua_type(L, -1);
166 if(t != LUA_TFUNCTION)
167 lua_pop(L, 1);
168 return (t == LUA_TFUNCTION);
171 void push_string(const std::string& s)
173 lua_pushlstring(L, s.c_str(), s.length());
176 void push_boolean(bool b)
178 lua_pushboolean(L, b ? 1 : 0);
181 #define TEMPORARY "LUAINTERP_INTERNAL_COMMAND_TEMPORARY"
183 const char* eval_lua_lua = "loadstring(" TEMPORARY ")();";
184 const char* run_lua_lua = "dofile(" TEMPORARY ");";
186 void run_lua_fragment() throw(std::bad_alloc)
188 if(recursive_flag)
189 return;
190 int t = lua_load(L, read_lua_fragment, NULL, "run_lua_fragment");
191 if(t == LUA_ERRSYNTAX) {
192 messages << "Can't run Lua: Internal syntax error: " << lua_tostring(L, -1) << std::endl;
193 lua_pop(L, 1);
194 return;
196 if(t == LUA_ERRMEM) {
197 messages << "Can't run Lua: Out of memory" << std::endl;
198 lua_pop(L, 1);
199 return;
201 recursive_flag = true;
202 int r = lua_pcall(L, 0, 0, 0);
203 recursive_flag = false;
204 if(r == LUA_ERRRUN) {
205 messages << "Error running Lua hunk: " << lua_tostring(L, -1) << std::endl;
206 lua_pop(L, 1);
208 if(r == LUA_ERRMEM) {
209 messages << "Error running Lua hunk: Out of memory" << std::endl;
210 lua_pop(L, 1);
212 if(r == LUA_ERRERR) {
213 messages << "Error running Lua hunk: Double Fault???" << std::endl;
214 lua_pop(L, 1);
216 if(lua_requests_repaint) {
217 lua_requests_repaint = false;
218 command::invokeC("repaint");
222 void do_eval_lua(const std::string& c) throw(std::bad_alloc)
224 push_string(c);
225 lua_setglobal(L, TEMPORARY);
226 luareader_fragment = eval_lua_lua;
227 run_lua_fragment();
230 void do_run_lua(const std::string& c) throw(std::bad_alloc)
232 push_string(c);
233 lua_setglobal(L, TEMPORARY);
234 luareader_fragment = run_lua_lua;
235 run_lua_fragment();
238 void run_lua_cb(int args) throw()
240 recursive_flag = true;
241 int r = lua_pcall(L, args, 0, 0);
242 recursive_flag = false;
243 if(r == LUA_ERRRUN) {
244 messages << "Error running Lua callback: " << lua_tostring(L, -1) << std::endl;
245 lua_pop(L, 1);
247 if(r == LUA_ERRMEM) {
248 messages << "Error running Lua callback: Out of memory" << std::endl;
249 lua_pop(L, 1);
251 if(r == LUA_ERRERR) {
252 messages << "Error running Lua callback: Double Fault???" << std::endl;
253 lua_pop(L, 1);
255 if(lua_requests_repaint) {
256 lua_requests_repaint = false;
257 command::invokeC("repaint");
262 void lua_callback_do_paint(struct lua_render_context* ctx) throw()
264 if(!callback_exists("on_paint"))
265 return;
266 lua_render_ctx = ctx;
267 run_lua_cb(0);
268 lua_render_ctx = NULL;
271 void lua_callback_do_video(struct lua_render_context* ctx) throw()
273 if(!callback_exists("on_video"))
274 return;
275 lua_render_ctx = ctx;
276 run_lua_cb(0);
277 lua_render_ctx = NULL;
280 void lua_callback_do_reset() throw()
282 if(!callback_exists("on_reset"))
283 return;
284 run_lua_cb(0);
287 void lua_callback_do_readwrite() throw()
289 if(!callback_exists("on_readwrite"))
290 return;
291 run_lua_cb(0);
294 void lua_callback_startup() throw()
296 if(!callback_exists("on_startup"))
297 return;
298 run_lua_cb(0);
301 void lua_callback_pre_load(const std::string& name) throw()
303 if(!callback_exists("on_pre_load"))
304 return;
305 push_string(name);
306 run_lua_cb(1);
309 void lua_callback_err_load(const std::string& name) throw()
311 if(!callback_exists("on_err_load"))
312 return;
313 push_string(name);
314 run_lua_cb(1);
317 void lua_callback_post_load(const std::string& name, bool was_state) throw()
319 if(!callback_exists("on_post_load"))
320 return;
321 push_string(name);
322 push_boolean(was_state);
323 run_lua_cb(2);
326 void lua_callback_pre_save(const std::string& name, bool is_state) throw()
328 if(!callback_exists("on_pre_save"))
329 return;
330 push_string(name);
331 push_boolean(is_state);
332 run_lua_cb(2);
335 void lua_callback_err_save(const std::string& name) throw()
337 if(!callback_exists("on_err_save"))
338 return;
339 push_string(name);
340 run_lua_cb(1);
343 void lua_callback_post_save(const std::string& name, bool is_state) throw()
345 if(!callback_exists("on_post_save"))
346 return;
347 push_string(name);
348 push_boolean(is_state);
349 run_lua_cb(2);
352 void lua_callback_do_input(controls_t& data, bool subframe) throw()
354 if(!callback_exists("on_input"))
355 return;
356 lua_input_controllerdata = &data;
357 push_boolean(subframe);
358 run_lua_cb(1);
359 lua_input_controllerdata = NULL;
362 void lua_callback_snoop_input(uint32_t port, uint32_t controller, uint32_t index, short value) throw()
364 if(!callback_exists("on_snoop"))
365 return;
366 lua_pushnumber(L, port);
367 lua_pushnumber(L, controller);
368 lua_pushnumber(L, index);
369 lua_pushnumber(L, value);
370 run_lua_cb(4);
373 namespace
375 function_ptr_command<const std::string&> evaluate_lua("evaluate-lua", "Evaluate expression in Lua VM",
376 "Syntax: evaluate-lua <expression>\nEvaluates <expression> in Lua VM.\n",
377 [](const std::string& args) throw(std::bad_alloc, std::runtime_error) {
378 if(args == "")
379 throw std::runtime_error("Expected expression to evaluate");
380 do_eval_lua(args);
383 function_ptr_command<arg_filename> run_lua("run-lua", "Run Lua script in Lua VM",
384 "Syntax: run-lua <file>\nRuns <file> in Lua VM.\n",
385 [](arg_filename args) throw(std::bad_alloc, std::runtime_error)
387 do_run_lua(args);
391 void lua_callback_quit() throw()
393 if(!callback_exists("on_quit"))
394 return;
395 run_lua_cb(0);
398 void init_lua() throw()
400 L = lua_newstate(alloc, NULL);
401 if(!L) {
402 messages << "Can't initialize Lua." << std::endl;
403 fatal_error();
405 luaL_openlibs(L);
407 register_lua_functions(L);
410 bool lua_requests_repaint = false;
411 bool lua_requests_subframe_paint = false;