Freeciv21
Develop your civilization from humble roots to a global empire
luascript_signal.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 
36 // utility
37 #include "deprecations.h"
38 
39 /* common/scriptcore */
40 #include "luascript.h"
41 #include "luascript_types.h"
42 
43 #include "luascript_signal.h"
44 
45 static struct signal_callback *signal_callback_new(const char *name);
46 static void signal_callback_destroy(struct signal_callback *pcallback);
47 static struct signal *signal_new(int nargs, enum api_types *parg_types);
48 static void signal_destroy(struct signal *psignal);
49 
53 static struct signal_callback *signal_callback_new(const char *name)
54 {
55  auto *pcallback = new signal_callback;
56 
57  pcallback->name = fc_strdup(name);
58  return pcallback;
59 }
60 
64 static void signal_callback_destroy(struct signal_callback *pcallback)
65 {
66  delete[] pcallback->name;
67  delete pcallback;
68 }
69 
73 static struct signal *signal_new(int nargs, enum api_types *parg_types)
74 {
75  auto *psignal = new struct signal;
76 
77  psignal->nargs = nargs;
78  psignal->arg_types = parg_types;
79  psignal->callbacks = new QList<signal_callback *>;
80  psignal->depr_msg = nullptr;
81 
82  return psignal;
83 }
84 
88 static void signal_destroy(struct signal *psignal)
89 {
90  delete[] psignal->arg_types;
91  delete[] psignal->depr_msg;
92  while (!psignal->callbacks->isEmpty()) {
93  signal_callback_destroy(psignal->callbacks->takeFirst());
94  }
95 
96  delete psignal->callbacks;
97  delete psignal;
98 }
99 
104  const char *signal_name, va_list args)
105 {
106  struct signal *psignal;
107 
109  fc_assert_ret(fcl->signals_hash);
110 
111  psignal = fcl->signals_hash->value(signal_name, nullptr);
112  if (psignal) {
113  for (auto *pcallback : qAsConst(*psignal->callbacks)) {
114  va_list args_cb;
115 
116  va_copy(args_cb, args);
117  if (luascript_callback_invoke(fcl, pcallback->name, psignal->nargs,
118  psignal->arg_types, args_cb)) {
119  va_end(args_cb);
120  break;
121  }
122  va_end(args_cb);
123  }
124  } else {
126  "Signal \"%s\" does not exist, so cannot "
127  "be invoked.",
128  signal_name);
129  }
130 }
131 
135 void luascript_signal_emit(struct fc_lua *fcl, const char *signal_name, ...)
136 {
137  va_list args;
138 
139  va_start(args, signal_name);
140  luascript_signal_emit_valist(fcl, signal_name, args);
141  va_end(args);
142 }
143 
148  const char *signal_name,
149  int nargs, va_list args)
150 {
151  struct signal *psignal;
152 
153  fc_assert_ret_val(fcl, nullptr);
154  fc_assert_ret_val(fcl->signals_hash, nullptr);
155 
156  psignal = fcl->signals_hash->value(signal_name, nullptr);
157  if (psignal) {
158  luascript_log(fcl, LOG_ERROR, "Signal \"%s\" was already created.",
159  signal_name);
160  return nullptr;
161  } else {
162  enum api_types *parg_types = new api_types[nargs]();
163  int i;
164  QString sn = QString(signal_name);
165  struct signal *created;
166 
167  for (i = 0; i < nargs; i++) {
168  *(parg_types + i) = api_types(va_arg(args, int));
169  }
170  created = signal_new(nargs, parg_types);
171  fcl->signals_hash->insert(signal_name, created);
172  fcl->signal_names->append(sn);
173 
174  return created;
175  }
176 }
177 
182  const char *signal_name,
183  int nargs, ...)
184 {
185  va_list args;
186  struct signal *created;
187 
188  va_start(args, nargs);
189  created = luascript_signal_create_valist(fcl, signal_name, nargs, args);
190  va_end(args);
191 
192  if (created != nullptr) {
193  return &(created->depr_msg);
194  }
195 
196  return nullptr;
197 }
198 
202 void deprecate_signal(signal_deprecator *deprecator, const char *signal_name,
203  const char *replacement, const char *deprecated_since)
204 {
205  if (deprecator != nullptr) {
206  char buffer[1024];
207 
208  if (deprecated_since != nullptr && replacement != nullptr) {
209  fc_snprintf(
210  buffer, sizeof(buffer),
211  "Deprecated: lua signal \"%s\", deprecated since \"%s\", used. "
212  "Use \"%s\" instead",
213  signal_name, deprecated_since, replacement);
214  } else if (replacement != nullptr) {
215  fc_snprintf(buffer, sizeof(buffer),
216  "Deprecated: lua signal \"%s\" used. Use \"%s\" instead",
217  signal_name, replacement);
218  } else {
219  fc_snprintf(buffer, sizeof(buffer),
220  "Deprecated: lua signal \"%s\" used.", signal_name);
221  }
222 
223  *deprecator = fc_strdup(buffer);
224  }
225 }
226 
230 void luascript_signal_callback(struct fc_lua *fcl, const char *signal_name,
231  const char *callback_name, bool create)
232 {
233  struct signal *psignal;
234  struct signal_callback *pcallback_found = nullptr;
235 
236  fc_assert_ret(fcl != nullptr);
237  fc_assert_ret(fcl->signals_hash != nullptr);
238 
239  psignal = fcl->signals_hash->value(signal_name, nullptr);
240  if (psignal) {
241  // check for a duplicate callback
242  for (auto *pcallback : qAsConst(*psignal->callbacks)) {
243  if (!strcmp(pcallback->name, callback_name)) {
244  pcallback_found = pcallback;
245  break;
246  }
247  }
248 
249  if (psignal->depr_msg != nullptr) {
250  qCWarning(deprecations_category, "%s", psignal->depr_msg);
251  }
252 
253  if (create) {
254  if (pcallback_found) {
255  luascript_error(fcl->state,
256  "Signal \"%s\" already has a callback "
257  "called \"%s\".",
258  signal_name, callback_name);
259  } else {
260  psignal->callbacks->append(signal_callback_new(callback_name));
261  }
262  } else {
263  if (pcallback_found) {
264  psignal->callbacks->removeAll(pcallback_found);
265  }
266  }
267  } else {
268  luascript_error(fcl->state, "Signal \"%s\" does not exist.",
269  signal_name);
270  }
271 }
272 
277  const char *signal_name,
278  const char *callback_name)
279 {
280  struct signal *psignal;
281 
282  fc_assert_ret_val(fcl != nullptr, false);
283  fc_assert_ret_val(fcl->signals_hash != nullptr, false);
284 
285  psignal = fcl->signals_hash->value(signal_name, nullptr);
286  if (psignal) {
287  // check for a duplicate callback
288  for (auto *pcallback : qAsConst(*psignal->callbacks)) {
289  if (!strcmp(pcallback->name, callback_name)) {
290  return true;
291  }
292  }
293  }
294 
295  return false;
296 }
297 
302 {
303  fc_assert_ret(fcl != nullptr);
304 
305  if (nullptr == fcl->signals_hash) {
306  fcl->signals_hash = new QHash<QString, struct signal *>;
307  fcl->signal_names = new QVector<QString>;
308  }
309 }
310 
315 {
316  if (!fcl || !fcl->signals_hash) {
317  return;
318  }
319  for (auto *nissan : qAsConst(*fcl->signals_hash)) {
320  signal_destroy(nissan);
321  }
322  delete fcl->signals_hash;
323  delete fcl->signal_names;
324  fcl->signals_hash = nullptr;
325  fcl->signal_names = nullptr;
326 }
327 
331 QString luascript_signal_by_index(struct fc_lua *fcl, int sindex)
332 {
333  fc_assert_ret_val(fcl != nullptr, QString());
334  fc_assert_ret_val(fcl->signal_names != nullptr, QString());
335 
336  return sindex < fcl->signal_names->size() ? fcl->signal_names->at(sindex)
337  : QString();
338 }
339 
345  const char *signal_name,
346  int sindex)
347 {
348  struct signal *psignal;
349 
350  fc_assert_ret_val(fcl != nullptr, nullptr);
351  fc_assert_ret_val(fcl->signals_hash != nullptr, nullptr);
352 
353  psignal = fcl->signals_hash->value(signal_name, nullptr);
354  if (psignal && sindex < psignal->callbacks->size()) {
355  struct signal_callback *pcallback = psignal->callbacks->at(sindex);
356  if (pcallback) {
357  return pcallback->name;
358  }
359  }
360  return nullptr;
361 }
const char * name
Definition: inputfile.cpp:118
#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
bool luascript_callback_invoke(struct fc_lua *fcl, const char *callback_name, int nargs, enum api_types *parg_types, va_list args)
Invoke the 'callback_name' Lua function.
Definition: luascript.cpp:657
int luascript_error(lua_State *L, const char *format,...)
Internal api error function - varg version.
Definition: luascript.cpp:231
void luascript_log(struct fc_lua *fcl, QtMsgType level, const char *format,...)
Print a message to the selected output handle.
Definition: luascript.cpp:428
void luascript_signal_free(struct fc_lua *fcl)
Free script signals and callbacks.
void luascript_signal_init(struct fc_lua *fcl)
Initialize script signals and callbacks.
static void signal_destroy(struct signal *psignal)
Free a signal.
bool luascript_signal_callback_defined(struct fc_lua *fcl, const char *signal_name, const char *callback_name)
Returns if a callback function to a certain signal is defined.
signal_deprecator * luascript_signal_create(struct fc_lua *fcl, const char *signal_name, int nargs,...)
Create a new signal type.
void deprecate_signal(signal_deprecator *deprecator, const char *signal_name, const char *replacement, const char *deprecated_since)
Mark signal deprecated.
void luascript_signal_emit_valist(struct fc_lua *fcl, const char *signal_name, va_list args)
Invoke all the callback functions attached to a given signal.
static struct signal_callback * signal_callback_new(const char *name)
Signals implementation.
static void signal_callback_destroy(struct signal_callback *pcallback)
Free a signal callback.
const char * luascript_signal_callback_by_index(struct fc_lua *fcl, const char *signal_name, int sindex)
Return the name of the 'index' callback function of the signal with the name 'signal_name'.
void luascript_signal_emit(struct fc_lua *fcl, const char *signal_name,...)
Invoke all the callback functions attached to a given signal.
void luascript_signal_callback(struct fc_lua *fcl, const char *signal_name, const char *callback_name, bool create)
Connects a callback function to a certain signal.
QString luascript_signal_by_index(struct fc_lua *fcl, int sindex)
Return the name of the signal with the given index.
static struct signal * signal_new(int nargs, enum api_types *parg_types)
Create a new signal.
static struct signal * luascript_signal_create_valist(struct fc_lua *fcl, const char *signal_name, int nargs, va_list args)
Create a new signal type.
char * signal_deprecator
static void static sol::state * fcl
Lua virtual machine state.
Definition: script_fcdb.cpp:48
enum api_types * arg_types
char * depr_msg
QList< signal_callback * > * callbacks
int fc_snprintf(char *str, size_t n, const char *format,...)
See also fc_utf8_snprintf_trunc(), fc_utf8_snprintf_rep().
Definition: support.cpp:537
#define fc_strdup(str)
Definition: support.h:111