Freeciv21
Develop your civilization from humble roots to a global empire
luascript_func.cpp
Go to the documentation of this file.
1 /*
2  Copyright (c) 1996-2020 Freeciv21 and Freeciv contributors. This file is
3  part of Freeciv21. Freeciv21 is free software: you can redistribute it
4  and/or modify it under the terms of the GNU General Public License as
5  published by the Free Software Foundation, either version 3 of the
6  License, or (at your option) any later version. You should have received
7  a copy of the GNU General Public License along with Freeciv21. If not,
8  see https://www.gnu.org/licenses/.
9  */
10 
11 #include <cstdarg>
12 
13 /* dependencies/lua */
14 extern "C" {
15 #include "lua.h"
16 #include "lualib.h"
17 }
18 
19 /* common/scriptcore */
20 #include "luascript.h"
21 #include "luascript_types.h"
22 
23 #include "luascript_func.h"
24 
25 static struct luascript_func *func_new(bool required, int nargs,
26  enum api_types *parg_types,
27  int nreturns,
28  enum api_types *preturn_types);
29 static void func_destroy(struct luascript_func *pfunc);
30 
32  bool required; // if this function is required
33  int nargs; // number of arguments to pass
34  int nreturns; // number of return values to accept
35  enum api_types *arg_types; // argument types
36  enum api_types *return_types; // return types
37 };
38 
42 static struct luascript_func *func_new(bool required, int nargs,
43  enum api_types *parg_types,
44  int nreturns,
45  enum api_types *preturn_types)
46 {
47  auto *pfunc = new luascript_func;
48 
49  pfunc->required = required;
50  pfunc->nargs = nargs;
51  pfunc->arg_types = parg_types;
52  pfunc->nreturns = nreturns;
53  pfunc->return_types = preturn_types;
54 
55  return pfunc;
56 }
57 
61 static void func_destroy(struct luascript_func *pfunc)
62 {
63  if (pfunc->arg_types) {
64  delete[] pfunc->arg_types;
65  delete[] pfunc->return_types;
66  }
67  delete pfunc;
68 }
69 
76  QVector<QString> *missing_func_required,
77  QVector<QString> *missing_func_optional)
78 {
79  bool ret = true;
80 
81  fc_assert_ret_val(fcl, false);
82  fc_assert_ret_val(fcl->funcs, false);
83 
84  for (auto const &qfunc_name : fcl->funcs->keys()) {
85  char *func_name = qfunc_name.toLocal8Bit().data();
86  if (!luascript_check_function(fcl, func_name)) {
87  fc_assert_ret_val(fcl->funcs->contains(func_name), false);
88  auto *pfunc = fcl->funcs->value(func_name);
89  if (pfunc->required) {
90  missing_func_required->append(func_name);
91  } else {
92  missing_func_optional->append(func_name);
93  }
94 
95  ret = false;
96  }
97  }
98 
99  return ret;
100 }
101 
105 void luascript_func_add_valist(struct fc_lua *fcl, const char *func_name,
106  bool required, int nargs, int nreturns,
107  va_list args)
108 {
109  struct luascript_func *pfunc;
110  api_types *parg_types;
111  api_types *pret_types;
112  int i;
113 
115  fc_assert_ret(fcl->funcs);
116 
117  if (fcl->funcs->contains(func_name)) {
118  luascript_log(fcl, LOG_ERROR, "Function '%s' was already created.",
119  func_name);
120  return;
121  }
122  pfunc = fcl->funcs->value(func_name);
123  parg_types = new api_types[nargs]();
124  pret_types = new api_types[nreturns]();
125 
126  for (i = 0; i < nargs; i++) {
127  *(parg_types + i) = api_types(va_arg(args, int));
128  }
129 
130  for (i = 0; i < nreturns; i++) {
131  *(pret_types + i) = api_types(va_arg(args, int));
132  }
133 
134  pfunc = func_new(required, nargs, parg_types, nreturns, pret_types);
135  fcl->funcs->insert(func_name, pfunc);
136 }
137 
141 void luascript_func_add(struct fc_lua *fcl, const char *func_name,
142  bool required, int nargs, int nreturns, ...)
143 {
144  va_list args;
145 
146  va_start(args, nreturns);
147  luascript_func_add_valist(fcl, func_name, required, nargs, nreturns, args);
148  va_end(args);
149 }
150 
155 {
156  if (fcl && fcl->funcs) {
157  for (auto *a : qAsConst(*fcl->funcs)) {
158  func_destroy(a);
159  }
160  delete fcl->funcs;
161  fcl->funcs = nullptr;
162  }
163 }
164 
169 {
170  fc_assert_ret(fcl != nullptr);
171 
172  if (fcl->funcs == nullptr) {
173  // Define the prototypes for the needed lua functions.
174  fcl->funcs = new QHash<QString, luascript_func *>;
175  }
176 }
177 
185 bool luascript_func_call_valist(struct fc_lua *fcl, const char *func_name,
186  va_list args)
187 {
188  struct luascript_func *pfunc;
189  bool success = false;
190 
191  fc_assert_ret_val(fcl, false);
192  fc_assert_ret_val(fcl->state, false);
193  fc_assert_ret_val(fcl->funcs, false);
194 
195  if (!(fcl->funcs->contains(func_name))) {
197  "Lua function '%s' does not exist, "
198  "so cannot be invoked.",
199  func_name);
200  return false;
201  }
202  pfunc = fcl->funcs->value(func_name);
203  // The function name
204  lua_getglobal(fcl->state, func_name);
205 
206  if (!lua_isfunction(fcl->state, -1)) {
207  if (pfunc->required) {
208  // This function is required. Thus, this is an error.
209  luascript_log(fcl, LOG_ERROR, "Unknown lua function '%s'", func_name);
210  lua_pop(fcl->state, 1);
211  }
212  return false;
213  }
214 
215  luascript_push_args(fcl, pfunc->nargs, pfunc->arg_types, args);
216 
217  // Call the function with nargs arguments, return 1 results
218  if (luascript_call(fcl, pfunc->nargs, pfunc->nreturns, nullptr) == 0) {
219  // Successful call to the script.
220  success = true;
221 
222  luascript_pop_returns(fcl, func_name, pfunc->nreturns,
223  pfunc->return_types, args);
224  }
225 
226  return success;
227 }
228 
236 bool luascript_func_call(struct fc_lua *fcl, const char *func_name, ...)
237 {
238  va_list args;
239  bool success;
240 
241  va_start(args, func_name);
242  success = luascript_func_call_valist(fcl, func_name, args);
243  va_end(args);
244 
245  return success;
246 }
247 
251 bool luascript_func_is_required(struct fc_lua *fcl, const char *func_name)
252 {
253  struct luascript_func *pfunc;
254 
255  fc_assert_ret_val(fcl, false);
256  fc_assert_ret_val(fcl->state, false);
257  fc_assert_ret_val(fcl->funcs, false);
258 
259  if (!fcl->funcs->contains(func_name)) {
260  luascript_log(fcl, LOG_ERROR, "Lua function '%s' does not exist.",
261  func_name);
262  return false;
263  }
264  pfunc = fcl->funcs->value(func_name);
265  return pfunc->required;
266 }
#define fc_assert_ret(condition)
Definition: log.h:112
constexpr auto LOG_ERROR
Definition: log.h:23
#define fc_assert_ret_val(condition, val)
Definition: log.h:114
void luascript_pop_returns(struct fc_lua *fcl, const char *func_name, int nreturns, enum api_types *preturn_types, va_list args)
Pop return values from the Lua stack.
Definition: luascript.cpp:461
void luascript_push_args(struct fc_lua *fcl, int nargs, enum api_types *parg_types, va_list args)
Push arguments into the Lua stack.
Definition: luascript.cpp:512
bool luascript_check_function(struct fc_lua *fcl, const char *funcname)
Return if the function 'funcname' is define in the lua state 'fcl->state'.
Definition: luascript.cpp:554
void luascript_log(struct fc_lua *fcl, QtMsgType level, const char *format,...)
Print a message to the selected output handle.
Definition: luascript.cpp:428
int luascript_call(struct fc_lua *fcl, int narg, int nret, const char *code)
Evaluate a Lua function call or loaded script on the stack.
Definition: luascript.cpp:580
bool luascript_func_call_valist(struct fc_lua *fcl, const char *func_name, va_list args)
Call a lua function; return value is TRUE if no errors occurred, otherwise FALSE.
static void func_destroy(struct luascript_func *pfunc)
Free a function definition.
void luascript_func_init(struct fc_lua *fcl)
Initialize the structures needed to save functions definitions.
void luascript_func_add(struct fc_lua *fcl, const char *func_name, bool required, int nargs, int nreturns,...)
Add a lua function.
static struct luascript_func * func_new(bool required, int nargs, enum api_types *parg_types, int nreturns, enum api_types *preturn_types)
Create a new function definition.
bool luascript_func_call(struct fc_lua *fcl, const char *func_name,...)
Call a lua function; return value is TRUE if no errors occurred, otherwise FALSE.
void luascript_func_add_valist(struct fc_lua *fcl, const char *func_name, bool required, int nargs, int nreturns, va_list args)
Add a lua function.
bool luascript_func_is_required(struct fc_lua *fcl, const char *func_name)
Return iff the function is required.
bool luascript_func_check(struct fc_lua *fcl, QVector< QString > *missing_func_required, QVector< QString > *missing_func_optional)
Test if all function are defines.
void luascript_func_free(struct fc_lua *fcl)
Free the function definitions.
static void static sol::state * fcl
Lua virtual machine state.
Definition: script_fcdb.cpp:48
enum api_types * arg_types
enum api_types * return_types