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