The Battle for Wesnoth  1.19.20+dev
lua_common.cpp
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  * @file
18  * Contains code common to the application and game lua kernels which
19  * cannot or should not go into the lua kernel base files.
20  *
21  * Currently contains implementation functions related to vconfig and
22  * gettext, also some macros to assist in writing C lua callbacks.
23  */
24 
25 #include "scripting/lua_common.hpp"
26 
27 #include "config.hpp"
28 #include "scripting/push_check.hpp"
29 #include "tstring.hpp" // for t_string
30 #include "variable.hpp" // for vconfig
31 #include "log.hpp"
32 #include "gettext.hpp"
34 #include "game_display.hpp"
35 
36 #include <cstring>
37 #include <iterator> // for distance, advance
38 #include <string> // for string, basic_string
39 
40 
41 static const char gettextKey[] = "gettext";
42 static const char vconfigKey[] = "vconfig";
43 static const char vconfigpairsKey[] = "vconfig pairs";
44 static const char tstringKey[] = "translatable string";
45 static const char executeKey[] = "err";
46 
47 static lg::log_domain log_scripting_lua("scripting/lua");
48 #define LOG_LUA LOG_STREAM(info, log_scripting_lua)
49 #define WRN_LUA LOG_STREAM(warn, log_scripting_lua)
50 #define ERR_LUA LOG_STREAM(err, log_scripting_lua)
51 
52 static lg::log_domain log_wml("wml");
53 #define ERR_WML LOG_STREAM(err, log_wml)
54 
55 namespace lua_common {
56 
57 /**
58  * Creates a t_string object (__call metamethod).
59  * - Arg 1: userdata containing the domain.
60  * - Arg 2: string to translate.
61  * - Ret 1: string containing the translatable string.
62  */
63 static int impl_gettext(lua_State *L)
64 {
65  char const *m = luaL_checkstring(L, 2);
66  char const *d = static_cast<char *>(lua_touserdata(L, 1));
67  // Hidden metamethod, so d has to be a string. Use it to create a t_string.
68  if(lua_isstring(L, 3)) {
69  const char* pl = luaL_checkstring(L, 3);
70  int count = luaL_checkinteger(L, 4);
71  luaW_pushtstring(L, t_string(m, pl, count, d));
72  } else {
73  luaW_pushtstring(L, t_string(m, d));
74  }
75  return 1;
76 }
77 
78 static int impl_gettext_tostr(lua_State* L)
79 {
80  char* d = static_cast<char*>(lua_touserdata(L, 1));
81  using namespace std::literals;
82  std::string str = "textdomain: "s + d;
83  lua_push(L, str);
84  return 1;
85 }
86 
87 /**
88  * Creates an interface for gettext
89  * - Arg 1: string containing the domain.
90  * - Ret 1: a full userdata with __call pointing to lua_gettext.
91  */
92 int intf_textdomain(lua_State *L)
93 {
94  std::size_t l;
95  char const *m = luaL_checklstring(L, 1, &l);
96 
97  void *p = lua_newuserdatauv(L, l + 1, 0);
98  memcpy(p, m, l + 1);
99 
100  luaL_setmetatable(L, gettextKey);
101  return 1;
102 }
103 
104 /**
105  * Converts a Lua value at position @a src and appends it to @a dst.
106  * @note This function is private to lua_tstring_concat. It expects two things.
107  * First, the t_string metatable is at the top of the stack on entry. (It
108  * is still there on exit.) Second, the caller hasn't any valuable object
109  * with dynamic lifetime, since they would be leaked on error.
110  */
111 static void tstring_concat_aux(lua_State *L, t_string &dst, int src)
112 {
113  switch (lua_type(L, src)) {
114  case LUA_TNUMBER:
115  case LUA_TSTRING:
116  dst += lua_tostring(L, src);
117  return;
118  case LUA_TUSERDATA:
119  // Compare its metatable with t_string's metatable.
120  if (t_string * src_ptr = static_cast<t_string *> (luaL_testudata(L, src, tstringKey))) {
121  dst += *src_ptr;
122  return;
123  }
124  //intentional fall-through
125  default:
126  luaW_type_error(L, src, "string");
127  }
128 }
129 
130 /**
131  * Appends a scalar to a t_string object (__concat metamethod).
132  */
133 static int impl_tstring_concat(lua_State *L)
134 {
135  // Create a new t_string.
136  t_string *t = new(L) t_string;
137  luaL_setmetatable(L, tstringKey);
138 
139  // Append both arguments to t.
140  tstring_concat_aux(L, *t, 1);
141  tstring_concat_aux(L, *t, 2);
142 
143  return 1;
144 }
145 
146 static int impl_tstring_len(lua_State* L)
147 {
148  t_string* t = static_cast<t_string*>(lua_touserdata(L, 1));
149  lua_pushnumber(L, t->size());
150  return 1;
151 }
152 
153 /**
154  * Destroys a t_string object before it is collected (__gc metamethod).
155  */
156 static int impl_tstring_collect(lua_State *L)
157 {
158  t_string *t = static_cast<t_string *>(lua_touserdata(L, 1));
159  t->t_string::~t_string();
160  return 0;
161 }
162 
163 static int impl_tstring_lt(lua_State *L)
164 {
165  t_string *t1 = static_cast<t_string *>(luaL_checkudata(L, 1, tstringKey));
166  t_string *t2 = static_cast<t_string *>(luaL_checkudata(L, 2, tstringKey));
167  lua_pushboolean(L, translation::compare(t1->get(), t2->get()) < 0);
168  return 1;
169 }
170 
171 static int impl_tstring_le(lua_State *L)
172 {
173  t_string *t1 = static_cast<t_string *>(luaL_checkudata(L, 1, tstringKey));
174  t_string *t2 = static_cast<t_string *>(luaL_checkudata(L, 2, tstringKey));
175  lua_pushboolean(L, translation::compare(t1->get(), t2->get()) < 1);
176  return 1;
177 }
178 
179 static int impl_tstring_eq(lua_State *L)
180 {
181  t_string *t1 = static_cast<t_string *>(lua_touserdata(L, 1));
182  t_string *t2 = static_cast<t_string *>(lua_touserdata(L, 2));
183  lua_pushboolean(L, translation::compare(t1->get(), t2->get()) == 0);
184  return 1;
185 }
186 
187 /**
188  * Converts a t_string object to a string (__tostring metamethod);
189  * that is, performs a translation.
190  */
191 static int impl_tstring_tostring(lua_State *L)
192 {
193  t_string *t = static_cast<t_string *>(lua_touserdata(L, 1));
194  lua_pushstring(L, t->c_str());
195  return 1;
196 }
197 
198 /**
199  * Gets the parsed field of a vconfig object (_index metamethod).
200  * Special fields __literal, __shallow_literal, __parsed, and
201  * __shallow_parsed, return Lua tables.
202  */
203 static int impl_vconfig_get(lua_State *L)
204 {
205  static const lua_named_tuple_builder tuple_builder{ {"tag", "contents"} };
206 
207  vconfig *v = static_cast<vconfig *>(lua_touserdata(L, 1));
208 
209  if (lua_isnumber(L, 2))
210  {
212  unsigned len = std::distance(i, v->ordered_end());
213  unsigned pos = lua_tointeger(L, 2) - 1;
214  if (pos >= len) return 0;
215  std::advance(i, pos);
216 
217  tuple_builder.push(L);
218  lua_pushstring(L, i.get_key().c_str());
219  lua_rawseti(L, -2, 1);
220  luaW_pushvconfig(L, i.get_child());
221  lua_rawseti(L, -2, 2);
222  return 1;
223  }
224 
225  char const *m = luaL_checkstring(L, 2);
226  if (strcmp(m, "__literal") == 0) {
227  luaW_pushconfig(L, v->get_config());
228  return 1;
229  }
230  if (strcmp(m, "__parsed") == 0) {
232  return 1;
233  }
234 
235  bool shallow_literal = strcmp(m, "__shallow_literal") == 0;
236  if (shallow_literal || strcmp(m, "__shallow_parsed") == 0)
237  {
238  lua_newtable(L);
239  for(const auto& [key, value] : v->get_config().attribute_range()) {
240  if (shallow_literal)
241  luaW_pushscalar(L, value);
242  else
243  luaW_pushscalar(L, v->expand(key));
244  lua_setfield(L, -2, key.c_str());
245  }
247  i_end = v->ordered_end();
248  if (shallow_literal) {
249  i.disable_insertion();
250  i_end.disable_insertion();
251  }
252  for (int j = 1; i != i_end; ++i, ++j)
253  {
254  tuple_builder.push(L);
255  lua_pushlstring(L, i.get_key().c_str(), i.get_key().size());
256  lua_rawseti(L, -2, 1);
257  luaW_pushvconfig(L, i.get_child());
258  lua_rawseti(L, -2, 2);
259  lua_rawseti(L, -2, j);
260  }
261  return 1;
262  }
263 
264  if (v->null() || !v->has_attribute(m)) return 0;
265  luaW_pushscalar(L, (*v)[m]);
266  return 1;
267 }
268 
269 static int impl_vconfig_dir(lua_State* L)
270 {
271  vconfig *v = static_cast<vconfig *>(lua_touserdata(L, 1));
272  std::vector<std::string> attributes;
273  for(const auto& [key, value] : v->get_config().attribute_range()) {
274  attributes.push_back(key);
275  }
276  lua_push(L, attributes);
277  return 1;
278 }
279 
280 /**
281  * Returns the number of a child of a vconfig object.
282  */
283 static int impl_vconfig_size(lua_State *L)
284 {
285  vconfig *v = static_cast<vconfig *>(lua_touserdata(L, 1));
286  lua_pushinteger(L, v->null() ? 0 :
287  std::distance(v->ordered_begin(), v->ordered_end()));
288  return 1;
289 }
290 
291 /**
292  * Destroys a vconfig object before it is collected (__gc metamethod).
293  */
294 static int impl_vconfig_collect(lua_State *L)
295 {
296  vconfig *v = static_cast<vconfig *>(lua_touserdata(L, 1));
297  v->~vconfig();
298  return 0;
299 }
300 
301 /**
302  * Iterate through the attributes of a vconfig
303  */
304 static int impl_vconfig_pairs_iter(lua_State *L)
305 {
306  vconfig vcfg = luaW_checkvconfig(L, 1);
307  void* p = luaL_checkudata(L, lua_upvalueindex(1), vconfigpairsKey);
308  config::const_attr_itors& range = *static_cast<config::const_attr_itors*>(p);
309  if (range.empty()) {
310  return 0;
311  }
312  config::attribute value = range.front();
313  range.pop_front();
314  lua_pushlstring(L, value.first.c_str(), value.first.length());
315  luaW_pushscalar(L, vcfg[value.first]);
316  return 2;
317 }
318 
319 /**
320  * Destroy a vconfig pairs iterator
321  */
322 static int impl_vconfig_pairs_collect(lua_State *L)
323 {
324  typedef config::const_attr_itors const_attr_itors;
325  void* p = lua_touserdata(L, 1);
326 
327  // Triggers a false positive of C4189 with Visual Studio. Suppress.
328 #if defined(_MSC_VER)
329 #pragma warning(push)
330 #pragma warning(disable: 4189)
331 #endif
332 
333  const_attr_itors* cai = static_cast<const_attr_itors*>(p);
334  cai->~const_attr_itors();
335 
336 #if defined(_MSC_VER)
337 #pragma warning(pop)
338 #endif
339 
340  return 0;
341 }
342 
343 /**
344  * Construct an iterator to iterate through the attributes of a vconfig
345  */
346 static int impl_vconfig_pairs(lua_State *L)
347 {
348  vconfig vcfg = luaW_checkvconfig(L, 1);
350  luaL_newmetatable(L, vconfigpairsKey);
351  lua_setmetatable(L, -2);
352  lua_pushcclosure(L, &impl_vconfig_pairs_iter, 1);
353  lua_pushvalue(L, 1);
354  return 2;
355 }
356 
357 /**
358  * Creates a vconfig containing the WML table.
359  * - Arg 1: WML table.
360  * - Ret 1: vconfig userdata.
361  */
362 int intf_tovconfig(lua_State *L)
363 {
364  vconfig vcfg = luaW_checkvconfig(L, 1);
365  luaW_pushvconfig(L, vcfg);
366  return 1;
367 }
368 
369 /**
370  * Adds the gettext metatable
371  */
372 std::string register_gettext_metatable(lua_State *L)
373 {
374  luaL_newmetatable(L, gettextKey);
375 
376  static luaL_Reg const callbacks[] {
377  { "__call", &impl_gettext},
378  { "__tostring", &impl_gettext_tostr},
379  { nullptr, nullptr }
380  };
381  luaL_setfuncs(L, callbacks, 0);
382 
383  lua_pushstring(L, "message domain");
384  lua_setfield(L, -2, "__metatable");
385 
386  return "Adding gettext metatable...\n";
387 }
388 
389 /**
390  * Adds the tstring metatable
391  */
392 std::string register_tstring_metatable(lua_State *L)
393 {
394  luaL_newmetatable(L, tstringKey);
395 
396  static luaL_Reg const callbacks[] {
397  { "__concat", &impl_tstring_concat},
398  { "__gc", &impl_tstring_collect},
399  { "__tostring", &impl_tstring_tostring},
400  { "__len", &impl_tstring_len},
401  { "__lt", &impl_tstring_lt},
402  { "__le", &impl_tstring_le},
403  { "__eq", &impl_tstring_eq},
404  { nullptr, nullptr }
405  };
406  luaL_setfuncs(L, callbacks, 0);
407 
408  lua_createtable(L, 0, 1);
409  luaW_getglobal(L, "string", "format");
410  lua_setfield(L, -2, "format");
411  luaW_getglobal(L, "stringx", "vformat");
412  lua_setfield(L, -2, "vformat");
413  lua_setfield(L, -2, "__index");
414 
415  lua_pushstring(L, "translatable string");
416  lua_setfield(L, -2, "__metatable");
417 
418  return "Adding tstring metatable...\n";
419 }
420 
421 /**
422  * Adds the vconfig metatable
423  */
424 std::string register_vconfig_metatable(lua_State *L)
425 {
426  luaL_newmetatable(L, vconfigKey);
427 
428  static luaL_Reg const callbacks[] {
429  { "__gc", &impl_vconfig_collect},
430  { "__index", &impl_vconfig_get},
431  { "__dir", &impl_vconfig_dir},
432  { "__len", &impl_vconfig_size},
433  { "__pairs", &impl_vconfig_pairs},
434  { nullptr, nullptr }
435  };
436  luaL_setfuncs(L, callbacks, 0);
437 
438  lua_pushstring(L, "wml object");
439  lua_setfield(L, -2, "__metatable");
440 
441  // Metatables for the iterator userdata
442 
443  // I don't bother setting __metatable because this
444  // userdata is only ever stored in the iterator's
445  // upvalues, so it's never visible to the user.
446  luaL_newmetatable(L, vconfigpairsKey);
447  lua_pushstring(L, "__gc");
448  lua_pushcfunction(L, &impl_vconfig_pairs_collect);
449  lua_rawset(L, -3);
450 
451  return "Adding vconfig metatable...\n";
452 }
453 
454 } // end namespace lua_common
455 
456 scoped_lua_argument::scoped_lua_argument(lua_State* L, int arg_index)
457  : state_(L)
458 {
459  lua_geti(state_, -1, arg_index);
460 }
461 
462 scoped_lua_argument::scoped_lua_argument(lua_State* L, int value_index, int arg_index)
463  : state_(L)
464 {
465  lua_geti(state_, value_index, arg_index);
466 }
467 
469 {
470  lua_pop(state_, 1);
471 }
472 
473 void* operator new(std::size_t sz, lua_State *L, int nuv)
474 {
475  return lua_newuserdatauv(L, sz, nuv);
476 }
477 
478 void operator delete(void*, lua_State *L, int)
479 {
480  // Not sure if this is needed since it's a no-op
481  // It's only called if a constructor throws while using the above operator new
482  // By removing the userdata from the stack, this should ensure that Lua frees it
483  lua_pop(L, 1);
484 }
485 
486 bool luaW_getmetafield(lua_State *L, int idx, const char* key)
487 {
488  if(key == nullptr) {
489  return false;
490  }
491  int n = strlen(key);
492  if(n == 0) {
493  return false;
494  }
495  if(n >= 2 && key[0] == '_' && key[1] == '_') {
496  return false;
497  }
498  return luaL_getmetafield(L, idx, key) != 0;
499 }
500 
501 void luaW_pushvconfig(lua_State *L, const vconfig& cfg)
502 {
503  new(L) vconfig(cfg);
504  luaL_setmetatable(L, vconfigKey);
505 }
506 
507 void luaW_pushtstring(lua_State *L, const t_string& v)
508 {
509  new(L) t_string(v);
510  luaL_setmetatable(L, tstringKey);
511 }
512 
513 
514 namespace {
515  struct luaW_pushscalar_visitor
516 #ifdef USING_BOOST_VARIANT
517  : boost::static_visitor<>
518 #endif
519  {
520  lua_State *L;
521  luaW_pushscalar_visitor(lua_State *l): L(l) {}
522 
523  void operator()(const utils::monostate&) const
524  { lua_pushnil(L); }
525  void operator()(bool b) const
526  { lua_pushboolean(L, b); }
527  void operator()(int i) const
528  { lua_pushinteger(L, i); }
529  void operator()(unsigned long long ull) const
530  { lua_pushnumber(L, ull); }
531  void operator()(double d) const
532  { lua_pushnumber(L, d); }
533  void operator()(const std::string& s) const
534  { lua_pushlstring(L, s.c_str(), s.size()); }
535  void operator()(const t_string& s) const
536  { luaW_pushtstring(L, s); }
537  };
538 }//unnamed namespace for luaW_pushscalar_visitor
539 
540 void luaW_pushscalar(lua_State *L, const config::attribute_value& v)
541 {
542  v.apply_visitor(luaW_pushscalar_visitor(L));
543 }
544 
545 bool luaW_toscalar(lua_State *L, int index, config::attribute_value& v)
546 {
547  switch (lua_type(L, index)) {
548  case LUA_TBOOLEAN:
549  v = luaW_toboolean(L, -1);
550  break;
551  case LUA_TNUMBER:
552  v = lua_tonumber(L, -1);
553  break;
554  case LUA_TSTRING:
555  v = std::string(luaW_tostring(L, -1));
556  break;
557  case LUA_TUSERDATA:
558  {
559  if (t_string * tptr = static_cast<t_string *>(luaL_testudata(L, -1, tstringKey))) {
560  v = *tptr;
561  break;
562  } else {
563  return false;
564  }
565  }
566  default:
567  return false;
568  }
569  return true;
570 }
571 
572 bool luaW_totstring(lua_State *L, int index, t_string &str)
573 {
574  switch (lua_type(L, index)) {
575  case LUA_TBOOLEAN:
576  str = lua_toboolean(L, index) ? "yes" : "no";
577  break;
578  case LUA_TNUMBER:
579  case LUA_TSTRING:
580  str = lua_tostring(L, index);
581  break;
582  case LUA_TUSERDATA:
583  {
584  if (t_string * tstr = static_cast<t_string *> (luaL_testudata(L, index, tstringKey))) {
585  str = *tstr;
586  break;
587  } else {
588  return false;
589  }
590  }
591  default:
592  return false;
593  }
594  return true;
595 }
596 
597 t_string luaW_checktstring(lua_State *L, int index)
598 {
599  t_string result;
600  if (!luaW_totstring(L, index, result))
601  luaW_type_error(L, index, "translatable string");
602  return result;
603 }
604 
605 bool luaW_iststring(lua_State* L, int index)
606 {
607  if(lua_isstring(L, index)) {
608  return true;
609  }
610  if(lua_isuserdata(L, index) && luaL_testudata(L, index, tstringKey)) {
611  return true;
612  }
613  return false;
614 }
615 
616 void luaW_filltable(lua_State *L, const config& cfg)
617 {
618  static const lua_named_tuple_builder tuple_builder{ {"tag", "contents"} };
619 
620  if (!lua_checkstack(L, LUA_MINSTACK))
621  return;
622 
623  int k = 1;
624  for(const auto [child_key, child_cfg] : cfg.all_children_view())
625  {
626  tuple_builder.push(L);
627  lua_pushstring(L, child_key.c_str());
628  lua_rawseti(L, -2, 1);
629  lua_newtable(L);
630  luaW_filltable(L, child_cfg);
631  lua_rawseti(L, -2, 2);
632  lua_rawseti(L, -2, k++);
633  }
634  for(const auto& [key, value] : cfg.attribute_range())
635  {
636  luaW_pushscalar(L, value);
637  lua_setfield(L, -2, key.c_str());
638  }
639 }
640 
642 {
643  if(lua_type(L, 2) == LUA_TSTRING) {
644  std::string k = lua_tostring(L, 2);
645  luaL_getmetafield(L, 1, "__names");
646  auto names = lua_check<std::vector<std::string>>(L, -1);
647  auto iter = std::find(names.begin(), names.end(), k);
648  if(iter != names.end()) {
649  int i = std::distance(names.begin(), iter) + 1;
650  lua_rawgeti(L, 1, i);
651  return 1;
652  }
653  }
654  return 0;
655 }
656 
658 {
659  if(lua_type(L, 2) == LUA_TSTRING) {
660  std::string k = lua_tostring(L, 2);
661  luaL_getmetafield(L, 1, "__names");
662  auto names = lua_check<std::vector<std::string>>(L, -1);
663  auto iter = std::find(names.begin(), names.end(), k);
664  if(iter != names.end()) {
665  int i = std::distance(names.begin(), iter) + 1;
666  lua_pushvalue(L, 3);
667  lua_rawseti(L, 1, i);
668  return 0;
669  }
670  }
671  // If it's not one of the special names, just assign normally
672  lua_settop(L, 3);
673  lua_rawset(L, 1);
674  return 0;
675 }
676 
678 {
679  luaL_getmetafield(L, 1, "__names");
680  return 1;
681 }
682 
684 {
685  std::vector<std::string> elems;
686  for(unsigned i = 1; i <= lua_rawlen(L, 1); i++) {
687  lua_getglobal(L, "tostring");
688  lua_rawgeti(L, 1, i);
689  lua_call(L, 1, 1);
690  elems.push_back(lua_tostring(L, -1));
691  }
692  lua_push(L, "(" + utils::join(elems) + ")");
693  return 1;
694 }
695 
697  // Comparing a named tuple with any other table is always false.
698  if(lua_type(L, 1) != LUA_TTABLE || lua_type(L, 2) != LUA_TTABLE) {
699  NOT_EQUAL:
700  lua_pushboolean(L, false);
701  return 1;
702  }
703  luaL_getmetafield(L, 1, "__name");
704  luaL_getmetafield(L, 2, "__name");
705  if(!lua_rawequal(L, 3, 4)) goto NOT_EQUAL;
706  lua_pop(L, 2);
707  // Named tuples can be equal only if they both have the exact same set of names.
708  luaL_getmetafield(L, 1, "__names");
709  luaL_getmetafield(L, 2, "__names");
710  auto lnames = lua_check<std::vector<std::string>>(L, 3);
711  auto rnames = lua_check<std::vector<std::string>>(L, 4);
712  if(lnames != rnames) goto NOT_EQUAL;
713  lua_pop(L, 2);
714  // They are equal if all of the corresponding members in each tuple are equal.
715  for(std::size_t i = 1; i <= lnames.size(); i++) {
716  lua_rawgeti(L, 1, i);
717  lua_rawgeti(L, 2, i);
718  if(!lua_compare(L, 3, 4, LUA_OPEQ)) goto NOT_EQUAL;
719  lua_pop(L, 2);
720  }
721  // Theoretically, they could have other members besides the special named ones.
722  // But we ignore those for the purposes of equality.
723  lua_pushboolean(L, true);
724  return 1;
725 }
726 
728  : names_{ names }
729  , key_{ build_key(names) }
730 {
731 }
732 
733 void lua_named_tuple_builder::push(lua_State *L) const
734 {
735  lua_createtable(L, names_.size(), 0);
736 
737  if (luaL_newmetatable(L, key_.c_str()) != 0) {
738  static luaL_Reg callbacks[] = {
739  { "__index", &impl_get },
740  { "__newindex", &impl_set },
741  { "__dir", &impl_dir },
742  { "__eq", &impl_compare },
743  { "__tostring", &impl_tostring },
744  { nullptr, nullptr }
745  };
746  luaL_setfuncs(L, callbacks, 0);
747 
748  lua_pushlstring(L, key_.c_str(), key_.size());
749  lua_setfield(L, -2, "__metatable");
750  lua_push(L, names_);
751  lua_setfield(L, -2, "__names");
752  // __name has already been set to KEY by luaL_newmetatable
753  }
754 
755  lua_setmetatable(L, -2);
756 }
757 
758 std::string lua_named_tuple_builder::build_key(const std::vector<std::string>& names)
759 {
760  std::ostringstream str;
761  str << base_name_ << '(';
762  if(!names.empty()) {
763  str << names[0];
764  }
765  for(std::size_t i = 1; i < names.size(); i++) {
766  str << ", " << names[i];
767  }
768  str << ')';
769  return str.str();
770 }
771 
772 std::vector<std::string> luaW_to_namedtuple(lua_State* L, int idx) {
773  std::vector<std::string> names;
774  if(luaL_getmetafield(L, idx, "__name")) {
775  if(lua_check<std::string>(L, -1) == "named tuple") {
776  luaL_getmetafield(L, idx, "__names");
777  names = lua_check<std::vector<std::string>>(L, -1);
778  lua_pop(L, 1);
779  }
780  lua_pop(L, 1);
781  }
782  return names;
783 }
784 
785 void luaW_pushlocation(lua_State *L, const map_location& ml)
786 {
787  static const lua_named_tuple_builder tuple_builder{ {"x", "y"} };
788 
789  tuple_builder.push(L);
790 
791  lua_pushinteger(L, ml.wml_x());
792  lua_rawseti(L, -2, 1);
793 
794  lua_pushinteger(L, ml.wml_y());
795  lua_rawseti(L, -2, 2);
796 }
797 
798 bool luaW_tolocation(lua_State *L, int index, map_location& loc) {
799  if (!lua_checkstack(L, LUA_MINSTACK)) {
800  return false;
801  }
802  if (lua_isnoneornil(L, index)) {
803  // Need this special check because luaW_tovconfig returns true in this case
804  return false;
805  }
806 
808 
809  index = lua_absindex(L, index);
810 
811  if (lua_istable(L, index) || lua_isuserdata(L, index)) {
812  map_location result;
813  int x_was_num = 0, y_was_num = 0;
814  lua_getfield(L, index, "x");
815  result.set_wml_x(lua_tointegerx(L, -1, &x_was_num));
816  lua_getfield(L, index, "y");
817  result.set_wml_y(lua_tointegerx(L, -1, &y_was_num));
818  lua_pop(L, 2);
819  if (!x_was_num || !y_was_num) {
820  // If we get here and it was userdata, checking numeric indices won't help
821  // (It won't help if it was a WML table either, but there's no easy way to check that.)
822  if (lua_isuserdata(L, index)) {
823  return false;
824  }
825  lua_rawgeti(L, index, 1);
826  result.set_wml_x(lua_tointegerx(L, -1, &x_was_num));
827  lua_rawgeti(L, index, 2);
828  result.set_wml_y(lua_tointegerx(L, -1, &y_was_num));
829  lua_pop(L, 2);
830  }
831  if (x_was_num && y_was_num) {
832  loc = result;
833  return true;
834  }
835  } else if (lua_isnumber(L, index) && lua_isnumber(L, index + 1)) {
836  // If it's a number, then we consume two elements on the stack
837  // Since we have no way of notifying the caller that we have
838  // done this, we remove the first number from the stack.
839  loc.set_wml_x(lua_tointeger(L, index));
840  lua_remove(L, index);
841  loc.set_wml_y(lua_tointeger(L, index));
842  return true;
843  }
844  return false;
845 }
846 
848 {
849  map_location result;
850  if (!luaW_tolocation(L, index, result))
851  luaW_type_error(L, index, "location");
852  return result;
853 }
854 
855 int luaW_push_locationset(lua_State* L, const std::set<map_location>& locs)
856 {
857  lua_createtable(L, locs.size(), 0);
858  int i = 1;
859  for(const map_location& loc : locs) {
861  lua_rawseti(L, -2, i);
862  ++i;
863  }
864  return 1;
865 }
866 
867 std::set<map_location> luaW_check_locationset(lua_State* L, int idx)
868 {
869  std::set<map_location> locs;
870  if(!lua_istable(L, idx)) {
871  luaW_type_error(L, idx, "array of locations");
872  }
873  lua_len(L, idx);
874  int len = luaL_checkinteger(L, -1);
875  for(int i = 1; i <= len; i++) {
876  const auto arg = scoped_lua_argument{L, idx, i};
877  locs.insert(luaW_checklocation(L, -1));
878  }
879  return locs;
880 
881 }
882 
883 void luaW_pushconfig(lua_State *L, const config& cfg)
884 {
885  lua_newtable(L);
886  luaW_filltable(L, cfg);
887 }
888 
890  return {L};
891 }
892 
893 std::ostream& operator<<(std::ostream& os, const luaW_PrintStack& s) {
894  int top = lua_gettop(s.L);
895  os << "Lua Stack\n";
896  for(int i = 1; i <= top; i++) {
897  luaW_getglobal(s.L, "wesnoth", "as_text");
898  lua_pushvalue(s.L, i);
899  lua_call(s.L, 1, 1);
900  auto value = luaL_checkstring(s.L, -1);
901  lua_pop(s.L, 1);
902  os << '[' << i << ']' << value << '\n';
903  }
904  if(top == 0) os << "(empty)\n";
905  os << std::flush;
906  return os;
907 }
908 
909 #define return_misformed() \
910  do { lua_settop(L, initial_top); return false; } while (0)
911 
912 bool luaW_toconfig(lua_State *L, int index, config &cfg)
913 {
914  cfg.clear();
915  if (!lua_checkstack(L, LUA_MINSTACK))
916  return false;
917 
918  // Get the absolute index of the table.
919  index = lua_absindex(L, index);
920  int initial_top = lua_gettop(L);
921 
922  switch (lua_type(L, index))
923  {
924  case LUA_TTABLE:
925  break;
926  case LUA_TUSERDATA:
927  {
928  if (vconfig * ptr = static_cast<vconfig *> (luaL_testudata(L, index, vconfigKey))) {
929  cfg = ptr->get_parsed_config();
930  return true;
931  } else {
932  return false;
933  }
934  }
935  case LUA_TNONE:
936  case LUA_TNIL:
937  return true;
938  default:
939  return false;
940  }
941 
942  // First convert the children (integer indices).
943  for (int i = 1, i_end = lua_rawlen(L, index); i <= i_end; ++i)
944  {
945  lua_rawgeti(L, index, i);
946  if (!lua_istable(L, -1)) return_misformed();
947  lua_rawgeti(L, -1, 1);
948  char const *m = lua_tostring(L, -1);
949  if (!m || !config::valid_tag(m)) return_misformed();
950  lua_rawgeti(L, -2, 2);
951  if (!luaW_toconfig(L, -1, cfg.add_child(m)))
953  lua_pop(L, 3);
954  }
955 
956  // Then convert the attributes (string indices).
957  for (lua_pushnil(L); lua_next(L, index); lua_pop(L, 1))
958  {
959  int indextype = lua_type(L, -2);
960  if (indextype == LUA_TNUMBER) continue;
961  if (indextype != LUA_TSTRING) return_misformed();
962  const char* m = lua_tostring(L, -2);
965  if (lua_istable(L, -1)) {
966  int subindex = lua_absindex(L, -1);
967  std::ostringstream str;
968  for (int i = 1, i_end = lua_rawlen(L, subindex); i <= i_end; ++i, lua_pop(L, 1)) {
969  lua_rawgeti(L, -1, i);
971  if (!luaW_toscalar(L, -1, item)) return_misformed();
972  if (i > 1) str << ',';
973  str << item;
974  }
975  // If there are any string keys, it's malformed
976  for (lua_pushnil(L); lua_next(L, subindex); lua_pop(L, 1)) {
977  if (lua_type(L, -2) != LUA_TNUMBER) return_misformed();
978  }
979  v = str.str();
980  } else if (!luaW_toscalar(L, -1, v)) return_misformed();
981  }
982 
983  lua_settop(L, initial_top);
984  return true;
985 }
986 
987 #undef return_misformed
988 
989 
990 config luaW_checkconfig(lua_State *L, int index)
991 {
992  config result;
993  if (!luaW_toconfig(L, index, result))
994  luaW_type_error(L, index, "WML table");
995  return result;
996 }
997 
998 config luaW_checkconfig(lua_State *L, int index, const vconfig*& vcfg)
999 {
1000  config result = luaW_checkconfig(L, index);
1001  if(void* p = luaL_testudata(L, index, vconfigKey)) {
1002  vcfg = static_cast<vconfig*>(p);
1003  }
1004  return result;
1005 }
1006 
1007 bool luaW_tovconfig(lua_State *L, int index, vconfig &vcfg)
1008 {
1009  switch (lua_type(L, index))
1010  {
1011  case LUA_TTABLE:
1012  {
1013  config cfg;
1014  bool ok = luaW_toconfig(L, index, cfg);
1015  if (!ok) return false;
1016  vcfg = vconfig(std::move(cfg));
1017  break;
1018  }
1019  case LUA_TUSERDATA:
1020  if (vconfig * ptr = static_cast<vconfig *> (luaL_testudata(L, index, vconfigKey))) {
1021  vcfg = *ptr;
1022  } else {
1023  return false;
1024  }
1025  case LUA_TNONE:
1026  case LUA_TNIL:
1027  break;
1028  default:
1029  return false;
1030  }
1031  return true;
1032 }
1033 
1034 vconfig luaW_checkvconfig(lua_State *L, int index, bool allow_missing)
1035 {
1037  if (!luaW_tovconfig(L, index, result) || (!allow_missing && result.null()))
1038  luaW_type_error(L, index, "WML table");
1039  return result;
1040 }
1041 
1042 bool luaW_getglobal(lua_State *L, const std::vector<std::string>& path)
1043 {
1044  lua_pushglobaltable(L);
1045  for (const std::string& s : path)
1046  {
1047  if (!lua_istable(L, -1)) goto discard;
1048  lua_pushlstring(L, s.c_str(), s.size());
1049  lua_rawget(L, -2);
1050  lua_remove(L, -2);
1051  }
1052 
1053  if (lua_isnil(L, -1)) {
1054  discard:
1055  lua_pop(L, 1);
1056  return false;
1057  }
1058  return true;
1059 }
1060 
1061 bool luaW_toboolean(lua_State *L, int n)
1062 {
1063  return lua_toboolean(L,n) != 0;
1064 }
1065 
1067 {
1068  try
1069  {
1070  if(v.exists_as_attribute())
1071  {
1072  luaW_pushscalar(L, v.as_scalar());
1073  return true;
1074  }
1075  else if(v.exists_as_container())
1076  {
1077  lua_newtable(L);
1078  luaW_filltable(L, v.as_container());
1079  return true;
1080  }
1081  else
1082  {
1083  lua_pushnil(L);
1084  return true;
1085  }
1086  }
1087  catch (const invalid_variablename_exception&)
1088  {
1089  WRN_LUA << v.get_error_message();
1090  return false;
1091  }
1092 }
1093 
1094 bool luaW_checkvariable(lua_State *L, variable_access_create& v, int n)
1095 {
1096  int variabletype = lua_type(L, n);
1097  try
1098  {
1099  switch (variabletype) {
1100  case LUA_TBOOLEAN:
1101  v.as_scalar() = luaW_toboolean(L, n);
1102  return true;
1103  case LUA_TNUMBER:
1104  v.as_scalar() = lua_tonumber(L, n);
1105  return true;
1106  case LUA_TSTRING:
1107  v.as_scalar() = std::string(luaW_tostring(L, n));
1108  return true;
1109  case LUA_TUSERDATA:
1110  if (t_string * t_str = static_cast<t_string*> (luaL_testudata(L, n, tstringKey))) {
1111  v.as_scalar() = *t_str;
1112  return true;
1113  }
1114  goto default_explicit;
1115  case LUA_TTABLE:
1116  {
1117  config &cfg = v.as_container();
1118  if (luaW_toconfig(L, n, cfg)) {
1119  return true;
1120  }
1121  [[fallthrough]];
1122  }
1123  default:
1124  default_explicit:
1125  return luaW_type_error(L, n, "WML table or scalar") != 0;
1126 
1127  }
1128  }
1129  catch (const invalid_variablename_exception&)
1130  {
1131  WRN_LUA << v.get_error_message() << " when attempting to write a '" << lua_typename(L, variabletype) << "'";
1132  return false;
1133  }
1134 }
1135 
1136 bool luaW_tableget(lua_State *L, int index, const char* key)
1137 {
1138  index = lua_absindex(L, index);
1139  lua_pushstring(L, key);
1140  lua_gettable(L, index);
1141  if(lua_isnoneornil(L, -1)) {
1142  lua_pop(L, 1);
1143  return false;
1144  }
1145  return true;
1146 }
1147 
1148 std::string_view luaW_tostring(lua_State *L, int index)
1149 {
1150  std::size_t len = 0;
1151  const char* str = lua_tolstring(L, index, &len);
1152  if(!str) {
1153  throw luaL_error (L, "not a string");
1154  }
1155  return std::string_view(str, len);
1156 }
1157 
1158 std::string_view luaW_tostring_or_default(lua_State *L, int index, std::string_view def)
1159 {
1160  std::size_t len = 0;
1161  const char* str = lua_tolstring(L, index, &len);
1162  if(!str) {
1163  return def;
1164  }
1165  return std::string_view(str, len);
1166 }
1167 
1168 void chat_message(const std::string& caption, const std::string& msg)
1169 {
1170  if (!game_display::get_singleton()) return;
1172  std::chrono::system_clock::now(), caption, 0, msg, events::chat_handler::MESSAGE_PUBLIC, false);
1173 }
1174 
1175 void push_error_handler(lua_State *L)
1176 {
1177  luaW_getglobal(L, "debug", "traceback");
1178  lua_setfield(L, LUA_REGISTRYINDEX, executeKey);
1179 }
1180 
1181 int luaW_pcall_internal(lua_State *L, int nArgs, int nRets)
1182 {
1183  // Load the error handler before the function and its arguments.
1184  lua_getfield(L, LUA_REGISTRYINDEX, executeKey);
1185  lua_insert(L, -2 - nArgs);
1186 
1187  int error_handler_index = lua_gettop(L) - nArgs - 1;
1188 
1190 
1191  // Call the function.
1192  int errcode = lua_pcall(L, nArgs, nRets, -2 - nArgs);
1193 
1196 
1197  // Remove the error handler.
1198  lua_remove(L, error_handler_index);
1199 
1200  return errcode;
1201 }
1202 
1203 #ifdef _MSC_VER
1204 #pragma warning (push)
1205 #pragma warning (disable: 4706)
1206 #endif
1207 bool luaW_pcall(lua_State *L, int nArgs, int nRets, bool allow_wml_error)
1208 {
1209  int res = luaW_pcall_internal(L, nArgs, nRets);
1210 
1211  if (res)
1212  {
1213  /*
1214  * When an exception is thrown which doesn't derive from
1215  * std::exception m will be nullptr pointer.
1216  * When adding a new conditional branch, remember to log the
1217  * error with ERR_LUA or ERR_WML.
1218  */
1219  char const *m = lua_tostring(L, -1);
1220  if(m) {
1221  if (allow_wml_error && strncmp(m, "~wml:", 5) == 0) {
1222  m += 5;
1223  char const *e = strstr(m, "stack traceback");
1224  lg::log_to_chat() << std::string(m, e ? e - m : strlen(m)) << '\n';
1225  ERR_WML << std::string(m, e ? e - m : strlen(m));
1226  } else if (allow_wml_error && strncmp(m, "~lua:", 5) == 0) {
1227  m += 5;
1228  char const *e = nullptr, *em = m;
1229  while (em[0] && ((em = strstr(em + 1, "stack traceback"))))
1230 #ifdef _MSC_VER
1231 #pragma warning (pop)
1232 #endif
1233  e = em;
1234  ERR_LUA << std::string(m, e ? e - m : strlen(m));
1235  chat_message("Lua error", std::string(m, e ? e - m : strlen(m)));
1236  } else {
1237  ERR_LUA << m;
1238  chat_message("Lua error", m);
1239  }
1240  } else {
1241  ERR_LUA << "Lua caught unknown exception";
1242  chat_message("Lua caught unknown exception", "");
1243  }
1244  lua_pop(L, 1);
1245  return false;
1246  }
1247 
1248  return true;
1249 }
1250 
1251 // Originally luaL_typerror, now deprecated.
1252 // Easier to define it for Wesnoth and not have to worry about it if we update Lua.
1253 int luaW_type_error(lua_State *L, int narg, const char *tname) {
1254  const char *msg = lua_pushfstring(L, "%s expected, got %s", tname, luaL_typename(L, narg));
1255  return luaL_argerror(L, narg, msg);
1256 }
1257 
1258 // An alternate version which raises an error for a key in a table.
1259 // In this version, narg should refer to the stack index of the table rather than the stack index of the key.
1260 // kpath should be the key name or a string such as "key[idx].key2" specifying a path to the key.
1261 int luaW_type_error (lua_State *L, int narg, const char* kpath, const char *tname) {
1262  const char *msg = lua_pushfstring(L, "%s expected for '%s', got %s", tname, kpath, luaL_typename(L, narg));
1263  return luaL_argerror(L, narg, msg);
1264 }
map_location loc
Definition: move.cpp:172
double t
Definition: astarsearch.cpp:63
std::vector< std::string > names
Definition: build_info.cpp:67
Variant for storing WML attributes.
std::string str(const std::string &fallback="") const
auto apply_visitor(const V &visitor) const
Visitor support: Applies a visitor to the underlying variant.
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:157
static bool valid_tag(std::string_view name)
Definition: config.cpp:129
config & add_child(std::string_view key)
Definition: config.cpp:436
const_attr_itors attribute_range() const
Definition: config.cpp:740
auto all_children_view() const
In-order iteration over all children.
Definition: config.hpp:795
static bool valid_attribute(std::string_view name)
Definition: config.cpp:152
boost::iterator_range< const_attribute_iterator > const_attr_itors
Definition: config.hpp:357
attribute_map::value_type attribute
Definition: config.hpp:297
void clear()
Definition: config.cpp:802
void add_chat_message(const std::chrono::system_clock::time_point &time, const std::string &speaker, int side, const std::string &msg, events::chat_handler::MESSAGE_TYPE type, bool bell)
static game_display * get_singleton()
display_chat_manager & get_chat_manager()
static void rethrow()
Rethrows the stored exception.
static int jail_depth
Depth of recursive luaW_pcall_internal() function calls.
Efficiently creates new LUA "named tuples" with the specified field names.
Definition: lua_common.hpp:85
static int impl_set(lua_State *L)
Definition: lua_common.cpp:657
static std::string build_key(const std::vector< std::string > &names)
Definition: lua_common.cpp:758
static int impl_tostring(lua_State *L)
Definition: lua_common.cpp:683
lua_named_tuple_builder(const std::vector< std::string > &names)
Definition: lua_common.cpp:727
static int impl_compare(lua_State *L)
Definition: lua_common.cpp:696
void push(lua_State *L) const
Push an empty "named tuple" onto the stack.
Definition: lua_common.cpp:733
static int impl_dir(lua_State *L)
Definition: lua_common.cpp:677
const std::vector< std::string > names_
Definition: lua_common.hpp:109
static int impl_get(lua_State *L)
Definition: lua_common.cpp:641
static constexpr std::string_view base_name_
Definition: lua_common.hpp:107
const std::string key_
Definition: lua_common.hpp:110
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:456
lua_State *const state_
Definition: lua_common.hpp:64
const t_string_base & get() const
Definition: tstring.hpp:214
Additional functionality for a non-const variable_info.
Information on a WML variable.
maybe_const_t< config::attribute_value, V > & as_scalar() const
If instantiated with vi_policy_const, the lifetime of the returned const attribute_value reference mi...
std::string get_error_message() const
bool exists_as_container() const
maybe_const_t< config, V > & as_container() const
If instantiated with vi_policy_const, the lifetime of the returned const attribute_value reference mi...
bool exists_as_attribute() const
A variable-expanding proxy for the config class.
Definition: variable.hpp:45
~vconfig()
Default destructor, but defined here for possibly faster compiles (templates sometimes can be rough o...
Definition: variable.cpp:138
all_children_iterator ordered_begin() const
In-order iteration over all children.
Definition: variable.cpp:481
bool has_attribute(const std::string &key) const
< Synonym for operator[]
Definition: variable.hpp:99
static vconfig unconstructed_vconfig()
This is just a wrapper for the default constructor; it exists for historical reasons and to make it c...
Definition: variable.cpp:153
bool null() const
Definition: variable.hpp:72
config::attribute_value expand(const std::string &) const
Definition: variable.cpp:353
const config & get_config() const
Definition: variable.hpp:75
config get_parsed_config() const
Definition: variable.cpp:177
all_children_iterator ordered_end() const
Definition: variable.cpp:486
Definitions for the interface to Wesnoth Markup Language (WML).
const config * cfg
std::size_t i
Definition: function.cpp:1031
Standard logging facilities (interface).
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:883
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:616
void chat_message(const std::string &caption, const std::string &msg)
Displays a message in the chat window.
#define ERR_LUA
Definition: lua_common.cpp:50
void push_error_handler(lua_State *L)
static const char executeKey[]
Definition: lua_common.cpp:45
static lg::log_domain log_scripting_lua("scripting/lua")
bool luaW_iststring(lua_State *L, int index)
Definition: lua_common.cpp:605
static const char vconfigKey[]
Definition: lua_common.cpp:42
config luaW_checkconfig(lua_State *L, int index)
Converts an optional table or vconfig to a config object.
Definition: lua_common.cpp:990
void luaW_pushlocation(lua_State *L, const map_location &ml)
Converts a map location object to a Lua table pushed at the top of the stack.
Definition: lua_common.cpp:785
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:867
void luaW_pushtstring(lua_State *L, const t_string &v)
Pushes a t_string on the top of the stack.
Definition: lua_common.cpp:507
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.
#define ERR_WML
Definition: lua_common.cpp:53
void luaW_pushvconfig(lua_State *L, const vconfig &cfg)
Pushes a vconfig on the top of the stack.
Definition: lua_common.cpp:501
bool luaW_toboolean(lua_State *L, int n)
static const char vconfigpairsKey[]
Definition: lua_common.cpp:43
int luaW_type_error(lua_State *L, int narg, const char *tname)
#define return_misformed()
Definition: lua_common.cpp:909
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:545
std::string_view luaW_tostring(lua_State *L, int index)
static const char tstringKey[]
Definition: lua_common.cpp:44
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:486
#define WRN_LUA
Definition: lua_common.cpp:49
static const char gettextKey[]
Definition: lua_common.cpp:41
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:540
bool luaW_totstring(lua_State *L, int index, t_string &str)
Converts a scalar to a translatable string.
Definition: lua_common.cpp:572
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:772
bool luaW_tableget(lua_State *L, int index, const char *key)
std::string_view luaW_tostring_or_default(lua_State *L, int index, std::string_view def)
bool luaW_checkvariable(lua_State *L, variable_access_create &v, int n)
static lg::log_domain log_wml("wml")
bool luaW_pcall(lua_State *L, int nArgs, int nRets, bool allow_wml_error)
Calls a Lua function stored below its nArgs arguments at the top of the stack.
bool luaW_toconfig(lua_State *L, int index, config &cfg)
Converts an optional table or vconfig to a config object.
Definition: lua_common.cpp:912
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:855
std::ostream & operator<<(std::ostream &os, const luaW_PrintStack &s)
Definition: lua_common.cpp:893
vconfig luaW_checkvconfig(lua_State *L, int index, bool allow_missing)
Gets an optional vconfig from either a table or a userdata.
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:798
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:847
luaW_PrintStack luaW_debugstack(lua_State *L)
Definition: lua_common.cpp:889
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:597
std::string path
Definition: filesystem.cpp:106
std::stringstream & log_to_chat()
Use this to show WML errors in the ingame chat.
Definition: log.cpp:550
static int impl_tstring_concat(lua_State *L)
Appends a scalar to a t_string object (__concat metamethod).
Definition: lua_common.cpp:133
int intf_textdomain(lua_State *L)
Creates an interface for gettext.
Definition: lua_common.cpp:92
static int impl_vconfig_pairs(lua_State *L)
Construct an iterator to iterate through the attributes of a vconfig.
Definition: lua_common.cpp:346
static int impl_tstring_collect(lua_State *L)
Destroys a t_string object before it is collected (__gc metamethod).
Definition: lua_common.cpp:156
static int impl_tstring_eq(lua_State *L)
Definition: lua_common.cpp:179
std::string register_gettext_metatable(lua_State *L)
Adds the gettext metatable.
Definition: lua_common.cpp:372
static int impl_tstring_lt(lua_State *L)
Definition: lua_common.cpp:163
std::string register_vconfig_metatable(lua_State *L)
Adds the vconfig metatable.
Definition: lua_common.cpp:424
static int impl_vconfig_get(lua_State *L)
Gets the parsed field of a vconfig object (_index metamethod).
Definition: lua_common.cpp:203
static int impl_vconfig_pairs_collect(lua_State *L)
Destroy a vconfig pairs iterator.
Definition: lua_common.cpp:322
std::string register_tstring_metatable(lua_State *L)
Adds the tstring metatable.
Definition: lua_common.cpp:392
static int impl_gettext(lua_State *L)
Creates a t_string object (__call metamethod).
Definition: lua_common.cpp:63
static int impl_gettext_tostr(lua_State *L)
Definition: lua_common.cpp:78
static int impl_tstring_tostring(lua_State *L)
Converts a t_string object to a string (__tostring metamethod); that is, performs a translation.
Definition: lua_common.cpp:191
static int impl_vconfig_size(lua_State *L)
Returns the number of a child of a vconfig object.
Definition: lua_common.cpp:283
int intf_tovconfig(lua_State *L)
Creates a vconfig containing the WML table.
Definition: lua_common.cpp:362
static int impl_tstring_len(lua_State *L)
Definition: lua_common.cpp:146
static int impl_vconfig_pairs_iter(lua_State *L)
Iterate through the attributes of a vconfig.
Definition: lua_common.cpp:304
static int impl_vconfig_dir(lua_State *L)
Definition: lua_common.cpp:269
static int impl_vconfig_collect(lua_State *L)
Destroys a vconfig object before it is collected (__gc metamethod).
Definition: lua_common.cpp:294
static int impl_tstring_le(lua_State *L)
Definition: lua_common.cpp:171
static void tstring_concat_aux(lua_State *L, t_string &dst, int src)
Converts a Lua value at position src and appends it to dst.
Definition: lua_common.cpp:111
int compare(const std::string &s1, const std::string &s2)
Case-sensitive lexicographical comparison.
Definition: gettext.cpp:502
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
std::string join(const T &v, const std::string &s=",")
Generates a new string joining container items in a list.
auto * find(Container &container, const Value &value)
Convenience wrapper for using find on a container without needing to comare to end()
Definition: general.hpp:141
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
Definition: debugger.cpp:109
void lua_push(lua_State *L, const T &val)
Definition: push_check.hpp:425
static std::string flush(std::ostringstream &s)
Definition: reports.cpp:97
rect dst
Location on the final composed sheet.
rect src
Non-transparent portion of the surface to compose.
Encapsulates the map of the game.
Definition: location.hpp:46
void set_wml_y(int v)
Definition: location.hpp:190
int wml_y() const
Definition: location.hpp:187
void set_wml_x(int v)
Definition: location.hpp:189
int wml_x() const
Definition: location.hpp:186
mock_party p
static map_location::direction n
static map_location::direction s
#define d
#define e
#define b