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