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