1 #include "core/command.hpp"
2 #include "core/globalwrap.hpp"
3 #include "lua/internal.hpp"
5 #include "core/mainloop.hpp"
6 #include "core/memorymanip.hpp"
7 #include "core/misc.hpp"
18 uint64_t lua_idle_hook_time
= 0x7EFFFFFFFFFFFFFFULL
;
19 uint64_t lua_timer_hook_time
= 0x7EFFFFFFFFFFFFFFULL
;
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
);
31 } catch(std::exception
& e
) {
32 lua_pushfstring(L
, "Error in internal function: %s", e
.what());
37 //Pushes given table to top of stack, creating if needed.
38 void recursive_lookup_table(lua_State
* L
, const std::string
& tab
)
41 lua_getglobal(L
, "_G");
45 size_t split
= u
.find_last_of(".");
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.
58 lua_setfield(L
, -2, u2
.c_str());
59 lua_getfield(L
, -1, u2
.c_str());
61 //Get rid of previous table.
66 void register_lua_function(lua_State
* L
, const std::string
& fun
)
69 size_t split
= u
.find_last_of(".");
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());
84 void register_lua_functions(lua_State
* L
)
86 for(auto i
: functions())
87 register_lua_function(L
, i
.first
);
92 lua_function::lua_function(const std::string
& name
) throw(std::bad_alloc
)
94 functions()[fname
= name
] = this;
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
)) {
108 sprintf(buffer
, "argument #%i to %s must be string", argindex
, fname
);
109 lua_pushstring(LS
, buffer
);
113 const char* f
= lua_tolstring(LS
, argindex
, &len
);
116 sprintf(buffer
, "argument #%i to %s must be string", argindex
, fname
);
117 lua_pushstring(LS
, buffer
);
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
)) {
127 sprintf(buffer
, "argument #%i to %s must be boolean", argindex
, fname
);
128 lua_pushstring(LS
, buffer
);
131 return (lua_toboolean(LS
, argindex
) != 0);
134 void push_keygroup_parameters(lua_State
* LS
, const struct keygroup::parameters
& p
)
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");
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;
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
;
193 void* alloc(void* user
, void* old
, size_t olds
, size_t news
)
196 void* m
= realloc(old
, news
);
205 bool callback_exists(const char* name
)
209 lua_getglobal(L
, name
);
210 int t
= lua_type(L
, -1);
211 if(t
!= LUA_TFUNCTION
)
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
)
235 #if LUA_VERSION_NUM == 501
236 int t
= lua_load(L
, read_lua_fragment
, NULL
, "run_lua_fragment");
238 #if LUA_VERSION_NUM == 502
239 int t
= lua_load(L
, read_lua_fragment
, NULL
, "run_lua_fragment", "bt");
241 if(t
== LUA_ERRSYNTAX
) {
242 messages
<< "Can't run Lua: Internal syntax error: " << lua_tostring(L
, -1) << std::endl
;
246 if(t
== LUA_ERRMEM
) {
247 messages
<< "Can't run Lua: Out of memory" << std::endl
;
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
;
258 if(r
== LUA_ERRMEM
) {
259 messages
<< "Error running Lua hunk: Out of memory" << std::endl
;
262 if(r
== LUA_ERRERR
) {
263 messages
<< "Error running Lua hunk: Double Fault???" << std::endl
;
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
)
275 lua_setglobal(L
, TEMPORARY
);
276 luareader_fragment
= eval_lua_lua
;
280 void do_run_lua(const std::string
& c
) throw(std::bad_alloc
)
283 lua_setglobal(L
, TEMPORARY
);
284 luareader_fragment
= run_lua_lua
;
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
;
297 if(r
== LUA_ERRMEM
) {
298 messages
<< "Error running Lua callback: Out of memory" << std::endl
;
301 if(r
== LUA_ERRERR
) {
302 messages
<< "Error running Lua callback: Double Fault???" << std::endl
;
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");
318 void copy_system_tables(lua_State
* L
)
320 lua_getglobal(L
, "_G");
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
329 //Stack: _SYSTEM, KEY, VALUE
331 //Stack: _SYSTEM, KEY
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"))
345 lua_render_ctx
= ctx
;
346 push_boolean(non_synthetic
);
348 lua_render_ctx
= NULL
;
351 void lua_callback_do_video(struct lua_render_context
* ctx
) throw()
353 if(!callback_exists("on_video"))
355 lua_render_ctx
= ctx
;
357 lua_render_ctx
= NULL
;
360 void lua_callback_do_reset() throw()
362 if(!callback_exists("on_reset"))
367 void lua_callback_do_frame() throw()
369 if(!callback_exists("on_frame"))
374 void lua_callback_do_rewind() throw()
376 if(!callback_exists("on_rewind"))
381 void lua_callback_do_idle() throw()
383 lua_idle_hook_time
= 0x7EFFFFFFFFFFFFFFULL
;
384 if(!callback_exists("on_idle"))
389 void lua_callback_do_timer() throw()
391 lua_timer_hook_time
= 0x7EFFFFFFFFFFFFFFULL
;
392 if(!callback_exists("on_timer"))
397 void lua_callback_do_frame_emulated() throw()
399 if(!callback_exists("on_frame_emulated"))
404 void lua_callback_do_readwrite() throw()
406 if(!callback_exists("on_readwrite"))
411 void lua_callback_startup() throw()
413 lua_booted_flag
= true;
414 if(!callback_exists("on_startup"))
419 void lua_callback_pre_load(const std::string
& name
) throw()
421 if(!callback_exists("on_pre_load"))
427 void lua_callback_err_load(const std::string
& name
) throw()
429 if(!callback_exists("on_err_load"))
435 void lua_callback_post_load(const std::string
& name
, bool was_state
) throw()
437 if(!callback_exists("on_post_load"))
440 push_boolean(was_state
);
444 void lua_callback_pre_save(const std::string
& name
, bool is_state
) throw()
446 if(!callback_exists("on_pre_save"))
449 push_boolean(is_state
);
453 void lua_callback_err_save(const std::string
& name
) throw()
455 if(!callback_exists("on_err_save"))
461 void lua_callback_post_save(const std::string
& name
, bool is_state
) throw()
463 if(!callback_exists("on_post_save"))
466 push_boolean(is_state
);
470 void lua_callback_do_input(controller_frame
& data
, bool subframe
) throw()
472 if(!callback_exists("on_input"))
474 lua_input_controllerdata
= &data
;
475 push_boolean(subframe
);
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"))
484 lua_pushnumber(L
, port
);
485 lua_pushnumber(L
, controller
);
486 lua_pushnumber(L
, index
);
487 lua_pushnumber(L
, value
);
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
) {
497 throw std::runtime_error("Expected expression to evaluate");
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
)
509 void lua_callback_quit() throw()
511 if(!callback_exists("on_quit"))
516 void lua_callback_keyhook(const std::string
& key
, const struct keygroup::parameters
& p
) throw()
518 if(!callback_exists("on_keyhook"))
520 lua_pushstring(L
, key
.c_str());
521 push_keygroup_parameters(L
, p
);
525 void init_lua() throw()
527 L
= lua_newstate(alloc
, NULL
);
529 messages
<< "Can't initialize Lua." << std::endl
;
534 register_lua_functions(L
);
535 copy_system_tables(L
);
538 void quit_lua() throw()
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()
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;