Freeciv-3.4
Loading...
Searching...
No Matches
luascript_signal.c
Go to the documentation of this file.
1/*****************************************************************************
2 Freeciv - Copyright (C) 2005 - The Freeciv Project
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12*****************************************************************************/
13
14/*****************************************************************************
15 Signals implementation.
16
17 New signal types can be declared with script_signal_create. Each
18 signal should have a unique name string.
19 All signal declarations are in signals_create, for convenience.
20
21 A signal may have any number of Lua callback functions connected to it
22 at any given time.
23
24 A signal emission invokes all associated callbacks in the order they were
25 connected:
26
27 * A callback can stop the current signal emission, preventing the callbacks
28 connected after it from being invoked.
29
30 * A callback can detach itself from its associated signal.
31
32 Lua callbacks functions are able to do these via their return values.
33
34 All Lua callback functions can return a value. Example:
35 return false
36
37 If the value is 'true' the current signal emission will be stopped.
38*****************************************************************************/
39
40#ifdef HAVE_CONFIG_H
41#include <fc_config.h>
42#endif
43
44#include <stdarg.h>
45
46/* utility */
47#include "deprecations.h"
48#include "log.h"
49
50/* common/scriptcore */
51#include "luascript.h"
52#include "luascript_types.h"
53
54#include "luascript_signal.h"
55
56struct signal;
57struct signal_callback;
58
59/* get 'struct signal_callback_list' and related functions: */
60#define SPECLIST_TAG signal_callback
61#define SPECLIST_TYPE struct signal_callback
62#include "speclist.h"
63
64#define signal_callback_list_iterate(list, pcallback) \
65 TYPED_LIST_ITERATE(struct signal_callback, list, pcallback)
66#define signal_callback_list_iterate_end \
67 LIST_ITERATE_END
68
69static struct signal_callback *signal_callback_new(const char *name);
71static struct signal *signal_new(int nargs, enum api_types *parg_types);
72static void signal_destroy(struct signal *psignal);
73
74/* Signal datastructure. */
75struct signal {
76 int nargs; /* Number of arguments to pass */
77 enum api_types *arg_types; /* Argument types */
78 struct signal_callback_list *callbacks; /* Connected callbacks */
80};
81
82/* Signal callback datastructure. */
84 char *name; /* callback function name */
85};
86
87/*****************************************************************************
88 Signal hash table.
89*****************************************************************************/
90#define SPECHASH_TAG luascript_signal
91#define SPECHASH_ASTR_KEY_TYPE
92#define SPECHASH_IDATA_TYPE struct signal *
93#define SPECHASH_IDATA_FREE signal_destroy
94#include "spechash.h"
95
96#define signal_hash_iterate(phash, key, data) \
97 TYPED_HASH_ITERATE(char *, struct signal *, phash, key, data)
98#define signal_hash_iterate_end \
99 HASH_ITERATE_END
100
101/* get 'struct luascript_signal_name_list' and related functions: */
102#define SPECLIST_TAG luascript_signal_name
103#define SPECLIST_TYPE char
104#include "speclist.h"
105
106#define luascript_signal_name_list_iterate(list, pname) \
107 TYPED_LIST_ITERATE(struct signal_callback, list, pcallback)
108#define luascript_signal_name_list_iterate_end \
109 LIST_ITERATE_END
110
111/**********************************************************************/
114static struct signal_callback *signal_callback_new(const char *name)
115{
116 struct signal_callback *pcallback = fc_malloc(sizeof(*pcallback));
117
118 pcallback->name = fc_strdup(name);
119 return pcallback;
120}
121
122/**********************************************************************/
126{
127 free(pcallback->name);
129}
130
131/**********************************************************************/
134static struct signal *signal_new(int nargs, enum api_types *parg_types)
135{
136 struct signal *psignal = fc_malloc(sizeof(*psignal));
137
138 psignal->nargs = nargs;
139 psignal->arg_types = parg_types;
140 psignal->callbacks
142 psignal->deprecator.depr_msg = nullptr;
143 psignal->deprecator.retired = nullptr;
144
145 return psignal;
146}
147
148/**********************************************************************/
151static void signal_destroy(struct signal *psignal)
152{
153 if (psignal->arg_types) {
154 free(psignal->arg_types);
155 }
156 if (psignal->deprecator.depr_msg) {
157 free(psignal->deprecator.depr_msg);
158 }
159 if (psignal->deprecator.retired) {
160 free(psignal->deprecator.retired);
161 }
163 free(psignal);
164}
165
166/**********************************************************************/
170 const char *signal_name,
171 va_list args)
172{
173 struct signal *psignal;
174
176 fc_assert_ret(fcl->signals);
177
181
182 va_copy(args_cb, args);
184 psignal->arg_types, args_cb)) {
186 break;
187 }
190 } else {
191 luascript_log(fcl, LOG_ERROR, "Signal \"%s\" does not exist, so cannot "
192 "be invoked.", signal_name);
193 }
194}
195
196/**********************************************************************/
200 const char *signal_name, ...)
201{
202 va_list args;
203
204 va_start(args, signal_name);
206 va_end(args);
207}
208
209/**********************************************************************/
213 const char *signal_name,
214 int nargs, va_list args)
215{
216 struct signal *psignal;
217
218 fc_assert_ret_val(fcl, nullptr);
219 fc_assert_ret_val(fcl->signals, nullptr);
220
222 luascript_log(fcl, LOG_ERROR, "Signal \"%s\" was already created.",
224 return nullptr;
225 } else {
226 enum api_types *parg_types;
227 char *sn = fc_malloc(strlen(signal_name) + 1);
228 struct signal *created;
229
230 if (nargs > 0) {
231 int i;
232
234
235 for (i = 0; i < nargs; i++) {
236 *(parg_types + i) = va_arg(args, int);
237 }
238 } else {
239 parg_types = nullptr;
240 }
241
244 created);
247
248 return created;
249 }
250}
251
252/**********************************************************************/
256 const char *signal_name,
257 int nargs, ...)
258{
259 va_list args;
260 struct signal *created;
261
262 va_start(args, nargs);
264 va_end(args);
265
266 if (created != nullptr) {
267 return &(created->deprecator);
268 }
269
270 return nullptr;
271}
272
273/**********************************************************************/
277 char *signal_name, char *replacement,
278 char *deprecated_since, char *retired_since)
279{
280 if (deprecator != nullptr) {
281 char buffer[1024];
282 char *deprtype
283 = ((retired_since != nullptr) ? "Retired:" : "Deprecated:");
284
285 if (deprecated_since != nullptr && replacement != nullptr) {
286 if (retired_since != nullptr) {
287 fc_snprintf(buffer, sizeof(buffer),
288 "%s lua signal \"%s\", retired since \"%s\", "
289 "and deprecated already since \"%s\", used. "
290 "Use \"%s\" instead",
293 } else {
294 fc_snprintf(buffer, sizeof(buffer),
295 "%s lua signal \"%s\", deprecated since \"%s\", used. "
296 "Use \"%s\" instead",
298 }
299 } else if (replacement != nullptr) {
300 fc_snprintf(buffer, sizeof(buffer),
301 "%s lua signal \"%s\" used. Use \"%s\" instead",
303 } else {
304 fc_snprintf(buffer, sizeof(buffer),
305 "%s lua signal \"%s\" used.", deprtype, signal_name);
306 }
307
308 deprecator->depr_msg = fc_strdup(buffer);
309
310 if (retired_since != nullptr) {
312 }
313 }
314}
315
316/**********************************************************************/
320 const char *callback_name, bool create)
321{
322 struct signal *psignal;
323 struct signal_callback *pcallback_found = nullptr;
324
325 fc_assert_ret(fcl != nullptr);
326 fc_assert_ret(fcl->signals != nullptr);
327
329
330 if (psignal->deprecator.depr_msg != nullptr) {
331 log_deprecation("%s", psignal->deprecator.depr_msg);
332 }
333
334 if (psignal->deprecator.retired != nullptr) {
335 luascript_error(fcl->state, "Signal \"%s\" has been retired.",
337 return;
338 }
339
340 /* Check for a duplicate callback */
342 if (!strcmp(pcallback->name, callback_name)) {
344 break;
345 }
347
348 if (create) {
349 if (pcallback_found) {
350 luascript_error(fcl->state, "Signal \"%s\" already has a callback "
351 "called \"%s\".", signal_name,
353 } else {
356 }
357 } else {
358 if (pcallback_found) {
360 }
361 }
362 } else {
363 luascript_error(fcl->state, "Signal \"%s\" does not exist.",
365 }
366}
367
368/**********************************************************************/
372 const char *signal_name,
373 const char *callback_name)
374{
375 struct signal *psignal;
376
377 fc_assert_ret_val(fcl != nullptr, FALSE);
378 fc_assert_ret_val(fcl->signals != nullptr, FALSE);
379
381 /* Check for a duplicate callback */
383 if (!strcmp(pcallback->name, callback_name)) {
384 return TRUE;
385 }
387 }
388
389 return FALSE;
390}
391
392/**********************************************************************/
396static void sn_free(char *name)
397{
398 FC_FREE(name);
399}
400
401/**********************************************************************/
405{
406 fc_assert_ret(fcl != nullptr);
407
408 if (fcl->signals == nullptr) {
409 fcl->signals = luascript_signal_hash_new();
411 }
412}
413
414/**********************************************************************/
418{
419 if (fcl != nullptr && fcl->signals != nullptr) {
421
423
424 fcl->signals = nullptr;
425 }
426}
427
428/**********************************************************************/
432{
433 fc_assert_ret_val(fcl != nullptr, nullptr);
434 fc_assert_ret_val(fcl->signal_names != nullptr, nullptr);
435
436 return luascript_signal_name_list_get(fcl->signal_names, sindex);
437}
438
439/**********************************************************************/
444 const char *signal_name,
445 int sindex)
446{
447 struct signal *psignal;
448
449 fc_assert_ret_val(fcl != nullptr, nullptr);
450 fc_assert_ret_val(fcl->signals != nullptr, nullptr);
451
455 if (pcallback) {
456 return pcallback->name;
457 }
458 }
459
460 return nullptr;
461}
char * incite_cost
Definition comments.c:76
#define log_deprecation(message,...)
const char * name
Definition inputfile.c:127
#define fc_assert_ret(condition)
Definition log.h:192
#define fc_assert_ret_val(condition, val)
Definition log.h:195
@ LOG_ERROR
Definition log.h:31
bool luascript_callback_invoke(struct fc_lua *fcl, const char *callback_name, int nargs, enum api_types *parg_types, va_list args)
Definition luascript.c:657
int luascript_error(lua_State *L, const char *format,...)
Definition luascript.c:291
void luascript_log(struct fc_lua *fcl, enum log_level level, const char *format,...)
Definition luascript.c:409
void luascript_signal_free(struct fc_lua *fcl)
void luascript_signal_init(struct fc_lua *fcl)
static void signal_destroy(struct signal *psignal)
bool luascript_signal_callback_defined(struct fc_lua *fcl, const char *signal_name, const char *callback_name)
void deprecate_signal(struct signal_deprecator *deprecator, char *signal_name, char *replacement, char *deprecated_since, char *retired_since)
struct signal_deprecator * luascript_signal_create(struct fc_lua *fcl, const char *signal_name, int nargs,...)
void luascript_signal_emit_valist(struct fc_lua *fcl, const char *signal_name, va_list args)
static struct signal * luascript_signal_create_valist(struct fc_lua *fcl, const char *signal_name, int nargs, va_list args)
const char * luascript_signal_by_index(struct fc_lua *fcl, int sindex)
#define signal_callback_list_iterate(list, pcallback)
static struct signal_callback * signal_callback_new(const char *name)
static void signal_callback_destroy(struct signal_callback *pcallback)
const char * luascript_signal_callback_by_index(struct fc_lua *fcl, const char *signal_name, int sindex)
void luascript_signal_emit(struct fc_lua *fcl, const char *signal_name,...)
#define signal_callback_list_iterate_end
void luascript_signal_callback(struct fc_lua *fcl, const char *signal_name, const char *callback_name, bool create)
static void sn_free(char *name)
static struct signal * signal_new(int nargs, enum api_types *parg_types)
#define fc_calloc(n, esz)
Definition mem.h:38
#define FC_FREE(ptr)
Definition mem.h:41
#define fc_strdup(str)
Definition mem.h:43
#define fc_malloc(sz)
Definition mem.h:34
struct signal_callback_list * callbacks
enum api_types * arg_types
struct signal_deprecator deprecator
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:960
#define TRUE
Definition support.h:46
#define FALSE
Definition support.h:47