The Battle for Wesnoth  1.19.18+dev
lua_common.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014 - 2025
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 /**
46  * Shallow wrapper around lua_geti which pops the top variable from the
47  * Lua stack when destroyed. This is meant to be used in local contexts
48  * for quick cleanup of the stack variable.
49  *
50  * @todo support different get* functions?
51  */
53 {
54 public:
55  scoped_lua_argument(lua_State* L, int arg_index);
56  scoped_lua_argument(lua_State* L, int value_index, int arg_index);
57 
59 
62 
63 private:
64  lua_State* const state_;
65 };
66 
67 void* operator new(std::size_t sz, lua_State *L, int nuv = 0);
68 void operator delete(void* p, lua_State *L, int nuv);
69 
70 /**
71  * Like luaL_getmetafield, but returns false if key is an empty string
72  * or begins with two underscores.
73  */
74 bool luaW_getmetafield(lua_State *L, int idx, const char* key);
75 
76 /**
77  * Pushes a vconfig on the top of the stack.
78  */
79 void luaW_pushvconfig(lua_State *L, const vconfig& cfg);
80 
81 /**
82  * Pushes a t_string on the top of the stack.
83  */
84 void luaW_pushtstring(lua_State *L, const t_string& v);
85 
86 /**
87  * Converts an attribute value into a Lua object pushed at the top of the stack.
88  */
89 void luaW_pushscalar(lua_State *L, const config::attribute_value& v);
90 
91 /**
92  * Converts the value at the top of the stack to an attribute value
93  */
94 bool luaW_toscalar(lua_State *L, int index, config::attribute_value& v);
95 
96 /**
97  * Converts a scalar to a translatable string.
98  */
99 bool luaW_totstring(lua_State *L, int index, t_string &str);
100 
101 /**
102  * Converts a scalar to a translatable string.
103  */
104 t_string luaW_checktstring(lua_State *L, int index);
105 
106 /*
107  * Test if a scalar is either a plain or translatable string.
108  * Also returns true if it's a number since that's convertible to string.
109  */
110 bool luaW_iststring(lua_State* L, int index);
111 
112 /**
113  * Converts a config object to a Lua table.
114  * The destination table should be at the top of the stack on entry. It is
115  * still at the top on exit.
116  */
117 void luaW_filltable(lua_State *L, const config& cfg);
118 
119 /**
120  * Push an empty "named tuple" onto the stack.
121  * A named tuple is an array where each index can also be accessed by name.
122  * Once it's pushed, you can set the elements, eg with lua_rawseti.
123  */
124 void luaW_push_namedtuple(lua_State* L, const std::vector<std::string>& names);
125 
126 /**
127  * Get the keys of a "named tuple" from the stack.
128  * Returns an empty array if the stack element is not a named tuple.
129  */
130 std::vector<std::string> luaW_to_namedtuple(lua_State* L, int idx);
131 
132 /**
133  * Converts a map location object to a Lua table pushed at the top of the stack.
134  */
135 void luaW_pushlocation(lua_State *L, const map_location& loc);
136 
137 /**
138  * Converts an optional table or pair of integers to a map location object.
139  * @param L the pointer to the lua interpreter.
140  * @param index stack position of the table or first integer.
141  * @param loc the location to write to.
142  * @return false if a map location couldn't be matched.
143  */
144 bool luaW_tolocation(lua_State *L, int index, map_location &loc);
145 
146 /**
147  * Converts an optional table or pair of integers to a map location object.
148  * @note If a pair of integers was found, the first one will be removed
149  * from the stack when the function returns.
150  */
151 map_location luaW_checklocation(lua_State *L, int index);
152 
153 /**
154  * Converts a set of map locations to a Lua table pushed at the top of the stack.
155  */
156 int luaW_push_locationset(lua_State* L, const std::set<map_location>& locs);
157 
158 /**
159  * Converts a table of integer pairs to a set of map location objects.
160  */
161 std::set<map_location> luaW_check_locationset(lua_State* L, int idx);
162 
163 /**
164  * Converts a config object to a Lua table pushed at the top of the stack.
165  */
166 void luaW_pushconfig(lua_State *L, const config& cfg);
167 
168 /**
169  * Converts an optional table or vconfig to a config object.
170  * @param L the pointer to the lua interpreter.
171  * @param index stack position of the table.
172  * @param cfg the config to write the data to.
173  * @return false if some attributes had not the proper type.
174  * @note If the table has holes in the integer keys or floating-point keys,
175  * some keys will be ignored and the error will go undetected.
176  */
177 bool luaW_toconfig(lua_State *L, int index, config &cfg);
178 
179 /**
180  * Converts an optional table or vconfig to a config object.
181  */
182 config luaW_checkconfig(lua_State *L, int index);
183 
184 /**
185  * Gets an optional vconfig from either a table or a userdata.
186  * @return false in case of failure.
187  */
188 bool luaW_tovconfig(lua_State *L, int index, vconfig &vcfg);
189 
190 /**
191  * Gets an optional vconfig from either a table or a userdata.
192  * @param L the pointer to the lua interpreter.
193  * @param index the location in the current lua execution stack to look at.
194  * @param allow_missing true if missing values are allowed; the function
195  * then returns an unconstructed vconfig.
196  */
197 vconfig luaW_checkvconfig(lua_State *L, int index, bool allow_missing = false);
198 
199 /**
200  * Like the two-argument version, but if it was a vconfig, also
201  * returns a pointer to that vconfig.
202  */
203 config luaW_checkconfig(lua_State *L, int index, const vconfig*& vcfg);
204 
205 /**
206  * Pushes the value found by following the variadic names (char *), if the
207  * value is not nil.
208  * @return true if an element was pushed.
209  */
210 bool luaW_getglobal(lua_State *L, const std::vector<std::string>& path);
211 
212 /**
213  * Pushes the value found by following the variadic names (char *), if the
214  * value is not nil.
215  * @return true if an element was pushed.
216  */
217 template<typename... T>
218 bool luaW_getglobal(lua_State *L, T... path) {
219  return luaW_getglobal(L, std::vector<std::string> {path...} );
220 }
221 
222 bool luaW_toboolean(lua_State *L, int n);
223 
224 
225 bool luaW_pushvariable(lua_State *L, variable_access_const& v);
226 
227 bool luaW_checkvariable(lua_State *L, variable_access_create& v, int n);
228 
229 bool luaW_tableget(lua_State *L, int index, const char* key);
230 
231 std::string_view luaW_tostring(lua_State *L, int index);
232 std::string_view luaW_tostring_or_default(lua_State *L, int index, std::string_view def = std::string_view());
233 
234 /**
235  * Displays a message in the chat window.
236  */
237 void chat_message(const std::string& caption, const std::string& msg);
238 
239 /**
240  * Calls a Lua function stored below its @a nArgs arguments at the top of the stack.
241  * @param L the pointer to the lua interpreter.
242  * @param nArgs
243  * @param nRets LUA_MULTRET for unbounded return values.
244  * @param allow_wml_error controls where any stack traces are output.
245  * @return true if the call was successful and @a nRets return values are available.
246  */
247 bool luaW_pcall(lua_State *L, int nArgs, int nRets, bool allow_wml_error = false);
248 
249 // Don't use these directly
250 void push_error_handler(lua_State *L);
251 int luaW_pcall_internal(lua_State *L, int nArgs, int nRets);
252 
253 int luaW_type_error(lua_State *L, int narg, const char *tname);
254 int luaW_type_error(lua_State *L, int narg, const char* kpath, const char *tname);
255 
256 struct luaW_PrintStack { lua_State* L; };
257 luaW_PrintStack luaW_debugstack(lua_State* L);
258 std::ostream& operator<<(std::ostream& os, const luaW_PrintStack&);
259 
260 #define deprecate_attrib(name, prefix, level, version, msg) deprecated_message(prefix "." name, DEP_LEVEL::level, version, msg)
261 
262 #define return_deprecated_attrib(type_macro, name, accessor, prefix, level, version, msg) \
263  type_macro(name, ( \
264  deprecate_attrib(name, prefix, level, version, msg), \
265  accessor \
266  ))
267 
268 #define return_tstring_attrib(name, accessor) \
269 do { \
270  if (strcmp(m, (name)) == 0) { \
271  luaW_pushtstring(L, (accessor)); \
272  return 1; \
273  } \
274 } while(false)
275 #define return_tstring_attrib_deprecated(name, prefix, level, version, msg, accessor) \
276  return_deprecated_attrib(return_tstring_attrib, name, accessor, prefix, level, version, msg)
277 
278 #define return_cstring_attrib(name, accessor) \
279 do { \
280  if (strcmp(m, (name)) == 0) { \
281  lua_pushstring(L, (accessor)); \
282  return 1; \
283  } \
284 } while(false)
285 #define return_cstring_attrib_deprecated(name, prefix, level, version, msg, accessor) \
286  return_deprecated_attrib(return_cstring_attrib, name, accessor, prefix, level, version, msg)
287 
288 #define return_string_attrib(name, accessor) \
289 do { \
290  if (strcmp(m, (name)) == 0) { \
291  const std::string& str = (accessor); \
292  lua_pushlstring(L, str.c_str(), str.length()); \
293  return 1; \
294  } \
295 } while(false)
296 #define return_string_attrib_deprecated(name, prefix, level, version, msg, accessor) \
297  return_deprecated_attrib(return_string_attrib, name, accessor, prefix, level, version, msg)
298 
299 #define return_int_attrib(name, accessor) \
300 do { \
301  if (strcmp(m, (name)) == 0) { \
302  lua_pushinteger(L, (accessor)); \
303  return 1; \
304  } \
305 } while(false)
306 #define return_int_attrib_deprecated(name, prefix, level, version, msg, accessor) \
307  return_deprecated_attrib(return_int_attrib, name, accessor, prefix, level, version, msg)
308 
309 #define return_float_attrib(name, accessor) \
310 do { \
311  if (strcmp(m, (name)) == 0) { \
312  lua_pushnumber(L, (accessor)); \
313  return 1; \
314  } \
315 } while(false)
316 #define return_float_attrib_deprecated(name, prefix, level, version, msg, accessor) \
317  return_deprecated_attrib(return_float_attrib, name, accessor, prefix, level, version, msg)
318 
319 #define return_bool_attrib(name, accessor) \
320 do { \
321  if (strcmp(m, (name)) == 0) { \
322  lua_pushboolean(L, (accessor)); \
323  return 1; \
324  } \
325 } while(false)
326 #define return_bool_attrib_deprecated(name, prefix, level, version, msg, accessor) \
327  return_deprecated_attrib(return_bool_attrib, name, accessor, prefix, level, version, msg)
328 
329 #define return_cfg_attrib(name, accessor) \
330 do { \
331  if (strcmp(m, (name)) == 0) { \
332  config cfg; \
333  {accessor;} \
334  luaW_pushconfig(L, cfg); \
335  return 1; \
336  } \
337 } while(false)
338 #define return_cfg_attrib_deprecated(name, prefix, level, version, msg, accessor) \
339  return_cfg_attrib(name, deprecate_attrib(name, prefix, level, version, msg); accessor)
340 
341 #define return_cfgref_attrib(name, accessor) \
342 do { \
343  if (strcmp(m, (name)) == 0) { \
344  luaW_pushconfig(L, (accessor)); \
345  return 1; \
346  } \
347 } while(false)
348 #define return_cfgref_attrib_deprecated(name, prefix, level, version, msg, accessor) \
349  return_deprecated_attrib(return_cfgref_attrib, name, accessor, prefix, level, version, msg)
350 
351 #define return_vector_string_attrib(name, accessor) \
352 do { \
353  if (strcmp(m, (name)) == 0) { \
354  const std::vector<std::string>& vector = (accessor); \
355  lua_createtable(L, vector.size(), 0); \
356  int i = 1; \
357  for (const std::string& s : vector) { \
358  lua_pushlstring(L, s.c_str(), s.length()); \
359  lua_rawseti(L, -2, i); \
360  ++i; \
361  } \
362  return 1; \
363  } \
364 } while(false)
365 #define return_vector_string_attrib_deprecated(name, prefix, level, version, msg, accessor) \
366  return_deprecated_attrib(return_vector_string_attrib, name, accessor, prefix, level, version, msg)
367 
368 #define modify_tstring_attrib(name, accessor) \
369 do { \
370  if (strcmp(m, (name)) == 0) { \
371  t_string value = luaW_checktstring(L, 3); \
372  {accessor;} \
373  return 0; \
374  } \
375 } while(false)
376 #define modify_tstring_attrib_deprecated(name, prefix, level, version, msg, accessor) \
377  modify_tstring_attrib(name, deprecate_attrib(name, prefix, level, version, msg); accessor)
378 
379 #define modify_string_attrib(name, accessor) \
380 do { \
381  if (strcmp(m, (name)) == 0) { \
382  const char *value = luaL_checkstring(L, 3); \
383  {accessor;} \
384  return 0; \
385  } \
386 } while(false)
387 #define modify_string_attrib_deprecated(name, prefix, level, version, msg, accessor) \
388  modify_string_attrib(name, deprecate_attrib(name, prefix, level, version, msg); accessor)
389 
390 #define modify_int_attrib(name, accessor) \
391 do { \
392  if (strcmp(m, (name)) == 0) { \
393  int value = static_cast<int>(luaL_checknumber(L, 3)); \
394  {accessor;} \
395  return 0; \
396  } \
397 } while(false)
398 #define modify_int_attrib_deprecated(name, prefix, level, version, msg, accessor) \
399  modify_int_attrib(name, deprecate_attrib(name, prefix, level, version, msg); accessor)
400 
401 #define modify_int_attrib_check_range(name, accessor, allowed_min, allowed_max) \
402 do { \
403  if (strcmp(m, (name)) == 0) { \
404  int value = static_cast<int>(luaL_checknumber(L, 3)); \
405  if (value < (allowed_min) || (allowed_max) < value) return luaL_argerror(L, 3, "out of bounds"); \
406  {accessor;} \
407  return 0; \
408  } \
409 } while(false)
410 #define modify_int_attrib_check_range_deprecated(name, prefix, level, version, msg, accessor, allowed_min, allowed_max) \
411  modify_int_attrib_check_range(name, deprecate_attrib(name, prefix, level, version, msg); accessor, allowed_min, allowed_max)
412 
413 #define modify_float_attrib(name, accessor) \
414 do { \
415  if (strcmp(m, (name)) == 0) { \
416  lua_Number value = luaL_checknumber(L, 3); \
417  {accessor;} \
418  return 0; \
419  } \
420 } while(false)
421 #define modify_float_attrib_deprecated(name, prefix, level, version, msg, accessor) \
422  modify_float_attrib(name, deprecate_attrib(name, prefix, level, version, msg); accessor)
423 
424 #define modify_float_attrib_check_range(name, accessor, allowed_min, allowed_max) \
425 do { \
426  if (strcmp(m, (name)) == 0) { \
427  lua_Number value = luaL_checknumber(L, 3); \
428  if (value < (allowed_min) || (allowed_max) < value) return luaL_argerror(L, 3, "out of bounds"); \
429  {accessor;} \
430  return 0; \
431  } \
432 } while(false)
433 #define modify_float_attrib_check_range_deprecated(name, prefix, level, version, msg, accessor, allowed_min, allowed_max) \
434  modify_float_attrib_check_range(name, deprecate_attrib(name, prefix, level, version, msg); accessor, allowed_min, allowed_max)
435 
436 #define modify_bool_attrib(name, accessor) \
437 do { \
438  if (strcmp(m, (name)) == 0) { \
439  bool value = luaW_toboolean(L, 3); \
440  {accessor;} \
441  return 0; \
442  } \
443 } while(false)
444 #define modify_bool_attrib_deprecated(name, prefix, level, version, msg, accessor) \
445  modify_bool_attrib(name, deprecate_attrib(name, prefix, level, version, msg); accessor)
446 
447 #define modify_cfg_attrib(name, accessor) \
448 do { \
449  if (strcmp(m, (name)) == 0) { \
450  const config& cfg = luaW_checkconfig(L, 3); \
451  {accessor;} \
452  return 0; \
453  } \
454 } while(false)
455 #define modify_cfg_attrib_deprecated(name, prefix, level, version, msg, accessor) \
456  modify_cfg_attrib(name, deprecate_attrib(name, prefix, level, version, msg); accessor)
457 
458 #define modify_vector_string_attrib(name, accessor) \
459 do { \
460  if (strcmp(m, (name)) == 0) { \
461  std::vector<std::string> value; \
462  char const* message = "table with unnamed indices holding strings expected"; \
463  if (!lua_istable(L, 3)) return luaL_argerror(L, 3, message); \
464  unsigned length = lua_rawlen(L, 3); \
465  for (unsigned i = 1; i <= length; ++i) { \
466  lua_rawgeti(L, 3, i); \
467  char const* string = lua_tostring(L, 4); \
468  if(!string) return luaL_argerror(L, 2 + i, message); \
469  value.push_back(string); \
470  lua_pop(L, 1); \
471  } \
472  {accessor;} \
473  return 0; \
474  } \
475 } while(false)
476 #define modify_vector_string_attrib_deprecated(name, prefix, level, version, msg, accessor) \
477  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:157
Shallow wrapper around lua_geti which pops the top variable from the Lua stack when destroyed.
Definition: lua_common.hpp:53
scoped_lua_argument(lua_State *L, int arg_index)
Definition: lua_common.cpp:454
scoped_lua_argument(const scoped_lua_argument &)=delete
lua_State *const state_
Definition: lua_common.hpp:64
scoped_lua_argument & operator=(const scoped_lua_argument &)=delete
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).
const config * cfg
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:864
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:614
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:603
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:723
config luaW_checkconfig(lua_State *L, int index)
Converts an optional table or vconfig to a config object.
Definition: lua_common.cpp:971
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:848
void luaW_pushtstring(lua_State *L, const t_string &v)
Pushes a t_string on the top of the stack.
Definition: lua_common.cpp:505
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.
Definition: lua_common.cpp:988
void luaW_pushvconfig(lua_State *L, const vconfig &cfg)
Pushes a vconfig on the top of the stack.
Definition: lua_common.cpp:499
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:543
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:484
std::ostream & operator<<(std::ostream &os, const luaW_PrintStack &)
Definition: lua_common.cpp:874
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:538
bool luaW_totstring(lua_State *L, int index, t_string &str)
Converts a scalar to a translatable string.
Definition: lua_common.cpp:570
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:768
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:755
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:893
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:836
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:779
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:828
luaW_PrintStack luaW_debugstack(lua_State *L)
Definition: lua_common.cpp:870
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:595
std::string path
Definition: filesystem.cpp:106
int intf_textdomain(lua_State *L)
Creates an interface for gettext.
Definition: lua_common.cpp:92
std::string register_gettext_metatable(lua_State *L)
Adds the gettext metatable.
Definition: lua_common.cpp:370
std::string register_vconfig_metatable(lua_State *L)
Adds the vconfig metatable.
Definition: lua_common.cpp:422
std::string register_tstring_metatable(lua_State *L)
Adds the tstring metatable.
Definition: lua_common.cpp:390
int intf_tovconfig(lua_State *L)
Creates a vconfig containing the WML table.
Definition: lua_common.cpp:360
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:256
Encapsulates the map of the game.
Definition: location.hpp:46
mock_party p
static map_location::direction n