1 /*
2 Copyright (c) 2009 Peter "Corsix" Cawley
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy of
5 this software and associated documentation files (the "Software"), to deal in
6 the Software without restriction, including without limitation the rights to
7 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
8 of the Software, and to permit persons to whom the Software is furnished to do
9 so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in all
12 copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 SOFTWARE.
21 */
22
23 #ifndef CORSIX_TH_TH_LUA_H_
24 #define CORSIX_TH_TH_LUA_H_
25 #include "config.h"
26
27 #include <cassert>
28 #include <cstdio>
29 #include <new>
30 #include <vector>
31
32 #include "lua.hpp"
33
34 int luaopen_th(lua_State* L);
35
luaT_rotate(lua_State * L,int idx,int n)36 inline void luaT_rotate(lua_State* L, int idx, int n) {
37 #if LUA_VERSION_NUM >= 503
38 lua_rotate(L, idx, n);
39 #else
40 if (n < 0) {
41 if (idx < 0) {
42 idx = lua_gettop(L) + idx + 1;
43 }
44 n = lua_gettop(L) - idx + 1 + n;
45 }
46
47 for (int i = 0; i < n; i++) {
48 lua_insert(L, idx);
49 }
50 #endif
51 }
52
53 // Compatibility layer for removal of environments in 5.2
54 #if LUA_VERSION_NUM >= 502
55 const int luaT_environindex = lua_upvalueindex(1);
56 #else
57 const int luaT_environindex = LUA_ENVIRONINDEX;
58 #endif
59
luaT_upvalueindex(int i)60 inline int luaT_upvalueindex(int i) {
61 #if LUA_VERSION_NUM >= 502
62 return lua_upvalueindex(i + 1);
63 #else
64 return lua_upvalueindex(i);
65 #endif
66 }
67
68 template <class Collection>
luaT_register(lua_State * L,const char * n,Collection & l)69 inline void luaT_register(lua_State* L, const char* n, Collection& l) {
70 #if LUA_VERSION_NUM >= 502
71 lua_createtable(L, 0, static_cast<int>(l.size()));
72 lua_pushvalue(L, luaT_environindex);
73 luaL_setfuncs(L, l.data(), 1);
74 lua_pushvalue(L, -1);
75 lua_setglobal(L, n);
76 #else
77 luaL_register(L, n, l.data());
78 #endif
79 }
80
luaT_setfuncs(lua_State * L,const luaL_Reg * R)81 inline void luaT_setfuncs(lua_State* L, const luaL_Reg* R) {
82 #if LUA_VERSION_NUM >= 502
83 lua_pushvalue(L, luaT_environindex);
84 luaL_setfuncs(L, R, 1);
85 #else
86 luaL_register(L, nullptr, R);
87 #endif
88 }
89
luaT_pushcclosure(lua_State * L,lua_CFunction f,int nups)90 inline void luaT_pushcclosure(lua_State* L, lua_CFunction f, int nups) {
91 #if LUA_VERSION_NUM >= 502
92 ++nups;
93 lua_pushvalue(L, luaT_environindex);
94 lua_insert(L, -nups);
95 lua_pushcclosure(L, f, nups);
96 #else
97 lua_pushcclosure(L, f, nups);
98 #endif
99 }
100
luaT_pushcfunction(lua_State * L,lua_CFunction f)101 inline void luaT_pushcfunction(lua_State* L, lua_CFunction f) {
102 luaT_pushcclosure(L, f, 0);
103 }
104
luaT_cpcall(lua_State * L,lua_CFunction f,void * u)105 inline int luaT_cpcall(lua_State* L, lua_CFunction f, void* u) {
106 #if LUA_VERSION_NUM >= 502
107 lua_checkstack(L, 2);
108 lua_pushcfunction(L, f);
109 lua_pushlightuserdata(L, u);
110 return lua_pcall(L, 1, 0, 0);
111 #else
112 return lua_cpcall(L, f, u);
113 #endif
114 }
115
116 // Compatibility for missing mode argument on lua_load in 5.1
luaT_load(lua_State * L,lua_Reader r,void * d,const char * s,const char * m)117 inline int luaT_load(lua_State* L, lua_Reader r, void* d, const char* s,
118 const char* m) {
119 #if LUA_VERSION_NUM >= 502
120 return lua_load(L, r, d, s, m);
121 #else
122 return lua_load(L, r, d, s);
123 #endif
124 }
125
126 // Compatibility for older versions of lua_resume
luaT_resume(lua_State * L,lua_State * f,int n,int * nresults)127 inline int luaT_resume(lua_State* L, lua_State* f, int n, int* nresults) {
128 #if LUA_VERSION_NUM >= 504
129 return lua_resume(L, f, n, nresults);
130 #elif LUA_VERSION_NUM >= 502
131 int res = lua_resume(L, f, n);
132 *nresults = lua_gettop(L);
133 return res;
134 #else
135 int res = lua_resume(L, n);
136 *nresults = lua_gettop(L);
137 return res;
138 #endif
139 }
140
141 //! Version of operator new which allocates into a Lua userdata
142 /*!
143 If a specific constructor of T is required, then call like:
144 T* variable = luaT_new<T>(L, constructor arguments);
145 If the default constructor is wanted, it can be called like:
146 T* variable = luaT_new<T>(L);
147 See also luaT_stdnew() which allocates, and also sets up the environment
148 table and metatable for the userdata.
149 */
150 template <typename T, typename... Ts>
luaT_new(lua_State * L,Ts...args)151 T* luaT_new(lua_State* L, Ts... args) {
152 return new (lua_newuserdata(L, sizeof(T))) T(args...);
153 }
154
155 //! Check that a Lua argument is a binary data blob
156 /*!
157 If the given argument is a string or (full) userdata, then returns a
158 pointer to the start of it, and the length of it. Otherwise, throws a
159 Lua error.
160 */
161 const uint8_t* luaT_checkfile(lua_State* L, int idx, size_t* pDataLen);
162
163 //! Check that a Lua argument is a string or a proxied string
164 const char* luaT_checkstring(lua_State* L, int idx, size_t* pLength);
165
166 //! Push a C closure as a callable table
167 void luaT_pushcclosuretable(lua_State* L, lua_CFunction fn, int n);
168
169 //! Set a field on the environment table of a value
170 /*!
171 Performs: env(stack[index])[k] = top; pop()
172 */
173 void luaT_setenvfield(lua_State* L, int index, const char* k);
174
175 //! Get a field from the environment table of a value
176 /*!
177 Performs: push(env(stack[index])[k])
178 */
179 void luaT_getenvfield(lua_State* L, int index, const char* k);
180
181 template <class T>
182 inline T* luaT_stdnew(lua_State* L, int mt_idx = luaT_environindex,
183 bool env = false) {
184 T* p = luaT_new<T>(L);
185 lua_pushvalue(L, mt_idx);
186 lua_setmetatable(L, -2);
187 if (env) {
188 lua_newtable(L);
189 lua_setfenv(L, -2);
190 }
191 return p;
192 }
193
194 template <typename T>
195 struct luaT_classinfo {};
196
197 class render_target;
198 template <>
199 struct luaT_classinfo<render_target> {
200 static inline const char* name() { return "Surface"; }
201 };
202
203 class level_map;
204 template <>
205 struct luaT_classinfo<level_map> {
206 static inline const char* name() { return "Map"; }
207 };
208
209 class sprite_sheet;
210 template <>
211 struct luaT_classinfo<sprite_sheet> {
212 static inline const char* name() { return "SpriteSheet"; }
213 };
214
215 class animation;
216 template <>
217 struct luaT_classinfo<animation> {
218 static inline const char* name() { return "Animation"; }
219 };
220
221 class animation_manager;
222 template <>
223 struct luaT_classinfo<animation_manager> {
224 static inline const char* name() { return "Animator"; }
225 };
226
227 class palette;
228 template <>
229 struct luaT_classinfo<palette> {
230 static inline const char* name() { return "Palette"; }
231 };
232
233 class raw_bitmap;
234 template <>
235 struct luaT_classinfo<raw_bitmap> {
236 static inline const char* name() { return "RawBitmap"; }
237 };
238
239 class font;
240 template <>
241 struct luaT_classinfo<font> {
242 static inline const char* name() { return "Font"; }
243 };
244
245 class bitmap_font;
246 template <>
247 struct luaT_classinfo<bitmap_font> {
248 static inline const char* name() { return "BitmapFont"; }
249 };
250
251 #ifdef CORSIX_TH_USE_FREETYPE2
252 class freetype_font;
253 template <>
254 struct luaT_classinfo<freetype_font> {
255 static inline const char* name() { return "FreeTypeFont"; }
256 };
257 #endif
258
259 struct layers;
260 template <>
261 struct luaT_classinfo<layers> {
262 static inline const char* name() { return "Layers"; }
263 };
264
265 class pathfinder;
266 template <>
267 struct luaT_classinfo<pathfinder> {
268 static inline const char* name() { return "Pathfinder"; }
269 };
270
271 class cursor;
272 template <>
273 struct luaT_classinfo<cursor> {
274 static inline const char* name() { return "Cursor"; }
275 };
276
277 class line;
278 template <>
279 struct luaT_classinfo<line> {
280 static inline const char* name() { return "Line"; }
281 };
282
283 class music;
284 template <>
285 struct luaT_classinfo<music> {
286 static inline const char* name() { return "Music"; }
287 };
288
289 class sound_archive;
290 template <>
291 struct luaT_classinfo<sound_archive> {
292 static inline const char* name() { return "SoundArchive"; }
293 };
294
295 class sound_player;
296 template <>
297 struct luaT_classinfo<sound_player> {
298 static inline const char* name() { return "SoundEffects"; }
299 };
300
301 class movie_player;
302 template <>
303 struct luaT_classinfo<movie_player> {
304 static inline const char* name() { return "Movie"; }
305 };
306
307 class abstract_window;
308 template <>
309 struct luaT_classinfo<abstract_window> {
310 static inline const char* name() { return "WindowBase"; }
311 };
312
313 class sprite_render_list;
314 template <>
315 struct luaT_classinfo<sprite_render_list> {
316 static inline const char* name() { return "SpriteRenderList"; }
317 };
318
319 class string_proxy;
320 template <>
321 struct luaT_classinfo<string_proxy> {
322 static inline const char* name() { return "StringProxy"; }
323 };
324
325 class lfs_ext;
326 template <>
327 struct luaT_classinfo<lfs_ext> {
328 static inline const char* name() { return "LfsExt"; }
329 };
330
331 class iso_filesystem;
332 template <>
333 struct luaT_classinfo<iso_filesystem> {
334 static inline const char* name() { return "ISO Filesystem"; }
335 };
336
337 template <class T>
338 T* luaT_testuserdata(lua_State* L, int idx, int mt_idx, bool required = true) {
339 // Turn mt_idx into an absolute index, as the stack size changes.
340 if (mt_idx > LUA_REGISTRYINDEX && mt_idx < 0) {
341 mt_idx = lua_gettop(L) + mt_idx + 1;
342 }
343
344 void* ud = lua_touserdata(L, idx);
345 if (ud != nullptr && lua_getmetatable(L, idx) != 0) {
346 while (true) {
347 if (lua_equal(L, mt_idx, -1) != 0) {
348 lua_pop(L, 1);
349 return static_cast<T*>(ud);
350 }
351 // Go up one inheritance level, if there is one.
352 if (lua_type(L, -1) != LUA_TTABLE) break;
353 lua_rawgeti(L, -1, 1);
354 lua_replace(L, -2);
355 }
356 lua_pop(L, 1);
357 }
358
359 if (required) {
360 const char* msg =
361 lua_pushfstring(L, "%s expected, got %s", luaT_classinfo<T>::name(),
362 luaL_typename(L, idx));
363 luaL_argerror(L, idx, msg);
364 assert(false); // unreachable
365 }
366 return nullptr;
367 }
368
369 template <class T>
370 T* luaT_testuserdata(lua_State* L, int idx = 1) {
371 int iMetaIndex = luaT_environindex;
372 if (idx > 1) iMetaIndex = luaT_upvalueindex(idx - 1);
373 return luaT_testuserdata<T>(L, idx, iMetaIndex);
374 }
375
376 template <class T, int mt>
377 int luaT_stdgc(lua_State* L) {
378 T* p = luaT_testuserdata<T>(L, 1, mt, false);
379 if (p != nullptr) {
380 p->~T();
381 }
382 return 0;
383 }
384
385 void luaT_execute(lua_State* L, const char* sLuaString);
386 void luaT_execute_loadstring(lua_State* L, const char* sLuaString);
387
388 void luaT_push(lua_State* L, lua_CFunction f);
389 void luaT_push(lua_State* L, int i);
390 void luaT_push(lua_State* L, const char* s);
391
392 template <class T>
393 void luaT_execute(lua_State* L, const char* sLuaString, T arg) {
394 luaT_execute_loadstring(L, sLuaString);
395 luaT_push(L, arg);
396 lua_call(L, 1, LUA_MULTRET);
397 }
398
399 template <class T1, class T2>
400 void luaT_execute(lua_State* L, const char* sLuaString, T1 arg1, T2 arg2) {
401 luaT_execute_loadstring(L, sLuaString);
402 luaT_push(L, arg1);
403 luaT_push(L, arg2);
404 lua_call(L, 2, LUA_MULTRET);
405 }
406
407 template <class T1, class T2, class T3>
408 void luaT_execute(lua_State* L, const char* sLuaString, T1 arg1, T2 arg2,
409 T3 arg3) {
410 luaT_execute_loadstring(L, sLuaString);
411 luaT_push(L, arg1);
412 luaT_push(L, arg2);
413 luaT_push(L, arg3);
414 lua_call(L, 3, LUA_MULTRET);
415 }
416
417 template <class T1, class T2, class T3, class T4>
418 void luaT_execute(lua_State* L, const char* sLuaString, T1 arg1, T2 arg2,
419 T3 arg3, T4 arg4) {
420 luaT_execute_loadstring(L, sLuaString);
421 luaT_push(L, arg1);
422 luaT_push(L, arg2);
423 luaT_push(L, arg3);
424 luaT_push(L, arg4);
425 lua_call(L, 4, LUA_MULTRET);
426 }
427
428 void luaT_pushtablebool(lua_State* L, const char* k, bool v);
429
430 // Print debugging helper functions
431
432 void luaT_printvalue(lua_State* L, int idx);
433
434 void luaT_printstack(lua_State* L);
435
436 void luaT_printrawtable(lua_State* L, int idx);
437
438 #endif // CORSIX_TH_TH_LUA_H_
439