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