The Battle for Wesnoth  1.17.23+dev
lua_common.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014 - 2023
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 static int impl_vconfig_dir(lua_State* L)
272 {
273  vconfig *v = static_cast<vconfig *>(lua_touserdata(L, 1));
274  std::vector<std::string> attributes;
275  for(const auto& [key, value] : v->get_config().attribute_range()) {
276  attributes.push_back(key);
277  }
278  lua_push(L, attributes);
279  return 1;
280 }
281 
282 /**
283  * Returns the number of a child of a vconfig object.
284  */
285 static int impl_vconfig_size(lua_State *L)
286 {
287  vconfig *v = static_cast<vconfig *>(lua_touserdata(L, 1));
288  lua_pushinteger(L, v->null() ? 0 :
289  std::distance(v->ordered_begin(), v->ordered_end()));
290  return 1;
291 }
292 
293 /**
294  * Destroys a vconfig object before it is collected (__gc metamethod).
295  */
296 static int impl_vconfig_collect(lua_State *L)
297 {
298  vconfig *v = static_cast<vconfig *>(lua_touserdata(L, 1));
299  v->~vconfig();
300  return 0;
301 }
302 
303 /**
304  * Iterate through the attributes of a vconfig
305  */
306 static int impl_vconfig_pairs_iter(lua_State *L)
307 {
308  vconfig vcfg = luaW_checkvconfig(L, 1);
309  void* p = luaL_checkudata(L, lua_upvalueindex(1), vconfigpairsKey);
310  config::const_attr_itors& range = *static_cast<config::const_attr_itors*>(p);
311  if (range.empty()) {
312  return 0;
313  }
314  config::attribute value = range.front();
315  range.pop_front();
316  lua_pushlstring(L, value.first.c_str(), value.first.length());
317  luaW_pushscalar(L, vcfg[value.first]);
318  return 2;
319 }
320 
321 /**
322  * Destroy a vconfig pairs iterator
323  */
324 static int impl_vconfig_pairs_collect(lua_State *L)
325 {
326  typedef config::const_attr_itors const_attr_itors;
327  void* p = lua_touserdata(L, 1);
328 
329  // Triggers a false positive of C4189 with Visual Studio. Suppress.
330 #if defined(_MSC_VER)
331 #pragma warning(push)
332 #pragma warning(disable: 4189)
333 #endif
334 
335  const_attr_itors* cai = static_cast<const_attr_itors*>(p);
336  cai->~const_attr_itors();
337 
338 #if defined(_MSC_VER)
339 #pragma warning(pop)
340 #endif
341 
342  return 0;
343 }
344 
345 /**
346  * Construct an iterator to iterate through the attributes of a vconfig
347  */
348 static int impl_vconfig_pairs(lua_State *L)
349 {
350  vconfig vcfg = luaW_checkvconfig(L, 1);
352  luaL_newmetatable(L, vconfigpairsKey);
353  lua_setmetatable(L, -2);
354  lua_pushcclosure(L, &impl_vconfig_pairs_iter, 1);
355  lua_pushvalue(L, 1);
356  return 2;
357 }
358 
359 typedef std::pair<vconfig::all_children_iterator, vconfig::all_children_iterator> vconfig_child_range;
360 
361 /**
362  * Iterate through the subtags of a vconfig
363  */
364 static int impl_vconfig_ipairs_iter(lua_State *L)
365 {
366  luaW_checkvconfig(L, 1);
367  int i = luaL_checkinteger(L, 2);
368  void* p = luaL_checkudata(L, lua_upvalueindex(1), vconfigipairsKey);
369  vconfig_child_range& range = *static_cast<vconfig_child_range*>(p);
370  if (range.first == range.second) {
371  return 0;
372  }
373  std::pair<std::string, vconfig> value = *range.first++;
374  lua_pushinteger(L, i + 1);
375  lua_createtable(L, 2, 0);
376  lua_pushlstring(L, value.first.c_str(), value.first.length());
377  lua_rawseti(L, -2, 1);
378  luaW_pushvconfig(L, value.second);
379  lua_rawseti(L, -2, 2);
380  return 2;
381 }
382 
383 /**
384  * Destroy a vconfig ipairs iterator
385  */
386 static int impl_vconfig_ipairs_collect(lua_State *L)
387 {
388  void* p = lua_touserdata(L, 1);
389  vconfig_child_range* vcr = static_cast<vconfig_child_range*>(p);
390  vcr->~vconfig_child_range();
391  return 0;
392 }
393 
394 /**
395  * Construct an iterator to iterate through the subtags of a vconfig
396  */
397 static int impl_vconfig_ipairs(lua_State *L)
398 {
399  vconfig cfg = luaW_checkvconfig(L, 1);
400  new(L) vconfig_child_range(cfg.ordered_begin(), cfg.ordered_end());
401  luaL_newmetatable(L, vconfigipairsKey);
402  lua_setmetatable(L, -2);
403  lua_pushcclosure(L, &impl_vconfig_ipairs_iter, 1);
404  lua_pushvalue(L, 1);
405  lua_pushinteger(L, 0);
406  return 3;
407 }
408 
409 /**
410  * Creates a vconfig containing the WML table.
411  * - Arg 1: WML table.
412  * - Ret 1: vconfig userdata.
413  */
414 int intf_tovconfig(lua_State *L)
415 {
416  vconfig vcfg = luaW_checkvconfig(L, 1);
417  luaW_pushvconfig(L, vcfg);
418  return 1;
419 }
420 
421 /**
422  * Adds the gettext metatable
423  */
424 std::string register_gettext_metatable(lua_State *L)
425 {
426  luaL_newmetatable(L, gettextKey);
427 
428  static luaL_Reg const callbacks[] {
429  { "__call", &impl_gettext},
430  { "__tostring", &impl_gettext_tostr},
431  { nullptr, nullptr }
432  };
433  luaL_setfuncs(L, callbacks, 0);
434 
435  lua_pushstring(L, "message domain");
436  lua_setfield(L, -2, "__metatable");
437 
438  return "Adding gettext metatable...\n";
439 }
440 
441 /**
442  * Adds the tstring metatable
443  */
444 std::string register_tstring_metatable(lua_State *L)
445 {
446  luaL_newmetatable(L, tstringKey);
447 
448  static luaL_Reg const callbacks[] {
449  { "__concat", &impl_tstring_concat},
450  { "__gc", &impl_tstring_collect},
451  { "__tostring", &impl_tstring_tostring},
452  { "__len", &impl_tstring_len},
453  { "__lt", &impl_tstring_lt},
454  { "__le", &impl_tstring_le},
455  { "__eq", &impl_tstring_eq},
456  { nullptr, nullptr }
457  };
458  luaL_setfuncs(L, callbacks, 0);
459 
460  lua_createtable(L, 0, 1);
461  luaW_getglobal(L, "string", "format");
462  lua_setfield(L, -2, "format");
463  luaW_getglobal(L, "stringx", "vformat");
464  lua_setfield(L, -2, "vformat");
465  lua_setfield(L, -2, "__index");
466 
467  lua_pushstring(L, "translatable string");
468  lua_setfield(L, -2, "__metatable");
469 
470  return "Adding tstring metatable...\n";
471 }
472 
473 /**
474  * Adds the vconfig metatable
475  */
476 std::string register_vconfig_metatable(lua_State *L)
477 {
478  luaL_newmetatable(L, vconfigKey);
479 
480  static luaL_Reg const callbacks[] {
481  { "__gc", &impl_vconfig_collect},
482  { "__index", &impl_vconfig_get},
483  { "__dir", &impl_vconfig_dir},
484  { "__len", &impl_vconfig_size},
485  { "__pairs", &impl_vconfig_pairs},
486  { "__ipairs", &impl_vconfig_ipairs},
487  { nullptr, nullptr }
488  };
489  luaL_setfuncs(L, callbacks, 0);
490 
491  lua_pushstring(L, "wml object");
492  lua_setfield(L, -2, "__metatable");
493 
494  // Metatables for the iterator userdata
495 
496  // I don't bother setting __metatable because this
497  // userdata is only ever stored in the iterator's
498  // upvalues, so it's never visible to the user.
499  luaL_newmetatable(L, vconfigpairsKey);
500  lua_pushstring(L, "__gc");
501  lua_pushcfunction(L, &impl_vconfig_pairs_collect);
502  lua_rawset(L, -3);
503 
504  luaL_newmetatable(L, vconfigipairsKey);
505  lua_pushstring(L, "__gc");
506  lua_pushcfunction(L, &impl_vconfig_ipairs_collect);
507  lua_rawset(L, -3);
508 
509  return "Adding vconfig metatable...\n";
510 }
511 
512 } // end namespace lua_common
513 
514 void* operator new(std::size_t sz, lua_State *L, int nuv)
515 {
516  return lua_newuserdatauv(L, sz, nuv);
517 }
518 
519 void operator delete(void*, lua_State *L, int)
520 {
521  // Not sure if this is needed since it's a no-op
522  // It's only called if a constructor throws while using the above operator new
523  // By removing the userdata from the stack, this should ensure that Lua frees it
524  lua_pop(L, 1);
525 }
526 
527 bool luaW_getmetafield(lua_State *L, int idx, const char* key)
528 {
529  if(key == nullptr) {
530  return false;
531  }
532  int n = strlen(key);
533  if(n == 0) {
534  return false;
535  }
536  if(n >= 2 && key[0] == '_' && key[1] == '_') {
537  return false;
538  }
539  return luaL_getmetafield(L, idx, key) != 0;
540 }
541 
542 void luaW_pushvconfig(lua_State *L, const vconfig& cfg)
543 {
544  new(L) vconfig(cfg);
545  luaL_setmetatable(L, vconfigKey);
546 }
547 
548 void luaW_pushtstring(lua_State *L, const t_string& v)
549 {
550  new(L) t_string(v);
551  luaL_setmetatable(L, tstringKey);
552 }
553 
554 
555 namespace {
556  struct luaW_pushscalar_visitor
557 #ifdef USING_BOOST_VARIANT
558  : boost::static_visitor<>
559 #endif
560  {
561  lua_State *L;
562  luaW_pushscalar_visitor(lua_State *l): L(l) {}
563 
564  void operator()(const utils::monostate&) const
565  { lua_pushnil(L); }
566  void operator()(bool b) const
567  { lua_pushboolean(L, b); }
568  void operator()(int i) const
569  { lua_pushinteger(L, i); }
570  void operator()(unsigned long long ull) const
571  { lua_pushnumber(L, ull); }
572  void operator()(double d) const
573  { lua_pushnumber(L, d); }
574  void operator()(const std::string& s) const
575  { lua_pushstring(L, s.c_str()); }
576  void operator()(const t_string& s) const
577  { luaW_pushtstring(L, s); }
578  };
579 }//unnamed namespace for luaW_pushscalar_visitor
580 
581 void luaW_pushscalar(lua_State *L, const config::attribute_value& v)
582 {
583  v.apply_visitor(luaW_pushscalar_visitor(L));
584 }
585 
586 bool luaW_toscalar(lua_State *L, int index, config::attribute_value& v)
587 {
588  switch (lua_type(L, index)) {
589  case LUA_TBOOLEAN:
590  v = luaW_toboolean(L, -1);
591  break;
592  case LUA_TNUMBER:
593  v = lua_tonumber(L, -1);
594  break;
595  case LUA_TSTRING:
596  v = lua_tostring(L, -1);
597  break;
598  case LUA_TUSERDATA:
599  {
600  if (t_string * tptr = static_cast<t_string *>(luaL_testudata(L, -1, tstringKey))) {
601  v = *tptr;
602  break;
603  } else {
604  return false;
605  }
606  }
607  default:
608  return false;
609  }
610  return true;
611 }
612 
613 bool luaW_totstring(lua_State *L, int index, t_string &str)
614 {
615  switch (lua_type(L, index)) {
616  case LUA_TBOOLEAN:
617  str = lua_toboolean(L, index) ? "yes" : "no";
618  break;
619  case LUA_TNUMBER:
620  case LUA_TSTRING:
621  str = lua_tostring(L, index);
622  break;
623  case LUA_TUSERDATA:
624  {
625  if (t_string * tstr = static_cast<t_string *> (luaL_testudata(L, index, tstringKey))) {
626  str = *tstr;
627  break;
628  } else {
629  return false;
630  }
631  }
632  default:
633  return false;
634  }
635  return true;
636 }
637 
638 t_string luaW_checktstring(lua_State *L, int index)
639 {
640  t_string result;
641  if (!luaW_totstring(L, index, result))
642  luaW_type_error(L, index, "translatable string");
643  return result;
644 }
645 
646 bool luaW_iststring(lua_State* L, int index)
647 {
648  if(lua_isstring(L, index)) {
649  return true;
650  }
651  if(lua_isuserdata(L, index) && luaL_testudata(L, index, tstringKey)) {
652  return true;
653  }
654  return false;
655 }
656 
657 void luaW_filltable(lua_State *L, const config& cfg)
658 {
659  if (!lua_checkstack(L, LUA_MINSTACK))
660  return;
661 
662  int k = 1;
663  for (const config::any_child ch : cfg.all_children_range())
664  {
665  luaW_push_namedtuple(L, {"tag", "contents"});
666  lua_pushstring(L, ch.key.c_str());
667  lua_rawseti(L, -2, 1);
668  lua_newtable(L);
669  luaW_filltable(L, ch.cfg);
670  lua_rawseti(L, -2, 2);
671  lua_rawseti(L, -2, k++);
672  }
673  for (const config::attribute &attr : cfg.attribute_range())
674  {
675  luaW_pushscalar(L, attr.second);
676  lua_setfield(L, -2, attr.first.c_str());
677  }
678 }
679 
680 static int impl_namedtuple_get(lua_State* L)
681 {
682  if(lua_isstring(L, 2)) {
683  std::string k = lua_tostring(L, 2);
684  luaL_getmetafield(L, 1, "__names");
685  auto names = lua_check<std::vector<std::string>>(L, -1);
686  auto iter = std::find(names.begin(), names.end(), k);
687  if(iter != names.end()) {
688  int i = std::distance(names.begin(), iter) + 1;
689  lua_rawgeti(L, 1, i);
690  return 1;
691  }
692  }
693  return 0;
694 }
695 
696 static int impl_namedtuple_dir(lua_State* L)
697 {
698  luaL_getmetafield(L, 1, "__names");
699  return 1;
700 }
701 
702 static int impl_namedtuple_tostring(lua_State* L)
703 {
704  std::vector<std::string> elems;
705  for(unsigned i = 1; i <= lua_rawlen(L, 1); i++) {
706  lua_getglobal(L, "tostring");
707  lua_rawgeti(L, 1, i);
708  lua_call(L, 1, 1);
709  elems.push_back(lua_tostring(L, -1));
710  }
711  lua_push(L, "(" + utils::join(elems) + ")");
712  return 1;
713 }
714 
715 void luaW_push_namedtuple(lua_State* L, const std::vector<std::string>& names)
716 {
717  lua_createtable(L, names.size(), 0);
718  lua_createtable(L, 0, 4);
719  static luaL_Reg callbacks[] = {
720  { "__index", &impl_namedtuple_get },
721  { "__dir", &impl_namedtuple_dir },
722  { "__tostring", &impl_namedtuple_tostring },
723  { nullptr, nullptr }
724  };
725  luaL_setfuncs(L, callbacks, 0);
726  lua_pushliteral(L, "named tuple");
727  lua_setfield(L, -2, "__metatable");
728  lua_push(L, names);
729  lua_setfield(L, -2, "__names");
730  lua_setmetatable(L, -2);
731 }
732 
733 void luaW_pushlocation(lua_State *L, const map_location& ml)
734 {
735  luaW_push_namedtuple(L, {"x", "y"});
736 
737  lua_pushinteger(L, ml.wml_x());
738  lua_rawseti(L, -2, 1);
739 
740  lua_pushinteger(L, ml.wml_y());
741  lua_rawseti(L, -2, 2);
742 }
743 
744 bool luaW_tolocation(lua_State *L, int index, map_location& loc) {
745  if (!lua_checkstack(L, LUA_MINSTACK)) {
746  return false;
747  }
748  if (lua_isnoneornil(L, index)) {
749  // Need this special check because luaW_tovconfig returns true in this case
750  return false;
751  }
752 
754 
755  index = lua_absindex(L, index);
756 
757  if (lua_istable(L, index) || lua_isuserdata(L, index)) {
758  map_location result;
759  int x_was_num = 0, y_was_num = 0;
760  lua_getfield(L, index, "x");
761  result.set_wml_x(lua_tointegerx(L, -1, &x_was_num));
762  lua_getfield(L, index, "y");
763  result.set_wml_y(lua_tointegerx(L, -1, &y_was_num));
764  lua_pop(L, 2);
765  if (!x_was_num || !y_was_num) {
766  // If we get here and it was userdata, checking numeric indices won't help
767  // (It won't help if it was a WML table either, but there's no easy way to check that.)
768  if (lua_isuserdata(L, index)) {
769  return false;
770  }
771  lua_rawgeti(L, index, 1);
772  result.set_wml_x(lua_tointegerx(L, -1, &x_was_num));
773  lua_rawgeti(L, index, 2);
774  result.set_wml_y(lua_tointegerx(L, -1, &y_was_num));
775  lua_pop(L, 2);
776  }
777  if (x_was_num && y_was_num) {
778  loc = result;
779  return true;
780  }
781  } else if (lua_isnumber(L, index) && lua_isnumber(L, index + 1)) {
782  // If it's a number, then we consume two elements on the stack
783  // Since we have no way of notifying the caller that we have
784  // done this, we remove the first number from the stack.
785  loc.set_wml_x(lua_tointeger(L, index));
786  lua_remove(L, index);
787  loc.set_wml_y(lua_tointeger(L, index));
788  return true;
789  }
790  return false;
791 }
792 
794 {
795  map_location result;
796  if (!luaW_tolocation(L, index, result))
797  luaW_type_error(L, index, "location");
798  return result;
799 }
800 
801 int luaW_push_locationset(lua_State* L, const std::set<map_location>& locs)
802 {
803  lua_createtable(L, locs.size(), 0);
804  int i = 1;
805  for(const map_location& loc : locs) {
806  luaW_pushlocation(L, loc);
807  lua_rawseti(L, -2, i);
808  ++i;
809  }
810  return 1;
811 }
812 
813 std::set<map_location> luaW_check_locationset(lua_State* L, int idx)
814 {
815  std::set<map_location> locs;
816  if(!lua_istable(L, idx)) {
817  luaW_type_error(L, idx, "array of locations");
818  }
819  lua_len(L, idx);
820  int len = luaL_checkinteger(L, -1);
821  for(int i = 1; i <= len; i++) {
822  lua_geti(L, idx, i);
823  locs.insert(luaW_checklocation(L, -1));
824  lua_pop(L, 1);
825  }
826  return locs;
827 
828 }
829 
830 void luaW_pushconfig(lua_State *L, const config& cfg)
831 {
832  lua_newtable(L);
833  luaW_filltable(L, cfg);
834 }
835 
836 
837 
838 
839 #define return_misformed() \
840  do { lua_settop(L, initial_top); return false; } while (0)
841 
842 bool luaW_toconfig(lua_State *L, int index, config &cfg)
843 {
844  cfg.clear();
845  if (!lua_checkstack(L, LUA_MINSTACK))
846  return false;
847 
848  // Get the absolute index of the table.
849  index = lua_absindex(L, index);
850  int initial_top = lua_gettop(L);
851 
852  switch (lua_type(L, index))
853  {
854  case LUA_TTABLE:
855  break;
856  case LUA_TUSERDATA:
857  {
858  if (vconfig * ptr = static_cast<vconfig *> (luaL_testudata(L, index, vconfigKey))) {
859  cfg = ptr->get_parsed_config();
860  return true;
861  } else {
862  return false;
863  }
864  }
865  case LUA_TNONE:
866  case LUA_TNIL:
867  return true;
868  default:
869  return false;
870  }
871 
872  // First convert the children (integer indices).
873  for (int i = 1, i_end = lua_rawlen(L, index); i <= i_end; ++i)
874  {
875  lua_rawgeti(L, index, i);
876  if (!lua_istable(L, -1)) return_misformed();
877  lua_rawgeti(L, -1, 1);
878  char const *m = lua_tostring(L, -1);
879  if (!m || !config::valid_tag(m)) return_misformed();
880  lua_rawgeti(L, -2, 2);
881  if (!luaW_toconfig(L, -1, cfg.add_child(m)))
883  lua_pop(L, 3);
884  }
885 
886  // Then convert the attributes (string indices).
887  for (lua_pushnil(L); lua_next(L, index); lua_pop(L, 1))
888  {
889  int indextype = lua_type(L, -2);
890  if (indextype == LUA_TNUMBER) continue;
891  if (indextype != LUA_TSTRING) return_misformed();
892  const char* m = lua_tostring(L, -2);
894  config::attribute_value &v = cfg[m];
895  if (lua_istable(L, -1)) {
896  int subindex = lua_absindex(L, -1);
897  std::ostringstream str;
898  for (int i = 1, i_end = lua_rawlen(L, subindex); i <= i_end; ++i, lua_pop(L, 1)) {
899  lua_rawgeti(L, -1, i);
901  if (!luaW_toscalar(L, -1, item)) return_misformed();
902  if (i > 1) str << ',';
903  str << item;
904  }
905  // If there are any string keys, it's malformed
906  for (lua_pushnil(L); lua_next(L, subindex); lua_pop(L, 1)) {
907  if (lua_type(L, -2) != LUA_TNUMBER) return_misformed();
908  }
909  v = str.str();
910  } else if (!luaW_toscalar(L, -1, v)) return_misformed();
911  }
912 
913  lua_settop(L, initial_top);
914  return true;
915 }
916 
917 #undef return_misformed
918 
919 
920 config luaW_checkconfig(lua_State *L, int index)
921 {
922  config result;
923  if (!luaW_toconfig(L, index, result))
924  luaW_type_error(L, index, "WML table");
925  return result;
926 }
927 
928 config luaW_checkconfig(lua_State *L, int index, const vconfig*& vcfg)
929 {
930  config result = luaW_checkconfig(L, index);
931  if(void* p = luaL_testudata(L, index, vconfigKey)) {
932  vcfg = static_cast<vconfig*>(p);
933  }
934  return result;
935 }
936 
937 bool luaW_tovconfig(lua_State *L, int index, vconfig &vcfg)
938 {
939  switch (lua_type(L, index))
940  {
941  case LUA_TTABLE:
942  {
943  config cfg;
944  bool ok = luaW_toconfig(L, index, cfg);
945  if (!ok) return false;
946  vcfg = vconfig(std::move(cfg));
947  break;
948  }
949  case LUA_TUSERDATA:
950  if (vconfig * ptr = static_cast<vconfig *> (luaL_testudata(L, index, vconfigKey))) {
951  vcfg = *ptr;
952  } else {
953  return false;
954  }
955  case LUA_TNONE:
956  case LUA_TNIL:
957  break;
958  default:
959  return false;
960  }
961  return true;
962 }
963 
964 vconfig luaW_checkvconfig(lua_State *L, int index, bool allow_missing)
965 {
967  if (!luaW_tovconfig(L, index, result) || (!allow_missing && result.null()))
968  luaW_type_error(L, index, "WML table");
969  return result;
970 }
971 
972 bool luaW_getglobal(lua_State *L, const std::vector<std::string>& path)
973 {
974  lua_pushglobaltable(L);
975  for (const std::string& s : path)
976  {
977  if (!lua_istable(L, -1)) goto discard;
978  lua_pushlstring(L, s.c_str(), s.size());
979  lua_rawget(L, -2);
980  lua_remove(L, -2);
981  }
982 
983  if (lua_isnil(L, -1)) {
984  discard:
985  lua_pop(L, 1);
986  return false;
987  }
988  return true;
989 }
990 
991 bool luaW_toboolean(lua_State *L, int n)
992 {
993  return lua_toboolean(L,n) != 0;
994 }
995 
997 {
998  try
999  {
1000  if(v.exists_as_attribute())
1001  {
1002  luaW_pushscalar(L, v.as_scalar());
1003  return true;
1004  }
1005  else if(v.exists_as_container())
1006  {
1007  lua_newtable(L);
1008  luaW_filltable(L, v.as_container());
1009  return true;
1010  }
1011  else
1012  {
1013  lua_pushnil(L);
1014  return true;
1015  }
1016  }
1017  catch (const invalid_variablename_exception&)
1018  {
1019  WRN_LUA << v.get_error_message();
1020  return false;
1021  }
1022 }
1023 
1024 bool luaW_checkvariable(lua_State *L, variable_access_create& v, int n)
1025 {
1026  int variabletype = lua_type(L, n);
1027  try
1028  {
1029  switch (variabletype) {
1030  case LUA_TBOOLEAN:
1031  v.as_scalar() = luaW_toboolean(L, n);
1032  return true;
1033  case LUA_TNUMBER:
1034  v.as_scalar() = lua_tonumber(L, n);
1035  return true;
1036  case LUA_TSTRING:
1037  v.as_scalar() = lua_tostring(L, n);
1038  return true;
1039  case LUA_TUSERDATA:
1040  if (t_string * t_str = static_cast<t_string*> (luaL_testudata(L, n, tstringKey))) {
1041  v.as_scalar() = *t_str;
1042  return true;
1043  }
1044  goto default_explicit;
1045  case LUA_TTABLE:
1046  {
1047  config &cfg = v.as_container();
1048  if (luaW_toconfig(L, n, cfg)) {
1049  return true;
1050  }
1051  [[fallthrough]];
1052  }
1053  default:
1054  default_explicit:
1055  return luaW_type_error(L, n, "WML table or scalar") != 0;
1056 
1057  }
1058  }
1059  catch (const invalid_variablename_exception&)
1060  {
1061  WRN_LUA << v.get_error_message() << " when attempting to write a '" << lua_typename(L, variabletype) << "'";
1062  return false;
1063  }
1064 }
1065 
1066 bool luaW_tableget(lua_State *L, int index, const char* key)
1067 {
1068  index = lua_absindex(L, index);
1069  lua_pushstring(L, key);
1070  lua_gettable(L, index);
1071  if(lua_isnoneornil(L, -1)) {
1072  lua_pop(L, 1);
1073  return false;
1074  }
1075  return true;
1076 }
1077 
1078 std::string_view luaW_tostring(lua_State *L, int index)
1079 {
1080  size_t len = 0;
1081  const char* str = lua_tolstring(L, index, &len);
1082  if(!str) {
1083  throw luaL_error (L, "not a string");
1084  }
1085  return std::string_view(str, len);
1086 }
1087 
1088 std::string_view luaW_tostring_or_default(lua_State *L, int index, std::string_view def)
1089 {
1090  size_t len = 0;
1091  const char* str = lua_tolstring(L, index, &len);
1092  if(!str) {
1093  return def;
1094  }
1095  return std::string_view(str, len);
1096 }
1097 
1098 void chat_message(const std::string& caption, const std::string& msg)
1099 {
1100  if (!game_display::get_singleton()) return;
1101  game_display::get_singleton()->get_chat_manager().add_chat_message(std::time(nullptr), caption, 0, msg,
1103 }
1104 
1105 void push_error_handler(lua_State *L)
1106 {
1107  luaW_getglobal(L, "debug", "traceback");
1108  lua_setfield(L, LUA_REGISTRYINDEX, executeKey);
1109 }
1110 
1111 int luaW_pcall_internal(lua_State *L, int nArgs, int nRets)
1112 {
1113  // Load the error handler before the function and its arguments.
1114  lua_getfield(L, LUA_REGISTRYINDEX, executeKey);
1115  lua_insert(L, -2 - nArgs);
1116 
1117  int error_handler_index = lua_gettop(L) - nArgs - 1;
1118 
1119  // Call the function.
1120  int errcode = lua_pcall(L, nArgs, nRets, -2 - nArgs);
1121 
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  */
1144  char const *m = lua_tostring(L, -1);
1145  if(m) {
1146  if (allow_wml_error && strncmp(m, "~wml:", 5) == 0) {
1147  m += 5;
1148  char const *e = strstr(m, "stack traceback");
1149  lg::log_to_chat() << std::string(m, e ? e - m : strlen(m)) << '\n';
1150  ERR_WML << std::string(m, e ? e - m : strlen(m));
1151  } else if (allow_wml_error && strncmp(m, "~lua:", 5) == 0) {
1152  m += 5;
1153  char const *e = nullptr, *em = m;
1154  while (em[0] && ((em = strstr(em + 1, "stack traceback"))))
1155 #ifdef _MSC_VER
1156 #pragma warning (pop)
1157 #endif
1158  e = em;
1159  chat_message("Lua error", std::string(m, e ? e - m : strlen(m)));
1160  } else {
1161  ERR_LUA << m;
1162  chat_message("Lua error", m);
1163  }
1164  } else {
1165  chat_message("Lua caught unknown exception", "");
1166  }
1167  lua_pop(L, 1);
1168  return false;
1169  }
1170 
1171  return true;
1172 }
1173 
1174 // Originally luaL_typerror, now deprecated.
1175 // Easier to define it for Wesnoth and not have to worry about it if we update Lua.
1176 int luaW_type_error(lua_State *L, int narg, const char *tname) {
1177  const char *msg = lua_pushfstring(L, "%s expected, got %s", tname, luaL_typename(L, narg));
1178  return luaL_argerror(L, narg, msg);
1179 }
1180 
1181 // An alternate version which raises an error for a key in a table.
1182 // In this version, narg should refer to the stack index of the table rather than the stack index of the key.
1183 // kpath should be the key name or a string such as "key[idx].key2" specifying a path to the key.
1184 int luaW_type_error (lua_State *L, int narg, const char* kpath, const char *tname) {
1185  const char *msg = lua_pushfstring(L, "%s expected for '%s', got %s", tname, kpath, luaL_typename(L, narg));
1186  return luaL_argerror(L, narg, msg);
1187 }
double t
Definition: astarsearch.cpp:65
std::vector< std::string > names
Definition: build_info.cpp:69
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:161
const_attr_itors attribute_range() const
Definition: config.cpp:767
static bool valid_tag(config_key_type name)
Definition: config.cpp:131
const_all_children_itors all_children_range() const
In-order iteration over all children.
Definition: config.cpp:891
boost::iterator_range< const_attribute_iterator > const_attr_itors
Definition: config.hpp:361
static bool valid_attribute(config_key_type name)
Definition: config.cpp:154
attribute_map::value_type attribute
Definition: config.hpp:301
void clear()
Definition: config.cpp:835
config & add_child(config_key_type key)
Definition: config.cpp:445
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.
const t_string_base & get() const
Definition: tstring.hpp:200
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:830
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:657
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:54
void push_error_handler(lua_State *L)
static const char executeKey[]
Definition: lua_common.cpp:49
static lg::log_domain log_scripting_lua("scripting/lua")
bool luaW_iststring(lua_State *L, int index)
Definition: lua_common.cpp:646
static const char vconfigKey[]
Definition: lua_common.cpp:45
static int impl_namedtuple_tostring(lua_State *L)
Definition: lua_common.cpp:702
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:715
config luaW_checkconfig(lua_State *L, int index)
Converts an optional table or vconfig to a config object.
Definition: lua_common.cpp:920
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:733
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:813
void luaW_pushtstring(lua_State *L, const t_string &v)
Pushes a t_string on the top of the stack.
Definition: lua_common.cpp:548
bool luaW_pushvariable(lua_State *L, variable_access_const &v)
Definition: lua_common.cpp:996
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:937
#define ERR_WML
Definition: lua_common.cpp:57
void luaW_pushvconfig(lua_State *L, const vconfig &cfg)
Pushes a vconfig on the top of the stack.
Definition: lua_common.cpp:542
bool luaW_toboolean(lua_State *L, int n)
Definition: lua_common.cpp:991
static const char vconfigpairsKey[]
Definition: lua_common.cpp:46
int luaW_type_error(lua_State *L, int narg, const char *tname)
#define return_misformed()
Definition: lua_common.cpp:839
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:586
std::string_view luaW_tostring(lua_State *L, int index)
static const char tstringKey[]
Definition: lua_common.cpp:48
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:527
#define WRN_LUA
Definition: lua_common.cpp:53
static int impl_namedtuple_dir(lua_State *L)
Definition: lua_common.cpp:696
static const char gettextKey[]
Definition: lua_common.cpp:44
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:581
bool luaW_totstring(lua_State *L, int index, t_string &str)
Converts a scalar to a translatable string.
Definition: lua_common.cpp:613
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:842
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:801
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:964
static int impl_namedtuple_get(lua_State *L)
Definition: lua_common.cpp:680
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:744
static const char vconfigipairsKey[]
Definition: lua_common.cpp:47
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:793
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:972
t_string luaW_checktstring(lua_State *L, int index)
Converts a scalar to a translatable string.
Definition: lua_common.cpp:638
std::string path
Definition: filesystem.cpp:86
std::pair< std::string, unsigned > item
Definition: help_impl.hpp:414
std::stringstream & log_to_chat()
Use this to show WML errors in the ingame chat.
Definition: log.cpp:474
static int impl_tstring_concat(lua_State *L)
Appends a scalar to a t_string object (__concat metamethod).
Definition: lua_common.cpp:137
std::pair< vconfig::all_children_iterator, vconfig::all_children_iterator > vconfig_child_range
Definition: lua_common.cpp:359
int intf_textdomain(lua_State *L)
Creates an interface for gettext.
Definition: lua_common.cpp:96
static int impl_vconfig_pairs(lua_State *L)
Construct an iterator to iterate through the attributes of a vconfig.
Definition: lua_common.cpp:348
static int impl_vconfig_ipairs(lua_State *L)
Construct an iterator to iterate through the subtags of a vconfig.
Definition: lua_common.cpp:397
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 int impl_tstring_eq(lua_State *L)
Definition: lua_common.cpp:183
static int impl_vconfig_ipairs_collect(lua_State *L)
Destroy a vconfig ipairs iterator.
Definition: lua_common.cpp:386
std::string register_gettext_metatable(lua_State *L)
Adds the gettext metatable.
Definition: lua_common.cpp:424
static int impl_tstring_lt(lua_State *L)
Definition: lua_common.cpp:167
std::string register_vconfig_metatable(lua_State *L)
Adds the vconfig metatable.
Definition: lua_common.cpp:476
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_vconfig_pairs_collect(lua_State *L)
Destroy a vconfig pairs iterator.
Definition: lua_common.cpp:324
std::string register_tstring_metatable(lua_State *L)
Adds the tstring metatable.
Definition: lua_common.cpp:444
static int impl_gettext(lua_State *L)
Creates a t_string object (__call metamethod).
Definition: lua_common.cpp:67
static int impl_gettext_tostr(lua_State *L)
Definition: lua_common.cpp:82
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_size(lua_State *L)
Returns the number of a child of a vconfig object.
Definition: lua_common.cpp:285
int intf_tovconfig(lua_State *L)
Creates a vconfig containing the WML table.
Definition: lua_common.cpp:414
static int impl_tstring_len(lua_State *L)
Definition: lua_common.cpp:150
static int impl_vconfig_pairs_iter(lua_State *L)
Iterate through the attributes of a vconfig.
Definition: lua_common.cpp:306
static int impl_vconfig_dir(lua_State *L)
Definition: lua_common.cpp:271
static int impl_vconfig_collect(lua_State *L)
Destroys a vconfig object before it is collected (__gc metamethod).
Definition: lua_common.cpp:296
static int impl_tstring_le(lua_State *L)
Definition: lua_common.cpp:175
static int impl_vconfig_ipairs_iter(lua_State *L)
Iterate through the subtags of a vconfig.
Definition: lua_common.cpp:364
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 compare(const std::string &s1, const std::string &s2)
Case-sensitive lexicographical comparison.
Definition: gettext.cpp:504
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
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:110
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