44#define LUASCRIPT_MAX_EXECUTION_TIME_SEC 5.0
45#define LUASCRIPT_CHECKINTERVAL 10000
48#define LUASCRIPT_GLOBAL_VAR_NAME "__fcl"
65#define LUASCRIPT_SECURE_LUA_VERSION1 503
66#define LUASCRIPT_SECURE_LUA_VERSION2 504
82#if LUA_VERSION_NUM != LUASCRIPT_SECURE_LUA_VERSION1 && LUA_VERSION_NUM != LUASCRIPT_SECURE_LUA_VERSION2
83#warning "The script runtime's unsafe symbols information is not up to date."
84#warning "This can be a big security hole!"
91#if LUA_VERSION_NUM == 503 || LUA_VERSION_NUM == 504
92static luaL_Reg luascript_lualibs_secure[] = {
95 {LUA_COLIBNAME, luaopen_coroutine},
96 {LUA_TABLIBNAME, luaopen_table},
97 {LUA_STRLIBNAME, luaopen_string},
98 {LUA_UTF8LIBNAME, luaopen_utf8},
99 {LUA_MATHLIBNAME, luaopen_math},
100 {LUA_DBLIBNAME, luaopen_debug},
104static luaL_Reg luascript_lualibs_permissive[] = {
106 {
"_G", luaopen_base},
107 {LUA_COLIBNAME, luaopen_coroutine},
108 {LUA_TABLIBNAME, luaopen_table},
109 {LUA_STRLIBNAME, luaopen_string},
110 {LUA_UTF8LIBNAME, luaopen_utf8},
111 {LUA_MATHLIBNAME, luaopen_math},
112 {LUA_DBLIBNAME, luaopen_debug},
113 {LUA_OSLIBNAME, luaopen_os},
117#error "Unsupported lua version"
143 if (!(msg = lua_tostring(fcl->
state, -1))) {
144 msg =
"(error with no message)";
153 if (sscanf(msg,
"%*[^:]:%d:", &lineno) == 1) {
154 const char *begin, *end;
160 for (begin = code; *begin !=
'\0';) {
163 end = strchr(begin,
'\n');
170 if (abs(lineno - i) <= 3) {
171 const char *indicator;
173 indicator = (lineno == i) ?
"-->" :
" ";
176 indicator, i,
len,
len, begin);
196 lua_pop(fcl->
state, 1);
208 lua_getglobal(L,
"debug");
209 if (lua_istable(L, -1)) {
210 lua_getfield(L, -1,
"traceback");
211 lua_setfield(L, LUA_REGISTRYINDEX,
"freeciv_traceback");
221 lua_getfield(L, LUA_REGISTRYINDEX,
"freeciv_traceback");
229 lua_Number exec_clock;
231 lua_getfield(L, LUA_REGISTRYINDEX,
"freeciv_exec_clock");
232 exec_clock = lua_tonumber(L, -1);
236 luaL_error(L,
"Execution time limit exceeded in script");
245#if LUASCRIPT_CHECKINTERVAL
247 lua_pushnumber(L, clock());
248 lua_setfield(L, LUA_REGISTRYINDEX,
"freeciv_exec_clock");
258#if LUASCRIPT_CHECKINTERVAL
269 for (; llib->func; llib++) {
270 luaL_requiref(L, llib->name, llib->func, 1);
282 for (i = 0; lsymbols[i] != NULL; i++) {
284 lua_setglobal(L, lsymbols[i]);
296 va_start(vargs, format);
313 lua_pushvfstring(L, format, vargs);
326 return luaL_argerror(L, narg, msg);
333 bool secured_environment)
337 fcl->
state = luaL_newstate();
345 if (secured_environment) {
357 lua_pushlightuserdata(fcl->
state, fcl);
358 lua_settable(fcl->
state, LUA_REGISTRYINDEX);
374 lua_gettable(L, LUA_REGISTRYINDEX);
375 fcl = lua_touserdata(L, -1);
399 lua_gc(fcl->
state, LUA_GCCOLLECT, 0);
400 lua_close(fcl->
state);
410 const char *format, ...)
414 va_start(args, format);
423 const char *format, va_list args)
443 int nreturns,
enum api_types *preturn_types,
453 for (i = 0; i < nreturns; i++) {
454 enum api_types
type = preturn_types[i];
462 int *pres = va_arg(args,
int*);
464 *pres = lua_tointegerx(L, -1, &isnum);
466 log_error(
"Return value from lua function %s is a %s, want int",
467 func_name, lua_typename(L, lua_type(L, -1)));
473 bool *pres = va_arg(args,
bool*);
474 *pres = lua_toboolean(L, -1);
477 case API_TYPE_STRING:
479 char **pres = va_arg(args,
char**);
481 if (lua_isstring(L, -1)) {
488 void **pres = va_arg(args,
void**);
490 *pres = tolua_tousertype(fcl->
state, -1, NULL);
502 enum api_types *parg_types, va_list args)
509 for (i = 0; i < nargs; i++) {
510 enum api_types
type = parg_types[i];
517 lua_Integer arg = va_arg(args, lua_Integer);
518 lua_pushinteger(fcl->
state, arg);
523 int arg = va_arg(args,
int);
524 lua_pushboolean(fcl->
state, arg);
527 case API_TYPE_STRING:
529 const char *arg = va_arg(args,
const char*);
530 lua_pushstring(fcl->
state, arg);
540 arg = va_arg(args,
void*);
541 tolua_pushusertype(fcl->
state, arg,
name);
559 lua_getglobal(fcl->
state, funcname);
560 defined = lua_isfunction(fcl->
state, -1);
561 lua_pop(fcl->
state, 1);
592 if (lua_isfunction(fcl->
state, -1)) {
596 lua_pop(fcl->
state, 1);
600 status = lua_pcall(fcl->
state, narg, nret, traceback);
608 lua_remove(fcl->
state, traceback);
644 status = luaL_loadfile(fcl->
state, filename);
658 const char *callback_name,
659 int nargs,
enum api_types *parg_types,
662 bool stop_emission =
FALSE;
668 lua_getglobal(fcl->
state, callback_name);
670 if (!lua_isfunction(fcl->
state, -1)) {
673 lua_pop(fcl->
state, 1);
687 if (lua_isboolean(fcl->
state, -1)) {
688 stop_emission = lua_toboolean(fcl->
state, -1);
690 lua_pop(fcl->
state, 1);
692 return stop_emission;
702 if (fcl && fcl->
state) {
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)) {
719 tolua_getmetatable(fcl->
state,
"Nonexistent");
720 lua_setmetatable(fcl->
state, -2);
722 *((
void **)lua_touserdata(fcl->
state, -1)) = NULL;
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 Direction etalon[8] = {DIR8_NORTHWEST, DIR8_NORTH, DIR8_NORTHEAST,
793 DIR8_WEST, DIR8_EAST,
794 DIR8_SOUTHWEST, DIR8_SOUTH, DIR8_SOUTHEAST};
void astr_free(struct astring *astr)
void astr_add_line(struct astring *astr, const char *format,...)
void astr_add(struct astring *astr, const char *format,...)
static const char * astr_str(const struct astring *astr) fc__attribute((nonnull(1)))
static void base(QVariant data1, QVariant data2)
#define fc_assert_ret(condition)
#define fc_assert(condition)
#define fc_assert_ret_val(condition, val)
#define log_base(level, message,...)
#define log_error(message,...)
static int luascript_report(struct fc_lua *fcl, int status, const char *code)
void luascript_pop_returns(struct fc_lua *fcl, const char *func_name, int nreturns, enum api_types *preturn_types, va_list args)
void luascript_push_args(struct fc_lua *fcl, int nargs, enum api_types *parg_types, va_list args)
static void luascript_traceback_func_push(lua_State *L)
static const char * luascript_unsafe_symbols_secure[]
bool luascript_check_function(struct fc_lua *fcl, const char *funcname)
int luascript_error_vargs(lua_State *L, const char *format, va_list vargs)
#define LUASCRIPT_CHECKINTERVAL
static void luascript_openlibs(lua_State *L, const luaL_Reg *llib)
int luascript_arg_error(lua_State *L, int narg, const char *msg)
#define LUASCRIPT_MAX_EXECUTION_TIME_SEC
bool luascript_callback_invoke(struct fc_lua *fcl, const char *callback_name, int nargs, enum api_types *parg_types, va_list args)
void luascript_remove_exported_object(struct fc_lua *fcl, void *object)
int luascript_do_string(struct fc_lua *fcl, const char *str, const char *name)
int luascript_error(lua_State *L, const char *format,...)
int luascript_do_file(struct fc_lua *fcl, const char *filename)
static void luascript_hook_end(lua_State *L)
static void luascript_exec_check(lua_State *L, lua_Debug *ar)
void luascript_vars_load(struct fc_lua *fcl, struct section_file *file, const char *section)
const Direction * luascript_dir(enum direction8 dir)
static void luascript_hook_start(lua_State *L)
static const char * luascript_unsafe_symbols_permissive[]
void luascript_log(struct fc_lua *fcl, enum log_level level, const char *format,...)
void luascript_log_vargs(struct fc_lua *fcl, enum log_level level, const char *format, va_list args)
void luascript_vars_save(struct fc_lua *fcl, struct section_file *file, const char *section)
struct fc_lua * luascript_get_fcl(lua_State *L)
struct fc_lua * luascript_new(luascript_log_func_t output_fct, bool secured_environment)
static void luascript_blacklist(lua_State *L, const char *lsymbols[])
int luascript_call(struct fc_lua *fcl, int narg, int nret, const char *code)
#define LUASCRIPT_GLOBAL_VAR_NAME
static void luascript_traceback_func_save(lua_State *L)
void luascript_destroy(struct fc_lua *fcl)
void(* luascript_log_func_t)(struct fc_lua *fcl, enum log_level level, const char *format,...) fc__attribute((__format__(__printf__
void luascript_func_free(struct fc_lua *fcl)
void luascript_signal_free(struct fc_lua *fcl)
enum direction8 Direction
bool is_valid_dir(enum direction8 dir)
#define fc_calloc(n, esz)
const char * secfile_lookup_str_default(const struct section_file *secfile, const char *def, const char *path,...)
#define secfile_insert_str_noescape(secfile, string, path,...)
struct setting_list * level[OLEVELS_NUM]
struct connection * caller
luascript_log_func_t output_fct
int fc_vsnprintf(char *str, size_t n, const char *format, va_list ap)