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