26 #include "sol/sol.hpp"
41 #include "tolua_common_a_gen.h"
49 #define LUASCRIPT_MAX_EXECUTION_TIME_SEC 5.0
50 #define LUASCRIPT_CHECKINTERVAL 10000
53 #define LUASCRIPT_GLOBAL_VAR_NAME "__fcl"
70 #define LUASCRIPT_SECURE_LUA_VERSION1 503
71 #define LUASCRIPT_SECURE_LUA_VERSION2 504
77 "debug",
"dofile",
"loadfile",
nullptr};
79 #if LUA_VERSION_NUM != LUASCRIPT_SECURE_LUA_VERSION1 \
80 && LUA_VERSION_NUM != LUASCRIPT_SECURE_LUA_VERSION2
81 #warning "The script runtime's unsafe symbols information is not up to date."
82 #warning "This can be a big security hole!"
89 #if LUA_VERSION_NUM == 503 || LUA_VERSION_NUM == 504
90 static luaL_Reg luascript_lualibs_secure[] = {
93 {LUA_COLIBNAME, luaopen_coroutine},
94 {LUA_TABLIBNAME, luaopen_table},
95 {LUA_STRLIBNAME, luaopen_string},
96 {LUA_UTF8LIBNAME, luaopen_utf8},
97 {LUA_MATHLIBNAME, luaopen_math},
98 {LUA_DBLIBNAME, luaopen_debug},
101 #error "Unsupported lua version"
126 if (!(msg = lua_tostring(
fcl->state, -1))) {
127 msg =
"(error with no message)";
131 str = QStringLiteral(
"lua error:\t") + msg;
134 lua_pop(
fcl->state, 1);
146 lua_getglobal(L,
"debug");
147 if (lua_istable(L, -1)) {
148 lua_getfield(L, -1,
"traceback");
149 lua_setfield(L, LUA_REGISTRYINDEX,
"freeciv_traceback");
159 lua_getfield(L, LUA_REGISTRYINDEX,
"freeciv_traceback");
168 lua_Number exec_clock;
170 lua_getfield(L, LUA_REGISTRYINDEX,
"freeciv_exec_clock");
171 exec_clock = lua_tonumber(L, -1);
173 if (
static_cast<float>(clock() - exec_clock) / CLOCKS_PER_SEC
175 luaL_error(L,
"Execution time limit exceeded in script");
184 #if LUASCRIPT_CHECKINTERVAL
186 lua_pushnumber(L, clock());
187 lua_setfield(L, LUA_REGISTRYINDEX,
"freeciv_exec_clock");
198 #if LUASCRIPT_CHECKINTERVAL
209 for (; llib->func; llib++) {
210 luaL_requiref(L, llib->name, llib->func, 1);
222 for (i = 0; lsymbols[i] !=
nullptr; i++) {
224 lua_setglobal(L, lsymbols[i]);
236 va_start(vargs, format);
253 lua_pushvfstring(L, format, vargs);
266 return luaL_argerror(L, narg, msg);
273 bool secured_environment)
277 fcl->state = luaL_newstate();
284 fcl->caller =
nullptr;
286 if (secured_environment) {
291 luaL_openlibs(
fcl->state);
308 lua_pushlightuserdata(
fcl->state,
fcl);
309 lua_settable(
fcl->state, LUA_REGISTRYINDEX);
323 lua_gettable(L, LUA_REGISTRYINDEX);
324 fcl =
static_cast<fc_lua *
>(lua_touserdata(L, -1));
348 lua_gc(
fcl->state, LUA_GCCOLLECT, 0);
349 lua_close(
fcl->state);
360 Q_INIT_RESOURCE(scriptcore);
363 if (!in.open(QFile::ReadOnly)) {
364 qCritical() <<
"Could not find resource:" << in.fileName();
365 qFatal(
"Missing resource");
367 const auto data = in.readAll();
370 sol::state_view lua(L);
371 lua.script(data.data(), in.fileName().toStdString());
373 Q_CLEANUP_RESOURCE(scriptcore);
389 sol::table log =
state.create_table_with(
392 log.new_enum(
"level",
412 tolua_common_a_open(L);
433 va_start(args, format);
442 const char *format, va_list args)
451 if (
fcl->output_fct) {
462 int nreturns,
enum api_types *preturn_types,
472 for (i = 0; i < nreturns; i++) {
473 enum api_types type = preturn_types[i];
480 int *pres = va_arg(args,
int *);
482 *pres = lua_tointegerx(L, -1, &isnum);
484 qCritical(
"Return value from lua function %s is a %s, want int",
485 func_name, lua_typename(L, lua_type(L, -1)));
488 case API_TYPE_BOOL: {
489 bool *pres = va_arg(args,
bool *);
490 *pres = lua_toboolean(L, -1);
492 case API_TYPE_STRING: {
493 char **pres = va_arg(args,
char **);
495 if (lua_isstring(L, -1)) {
500 void **pres = va_arg(args,
void **);
502 *pres = tolua_tousertype(
fcl->state, -1,
nullptr);
513 enum api_types *parg_types, va_list args)
520 for (i = 0; i < nargs; i++) {
521 enum api_types type = parg_types[i];
527 lua_Integer arg = va_arg(args, lua_Integer);
528 lua_pushinteger(
fcl->state, arg);
530 case API_TYPE_BOOL: {
531 int arg = va_arg(args,
int);
532 lua_pushboolean(
fcl->state, arg);
534 case API_TYPE_STRING: {
535 const char *arg = va_arg(args,
const char *);
536 lua_pushstring(
fcl->state, arg);
542 name = api_types_name(type);
544 arg = va_arg(args,
void *);
545 tolua_pushusertype(
fcl->state, arg,
name);
561 lua_getglobal(
fcl->state, funcname);
562 defined = lua_isfunction(
fcl->state, -1);
563 lua_pop(
fcl->state, 1);
589 base = lua_gettop(
fcl->state) - narg;
593 if (lua_isfunction(
fcl->state, -1)) {
597 lua_pop(
fcl->state, 1);
601 status = lua_pcall(
fcl->state, narg, nret, traceback);
609 lua_remove(
fcl->state, traceback);
626 status = luaL_loadbuffer(
fcl->state, str, qstrlen(str),
name);
645 status = luaL_loadfile(
fcl->state, filename);
658 int nargs,
enum api_types *parg_types,
661 bool stop_emission =
false;
667 lua_getglobal(
fcl->state, callback_name);
669 if (!lua_isfunction(
fcl->state, -1)) {
672 lua_pop(
fcl->state, 1);
686 if (lua_isboolean(
fcl->state, -1)) {
687 stop_emission = lua_toboolean(
fcl->state, -1);
689 lua_pop(
fcl->state, 1);
691 return stop_emission;
707 lua_pushstring(
fcl->state,
"tolua_ubox");
709 lua_rawget(
fcl->state, LUA_REGISTRYINDEX);
711 lua_pushlightuserdata(
fcl->state,
object);
713 lua_rawget(
fcl->state, -2);
715 if (!lua_isnil(
fcl->state, -1)) {
716 fc_assert(
object == tolua_tousertype(
fcl->state, -1,
nullptr));
719 tolua_getmetatable(
fcl->state,
"Nonexistent");
720 lua_setmetatable(
fcl->state, -2);
722 *(
static_cast<void **
>(lua_touserdata(
fcl->state, -1))) =
nullptr;
725 lua_pushlightuserdata(
fcl->state,
object);
727 lua_pushnil(
fcl->state);
728 lua_rawset(
fcl->state, -4);
730 lua_pop(
fcl->state, 2);
744 lua_getglobal(
fcl->state,
"_freeciv_state_dump");
748 vars = lua_tostring(
fcl->state, -1);
749 lua_pop(
fcl->state, 1);
792 DIR8_NORTHWEST, DIR8_NORTH, DIR8_NORTHEAST, DIR8_WEST,
793 DIR8_EAST, DIR8_SOUTHWEST, DIR8_SOUTH, DIR8_SOUTHEAST};
const char * api_intl_PL_(sol::this_state s, const char *singular, const char *plural, int n)
Translation helper function.
const char * api_intl_N_(sol::this_state s, const char *untranslated)
Translation helper function.
const char * api_intl_Q_(sol::this_state s, const char *untranslated)
Translation helper function.
const char * api_intl__(sol::this_state s, const char *untranslated)
Translation helper function.
void api_utilities_log_base(sol::this_state s, int level, const char *message)
One log message.
int api_utilities_random(int min, int max)
Generate random number.
const char * api_utilities_fc_version()
Return the version of freeciv lua script.
void api_utilities_deprecation_warning(char *method, char *replacement, char *deprecated_since)
Lua script wants to warn about use of deprecated construct.
static void base(QVariant data1, QVariant data2)
Action "Build Base" for choice dialog.
#define fc_assert_ret(condition)
constexpr auto LOG_VERBOSE
#define fc_assert(condition)
constexpr auto LOG_NORMAL
#define fc_assert_ret_val(condition, val)
#define log_base(level, message,...)
static int luascript_report(struct fc_lua *fcl, int status, const char *code)
Lua libraries to load (all default libraries, excluding operating system and library loading modules)...
void luascript_pop_returns(struct fc_lua *fcl, const char *func_name, int nreturns, enum api_types *preturn_types, va_list args)
Pop return values from the Lua stack.
const Direction * luascript_dir(enum direction8 dir)
Returns a pointer to a given value of enum direction8 (always the same address for the same value),...
void luascript_push_args(struct fc_lua *fcl, int nargs, enum api_types *parg_types, va_list args)
Push arguments into the Lua stack.
static void luascript_traceback_func_push(lua_State *L)
Push the traceback function to the stack.
static const char * luascript_unsafe_symbols_secure[]
void luascript_init(fc_lua *fcl)
Sets the freeciv lua struct for a lua state.
bool luascript_check_function(struct fc_lua *fcl, const char *funcname)
Return if the function 'funcname' is define in the lua state 'fcl->state'.
int luascript_error_vargs(lua_State *L, const char *format, va_list vargs)
Internal api error function.
#define LUASCRIPT_CHECKINTERVAL
static void luascript_openlibs(lua_State *L, const luaL_Reg *llib)
Open lua libraries in the array of library definitions in llib.
int luascript_arg_error(lua_State *L, int narg, const char *msg)
Like script_error, but using a prefix identifying the called lua function:
#define LUASCRIPT_MAX_EXECUTION_TIME_SEC
Configuration for script execution time limits.
bool luascript_callback_invoke(struct fc_lua *fcl, const char *callback_name, int nargs, enum api_types *parg_types, va_list args)
Invoke the 'callback_name' Lua function.
void luascript_remove_exported_object(struct fc_lua *fcl, void *object)
Mark any, if exported, full userdata representing 'object' in the current script state as 'Nonexisten...
int luascript_do_string(struct fc_lua *fcl, const char *str, const char *name)
lua_dostring replacement with error message showing on errors.
int luascript_error(lua_State *L, const char *format,...)
Internal api error function - varg version.
int luascript_do_file(struct fc_lua *fcl, const char *filename)
Parse and execute the script at filename.
static void luascript_common_a_register(sol::state_view state)
Registers tolua_common_a functions and modules.
static void luascript_hook_end(lua_State *L)
Clear function execution guard.
static void luascript_exec_check(lua_State *L, lua_Debug *ar)
Check currently excecuting lua function for execution time limit.
void luascript_vars_load(struct fc_lua *fcl, struct section_file *file, const char *section)
Load lua variables from file.
static void luascript_hook_start(lua_State *L)
Setup function execution guard.
void luascript_log_vargs(struct fc_lua *fcl, QtMsgType level, const char *format, va_list args)
Print a message to the selected output handle.
static const char * luascript_unsafe_symbols_permissive[]
void luascript_common_z(lua_State *L)
Runs tolua_common_z.lua.
struct fc_lua * luascript_new(luascript_log_func_t output_fct, bool secured_environment)
Initialize the scripting state.
void luascript_log(struct fc_lua *fcl, QtMsgType level, const char *format,...)
Print a message to the selected output handle.
void luascript_vars_save(struct fc_lua *fcl, struct section_file *file, const char *section)
Save lua variables to file.
void luascript_common_a(lua_State *L)
Runs tolua_common_a.lua.
static void luascript_exec_resource(lua_State *L, const QString &filename)
Loads a script from a Qt resource file and executes it.
struct fc_lua * luascript_get_fcl(lua_State *L)
Get the freeciv lua struct from a lua state.
static void luascript_blacklist(lua_State *L, const char *lsymbols[])
Remove global symbols from lua state L.
int luascript_call(struct fc_lua *fcl, int narg, int nret, const char *code)
Evaluate a Lua function call or loaded script on the stack.
#define LUASCRIPT_GLOBAL_VAR_NAME
static void luascript_traceback_func_save(lua_State *L)
Find the debug.traceback function and store in the registry.
void luascript_destroy(struct fc_lua *fcl)
Free the scripting data.
void(* luascript_log_func_t)(struct fc_lua *fcl, QtMsgType level, const char *format,...) fc__attribute((__format__(__printf__
void luascript_func_free(struct fc_lua *fcl)
Free the function definitions.
void luascript_signal_free(struct fc_lua *fcl)
Free script signals and callbacks.
enum direction8 Direction
bool is_valid_dir(enum direction8 dir)
Returns TRUE iff the given direction is a valid one.
const char * secfile_lookup_str_default(const struct section_file *secfile, const char *def, const char *path,...)
Lookup a string value in the secfile.
#define secfile_insert_str_noescape(secfile, string, path,...)
static void static sol::state * fcl
Lua virtual machine state.
struct setting_list * level[OLEVELS_NUM]
luascript_log_func_t output_fct
int fc_vsnprintf(char *str, size_t n, const char *format, va_list ap)