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