Freeciv-3.2: /fast/freeciv/nightly/S3_2/common/scriptcore/luascript_signal.c Source File

Freeciv-3.2

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 struct signal_deprecator deprecator;
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->deprecator.depr_msg = NULL;
143 psignal->deprecator.retired = NULL;
144
145 return psignal;
146}
147
148/**********************************************************************/
151 static 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 }
162 signal_callback_list_destroy(psignal->callbacks);
163 free(psignal);
164}
165
166/**********************************************************************/
169 void luascript_signal_emit_valist(struct fc_lua *fcl,
170 const char *signal_name,
171 va_list args)
172{
173 struct signal *psignal;
174
175 fc_assert_ret(fcl);
176 fc_assert_ret(fcl->signals);
177
178 if (luascript_signal_hash_lookup(fcl->signals, signal_name, &psignal)) {
179 signal_callback_list_iterate(psignal->callbacks, pcallback) {
180 va_list args_cb;
181
182 va_copy(args_cb, args);
183 if (luascript_callback_invoke(fcl, pcallback->name, psignal->nargs,
184 psignal->arg_types, args_cb)) {
185 va_end(args_cb);
186 break;
187 }
188 va_end(args_cb);
189 } signal_callback_list_iterate_end;
190 } else {
191 luascript_log(fcl, LOG_ERROR, "Signal \"%s\" does not exist, so cannot "
192 "be invoked.", signal_name);
193 }
194}
195
196/**********************************************************************/
199 void luascript_signal_emit(struct fc_lua *fcl,
200 const char *signal_name, ...)
201{
202 va_list args;
203
204 va_start(args, signal_name);
205 luascript_signal_emit_valist(fcl, signal_name, args);
206 va_end(args);
207}
208
209/**********************************************************************/
212 static struct signal *luascript_signal_create_valist(struct fc_lua *fcl,
213 const char *signal_name,
214 int nargs, va_list args)
215{
216 struct signal *psignal;
217
218 fc_assert_ret_val(fcl, NULL);
219 fc_assert_ret_val(fcl->signals, NULL);
220
221 if (luascript_signal_hash_lookup(fcl->signals, signal_name, &psignal)) {
222 luascript_log(fcl, LOG_ERROR, "Signal \"%s\" was already created.",
223 signal_name);
224 return NULL;
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
233 parg_types = fc_calloc(nargs, sizeof(*parg_types));
234
235 for (i = 0; i < nargs; i++) {
236 *(parg_types + i) = va_arg(args, int);
237 }
238 } else {
239 parg_types = NULL;
240 }
241
242 created = signal_new(nargs, parg_types);
243 luascript_signal_hash_insert(fcl->signals, signal_name,
244 created);
245 strcpy(sn, signal_name);
246 luascript_signal_name_list_append(fcl->signal_names, sn);
247
248 return created;
249 }
250}
251
252/**********************************************************************/
255 struct signal_deprecator *luascript_signal_create(struct fc_lua *fcl,
256 const char *signal_name,
257 int nargs, ...)
258{
259 va_list args;
260 struct signal *created;
261
262 va_start(args, nargs);
263 created = luascript_signal_create_valist(fcl, signal_name, nargs, args);
264 va_end(args);
265
266 if (created != NULL) {
267 return &(created->deprecator);
268 }
269
270 return NULL;
271}
272
273/**********************************************************************/
276 void deprecate_signal(struct signal_deprecator *deprecator, char *signal_name,
277 char *replacement, char *deprecated_since,
278 char *retired_since)
279{
280 if (deprecator != NULL) {
281 char buffer[1024];
282 char *deprtype = ((retired_since != NULL) ? "Retired:" : "Deprecated:");
283
284 if (deprecated_since != NULL && replacement != NULL) {
285 if (retired_since != NULL) {
286 fc_snprintf(buffer, sizeof(buffer),
287 "%s lua signal \"%s\", retired since \"%s\", "
288 "and deprecated already since \"%s\", used. "
289 "Use \"%s\" instead",
290 deprtype, signal_name, retired_since, deprecated_since, replacement);
291 } else {
292 fc_snprintf(buffer, sizeof(buffer),
293 "%s lua signal \"%s\", deprecated since \"%s\", used. "
294 "Use \"%s\" instead",
295 deprtype, signal_name, deprecated_since, replacement);
296 }
297 } else if (replacement != NULL) {
298 fc_snprintf(buffer, sizeof(buffer),
299 "%s lua signal \"%s\" used. Use \"%s\" instead",
300 deprtype, signal_name, replacement);
301 } else {
302 fc_snprintf(buffer, sizeof(buffer),
303 "%s lua signal \"%s\" used.", deprtype, signal_name);
304 }
305
306 deprecator->depr_msg = fc_strdup(buffer);
307
308 if (retired_since != NULL) {
309 deprecator->retired = fc_strdup(retired_since);
310 }
311 }
312}
313
314/**********************************************************************/
317 void luascript_signal_callback(struct fc_lua *fcl, const char *signal_name,
318 const char *callback_name, bool create)
319{
320 struct signal *psignal;
321 struct signal_callback *pcallback_found = NULL;
322
323 fc_assert_ret(fcl != NULL);
324 fc_assert_ret(fcl->signals != NULL);
325
326 if (luascript_signal_hash_lookup(fcl->signals, signal_name, &psignal)) {
327
328 if (psignal->deprecator.depr_msg != NULL) {
329 log_deprecation("%s", psignal->deprecator.depr_msg);
330 }
331
332 if (psignal->deprecator.retired != NULL) {
333 luascript_error(fcl->state, "Signal \"%s\" has been retired.",
334 signal_name);
335 return;
336 }
337
338 /* Check for a duplicate callback */
339 signal_callback_list_iterate(psignal->callbacks, pcallback) {
340 if (!strcmp(pcallback->name, callback_name)) {
341 pcallback_found = pcallback;
342 break;
343 }
344 } signal_callback_list_iterate_end;
345
346 if (create) {
347 if (pcallback_found) {
348 luascript_error(fcl->state, "Signal \"%s\" already has a callback "
349 "called \"%s\".", signal_name,
350 callback_name);
351 } else {
352 signal_callback_list_append(psignal->callbacks,
353 signal_callback_new(callback_name));
354 }
355 } else {
356 if (pcallback_found) {
357 signal_callback_list_remove(psignal->callbacks, pcallback_found);
358 }
359 }
360 } else {
361 luascript_error(fcl->state, "Signal \"%s\" does not exist.",
362 signal_name);
363 }
364}
365
366/**********************************************************************/
369 bool luascript_signal_callback_defined(struct fc_lua *fcl,
370 const char *signal_name,
371 const char *callback_name)
372{
373 struct signal *psignal;
374
375 fc_assert_ret_val(fcl != NULL, FALSE);
376 fc_assert_ret_val(fcl->signals != NULL, FALSE);
377
378 if (luascript_signal_hash_lookup(fcl->signals, signal_name, &psignal)) {
379 /* check for a duplicate callback */
380 signal_callback_list_iterate(psignal->callbacks, pcallback) {
381 if (!strcmp(pcallback->name, callback_name)) {
382 return TRUE;
383 }
384 } signal_callback_list_iterate_end;
385 }
386
387 return FALSE;
388}
389
390/**********************************************************************/
394 static void sn_free(char *name)
395{
396 FC_FREE(name);
397}
398
399/**********************************************************************/
402 void luascript_signal_init(struct fc_lua *fcl)
403{
404 fc_assert_ret(fcl != NULL);
405
406 if (NULL == fcl->signals) {
407 fcl->signals = luascript_signal_hash_new();
408 fcl->signal_names = luascript_signal_name_list_new_full(sn_free);
409 }
410}
411
412/**********************************************************************/
415 void luascript_signal_free(struct fc_lua *fcl)
416{
417 if (NULL != fcl && NULL != fcl->signals) {
418 luascript_signal_hash_destroy(fcl->signals);
419
420 luascript_signal_name_list_destroy(fcl->signal_names);
421
422 fcl->signals = NULL;
423 }
424}
425
426/**********************************************************************/
429 const char *luascript_signal_by_index(struct fc_lua *fcl, int sindex)
430{
431 fc_assert_ret_val(fcl != NULL, NULL);
432 fc_assert_ret_val(fcl->signal_names != NULL, NULL);
433
434 return luascript_signal_name_list_get(fcl->signal_names, sindex);
435}
436
437/**********************************************************************/
441 const char *luascript_signal_callback_by_index(struct fc_lua *fcl,
442 const char *signal_name,
443 int sindex)
444{
445 struct signal *psignal;
446
447 fc_assert_ret_val(fcl != NULL, NULL);
448 fc_assert_ret_val(fcl->signals != NULL, NULL);
449
450 if (luascript_signal_hash_lookup(fcl->signals, signal_name, &psignal)) {
451 struct signal_callback *pcallback
452 = signal_callback_list_get(psignal->callbacks, sindex);
453 if (pcallback) {
454 return pcallback->name;
455 }
456 }
457
458 return NULL;
459}
incite_cost
char * incite_cost
Definition comments.c:74
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:658
luascript_error
int luascript_error(lua_State *L, const char *format,...)
Definition luascript.c:292
luascript_log
void luascript_log(struct fc_lua *fcl, enum log_level level, const char *format,...)
Definition luascript.c:410
luascript.h
luascript_signal_free
void luascript_signal_free(struct fc_lua *fcl)
Definition luascript_signal.c:415
luascript_signal_init
void luascript_signal_init(struct fc_lua *fcl)
Definition luascript_signal.c:402
signal_destroy
static void signal_destroy(struct signal *psignal)
Definition luascript_signal.c:151
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:369
deprecate_signal
void deprecate_signal(struct signal_deprecator *deprecator, char *signal_name, char *replacement, char *deprecated_since, char *retired_since)
Definition luascript_signal.c:276
luascript_signal_create
struct signal_deprecator * luascript_signal_create(struct fc_lua *fcl, const char *signal_name, int nargs,...)
Definition luascript_signal.c:255
luascript_signal_emit_valist
void luascript_signal_emit_valist(struct fc_lua *fcl, const char *signal_name, va_list args)
Definition luascript_signal.c:169
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:212
luascript_signal_by_index
const char * luascript_signal_by_index(struct fc_lua *fcl, int sindex)
Definition luascript_signal.c:429
signal_callback_list_iterate
#define signal_callback_list_iterate(list, pcallback)
Definition luascript_signal.c:64
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:441
luascript_signal_emit
void luascript_signal_emit(struct fc_lua *fcl, const char *signal_name,...)
Definition luascript_signal.c:199
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:317
sn_free
static void sn_free(char *name)
Definition luascript_signal.c:394
signal_new
static struct signal * signal_new(int nargs, enum api_types *parg_types)
Definition luascript_signal.c:134
luascript_signal.h
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
signal_callback
Definition luascript_signal.c:83
signal_callback::name
char * name
Definition luascript_signal.c:84
signal_deprecator
Definition luascript_signal.h:25
signal_deprecator::depr_msg
char * depr_msg
Definition luascript_signal.h:26
signal_deprecator::retired
char * retired
Definition luascript_signal.h:27
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::deprecator
struct signal_deprecator deprecator
Definition luascript_signal.c:79
signal::nargs
int nargs
Definition luascript_signal.c:76
fc_snprintf
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:974
TRUE
#define TRUE
Definition support.h:46
FALSE
#define FALSE
Definition support.h:47