The Battle for Wesnoth  1.19.0-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 config::attribute &a : v->get_config().attribute_range()) {
239  if (shallow_literal)
240  luaW_pushscalar(L, a.second);
241  else
242  luaW_pushscalar(L, v->expand(a.first));
243  lua_setfield(L, -2, a.first.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 config::any_child ch : cfg.all_children_range())
661  {
662  luaW_push_namedtuple(L, {"tag", "contents"});
663  lua_pushstring(L, ch.key.c_str());
664  lua_rawseti(L, -2, 1);
665  lua_newtable(L);
666  luaW_filltable(L, ch.cfg);
667  lua_rawseti(L, -2, 2);
668  lua_rawseti(L, -2, k++);
669  }
670  for (const config::attribute &attr : cfg.attribute_range())
671  {
672  luaW_pushscalar(L, attr.second);
673  lua_setfield(L, -2, attr.first.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  lua_pushliteral(L, "named tuple");
724  lua_setfield(L, -2, "__metatable");
725  lua_push(L, names);
726  lua_setfield(L, -2, "__names");
727  lua_setmetatable(L, -2);
728 }
729 
730 void luaW_pushlocation(lua_State *L, const map_location& ml)
731 {
732  luaW_push_namedtuple(L, {"x", "y"});
733 
734  lua_pushinteger(L, ml.wml_x());
735  lua_rawseti(L, -2, 1);
736 
737  lua_pushinteger(L, ml.wml_y());
738  lua_rawseti(L, -2, 2);
739 }
740 
741 bool luaW_tolocation(lua_State *L, int index, map_location& loc) {
742  if (!lua_checkstack(L, LUA_MINSTACK)) {
743  return false;
744  }
745  if (lua_isnoneornil(L, index)) {
746  // Need this special check because luaW_tovconfig returns true in this case
747  return false;
748  }
749 
751 
752  index = lua_absindex(L, index);
753 
754  if (lua_istable(L, index) || lua_isuserdata(L, index)) {
755  map_location result;
756  int x_was_num = 0, y_was_num = 0;
757  lua_getfield(L, index, "x");
758  result.set_wml_x(lua_tointegerx(L, -1, &x_was_num));
759  lua_getfield(L, index, "y");
760  result.set_wml_y(lua_tointegerx(L, -1, &y_was_num));
761  lua_pop(L, 2);
762  if (!x_was_num || !y_was_num) {
763  // If we get here and it was userdata, checking numeric indices won't help
764  // (It won't help if it was a WML table either, but there's no easy way to check that.)
765  if (lua_isuserdata(L, index)) {
766  return false;
767  }
768  lua_rawgeti(L, index, 1);
769  result.set_wml_x(lua_tointegerx(L, -1, &x_was_num));
770  lua_rawgeti(L, index, 2);
771  result.set_wml_y(lua_tointegerx(L, -1, &y_was_num));
772  lua_pop(L, 2);
773  }
774  if (x_was_num && y_was_num) {
775  loc = result;
776  return true;
777  }
778  } else if (lua_isnumber(L, index) && lua_isnumber(L, index + 1)) {
779  // If it's a number, then we consume two elements on the stack
780  // Since we have no way of notifying the caller that we have
781  // done this, we remove the first number from the stack.
782  loc.set_wml_x(lua_tointeger(L, index));
783  lua_remove(L, index);
784  loc.set_wml_y(lua_tointeger(L, index));
785  return true;
786  }
787  return false;
788 }
789 
791 {
792  map_location result;
793  if (!luaW_tolocation(L, index, result))
794  luaW_type_error(L, index, "location");
795  return result;
796 }
797 
798 int luaW_push_locationset(lua_State* L, const std::set<map_location>& locs)
799 {
800  lua_createtable(L, locs.size(), 0);
801  int i = 1;
802  for(const map_location& loc : locs) {
803  luaW_pushlocation(L, loc);
804  lua_rawseti(L, -2, i);
805  ++i;
806  }
807  return 1;
808 }
809 
810 std::set<map_location> luaW_check_locationset(lua_State* L, int idx)
811 {
812  std::set<map_location> locs;
813  if(!lua_istable(L, idx)) {
814  luaW_type_error(L, idx, "array of locations");
815  }
816  lua_len(L, idx);
817  int len = luaL_checkinteger(L, -1);
818  for(int i = 1; i <= len; i++) {
819  lua_geti(L, idx, i);
820  locs.insert(luaW_checklocation(L, -1));
821  lua_pop(L, 1);
822  }
823  return locs;
824 
825 }
826 
827 void luaW_pushconfig(lua_State *L, const config& cfg)
828 {
829  lua_newtable(L);
830  luaW_filltable(L, cfg);
831 }
832 
833 
834 
835 
836 #define return_misformed() \
837  do { lua_settop(L, initial_top); return false; } while (0)
838 
839 bool luaW_toconfig(lua_State *L, int index, config &cfg)
840 {
841  cfg.clear();
842  if (!lua_checkstack(L, LUA_MINSTACK))
843  return false;
844 
845  // Get the absolute index of the table.
846  index = lua_absindex(L, index);
847  int initial_top = lua_gettop(L);
848 
849  switch (lua_type(L, index))
850  {
851  case LUA_TTABLE:
852  break;
853  case LUA_TUSERDATA:
854  {
855  if (vconfig * ptr = static_cast<vconfig *> (luaL_testudata(L, index, vconfigKey))) {
856  cfg = ptr->get_parsed_config();
857  return true;
858  } else {
859  return false;
860  }
861  }
862  case LUA_TNONE:
863  case LUA_TNIL:
864  return true;
865  default:
866  return false;
867  }
868 
869  // First convert the children (integer indices).
870  for (int i = 1, i_end = lua_rawlen(L, index); i <= i_end; ++i)
871  {
872  lua_rawgeti(L, index, i);
873  if (!lua_istable(L, -1)) return_misformed();
874  lua_rawgeti(L, -1, 1);
875  char const *m = lua_tostring(L, -1);
876  if (!m || !config::valid_tag(m)) return_misformed();
877  lua_rawgeti(L, -2, 2);
878  if (!luaW_toconfig(L, -1, cfg.add_child(m)))
880  lua_pop(L, 3);
881  }
882 
883  // Then convert the attributes (string indices).
884  for (lua_pushnil(L); lua_next(L, index); lua_pop(L, 1))
885  {
886  int indextype = lua_type(L, -2);
887  if (indextype == LUA_TNUMBER) continue;
888  if (indextype != LUA_TSTRING) return_misformed();
889  const char* m = lua_tostring(L, -2);
891  config::attribute_value &v = cfg[m];
892  if (lua_istable(L, -1)) {
893  int subindex = lua_absindex(L, -1);
894  std::ostringstream str;
895  for (int i = 1, i_end = lua_rawlen(L, subindex); i <= i_end; ++i, lua_pop(L, 1)) {
896  lua_rawgeti(L, -1, i);
898  if (!luaW_toscalar(L, -1, item)) return_misformed();
899  if (i > 1) str << ',';
900  str << item;
901  }
902  // If there are any string keys, it's malformed
903  for (lua_pushnil(L); lua_next(L, subindex); lua_pop(L, 1)) {
904  if (lua_type(L, -2) != LUA_TNUMBER) return_misformed();
905  }
906  v = str.str();
907  } else if (!luaW_toscalar(L, -1, v)) return_misformed();
908  }
909 
910  lua_settop(L, initial_top);
911  return true;
912 }
913 
914 #undef return_misformed
915 
916 
917 config luaW_checkconfig(lua_State *L, int index)
918 {
919  config result;
920  if (!luaW_toconfig(L, index, result))
921  luaW_type_error(L, index, "WML table");
922  return result;
923 }
924 
925 config luaW_checkconfig(lua_State *L, int index, const vconfig*& vcfg)
926 {
927  config result = luaW_checkconfig(L, index);
928  if(void* p = luaL_testudata(L, index, vconfigKey)) {
929  vcfg = static_cast<vconfig*>(p);
930  }
931  return result;
932 }
933 
934 bool luaW_tovconfig(lua_State *L, int index, vconfig &vcfg)
935 {
936  switch (lua_type(L, index))
937  {
938  case LUA_TTABLE:
939  {
940  config cfg;
941  bool ok = luaW_toconfig(L, index, cfg);
942  if (!ok) return false;
943  vcfg = vconfig(std::move(cfg));
944  break;
945  }
946  case LUA_TUSERDATA:
947  if (vconfig * ptr = static_cast<vconfig *> (luaL_testudata(L, index, vconfigKey))) {
948  vcfg = *ptr;
949  } else {
950  return false;
951  }
952  case LUA_TNONE:
953  case LUA_TNIL:
954  break;
955  default:
956  return false;
957  }
958  return true;
959 }
960 
961 vconfig luaW_checkvconfig(lua_State *L, int index, bool allow_missing)
962 {
964  if (!luaW_tovconfig(L, index, result) || (!allow_missing && result.null()))
965  luaW_type_error(L, index, "WML table");
966  return result;
967 }
968 
969 bool luaW_getglobal(lua_State *L, const std::vector<std::string>& path)
970 {
971  lua_pushglobaltable(L);
972  for (const std::string& s : path)
973  {
974  if (!lua_istable(L, -1)) goto discard;
975  lua_pushlstring(L, s.c_str(), s.size());
976  lua_rawget(L, -2);
977  lua_remove(L, -2);
978  }
979 
980  if (lua_isnil(L, -1)) {
981  discard:
982  lua_pop(L, 1);
983  return false;
984  }
985  return true;
986 }
987 
988 bool luaW_toboolean(lua_State *L, int n)
989 {
990  return lua_toboolean(L,n) != 0;
991 }
992 
994 {
995  try
996  {
997  if(v.exists_as_attribute())
998  {
999  luaW_pushscalar(L, v.as_scalar());
1000  return true;
1001  }
1002  else if(v.exists_as_container())
1003  {
1004  lua_newtable(L);
1005  luaW_filltable(L, v.as_container());
1006  return true;
1007  }
1008  else
1009  {
1010  lua_pushnil(L);
1011  return true;
1012  }
1013  }
1014  catch (const invalid_variablename_exception&)
1015  {
1016  WRN_LUA << v.get_error_message();
1017  return false;
1018  }
1019 }
1020 
1021 bool luaW_checkvariable(lua_State *L, variable_access_create& v, int n)
1022 {
1023  int variabletype = lua_type(L, n);
1024  try
1025  {
1026  switch (variabletype) {
1027  case LUA_TBOOLEAN:
1028  v.as_scalar() = luaW_toboolean(L, n);
1029  return true;
1030  case LUA_TNUMBER:
1031  v.as_scalar() = lua_tonumber(L, n);
1032  return true;
1033  case LUA_TSTRING:
1034  v.as_scalar() = lua_tostring(L, n);
1035  return true;
1036  case LUA_TUSERDATA:
1037  if (t_string * t_str = static_cast<t_string*> (luaL_testudata(L, n, tstringKey))) {
1038  v.as_scalar() = *t_str;
1039  return true;
1040  }
1041  goto default_explicit;
1042  case LUA_TTABLE:
1043  {
1044  config &cfg = v.as_container();
1045  if (luaW_toconfig(L, n, cfg)) {
1046  return true;
1047  }
1048  [[fallthrough]];
1049  }
1050  default:
1051  default_explicit:
1052  return luaW_type_error(L, n, "WML table or scalar") != 0;
1053 
1054  }
1055  }
1056  catch (const invalid_variablename_exception&)
1057  {
1058  WRN_LUA << v.get_error_message() << " when attempting to write a '" << lua_typename(L, variabletype) << "'";
1059  return false;
1060  }
1061 }
1062 
1063 bool luaW_tableget(lua_State *L, int index, const char* key)
1064 {
1065  index = lua_absindex(L, index);
1066  lua_pushstring(L, key);
1067  lua_gettable(L, index);
1068  if(lua_isnoneornil(L, -1)) {
1069  lua_pop(L, 1);
1070  return false;
1071  }
1072  return true;
1073 }
1074 
1075 std::string_view luaW_tostring(lua_State *L, int index)
1076 {
1077  size_t len = 0;
1078  const char* str = lua_tolstring(L, index, &len);
1079  if(!str) {
1080  throw luaL_error (L, "not a string");
1081  }
1082  return std::string_view(str, len);
1083 }
1084 
1085 std::string_view luaW_tostring_or_default(lua_State *L, int index, std::string_view def)
1086 {
1087  size_t len = 0;
1088  const char* str = lua_tolstring(L, index, &len);
1089  if(!str) {
1090  return def;
1091  }
1092  return std::string_view(str, len);
1093 }
1094 
1095 void chat_message(const std::string& caption, const std::string& msg)
1096 {
1097  if (!game_display::get_singleton()) return;
1098  game_display::get_singleton()->get_chat_manager().add_chat_message(std::time(nullptr), caption, 0, msg,
1100 }
1101 
1102 void push_error_handler(lua_State *L)
1103 {
1104  luaW_getglobal(L, "debug", "traceback");
1105  lua_setfield(L, LUA_REGISTRYINDEX, executeKey);
1106 }
1107 
1108 int luaW_pcall_internal(lua_State *L, int nArgs, int nRets)
1109 {
1110  // Load the error handler before the function and its arguments.
1111  lua_getfield(L, LUA_REGISTRYINDEX, executeKey);
1112  lua_insert(L, -2 - nArgs);
1113 
1114  int error_handler_index = lua_gettop(L) - nArgs - 1;
1115 
1117 
1118  // Call the function.
1119  int errcode = lua_pcall(L, nArgs, nRets, -2 - nArgs);
1120 
1123 
1124  // Remove the error handler.
1125  lua_remove(L, error_handler_index);
1126 
1127  return errcode;
1128 }
1129 
1130 #ifdef _MSC_VER
1131 #pragma warning (push)
1132 #pragma warning (disable: 4706)
1133 #endif
1134 bool luaW_pcall(lua_State *L, int nArgs, int nRets, bool allow_wml_error)
1135 {
1136  int res = luaW_pcall_internal(L, nArgs, nRets);
1137 
1138  if (res)
1139  {
1140  /*
1141  * When an exception is thrown which doesn't derive from
1142  * std::exception m will be nullptr pointer.
1143  * When adding a new conditional branch, remember to log the
1144  * error with ERR_LUA or ERR_WML.
1145  */
1146  char const *m = lua_tostring(L, -1);
1147  if(m) {
1148  if (allow_wml_error && strncmp(m, "~wml:", 5) == 0) {
1149  m += 5;
1150  char const *e = strstr(m, "stack traceback");
1151  lg::log_to_chat() << std::string(m, e ? e - m : strlen(m)) << '\n';
1152  ERR_WML << std::string(m, e ? e - m : strlen(m));
1153  } else if (allow_wml_error && strncmp(m, "~lua:", 5) == 0) {
1154  m += 5;
1155  char const *e = nullptr, *em = m;
1156  while (em[0] && ((em = strstr(em + 1, "stack traceback"))))
1157 #ifdef _MSC_VER
1158 #pragma warning (pop)
1159 #endif
1160  e = em;
1161  ERR_LUA << std::string(m, e ? e - m : strlen(m));
1162  chat_message("Lua error", std::string(m, e ? e - m : strlen(m)));
1163  } else {
1164  ERR_LUA << m;
1165  chat_message("Lua error", m);
1166  }
1167  } else {
1168  ERR_LUA << "Lua caught unknown exception";
1169  chat_message("Lua caught unknown exception", "");
1170  }
1171  lua_pop(L, 1);
1172  return false;
1173  }
1174 
1175  return true;
1176 }
1177 
1178 // Originally luaL_typerror, now deprecated.
1179 // Easier to define it for Wesnoth and not have to worry about it if we update Lua.
1180 int luaW_type_error(lua_State *L, int narg, const char *tname) {
1181  const char *msg = lua_pushfstring(L, "%s expected, got %s", tname, luaL_typename(L, narg));
1182  return luaL_argerror(L, narg, msg);
1183 }
1184 
1185 // An alternate version which raises an error for a key in a table.
1186 // In this version, narg should refer to the stack index of the table rather than the stack index of the key.
1187 // kpath should be the key name or a string such as "key[idx].key2" specifying a path to the key.
1188 int luaW_type_error (lua_State *L, int narg, const char* kpath, const char *tname) {
1189  const char *msg = lua_pushfstring(L, "%s expected for '%s', got %s", tname, kpath, luaL_typename(L, narg));
1190  return luaL_argerror(L, narg, msg);
1191 }
double t
Definition: astarsearch.cpp:63
std::vector< std::string > names
Definition: build_info.cpp:66
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:159
const_attr_itors attribute_range() const
Definition: config.cpp:763
static bool valid_tag(config_key_type name)
Definition: config.cpp:127
const_all_children_itors all_children_range() const
In-order iteration over all children.
Definition: config.cpp:887
boost::iterator_range< const_attribute_iterator > const_attr_itors
Definition: config.hpp:359
static bool valid_attribute(config_key_type name)
Definition: config.cpp:150
attribute_map::value_type attribute
Definition: config.hpp:299
void clear()
Definition: config.cpp:831
config & add_child(config_key_type key)
Definition: config.cpp:441
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:199
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
std::size_t i
Definition: function.cpp:968
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:827
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:917
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:730
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:810
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)
Definition: lua_common.cpp:993
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:934
#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:988
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:836
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:839
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:798
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:961
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:741
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:790
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:969
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:83
std::pair< std::string, unsigned > item
Definition: help_impl.hpp:412
std::stringstream & log_to_chat()
Use this to show WML errors in the ingame chat.
Definition: log.cpp:544
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:373
Encapsulates the map of the game.
Definition: location.hpp:38
void set_wml_y(int v)
Definition: location.hpp:157
int wml_y() const
Definition: location.hpp:154
void set_wml_x(int v)
Definition: location.hpp:156
int wml_x() const
Definition: location.hpp:153
mock_party p
static map_location::DIRECTION n
static map_location::DIRECTION s
#define d
#define e
#define a
#define b