The Battle for Wesnoth  1.19.8+dev
lua_common.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014 - 2024
3  by Chris Beck <render787@gmail.com>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 /**
17  * Common callbacks and functions to manipulate config, vconfig, tstring
18  * in lua, and macros to get them from the stack.
19  */
20 
21 #pragma once
22 
23 struct lua_State;
24 class t_string;
25 class vconfig;
26 
27 #include "config.hpp"
28 #include "variable_info.hpp"
29 #include "map/location.hpp"
30 
31 #include <string>
32 #include <string_view>
33 #include <vector>
34 
35 namespace lua_common {
36  int intf_textdomain(lua_State *L);
37  int intf_tovconfig(lua_State* L);
38 
39  std::string register_gettext_metatable(lua_State *L);
40  std::string register_tstring_metatable(lua_State *L);
41  std::string register_vconfig_metatable(lua_State *L);
42 
43 }
44 
45 void* operator new(std::size_t sz, lua_State *L, int nuv = 0);
46 void operator delete(void* p, lua_State *L, int nuv);
47 
48 /**
49  * Like luaL_getmetafield, but returns false if key is an empty string
50  * or begins with two underscores.
51  */
52 bool luaW_getmetafield(lua_State *L, int idx, const char* key);
53 
54 /**
55  * Pushes a vconfig on the top of the stack.
56  */
57 void luaW_pushvconfig(lua_State *L, const vconfig& cfg);
58 
59 /**
60  * Pushes a t_string on the top of the stack.
61  */
62 void luaW_pushtstring(lua_State *L, const t_string& v);
63 
64 /**
65  * Converts an attribute value into a Lua object pushed at the top of the stack.
66  */
67 void luaW_pushscalar(lua_State *L, const config::attribute_value& v);
68 
69 /**
70  * Converts the value at the top of the stack to an attribute value
71  */
72 bool luaW_toscalar(lua_State *L, int index, config::attribute_value& v);
73 
74 /**
75  * Converts a scalar to a translatable string.
76  */
77 bool luaW_totstring(lua_State *L, int index, t_string &str);
78 
79 /**
80  * Converts a scalar to a translatable string.
81  */
82 t_string luaW_checktstring(lua_State *L, int index);
83 
84 /*
85  * Test if a scalar is either a plain or translatable string.
86  * Also returns true if it's a number since that's convertible to string.
87  */
88 bool luaW_iststring(lua_State* L, int index);
89 
90 /**
91  * Converts a config object to a Lua table.
92  * The destination table should be at the top of the stack on entry. It is
93  * still at the top on exit.
94  */
95 void luaW_filltable(lua_State *L, const config& cfg);
96 
97 /**
98  * Push an empty "named tuple" onto the stack.
99  * A named tuple is an array where each index can also be accessed by name.
100  * Once it's pushed, you can set the elements, eg with lua_rawseti.
101  */
102 void luaW_push_namedtuple(lua_State* L, const std::vector<std::string>& names);
103 
104 /**
105  * Get the keys of a "named tuple" from the stack.
106  * Returns an empty array if the stack element is not a named tuple.
107  */
108 std::vector<std::string> luaW_to_namedtuple(lua_State* L, int idx);
109 
110 /**
111  * Converts a map location object to a Lua table pushed at the top of the stack.
112  */
113 void luaW_pushlocation(lua_State *L, const map_location& loc);
114 
115 /**
116  * Converts an optional table or pair of integers to a map location object.
117  * @param L the pointer to the lua interpreter.
118  * @param index stack position of the table or first integer.
119  * @param loc the location to write to.
120  * @return false if a map location couldn't be matched.
121  */
122 bool luaW_tolocation(lua_State *L, int index, map_location &loc);
123 
124 /**
125  * Converts an optional table or pair of integers to a map location object.
126  * @note If a pair of integers was found, the first one will be removed
127  * from the stack when the function returns.
128  */
129 map_location luaW_checklocation(lua_State *L, int index);
130 
131 /**
132  * Converts a set of map locations to a Lua table pushed at the top of the stack.
133  */
134 int luaW_push_locationset(lua_State* L, const std::set<map_location>& locs);
135 
136 /**
137  * Converts a table of integer pairs to a set of map location objects.
138  */
139 std::set<map_location> luaW_check_locationset(lua_State* L, int idx);
140 
141 /**
142  * Converts a config object to a Lua table pushed at the top of the stack.
143  */
144 void luaW_pushconfig(lua_State *L, const config& cfg);
145 
146 /**
147  * Converts an optional table or vconfig to a config object.
148  * @param L the pointer to the lua interpreter.
149  * @param index stack position of the table.
150  * @param cfg the config to write the data to.
151  * @return false if some attributes had not the proper type.
152  * @note If the table has holes in the integer keys or floating-point keys,
153  * some keys will be ignored and the error will go undetected.
154  */
155 bool luaW_toconfig(lua_State *L, int index, config &cfg);
156 
157 /**
158  * Converts an optional table or vconfig to a config object.
159  */
160 config luaW_checkconfig(lua_State *L, int index);
161 
162 /**
163  * Gets an optional vconfig from either a table or a userdata.
164  * @return false in case of failure.
165  */
166 bool luaW_tovconfig(lua_State *L, int index, vconfig &vcfg);
167 
168 /**
169  * Gets an optional vconfig from either a table or a userdata.
170  * @param L the pointer to the lua interpreter.
171  * @param index the location in the current lua execution stack to look at.
172  * @param allow_missing true if missing values are allowed; the function
173  * then returns an unconstructed vconfig.
174  */
175 vconfig luaW_checkvconfig(lua_State *L, int index, bool allow_missing = false);
176 
177 /**
178  * Like the two-argument version, but if it was a vconfig, also
179  * returns a pointer to that vconfig.
180  */
181 config luaW_checkconfig(lua_State *L, int index, const vconfig*& vcfg);
182 
183 /**
184  * Pushes the value found by following the variadic names (char *), if the
185  * value is not nil.
186  * @return true if an element was pushed.
187  */
188 bool luaW_getglobal(lua_State *L, const std::vector<std::string>& path);
189 
190 /**
191  * Pushes the value found by following the variadic names (char *), if the
192  * value is not nil.
193  * @return true if an element was pushed.
194  */
195 template<typename... T>
196 bool luaW_getglobal(lua_State *L, T... path) {
197  return luaW_getglobal(L, std::vector<std::string> {path...} );
198 }
199 
200 bool luaW_toboolean(lua_State *L, int n);
201 
202 
203 bool luaW_pushvariable(lua_State *L, variable_access_const& v);
204 
205 bool luaW_checkvariable(lua_State *L, variable_access_create& v, int n);
206 
207 bool luaW_tableget(lua_State *L, int index, const char* key);
208 
209 std::string_view luaW_tostring(lua_State *L, int index);
210 std::string_view luaW_tostring_or_default(lua_State *L, int index, std::string_view def = std::string_view());
211 
212 /**
213  * Displays a message in the chat window.
214  */
215 void chat_message(const std::string& caption, const std::string& msg);
216 
217 /**
218  * Calls a Lua function stored below its @a nArgs arguments at the top of the stack.
219  * @param L the pointer to the lua interpreter.
220  * @param nArgs
221  * @param nRets LUA_MULTRET for unbounded return values.
222  * @param allow_wml_error controls where any stack traces are output.
223  * @return true if the call was successful and @a nRets return values are available.
224  */
225 bool luaW_pcall(lua_State *L, int nArgs, int nRets, bool allow_wml_error = false);
226 
227 // Don't use these directly
228 void push_error_handler(lua_State *L);
229 int luaW_pcall_internal(lua_State *L, int nArgs, int nRets);
230 
231 int luaW_type_error(lua_State *L, int narg, const char *tname);
232 int luaW_type_error(lua_State *L, int narg, const char* kpath, const char *tname);
233 
234 struct luaW_PrintStack { lua_State* L; };
235 luaW_PrintStack luaW_debugstack(lua_State* L);
236 std::ostream& operator<<(std::ostream& os, const luaW_PrintStack&);
237 
238 #define deprecate_attrib(name, prefix, level, version, msg) deprecated_message(prefix "." name, DEP_LEVEL::level, version, msg)
239 
240 #define return_deprecated_attrib(type_macro, name, accessor, prefix, level, version, msg) \
241  type_macro(name, ( \
242  deprecate_attrib(name, prefix, level, version, msg), \
243  accessor \
244  ))
245 
246 #define return_tstring_attrib(name, accessor) \
247 do { \
248  if (strcmp(m, (name)) == 0) { \
249  luaW_pushtstring(L, (accessor)); \
250  return 1; \
251  } \
252 } while(false)
253 #define return_tstring_attrib_deprecated(name, prefix, level, version, msg, accessor) \
254  return_deprecated_attrib(return_tstring_attrib, name, accessor, prefix, level, version, msg)
255 
256 #define return_cstring_attrib(name, accessor) \
257 do { \
258  if (strcmp(m, (name)) == 0) { \
259  lua_pushstring(L, (accessor)); \
260  return 1; \
261  } \
262 } while(false)
263 #define return_cstring_attrib_deprecated(name, prefix, level, version, msg, accessor) \
264  return_deprecated_attrib(return_cstring_attrib, name, accessor, prefix, level, version, msg)
265 
266 #define return_string_attrib(name, accessor) \
267 do { \
268  if (strcmp(m, (name)) == 0) { \
269  const std::string& str = (accessor); \
270  lua_pushlstring(L, str.c_str(), str.length()); \
271  return 1; \
272  } \
273 } while(false)
274 #define return_string_attrib_deprecated(name, prefix, level, version, msg, accessor) \
275  return_deprecated_attrib(return_string_attrib, name, accessor, prefix, level, version, msg)
276 
277 #define return_int_attrib(name, accessor) \
278 do { \
279  if (strcmp(m, (name)) == 0) { \
280  lua_pushinteger(L, (accessor)); \
281  return 1; \
282  } \
283 } while(false)
284 #define return_int_attrib_deprecated(name, prefix, level, version, msg, accessor) \
285  return_deprecated_attrib(return_int_attrib, name, accessor, prefix, level, version, msg)
286 
287 #define return_float_attrib(name, accessor) \
288 do { \
289  if (strcmp(m, (name)) == 0) { \
290  lua_pushnumber(L, (accessor)); \
291  return 1; \
292  } \
293 } while(false)
294 #define return_float_attrib_deprecated(name, prefix, level, version, msg, accessor) \
295  return_deprecated_attrib(return_float_attrib, name, accessor, prefix, level, version, msg)
296 
297 #define return_bool_attrib(name, accessor) \
298 do { \
299  if (strcmp(m, (name)) == 0) { \
300  lua_pushboolean(L, (accessor)); \
301  return 1; \
302  } \
303 } while(false)
304 #define return_bool_attrib_deprecated(name, prefix, level, version, msg, accessor) \
305  return_deprecated_attrib(return_bool_attrib, name, accessor, prefix, level, version, msg)
306 
307 #define return_cfg_attrib(name, accessor) \
308 do { \
309  if (strcmp(m, (name)) == 0) { \
310  config cfg; \
311  {accessor;} \
312  luaW_pushconfig(L, cfg); \
313  return 1; \
314  } \
315 } while(false)
316 #define return_cfg_attrib_deprecated(name, prefix, level, version, msg, accessor) \
317  return_cfg_attrib(name, deprecate_attrib(name, prefix, level, version, msg); accessor)
318 
319 #define return_cfgref_attrib(name, accessor) \
320 do { \
321  if (strcmp(m, (name)) == 0) { \
322  luaW_pushconfig(L, (accessor)); \
323  return 1; \
324  } \
325 } while(false)
326 #define return_cfgref_attrib_deprecated(name, prefix, level, version, msg, accessor) \
327  return_deprecated_attrib(return_cfgref_attrib, name, accessor, prefix, level, version, msg)
328 
329 #define return_vector_string_attrib(name, accessor) \
330 do { \
331  if (strcmp(m, (name)) == 0) { \
332  const std::vector<std::string>& vector = (accessor); \
333  lua_createtable(L, vector.size(), 0); \
334  int i = 1; \
335  for (const std::string& s : vector) { \
336  lua_pushlstring(L, s.c_str(), s.length()); \
337  lua_rawseti(L, -2, i); \
338  ++i; \
339  } \
340  return 1; \
341  } \
342 } while(false)
343 #define return_vector_string_attrib_deprecated(name, prefix, level, version, msg, accessor) \
344  return_deprecated_attrib(return_vector_string_attrib, name, accessor, prefix, level, version, msg)
345 
346 #define modify_tstring_attrib(name, accessor) \
347 do { \
348  if (strcmp(m, (name)) == 0) { \
349  t_string value = luaW_checktstring(L, 3); \
350  {accessor;} \
351  return 0; \
352  } \
353 } while(false)
354 #define modify_tstring_attrib_deprecated(name, prefix, level, version, msg, accessor) \
355  modify_tstring_attrib(name, deprecate_attrib(name, prefix, level, version, msg); accessor)
356 
357 #define modify_string_attrib(name, accessor) \
358 do { \
359  if (strcmp(m, (name)) == 0) { \
360  const char *value = luaL_checkstring(L, 3); \
361  {accessor;} \
362  return 0; \
363  } \
364 } while(false)
365 #define modify_string_attrib_deprecated(name, prefix, level, version, msg, accessor) \
366  modify_string_attrib(name, deprecate_attrib(name, prefix, level, version, msg); accessor)
367 
368 #define modify_int_attrib(name, accessor) \
369 do { \
370  if (strcmp(m, (name)) == 0) { \
371  int value = static_cast<int>(luaL_checknumber(L, 3)); \
372  {accessor;} \
373  return 0; \
374  } \
375 } while(false)
376 #define modify_int_attrib_deprecated(name, prefix, level, version, msg, accessor) \
377  modify_int_attrib(name, deprecate_attrib(name, prefix, level, version, msg); accessor)
378 
379 #define modify_int_attrib_check_range(name, accessor, allowed_min, allowed_max) \
380 do { \
381  if (strcmp(m, (name)) == 0) { \
382  int value = static_cast<int>(luaL_checknumber(L, 3)); \
383  if (value < (allowed_min) || (allowed_max) < value) return luaL_argerror(L, 3, "out of bounds"); \
384  {accessor;} \
385  return 0; \
386  } \
387 } while(false)
388 #define modify_int_attrib_check_range_deprecated(name, prefix, level, version, msg, accessor, allowed_min, allowed_max) \
389  modify_int_attrib_check_range(name, deprecate_attrib(name, prefix, level, version, msg); accessor, allowed_min, allowed_max)
390 
391 #define modify_float_attrib(name, accessor) \
392 do { \
393  if (strcmp(m, (name)) == 0) { \
394  lua_Number value = luaL_checknumber(L, 3); \
395  {accessor;} \
396  return 0; \
397  } \
398 } while(false)
399 #define modify_float_attrib_deprecated(name, prefix, level, version, msg, accessor) \
400  modify_float_attrib(name, deprecate_attrib(name, prefix, level, version, msg); accessor)
401 
402 #define modify_float_attrib_check_range(name, accessor, allowed_min, allowed_max) \
403 do { \
404  if (strcmp(m, (name)) == 0) { \
405  lua_Number value = luaL_checknumber(L, 3); \
406  if (value < (allowed_min) || (allowed_max) < value) return luaL_argerror(L, 3, "out of bounds"); \
407  {accessor;} \
408  return 0; \
409  } \
410 } while(false)
411 #define modify_float_attrib_check_range_deprecated(name, prefix, level, version, msg, accessor, allowed_min, allowed_max) \
412  modify_float_attrib_check_range(name, deprecate_attrib(name, prefix, level, version, msg); accessor, allowed_min, allowed_max)
413 
414 #define modify_bool_attrib(name, accessor) \
415 do { \
416  if (strcmp(m, (name)) == 0) { \
417  bool value = luaW_toboolean(L, 3); \
418  {accessor;} \
419  return 0; \
420  } \
421 } while(false)
422 #define modify_bool_attrib_deprecated(name, prefix, level, version, msg, accessor) \
423  modify_bool_attrib(name, deprecate_attrib(name, prefix, level, version, msg); accessor)
424 
425 #define modify_cfg_attrib(name, accessor) \
426 do { \
427  if (strcmp(m, (name)) == 0) { \
428  const config& cfg = luaW_checkconfig(L, 3); \
429  {accessor;} \
430  return 0; \
431  } \
432 } while(false)
433 #define modify_cfg_attrib_deprecated(name, prefix, level, version, msg, accessor) \
434  modify_cfg_attrib(name, deprecate_attrib(name, prefix, level, version, msg); accessor)
435 
436 #define modify_vector_string_attrib(name, accessor) \
437 do { \
438  if (strcmp(m, (name)) == 0) { \
439  std::vector<std::string> value; \
440  char const* message = "table with unnamed indices holding strings expected"; \
441  if (!lua_istable(L, 3)) return luaL_argerror(L, 3, message); \
442  unsigned length = lua_rawlen(L, 3); \
443  for (unsigned i = 1; i <= length; ++i) { \
444  lua_rawgeti(L, 3, i); \
445  char const* string = lua_tostring(L, 4); \
446  if(!string) return luaL_argerror(L, 2 + i, message); \
447  value.push_back(string); \
448  lua_pop(L, 1); \
449  } \
450  {accessor;} \
451  return 0; \
452  } \
453 } while(false)
454 #define modify_vector_string_attrib_deprecated(name, prefix, level, version, msg, accessor) \
455  modify_vector_string_attrib(name, deprecate_attrib(name, prefix, level, version, msg); accessor)
map_location loc
Definition: move.cpp:172
std::vector< std::string > names
Definition: build_info.cpp:67
Variant for storing WML attributes.
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:158
Additional functionality for a non-const variable_info.
Information on a WML variable.
A variable-expanding proxy for the config class.
Definition: variable.hpp:45
Definitions for the interface to Wesnoth Markup Language (WML).
void luaW_pushconfig(lua_State *L, const config &cfg)
Converts a config object to a Lua table pushed at the top of the stack.
Definition: lua_common.cpp:905
int luaW_pcall_internal(lua_State *L, int nArgs, int nRets)
void luaW_filltable(lua_State *L, const config &cfg)
Converts a config object to a Lua table.
Definition: lua_common.cpp:654
void chat_message(const std::string &caption, const std::string &msg)
Displays a message in the chat window.
void push_error_handler(lua_State *L)
vconfig luaW_checkvconfig(lua_State *L, int index, bool allow_missing=false)
Gets an optional vconfig from either a table or a userdata.
bool luaW_iststring(lua_State *L, int index)
Definition: lua_common.cpp:643
void luaW_push_namedtuple(lua_State *L, const std::vector< std::string > &names)
Push an empty "named tuple" onto the stack.
Definition: lua_common.cpp:763
config luaW_checkconfig(lua_State *L, int index)
Converts an optional table or vconfig to a config object.
std::set< map_location > luaW_check_locationset(lua_State *L, int idx)
Converts a table of integer pairs to a set of map location objects.
Definition: lua_common.cpp:888
void luaW_pushtstring(lua_State *L, const t_string &v)
Pushes a t_string on the top of the stack.
Definition: lua_common.cpp:545
bool luaW_pushvariable(lua_State *L, variable_access_const &v)
bool luaW_tovconfig(lua_State *L, int index, vconfig &vcfg)
Gets an optional vconfig from either a table or a userdata.
void luaW_pushvconfig(lua_State *L, const vconfig &cfg)
Pushes a vconfig on the top of the stack.
Definition: lua_common.cpp:539
bool luaW_toboolean(lua_State *L, int n)
int luaW_type_error(lua_State *L, int narg, const char *tname)
bool luaW_toscalar(lua_State *L, int index, config::attribute_value &v)
Converts the value at the top of the stack to an attribute value.
Definition: lua_common.cpp:583
std::string_view luaW_tostring(lua_State *L, int index)
bool luaW_getmetafield(lua_State *L, int idx, const char *key)
Like luaL_getmetafield, but returns false if key is an empty string or begins with two underscores.
Definition: lua_common.cpp:524
std::ostream & operator<<(std::ostream &os, const luaW_PrintStack &)
Definition: lua_common.cpp:915
void luaW_pushscalar(lua_State *L, const config::attribute_value &v)
Converts an attribute value into a Lua object pushed at the top of the stack.
Definition: lua_common.cpp:578
bool luaW_totstring(lua_State *L, int index, t_string &str)
Converts a scalar to a translatable string.
Definition: lua_common.cpp:610
void luaW_pushlocation(lua_State *L, const map_location &loc)
Converts a map location object to a Lua table pushed at the top of the stack.
Definition: lua_common.cpp:808
std::vector< std::string > luaW_to_namedtuple(lua_State *L, int idx)
Get the keys of a "named tuple" from the stack.
Definition: lua_common.cpp:795
bool luaW_tableget(lua_State *L, int index, const char *key)
bool luaW_checkvariable(lua_State *L, variable_access_create &v, int n)
bool luaW_toconfig(lua_State *L, int index, config &cfg)
Converts an optional table or vconfig to a config object.
Definition: lua_common.cpp:934
bool luaW_pcall(lua_State *L, int nArgs, int nRets, bool allow_wml_error=false)
Calls a Lua function stored below its nArgs arguments at the top of the stack.
int luaW_push_locationset(lua_State *L, const std::set< map_location > &locs)
Converts a set of map locations to a Lua table pushed at the top of the stack.
Definition: lua_common.cpp:876
std::string_view luaW_tostring_or_default(lua_State *L, int index, std::string_view def=std::string_view())
bool luaW_tolocation(lua_State *L, int index, map_location &loc)
Converts an optional table or pair of integers to a map location object.
Definition: lua_common.cpp:819
map_location luaW_checklocation(lua_State *L, int index)
Converts an optional table or pair of integers to a map location object.
Definition: lua_common.cpp:868
luaW_PrintStack luaW_debugstack(lua_State *L)
Definition: lua_common.cpp:911
bool luaW_getglobal(lua_State *L, const std::vector< std::string > &path)
Pushes the value found by following the variadic names (char *), if the value is not nil.
t_string luaW_checktstring(lua_State *L, int index)
Converts a scalar to a translatable string.
Definition: lua_common.cpp:635
std::string path
Definition: filesystem.cpp:92
int intf_textdomain(lua_State *L)
Creates an interface for gettext.
Definition: lua_common.cpp:93
std::string register_gettext_metatable(lua_State *L)
Adds the gettext metatable.
Definition: lua_common.cpp:421
std::string register_vconfig_metatable(lua_State *L)
Adds the vconfig metatable.
Definition: lua_common.cpp:473
std::string register_tstring_metatable(lua_State *L)
Adds the tstring metatable.
Definition: lua_common.cpp:441
int intf_tovconfig(lua_State *L)
Creates a vconfig containing the WML table.
Definition: lua_common.cpp:411
std::size_t index(std::string_view str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
Definition: unicode.cpp:70
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
Definition: debugger.cpp:109
lua_State * L
Definition: lua_common.hpp:234
Encapsulates the map of the game.
Definition: location.hpp:45
mock_party p
static map_location::direction n