1 /* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */
2 
3 #ifndef SPRING_LUA_INCLUDE
4 #define SPRING_LUA_INCLUDE
5 
6 #include <string>
7 #include <string.h> // strlen
8 #include <assert.h>
9 #include "LuaUser.h"
10 #include "lua.h"
11 #include "lualib.h"
12 #include "lauxlib.h"
13 #include "lib/lua/src/lstate.h"
14 #include "lib/streflop/streflop_cond.h"
15 #include "System/Log/ILog.h"
16 
17 
18 
19 ///////////////////////////////////////////////////////////////////////////
20 // A few missing lua_to..., lua_check..., lua_opt...
21 //
22 
lua_pushsstring(lua_State * L,const std::string & str)23 static inline void lua_pushsstring(lua_State* L, const std::string& str)
24 {
25 	lua_pushlstring(L, str.data(), str.size());
26 }
27 
28 
luaL_tosstring(lua_State * L,int index)29 static inline std::string luaL_tosstring(lua_State* L, int index)
30 {
31 	size_t len = 0;
32 	const char* s = lua_tolstring(L, index, &len);
33 	return std::string(s, len);
34 }
35 
36 
luaL_checksstring(lua_State * L,int index)37 static inline std::string luaL_checksstring(lua_State* L, int index)
38 {
39 	size_t len = 0;
40 	const char* s = luaL_checklstring(L, index, &len);
41 	return std::string(s, len);
42 }
43 
44 
luaL_optsstring(lua_State * L,int index,const std::string & def)45 static inline std::string luaL_optsstring(lua_State* L, int index, const std::string& def)
46 {
47 	return luaL_opt(L, luaL_checksstring, index, def);
48 }
49 
50 
lua_israwnumber(lua_State * L,int index)51 static inline bool lua_israwnumber(lua_State* L, int index)
52 {
53 	return (lua_type(L, index) == LUA_TNUMBER);
54 }
55 
56 
lua_israwstring(lua_State * L,int index)57 static inline bool lua_israwstring(lua_State* L, int index)
58 {
59 	return (lua_type(L, index) == LUA_TSTRING);
60 }
61 
62 
lua_checkgeti(lua_State * L,int idx,int n)63 static inline int lua_checkgeti(lua_State* L, int idx, int n)
64 {
65 	lua_rawgeti(L, idx, n);
66 	if (lua_isnoneornil(L, -1)) {
67 		lua_pop(L, 1);
68 		return 0;
69 	}
70 	return 1;
71 }
72 
73 
lua_toint(lua_State * L,int idx)74 static inline int lua_toint(lua_State* L, int idx)
75 {
76 	return (int)lua_tointeger(L, idx);
77 }
78 
79 
lua_tofloat(lua_State * L,int idx)80 static inline float lua_tofloat(lua_State* L, int idx)
81 {
82 	const float n = lua_tonumber(L, idx);
83 #ifdef DEBUG
84 	// Note:
85 	// luaL_argerror must be called from inside of lua, else it calls exit()
86 	// so it can't be used in LuaParser::Get...() and similar
87 	if (math::isinf(n) || math::isnan(n)) luaL_argerror(L, idx, "number expected, got NAN (check your code for div0)");
88 #endif
89 	return n;
90 }
91 
92 
luaL_checkfloat(lua_State * L,int idx)93 static inline float luaL_checkfloat(lua_State* L, int idx)
94 {
95 	return (float)luaL_checknumber(L, idx);
96 }
97 
98 
luaL_optfloat(lua_State * L,int idx,float def)99 static inline float luaL_optfloat(lua_State* L, int idx, float def)
100 {
101 	return (float)luaL_optnumber(L, idx, def);
102 }
103 
104 
luaL_checkboolean(lua_State * L,int idx)105 static inline bool luaL_checkboolean(lua_State* L, int idx)
106 {
107 	luaL_checktype(L, idx, LUA_TBOOLEAN);
108 	return lua_toboolean(L, idx);
109 }
110 
111 
luaL_optboolean(lua_State * L,int idx,bool def)112 static inline bool luaL_optboolean(lua_State* L, int idx, bool def)
113 {
114 	return luaL_opt(L, luaL_checkboolean, idx, def);
115 }
116 
117 
118 
119 ///////////////////////////////////////////////////////////////////////////
120 // A few custom safety wrappers
121 //
122 
123 #undef lua_pop
lua_pop(lua_State * L,const int args)124 static inline void lua_pop(lua_State* L, const int args)
125 {
126 	assert(args > 0); // prevent lua_pop(L, -1) which is wrong, args is _count_ and not index (use lua_remove for that)
127 	lua_settop(L, -(args)-1); // from lua.h!
128 }
129 
130 
luaS_absIndex(lua_State * L,const int i)131 static inline int luaS_absIndex(lua_State* L, const int i)
132 {
133 	if (i <= 0 && i > LUA_REGISTRYINDEX)
134 		return lua_gettop(L) + (i) + 1;
135 
136 	return i;
137 }
138 
139 
140 template<typename T>
luaL_SpringOpt(lua_State * L,int idx,const T def,T (* lua_optFoo)(lua_State *,int,const T),T (* lua_toFoo)(lua_State *,int),int typeFoo,const char * caller)141 static inline T luaL_SpringOpt(lua_State* L, int idx, const T def, T(*lua_optFoo)(lua_State*, int, const T), T(*lua_toFoo)(lua_State*, int), int typeFoo, const char* caller)
142 {
143 	if (L->errorJmp) {
144 		return (*lua_optFoo)(L, idx, def);
145 	}
146 
147 	T ret = (*lua_toFoo)(L, idx);
148 	if (ret || (lua_type(L, idx) == typeFoo)) {
149 		return ret;
150 	}
151 
152 	if (!lua_isnoneornil(L, idx)) {
153 		LOG_L(L_WARNING, "Got wrong type for return argument #%d in \"%s::%s\" (%s expected, got %s)", luaS_absIndex(L, idx), spring_lua_getName(L), caller, lua_typename(L, typeFoo), luaL_typename(L, idx));
154 	}
155 	return def;
156 }
157 
158 
luaL_SpringOptString(lua_State * L,int idx,const std::string & def,std::string (* lua_optFoo)(lua_State *,int,const std::string &),std::string (* lua_toFoo)(lua_State *,int),int typeFoo,const char * caller)159 static inline std::string luaL_SpringOptString(lua_State* L, int idx, const std::string& def, std::string(*lua_optFoo)(lua_State*, int, const std::string&), std::string(*lua_toFoo)(lua_State*, int), int typeFoo, const char* caller)
160 {
161 	if (L->errorJmp) {
162 		return (*lua_optFoo)(L, idx, def);
163 	}
164 
165 	std::string ret = (*lua_toFoo)(L, idx);
166 	if (!ret.empty() || (lua_type(L, idx) == typeFoo)) {
167 		return ret;
168 	}
169 
170 	if (!lua_isnoneornil(L, idx)) {
171 		LOG_L(L_WARNING, "Got wrong type for return argument #%d in \"%s::%s\" (%s expected, got %s)", luaS_absIndex(L, idx), spring_lua_getName(L), caller, lua_typename(L, typeFoo), luaL_typename(L, idx));
172 	}
173 	return def;
174 }
175 
176 
luaL_SpringOptCString(lua_State * L,int idx,const char * def,size_t * len,const char * (* lua_optFoo)(lua_State *,int,const char *,size_t *),const char * (* lua_toFoo)(lua_State *,int,size_t *),int typeFoo,const char * caller)177 static inline const char* luaL_SpringOptCString(lua_State* L, int idx, const char* def, size_t* len, const char*(*lua_optFoo)(lua_State*, int, const char*, size_t*), const char*(*lua_toFoo)(lua_State*, int, size_t*), int typeFoo, const char* caller)
178 {
179 	if (L->errorJmp) {
180 		return (*lua_optFoo)(L, idx, def, len);
181 	}
182 
183 	const char* ret = (*lua_toFoo)(L, idx, len);
184 	if (ret || (lua_type(L, idx) == typeFoo)) {
185 		return ret;
186 	}
187 
188 	if (!lua_isnoneornil(L, idx)) {
189 		LOG_L(L_WARNING, "Got wrong type for return argument #%d in \"%s::%s\" (%s expected, got %s)", luaS_absIndex(L, idx), spring_lua_getName(L), caller, lua_typename(L, typeFoo), luaL_typename(L, idx));
190 	}
191 	if (len != NULL) *len = strlen(def);
192 	return def;
193 }
194 
195 
196 #define luaL_optboolean(L,idx,def)     (luaL_SpringOpt<bool>(L,idx,def,::luaL_optboolean,lua_toboolean,LUA_TBOOLEAN,__FUNCTION__))
197 #define luaL_optfloat(L,idx,def)       ((float)luaL_SpringOpt<lua_Number>(L,idx,def,::luaL_optfloat,lua_tofloat,LUA_TNUMBER,__FUNCTION__))
198 #define luaL_optinteger(L,idx,def)     (luaL_SpringOpt<lua_Integer>(L,idx,def,::luaL_optinteger,lua_tointeger,LUA_TNUMBER,__FUNCTION__))
199 #define luaL_optlstring(L,idx,def,len) (luaL_SpringOptCString(L,idx,def,len,::luaL_optlstring,lua_tolstring,LUA_TSTRING,__FUNCTION__))
200 #define luaL_optnumber(L,idx,def)      (luaL_SpringOpt<lua_Number>(L,idx,def,::luaL_optnumber,lua_tonumber,LUA_TNUMBER,__FUNCTION__))
201 
202 #define luaL_optsstring(L,idx,def)     (luaL_SpringOptString(L,idx,def,::luaL_optsstring,luaL_tosstring,LUA_TSTRING,__FUNCTION__))
203 
204 #ifdef luaL_optint
205 	#undef luaL_optint
206 	#define luaL_optint(L,idx,def) ((int)luaL_SpringOpt<lua_Integer>(L,idx,def,::luaL_optinteger,lua_tointeger,LUA_TNUMBER,__FUNCTION__))
207 #endif
208 #ifdef luaL_optstring
209 	#undef luaL_optstring
210 	#define luaL_optstring(L,idx,def) (luaL_SpringOptCString(L,idx,def,NULL,::luaL_optlstring,lua_tolstring,LUA_TSTRING,__FUNCTION__))
211 #endif
212 
213 
214 
215 ///////////////////////////////////////////////////////////////////////////
216 // State creation & destruction
217 //
218 
219 struct luaContextData;
220 
GetLuaContextData(const lua_State * L)221 static inline luaContextData* GetLuaContextData(const lua_State* L)
222 {
223 	return reinterpret_cast<luaContextData*>(G(L)->ud);
224 }
225 
226 static inline lua_State* LUA_OPEN(luaContextData* lcd = NULL) {
227 	lua_State* L = lua_newstate(spring_lua_alloc, lcd); // we want to use our own memory allocator
228 	return L;
229 }
230 
LUA_CLOSE(lua_State * L_Old)231 static inline void LUA_CLOSE(lua_State* L_Old) {
232 	lua_close(L_Old);
233 }
234 
235 
LUA_UNLOAD_LIB(lua_State * L,std::string libname)236 static inline void LUA_UNLOAD_LIB(lua_State* L, std::string libname) {
237 	luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 1);
238 	lua_pushsstring(L, libname);
239 	lua_pushnil(L);
240 	lua_rawset(L, -3);
241 
242 	lua_pushnil(L); lua_setglobal(L, libname.c_str());
243 }
244 
245 
246 #if (LUA_VERSION_NUM < 500)
247 #  define LUA_OPEN_LIB(L, lib) lib(L)
248 #else
249 #  define LUA_OPEN_LIB(L, lib) \
250      lua_pushcfunction((L), lib); \
251      lua_pcall((L), 0, 0, 0);
252 #endif
253 
254 
255 #endif // SPRING_LUA_INCLUDE
256