The Battle for Wesnoth  1.19.0-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  * Converts a map location object to a Lua table pushed at the top of the stack.
106  */
107 void luaW_pushlocation(lua_State *L, const map_location& loc);
108 
109 /**
110  * Converts an optional table or pair of integers to a map location object.
111  * @param L the pointer to the lua interpreter.
112  * @param index stack position of the table or first integer.
113  * @param loc the location to write to.
114  * @return false if a map location couldn't be matched.
115  */
116 bool luaW_tolocation(lua_State *L, int index, map_location &loc);
117 
118 /**
119  * Converts an optional table or pair of integers to a map location object.
120  * @note If a pair of integers was found, the first one will be removed
121  * from the stack when the function returns.
122  */
123 map_location luaW_checklocation(lua_State *L, int index);
124 
125 /**
126  * Converts a set of map locations to a Lua table pushed at the top of the stack.
127  */
128 int luaW_push_locationset(lua_State* L, const std::set<map_location>& locs);
129 
130 /**
131  * Converts a table of integer pairs to a set of map location objects.
132  */
133 std::set<map_location> luaW_check_locationset(lua_State* L, int idx);
134 
135 /**
136  * Converts a config object to a Lua table pushed at the top of the stack.
137  */
138 void luaW_pushconfig(lua_State *L, const config& cfg);
139 
140 /**
141  * Converts an optional table or vconfig to a config object.
142  * @param L the pointer to the lua interpreter.
143  * @param index stack position of the table.
144  * @param cfg the config to write the data to.
145  * @return false if some attributes had not the proper type.
146  * @note If the table has holes in the integer keys or floating-point keys,
147  * some keys will be ignored and the error will go undetected.
148  */
149 bool luaW_toconfig(lua_State *L, int index, config &cfg);
150 
151 /**
152  * Converts an optional table or vconfig to a config object.
153  */
154 config luaW_checkconfig(lua_State *L, int index);
155 
156 /**
157  * Gets an optional vconfig from either a table or a userdata.
158  * @return false in case of failure.
159  */
160 bool luaW_tovconfig(lua_State *L, int index, vconfig &vcfg);
161 
162 /**
163  * Gets an optional vconfig from either a table or a userdata.
164  * @param L the pointer to the lua interpreter.
165  * @param index the location in the current lua execution stack to look at.
166  * @param allow_missing true if missing values are allowed; the function
167  * then returns an unconstructed vconfig.
168  */
169 vconfig luaW_checkvconfig(lua_State *L, int index, bool allow_missing = false);
170 
171 /**
172  * Like the two-argument version, but if it was a vconfig, also
173  * returns a pointer to that vconfig.
174  */
175 config luaW_checkconfig(lua_State *L, int index, const vconfig*& vcfg);
176 
177 /**
178  * Pushes the value found by following the variadic names (char *), if the
179  * value is not nil.
180  * @return true if an element was pushed.
181  */
182 bool luaW_getglobal(lua_State *L, const std::vector<std::string>& path);
183 
184 /**
185  * Pushes the value found by following the variadic names (char *), if the
186  * value is not nil.
187  * @return true if an element was pushed.
188  */
189 template<typename... T>
190 bool luaW_getglobal(lua_State *L, T... path) {
191  return luaW_getglobal(L, std::vector<std::string> {path...} );
192 }
193 
194 bool luaW_toboolean(lua_State *L, int n);
195 
196 
197 bool luaW_pushvariable(lua_State *L, variable_access_const& v);
198 
199 bool luaW_checkvariable(lua_State *L, variable_access_create& v, int n);
200 
201 bool luaW_tableget(lua_State *L, int index, const char* key);
202 
203 std::string_view luaW_tostring(lua_State *L, int index);
204 std::string_view luaW_tostring_or_default(lua_State *L, int index, std::string_view def = std::string_view());
205 
206 /**
207  * Displays a message in the chat window.
208  */
209 void chat_message(const std::string& caption, const std::string& msg);
210 
211 /**
212  * Calls a Lua function stored below its @a nArgs arguments at the top of the stack.
213  * @param L the pointer to the lua interpreter.
214  * @param nArgs
215  * @param nRets LUA_MULTRET for unbounded return values.
216  * @param allow_wml_error controls where any stack traces are output.
217  * @return true if the call was successful and @a nRets return values are available.
218  */
219 bool luaW_pcall(lua_State *L, int nArgs, int nRets, bool allow_wml_error = false);
220 
221 // Don't use these directly
222 void push_error_handler(lua_State *L);
223 int luaW_pcall_internal(lua_State *L, int nArgs, int nRets);
224 
225 int luaW_type_error(lua_State *L, int narg, const char *tname);
226 int luaW_type_error(lua_State *L, int narg, const char* kpath, const char *tname);
227 
228 #define deprecate_attrib(name, prefix, level, version, msg) deprecated_message(prefix "." name, DEP_LEVEL::level, version, msg)
229 
230 #define return_deprecated_attrib(type_macro, name, accessor, prefix, level, version, msg) \
231  type_macro(name, ( \
232  deprecate_attrib(name, prefix, level, version, msg), \
233  accessor \
234  ))
235 
236 #define return_tstring_attrib(name, accessor) \
237 do { \
238  if (strcmp(m, (name)) == 0) { \
239  luaW_pushtstring(L, (accessor)); \
240  return 1; \
241  } \
242 } while(false)
243 #define return_tstring_attrib_deprecated(name, prefix, level, version, msg, accessor) \
244  return_deprecated_attrib(return_tstring_attrib, name, accessor, prefix, level, version, msg)
245 
246 #define return_cstring_attrib(name, accessor) \
247 do { \
248  if (strcmp(m, (name)) == 0) { \
249  lua_pushstring(L, (accessor)); \
250  return 1; \
251  } \
252 } while(false)
253 #define return_cstring_attrib_deprecated(name, prefix, level, version, msg, accessor) \
254  return_deprecated_attrib(return_cstring_attrib, name, accessor, prefix, level, version, msg)
255 
256 #define return_string_attrib(name, accessor) \
257 do { \
258  if (strcmp(m, (name)) == 0) { \
259  const std::string& str = (accessor); \
260  lua_pushlstring(L, str.c_str(), str.length()); \
261  return 1; \
262  } \
263 } while(false)
264 #define return_string_attrib_deprecated(name, prefix, level, version, msg, accessor) \
265  return_deprecated_attrib(return_string_attrib, name, accessor, prefix, level, version, msg)
266 
267 #define return_int_attrib(name, accessor) \
268 do { \
269  if (strcmp(m, (name)) == 0) { \
270  lua_pushinteger(L, (accessor)); \
271  return 1; \
272  } \
273 } while(false)
274 #define return_int_attrib_deprecated(name, prefix, level, version, msg, accessor) \
275  return_deprecated_attrib(return_int_attrib, name, accessor, prefix, level, version, msg)
276 
277 #define return_float_attrib(name, accessor) \
278 do { \
279  if (strcmp(m, (name)) == 0) { \
280  lua_pushnumber(L, (accessor)); \
281  return 1; \
282  } \
283 } while(false)
284 #define return_float_attrib_deprecated(name, prefix, level, version, msg, accessor) \
285  return_deprecated_attrib(return_float_attrib, name, accessor, prefix, level, version, msg)
286 
287 #define return_bool_attrib(name, accessor) \
288 do { \
289  if (strcmp(m, (name)) == 0) { \
290  lua_pushboolean(L, (accessor)); \
291  return 1; \
292  } \
293 } while(false)
294 #define return_bool_attrib_deprecated(name, prefix, level, version, msg, accessor) \
295  return_deprecated_attrib(return_bool_attrib, name, accessor, prefix, level, version, msg)
296 
297 #define return_cfg_attrib(name, accessor) \
298 do { \
299  if (strcmp(m, (name)) == 0) { \
300  config cfg; \
301  {accessor;} \
302  luaW_pushconfig(L, cfg); \
303  return 1; \
304  } \
305 } while(false)
306 #define return_cfg_attrib_deprecated(name, prefix, level, version, msg, accessor) \
307  return_cfg_attrib(name, deprecate_attrib(name, prefix, level, version, msg); accessor)
308 
309 #define return_cfgref_attrib(name, accessor) \
310 do { \
311  if (strcmp(m, (name)) == 0) { \
312  luaW_pushconfig(L, (accessor)); \
313  return 1; \
314  } \
315 } while(false)
316 #define return_cfgref_attrib_deprecated(name, prefix, level, version, msg, accessor) \
317  return_deprecated_attrib(return_cfgref_attrib, name, accessor, prefix, level, version, msg)
318 
319 #define return_vector_string_attrib(name, accessor) \
320 do { \
321  if (strcmp(m, (name)) == 0) { \
322  const std::vector<std::string>& vector = (accessor); \
323  lua_createtable(L, vector.size(), 0); \
324  int i = 1; \
325  for (const std::string& s : vector) { \
326  lua_pushlstring(L, s.c_str(), s.length()); \
327  lua_rawseti(L, -2, i); \
328  ++i; \
329  } \
330  return 1; \
331  } \
332 } while(false)
333 #define return_vector_string_attrib_deprecated(name, prefix, level, version, msg, accessor) \
334  return_deprecated_attrib(return_vector_string_attrib, name, accessor, prefix, level, version, msg)
335 
336 #define modify_tstring_attrib(name, accessor) \
337 do { \
338  if (strcmp(m, (name)) == 0) { \
339  t_string value = luaW_checktstring(L, 3); \
340  {accessor;} \
341  return 0; \
342  } \
343 } while(false)
344 #define modify_tstring_attrib_deprecated(name, prefix, level, version, msg, accessor) \
345  modify_tstring_attrib(name, deprecate_attrib(name, prefix, level, version, msg); accessor)
346 
347 #define modify_string_attrib(name, accessor) \
348 do { \
349  if (strcmp(m, (name)) == 0) { \
350  const char *value = luaL_checkstring(L, 3); \
351  {accessor;} \
352  return 0; \
353  } \
354 } while(false)
355 #define modify_string_attrib_deprecated(name, prefix, level, version, msg, accessor) \
356  modify_string_attrib(name, deprecate_attrib(name, prefix, level, version, msg); accessor)
357 
358 #define modify_int_attrib(name, accessor) \
359 do { \
360  if (strcmp(m, (name)) == 0) { \
361  int value = static_cast<int>(luaL_checknumber(L, 3)); \
362  {accessor;} \
363  return 0; \
364  } \
365 } while(false)
366 #define modify_int_attrib_deprecated(name, prefix, level, version, msg, accessor) \
367  modify_int_attrib(name, deprecate_attrib(name, prefix, level, version, msg); accessor)
368 
369 #define modify_int_attrib_check_range(name, accessor, allowed_min, allowed_max) \
370 do { \
371  if (strcmp(m, (name)) == 0) { \
372  int value = static_cast<int>(luaL_checknumber(L, 3)); \
373  if (value < (allowed_min) || (allowed_max) < value) return luaL_argerror(L, 3, "out of bounds"); \
374  {accessor;} \
375  return 0; \
376  } \
377 } while(false)
378 #define modify_int_attrib_check_range_deprecated(name, prefix, level, version, msg, accessor, allowed_min, allowed_max) \
379  modify_int_attrib_check_range(name, deprecate_attrib(name, prefix, level, version, msg); accessor, allowed_min, allowed_max)
380 
381 #define modify_float_attrib(name, accessor) \
382 do { \
383  if (strcmp(m, (name)) == 0) { \
384  lua_Number value = luaL_checknumber(L, 3); \
385  {accessor;} \
386  return 0; \
387  } \
388 } while(false)
389 #define modify_float_attrib_deprecated(name, prefix, level, version, msg, accessor) \
390  modify_float_attrib(name, deprecate_attrib(name, prefix, level, version, msg); accessor)
391 
392 #define modify_float_attrib_check_range(name, accessor, allowed_min, allowed_max) \
393 do { \
394  if (strcmp(m, (name)) == 0) { \
395  lua_Number value = luaL_checknumber(L, 3); \
396  if (value < (allowed_min) || (allowed_max) < value) return luaL_argerror(L, 3, "out of bounds"); \
397  {accessor;} \
398  return 0; \
399  } \
400 } while(false)
401 #define modify_float_attrib_check_range_deprecated(name, prefix, level, version, msg, accessor, allowed_min, allowed_max) \
402  modify_float_attrib_check_range(name, deprecate_attrib(name, prefix, level, version, msg); accessor, allowed_min, allowed_max)
403 
404 #define modify_bool_attrib(name, accessor) \
405 do { \
406  if (strcmp(m, (name)) == 0) { \
407  bool value = luaW_toboolean(L, 3); \
408  {accessor;} \
409  return 0; \
410  } \
411 } while(false)
412 #define modify_bool_attrib_deprecated(name, prefix, level, version, msg, accessor) \
413  modify_bool_attrib(name, deprecate_attrib(name, prefix, level, version, msg); accessor)
414 
415 #define modify_cfg_attrib(name, accessor) \
416 do { \
417  if (strcmp(m, (name)) == 0) { \
418  const config& cfg = luaW_checkconfig(L, 3); \
419  {accessor;} \
420  return 0; \
421  } \
422 } while(false)
423 #define modify_cfg_attrib_deprecated(name, prefix, level, version, msg, accessor) \
424  modify_cfg_attrib(name, deprecate_attrib(name, prefix, level, version, msg); accessor)
425 
426 #define modify_vector_string_attrib(name, accessor) \
427 do { \
428  if (strcmp(m, (name)) == 0) { \
429  std::vector<std::string> value; \
430  char const* message = "table with unnamed indices holding strings expected"; \
431  if (!lua_istable(L, 3)) return luaL_argerror(L, 3, message); \
432  unsigned length = lua_rawlen(L, 3); \
433  for (unsigned i = 1; i <= length; ++i) { \
434  lua_rawgeti(L, 3, i); \
435  char const* string = lua_tostring(L, 4); \
436  if(!string) return luaL_argerror(L, 2 + i, message); \
437  value.push_back(string); \
438  lua_pop(L, 1); \
439  } \
440  {accessor;} \
441  return 0; \
442  } \
443 } while(false)
444 #define modify_vector_string_attrib_deprecated(name, prefix, level, version, msg, accessor) \
445  modify_vector_string_attrib(name, deprecate_attrib(name, prefix, level, version, msg); accessor)
std::vector< std::string > names
Definition: build_info.cpp:66
Variant for storing WML attributes.
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:159
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
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:827
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.
Definition: lua_common.cpp:961
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:712
config luaW_checkconfig(lua_State *L, int index)
Converts an optional table or vconfig to a config object.
Definition: lua_common.cpp:917
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:810
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)
Definition: lua_common.cpp:993
bool luaW_tovconfig(lua_State *L, int index, vconfig &vcfg)
Gets an optional vconfig from either a table or a userdata.
Definition: lua_common.cpp:934
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)
Definition: lua_common.cpp:988
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
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:730
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:839
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:798
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:741
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:790
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.
Definition: lua_common.cpp:969
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:83
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(const std::string &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
Encapsulates the map of the game.
Definition: location.hpp:38
mock_party p
static map_location::DIRECTION n