Freeciv-3.1: /fast/freeciv/nightly/S3_1/common/scriptcore/luascript_signal.c Source File

Freeciv-3.1

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);
70static void signal_callback_destroy(struct signal_callback *pcallback);
71static struct signal *signal_new(int nargs, enum api_types *parg_types);
72static void signal_destroy(struct signal *psignal);
73
74/* Signal datastructure. */
75 struct 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 */
79 char *depr_msg; /* deprecation message to show if handler added */
80};
81
82/* Signal callback datastructure. */
83 struct signal_callback {
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/**********************************************************************/
114 static 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/**********************************************************************/
125 static void signal_callback_destroy(struct signal_callback *pcallback)
126{
127 free(pcallback->name);
128 free(pcallback);
129}
130
131/**********************************************************************/
134 static 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
141 = signal_callback_list_new_full(signal_callback_destroy);
142 psignal->depr_msg = NULL;
143
144 return psignal;
145}
146
147/**********************************************************************/
150 static void signal_destroy(struct signal *psignal)
151{
152 if (psignal->arg_types) {
153 free(psignal->arg_types);
154 }
155 if (psignal->depr_msg) {
156 free(psignal->depr_msg);
157 }
158 signal_callback_list_destroy(psignal->callbacks);
159 free(psignal);
160}
161
162/**********************************************************************/
165 void luascript_signal_emit_valist(struct fc_lua *fcl,
166 const char *signal_name,
167 va_list args)
168{
169 struct signal *psignal;
170
171 fc_assert_ret(fcl);
172 fc_assert_ret(fcl->signals);
173
174 if (luascript_signal_hash_lookup(fcl->signals, signal_name, &psignal)) {
175 signal_callback_list_iterate(psignal->callbacks, pcallback) {
176 va_list args_cb;
177
178 va_copy(args_cb, args);
179 if (luascript_callback_invoke(fcl, pcallback->name, psignal->nargs,
180 psignal->arg_types, args_cb)) {
181 va_end(args_cb);
182 break;
183 }
184 va_end(args_cb);
185 } signal_callback_list_iterate_end;
186 } else {
187 luascript_log(fcl, LOG_ERROR, "Signal \"%s\" does not exist, so cannot "
188 "be invoked.", signal_name);
189 }
190}
191
192/**********************************************************************/
195 void luascript_signal_emit(struct fc_lua *fcl,
196 const char *signal_name, ...)
197{
198 va_list args;
199
200 va_start(args, signal_name);
201 luascript_signal_emit_valist(fcl, signal_name, args);
202 va_end(args);
203}
204
205/**********************************************************************/
208 static struct signal *luascript_signal_create_valist(struct fc_lua *fcl,
209 const char *signal_name,
210 int nargs, va_list args)
211{
212 struct signal *psignal;
213
214 fc_assert_ret_val(fcl, NULL);
215 fc_assert_ret_val(fcl->signals, NULL);
216
217 if (luascript_signal_hash_lookup(fcl->signals, signal_name, &psignal)) {
218 luascript_log(fcl, LOG_ERROR, "Signal \"%s\" was already created.",
219 signal_name);
220 return NULL;
221 } else {
222 enum api_types *parg_types;
223 char *sn = fc_malloc(strlen(signal_name) + 1);
224 struct signal *created;
225
226 if (nargs > 0) {
227 int i;
228
229 parg_types = fc_calloc(nargs, sizeof(*parg_types));
230
231 for (i = 0; i < nargs; i++) {
232 *(parg_types + i) = va_arg(args, int);
233 }
234 } else {
235 parg_types = NULL;
236 }
237
238 created = signal_new(nargs, parg_types);
239 luascript_signal_hash_insert(fcl->signals, signal_name,
240 created);
241 strcpy(sn, signal_name);
242 luascript_signal_name_list_append(fcl->signal_names, sn);
243
244 return created;
245 }
246}
247
248/**********************************************************************/
251 signal_deprecator *luascript_signal_create(struct fc_lua *fcl,
252 const char *signal_name,
253 int nargs, ...)
254{
255 va_list args;
256 struct signal *created;
257
258 va_start(args, nargs);
259 created = luascript_signal_create_valist(fcl, signal_name, nargs, args);
260 va_end(args);
261
262 if (created != NULL) {
263 return &(created->depr_msg);
264 }
265
266 return NULL;
267}
268
269/**********************************************************************/
272 void deprecate_signal(signal_deprecator *deprecator, char *signal_name,
273 char *replacement, char *deprecated_since)
274{
275 if (deprecator != NULL) {
276 char buffer[1024];
277
278 if (deprecated_since != NULL && replacement != NULL) {
279 fc_snprintf(buffer, sizeof(buffer),
280 "Deprecated: lua signal \"%s\", deprecated since \"%s\", used. "
281 "Use \"%s\" instead", signal_name, deprecated_since, replacement);
282 } else if (replacement != NULL) {
283 fc_snprintf(buffer, sizeof(buffer),
284 "Deprecated: lua signal \"%s\" used. Use \"%s\" instead",
285 signal_name, replacement);
286 } else {
287 fc_snprintf(buffer, sizeof(buffer),
288 "Deprecated: lua signal \"%s\" used.", signal_name);
289 }
290
291 *deprecator = fc_strdup(buffer);
292 }
293}
294
295/**********************************************************************/
298 void luascript_signal_callback(struct fc_lua *fcl, const char *signal_name,
299 const char *callback_name, bool create)
300{
301 struct signal *psignal;
302 struct signal_callback *pcallback_found = NULL;
303
304 fc_assert_ret(fcl != NULL);
305 fc_assert_ret(fcl->signals != NULL);
306
307 if (luascript_signal_hash_lookup(fcl->signals, signal_name, &psignal)) {
308 /* check for a duplicate callback */
309 signal_callback_list_iterate(psignal->callbacks, pcallback) {
310 if (!strcmp(pcallback->name, callback_name)) {
311 pcallback_found = pcallback;
312 break;
313 }
314 } signal_callback_list_iterate_end;
315
316 if (psignal->depr_msg != NULL) {
317 log_deprecation("%s", psignal->depr_msg);
318 }
319
320 if (create) {
321 if (pcallback_found) {
322 luascript_error(fcl->state, "Signal \"%s\" already has a callback "
323 "called \"%s\".", signal_name,
324 callback_name);
325 } else {
326 signal_callback_list_append(psignal->callbacks,
327 signal_callback_new(callback_name));
328 }
329 } else {
330 if (pcallback_found) {
331 signal_callback_list_remove(psignal->callbacks, pcallback_found);
332 }
333 }
334 } else {
335 luascript_error(fcl->state, "Signal \"%s\" does not exist.",
336 signal_name);
337 }
338}
339
340/**********************************************************************/
343 bool luascript_signal_callback_defined(struct fc_lua *fcl,
344 const char *signal_name,
345 const char *callback_name)
346{
347 struct signal *psignal;
348
349 fc_assert_ret_val(fcl != NULL, FALSE);
350 fc_assert_ret_val(fcl->signals != NULL, FALSE);
351
352 if (luascript_signal_hash_lookup(fcl->signals, signal_name, &psignal)) {
353 /* check for a duplicate callback */
354 signal_callback_list_iterate(psignal->callbacks, pcallback) {
355 if (!strcmp(pcallback->name, callback_name)) {
356 return TRUE;
357 }
358 } signal_callback_list_iterate_end;
359 }
360
361 return FALSE;
362}
363
364/**********************************************************************/
368 static void sn_free(char *name)
369{
370 FC_FREE(name);
371}
372
373/**********************************************************************/
376 void luascript_signal_init(struct fc_lua *fcl)
377{
378 fc_assert_ret(fcl != NULL);
379
380 if (NULL == fcl->signals) {
381 fcl->signals = luascript_signal_hash_new();
382 fcl->signal_names = luascript_signal_name_list_new_full(sn_free);
383 }
384}
385
386/**********************************************************************/
389 void luascript_signal_free(struct fc_lua *fcl)
390{
391 if (NULL != fcl && NULL != fcl->signals) {
392 luascript_signal_hash_destroy(fcl->signals);
393
394 luascript_signal_name_list_destroy(fcl->signal_names);
395
396 fcl->signals = NULL;
397 }
398}
399
400/**********************************************************************/
403 const char *luascript_signal_by_index(struct fc_lua *fcl, int sindex)
404{
405 fc_assert_ret_val(fcl != NULL, NULL);
406 fc_assert_ret_val(fcl->signal_names != NULL, NULL);
407
408 return luascript_signal_name_list_get(fcl->signal_names, sindex);
409}
410
411/**********************************************************************/
415 const char *luascript_signal_callback_by_index(struct fc_lua *fcl,
416 const char *signal_name,
417 int sindex)
418{
419 struct signal *psignal;
420
421 fc_assert_ret_val(fcl != NULL, NULL);
422 fc_assert_ret_val(fcl->signals != NULL, NULL);
423
424 if (luascript_signal_hash_lookup(fcl->signals, signal_name, &psignal)) {
425 struct signal_callback *pcallback
426 = signal_callback_list_get(psignal->callbacks, sindex);
427 if (pcallback) {
428 return pcallback->name;
429 }
430 }
431
432 return NULL;
433}
deprecations.h
log_deprecation
#define log_deprecation(message,...)
Definition deprecations.h:35
name
const char * name
Definition inputfile.c:127
log.h
fc_assert_ret
#define fc_assert_ret(condition)
Definition log.h:191
fc_assert_ret_val
#define fc_assert_ret_val(condition, val)
Definition log.h:194
LOG_ERROR
@ LOG_ERROR
Definition log.h:30
luascript_callback_invoke
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
luascript_error
int luascript_error(lua_State *L, const char *format,...)
Definition luascript.c:291
luascript_log
void luascript_log(struct fc_lua *fcl, enum log_level level, const char *format,...)
Definition luascript.c:409
luascript.h
luascript_signal_free
void luascript_signal_free(struct fc_lua *fcl)
Definition luascript_signal.c:389
luascript_signal_init
void luascript_signal_init(struct fc_lua *fcl)
Definition luascript_signal.c:376
signal_destroy
static void signal_destroy(struct signal *psignal)
Definition luascript_signal.c:150
luascript_signal_callback_defined
bool luascript_signal_callback_defined(struct fc_lua *fcl, const char *signal_name, const char *callback_name)
Definition luascript_signal.c:343
luascript_signal_emit_valist
void luascript_signal_emit_valist(struct fc_lua *fcl, const char *signal_name, va_list args)
Definition luascript_signal.c:165
luascript_signal_create_valist
static struct signal * luascript_signal_create_valist(struct fc_lua *fcl, const char *signal_name, int nargs, va_list args)
Definition luascript_signal.c:208
luascript_signal_by_index
const char * luascript_signal_by_index(struct fc_lua *fcl, int sindex)
Definition luascript_signal.c:403
signal_callback_list_iterate
#define signal_callback_list_iterate(list, pcallback)
Definition luascript_signal.c:64
deprecate_signal
void deprecate_signal(signal_deprecator *deprecator, char *signal_name, char *replacement, char *deprecated_since)
Definition luascript_signal.c:272
signal_callback_new
static struct signal_callback * signal_callback_new(const char *name)
Definition luascript_signal.c:114
signal_callback_destroy
static void signal_callback_destroy(struct signal_callback *pcallback)
Definition luascript_signal.c:125
luascript_signal_callback_by_index
const char * luascript_signal_callback_by_index(struct fc_lua *fcl, const char *signal_name, int sindex)
Definition luascript_signal.c:415
luascript_signal_emit
void luascript_signal_emit(struct fc_lua *fcl, const char *signal_name,...)
Definition luascript_signal.c:195
signal_callback_list_iterate_end
#define signal_callback_list_iterate_end
Definition luascript_signal.c:66
luascript_signal_callback
void luascript_signal_callback(struct fc_lua *fcl, const char *signal_name, const char *callback_name, bool create)
Definition luascript_signal.c:298
sn_free
static void sn_free(char *name)
Definition luascript_signal.c:368
luascript_signal_create
signal_deprecator * luascript_signal_create(struct fc_lua *fcl, const char *signal_name, int nargs,...)
Definition luascript_signal.c:251
signal_new
static struct signal * signal_new(int nargs, enum api_types *parg_types)
Definition luascript_signal.c:134
luascript_signal.h
signal_deprecator
char * signal_deprecator
Definition luascript_signal.h:25
luascript_types.h
fc_calloc
#define fc_calloc(n, esz)
Definition mem.h:38
FC_FREE
#define FC_FREE(ptr)
Definition mem.h:41
fc_strdup
#define fc_strdup(str)
Definition mem.h:43
fc_malloc
#define fc_malloc(sz)
Definition mem.h:34
spechash.h
speclist.h
fc_lua
Definition luascript.h:44
fc_lua::signals
struct luascript_signal_hash * signals
Definition luascript.h:53
fc_lua::signal_names
struct luascript_signal_name_list * signal_names
Definition luascript.h:54
fc_lua::state
lua_State * state
Definition luascript.h:45
signal_callback
Definition luascript_signal.c:83
signal_callback::name
char * name
Definition luascript_signal.c:84
signal
Definition luascript_signal.c:75
signal::callbacks
struct signal_callback_list * callbacks
Definition luascript_signal.c:78
signal::arg_types
enum api_types * arg_types
Definition luascript_signal.c:77
signal::nargs
int nargs
Definition luascript_signal.c:76
signal::depr_msg
char * depr_msg
Definition luascript_signal.c:79
fc_snprintf
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:969
TRUE
#define TRUE
Definition support.h:46
FALSE
#define FALSE
Definition support.h:47