1 /*
2    Copyright (C) 2014 - 2018 by Chris Beck <render787@gmail.com>
3    Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY.
11 
12    See the COPYING file for more details.
13 */
14 
15 /**
16  * Common callbacks and functions to manipulate config, vconfig, tstring
17  * in lua, and macros to get them from the stack.
18  */
19 
20 #pragma once
21 
22 struct lua_State;
23 class t_string;
24 class vconfig;
25 
26 #include "config.hpp"
27 #include "variable_info.hpp"
28 #include "map/location.hpp"
29 #include <vector>
30 #include <string>
31 
32 namespace lua_common {
33 	int intf_textdomain(lua_State *L);
34 	int intf_tovconfig(lua_State* L);
35 
36 	std::string register_gettext_metatable(lua_State *L);
37 	std::string register_tstring_metatable(lua_State *L);
38 	std::string register_vconfig_metatable(lua_State *L);
39 
40 }
41 
42 void* operator new(size_t sz, lua_State *L);
43 void operator delete(void* p, lua_State *L);
44 
45 /**
46  * Like luaL_getmetafield, but returns false if key is an empty string
47  * or begins with two underscores.
48  */
49 bool luaW_getmetafield(lua_State *L, int idx, const char* key);
50 
51 /**
52  * Pushes a vconfig on the top of the stack.
53  */
54 void luaW_pushvconfig(lua_State *L, const vconfig& cfg);
55 
56 /**
57  * Pushes a t_string on the top of the stack.
58  */
59 void luaW_pushtstring(lua_State *L, const t_string& v);
60 
61 /**
62  * Converts an attribute value into a Lua object pushed at the top of the stack.
63  */
64 void luaW_pushscalar(lua_State *L, const config::attribute_value& v);
65 
66 /**
67  * Converts the value at the top of the stack to an attribute value
68  */
69 bool luaW_toscalar(lua_State *L, int index, config::attribute_value& v);
70 
71 /**
72  * Converts a scalar to a translatable string.
73  */
74 bool luaW_totstring(lua_State *L, int index, t_string &str);
75 
76 /**
77  * Converts a scalar to a translatable string.
78  */
79 t_string luaW_checktstring(lua_State *L, int index);
80 
81 /*
82  * Test if a scalar is either a plain or translatable string.
83  * Also returns true if it's a number since that's convertible to string.
84  */
85 bool luaW_iststring(lua_State* L, int index);
86 
87 /**
88  * Converts a config object to a Lua table.
89  * The destination table should be at the top of the stack on entry. It is
90  * still at the top on exit.
91  */
92 void luaW_filltable(lua_State *L, const config& cfg);
93 
94 /**
95  * Converts a map location object to a Lua table pushed at the top of the stack.
96  */
97 void luaW_pushlocation(lua_State *L, const map_location& loc);
98 
99 /**
100  * Converts an optional table or pair of integers to a map location object.
101  * @param index stack position of the table or first integer.
102  * @return false if a map location couldn't be matched.
103  */
104 bool luaW_tolocation(lua_State *L, int index, map_location &loc);
105 
106 /**
107  * Converts an optional table or pair of integers to a map location object.
108  * @note If a pair of integers was found, the first one will be removed
109  *       from the stack when the function returns.
110  */
111 map_location luaW_checklocation(lua_State *L, int index);
112 
113 /**
114  * Converts a config object to a Lua table pushed at the top of the stack.
115  */
116 void luaW_pushconfig(lua_State *L, const config& cfg);
117 
118 /**
119  * Converts an optional table or vconfig to a config object.
120  * @param index stack position of the table.
121  * @return false if some attributes had not the proper type.
122  * @note If the table has holes in the integer keys or floating-point keys,
123  *       some keys will be ignored and the error will go undetected.
124  */
125 bool luaW_toconfig(lua_State *L, int index, config &cfg);
126 
127 /**
128  * Converts an optional table or vconfig to a config object.
129  */
130 config luaW_checkconfig(lua_State *L, int index);
131 
132 /**
133  * Gets an optional vconfig from either a table or a userdata.
134  * @return false in case of failure.
135  */
136 bool luaW_tovconfig(lua_State *L, int index, vconfig &vcfg);
137 
138 /**
139  * Gets an optional vconfig from either a table or a userdata.
140  * @param allow_missing true if missing values are allowed; the function
141  *        then returns an unconstructed vconfig.
142  */
143 vconfig luaW_checkvconfig(lua_State *L, int index, bool allow_missing = false);
144 
145 /**
146  * Like the two-argument version, but if it was a vconfig, also
147  * returns a pointer to that vconfig.
148  */
149 config luaW_checkconfig(lua_State *L, int index, const vconfig*& vcfg);
150 
151 /**
152  * Pushes the value found by following the variadic names (char *), if the
153  * value is not nil.
154  * @return true if an element was pushed.
155  */
156 bool luaW_getglobal(lua_State *L, const std::vector<std::string>& path);
157 
158 /**
159  * Pushes the value found by following the variadic names (char *), if the
160  * value is not nil.
161  * @return true if an element was pushed.
162  */
163 template<typename... T>
luaW_getglobal(lua_State * L,T...path)164 bool luaW_getglobal(lua_State *L, T... path) {
165 	return luaW_getglobal(L, std::vector<std::string> {path...} );
166 }
167 
168 bool luaW_toboolean(lua_State *L, int n);
169 
170 
171 bool luaW_pushvariable(lua_State *L, variable_access_const& v);
172 
173 bool luaW_checkvariable(lua_State *L, variable_access_create& v, int n);
174 
175 /**
176  * Displays a message in the chat window.
177  */
178 void chat_message(const std::string& caption, const std::string& msg);
179 
180 /**
181  * Calls a Lua function stored below its @a nArgs arguments at the top of the stack.
182  * @param nRets LUA_MULTRET for unbounded return values.
183  * @return true if the call was successful and @a nRets return values are available.
184  */
185 bool luaW_pcall(lua_State *L, int nArgs, int nRets, bool allow_wml_error = false);
186 
187 // Don't use these directly
188 void push_error_handler(lua_State *L);
189 int luaW_pcall_internal(lua_State *L, int nArgs, int nRets);
190 
191 int luaW_type_error(lua_State *L, int narg, const char *tname);
192 int luaW_type_error(lua_State *L, int narg, const char* kpath, const char *tname);
193 
194 #define return_tstring_attrib(name, accessor) \
195 do { \
196 	if (strcmp(m, (name)) == 0) { \
197 		luaW_pushtstring(L, (accessor)); \
198 		return 1; \
199 	} \
200 } while(false)
201 
202 #define return_cstring_attrib(name, accessor) \
203 do { \
204 	if (strcmp(m, (name)) == 0) { \
205 		lua_pushstring(L, (accessor)); \
206 		return 1; \
207 	} \
208 } while(false)
209 
210 #define return_string_attrib(name, accessor) \
211 do { \
212 	if (strcmp(m, (name)) == 0) { \
213 		const std::string& str = (accessor); \
214 		lua_pushlstring(L, str.c_str(), str.length()); \
215 		return 1; \
216 	} \
217 } while(false)
218 
219 #define return_int_attrib(name, accessor) \
220 do { \
221 	if (strcmp(m, (name)) == 0) { \
222 		lua_pushinteger(L, (accessor)); \
223 		return 1; \
224 	} \
225 } while(false)
226 
227 #define return_float_attrib(name, accessor) \
228 do { \
229 	if (strcmp(m, (name)) == 0) { \
230 		lua_pushnumber(L, (accessor)); \
231 		return 1; \
232 	} \
233 } while(false)
234 
235 #define return_bool_attrib(name, accessor) \
236 do { \
237 	if (strcmp(m, (name)) == 0) { \
238 		lua_pushboolean(L, (accessor)); \
239 		return 1; \
240 	} \
241 } while(false)
242 
243 #define return_cfg_attrib(name, accessor) \
244 do { \
245 	if (strcmp(m, (name)) == 0) { \
246 		config cfg; \
247 		{accessor;} \
248 		luaW_pushconfig(L, cfg); \
249 		return 1; \
250 	} \
251 } while(false)
252 
253 #define return_cfgref_attrib(name, accessor) \
254 do { \
255 	if (strcmp(m, (name)) == 0) { \
256 		luaW_pushconfig(L, (accessor)); \
257 		return 1; \
258 	} \
259 } while(false)
260 
261 #define return_vector_string_attrib(name, accessor) \
262 do { \
263 	if (strcmp(m, (name)) == 0) { \
264 		const std::vector<std::string>& vector = (accessor); \
265 		lua_createtable(L, vector.size(), 0); \
266 		int i = 1; \
267 		for (const std::string& s : vector) { \
268 			lua_pushlstring(L, s.c_str(), s.length()); \
269 			lua_rawseti(L, -2, i); \
270 			++i; \
271 		} \
272 		return 1; \
273 	} \
274 } while(false)
275 
276 #define modify_tstring_attrib(name, accessor) \
277 do { \
278 	if (strcmp(m, (name)) == 0) { \
279 		t_string value = luaW_checktstring(L, 3); \
280 		{accessor;} \
281 		return 0; \
282 	} \
283 } while(false)
284 
285 #define modify_string_attrib(name, accessor) \
286 do { \
287 	if (strcmp(m, (name)) == 0) { \
288 		const char *value = luaL_checkstring(L, 3); \
289 		{accessor;} \
290 		return 0; \
291 	} \
292 } while(false)
293 
294 #define modify_int_attrib(name, accessor) \
295 do { \
296 	if (strcmp(m, (name)) == 0) { \
297 		int value = static_cast<int>(luaL_checknumber(L, 3)); \
298 		{accessor;} \
299 		return 0; \
300 	} \
301 } while(false)
302 
303 #define modify_int_attrib_check_range(name, accessor, allowed_min, allowed_max) \
304 do { \
305 	if (strcmp(m, (name)) == 0) { \
306 		int value = static_cast<int>(luaL_checknumber(L, 3)); \
307 		if (value < (allowed_min) || (allowed_max) < value) return luaL_argerror(L, 3, "out of bounds"); \
308 		{accessor;} \
309 		return 0; \
310 	} \
311 } while(false)
312 
313 #define modify_float_attrib(name, accessor) \
314 do { \
315 	if (strcmp(m, (name)) == 0) { \
316 		lua_Number value = luaL_checknumber(L, 3); \
317 		{accessor;} \
318 		return 0; \
319 	} \
320 } while(false)
321 
322 #define modify_float_attrib_check_range(name, accessor, allowed_min, allowed_max) \
323 do { \
324 	if (strcmp(m, (name)) == 0) { \
325 		lua_Number value = luaL_checknumber(L, 3); \
326 		if (value < (allowed_min) || (allowed_max) < value) return luaL_argerror(L, 3, "out of bounds"); \
327 		{accessor;} \
328 		return 0; \
329 	} \
330 } while(false)
331 
332 #define modify_bool_attrib(name, accessor) \
333 do { \
334 	if (strcmp(m, (name)) == 0) { \
335 		bool value = luaW_toboolean(L, 3); \
336 		{accessor;} \
337 		return 0; \
338 	} \
339 } while(false)
340 
341 #define modify_vector_string_attrib(name, accessor) \
342 do { \
343 	if (strcmp(m, (name)) == 0) { \
344 		std::vector<std::string> value; \
345 		char const* message = "table with unnamed indices holding strings expected"; \
346 		if (!lua_istable(L, 3)) return luaL_argerror(L, 3, message); \
347 		unsigned length = lua_rawlen(L, 3); \
348 		for (unsigned i = 1; i <= length; ++i) { \
349 			lua_rawgeti(L, 3, i); \
350 			char const* string = lua_tostring(L, 4); \
351 			if(!string) return luaL_argerror(L, 2 + i, message); \
352 			value.push_back(string); \
353 			lua_pop(L, 1); \
354 		} \
355 		{accessor;} \
356 		return 0; \
357 	} \
358 } while(false)
359