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