2010-08-08 10:06:34 +02:00
|
|
|
/* vi: set ts=2:
|
|
|
|
+-------------------+ Christian Schlittchen <corwin@amber.kn-bremen.de>
|
|
|
|
| | Enno Rehling <enno@eressea.de>
|
|
|
|
| Eressea PBEM host | Katja Zedel <katze@felidae.kn-bremen.de>
|
|
|
|
| (c) 1998 - 2003 | Henning Peters <faroul@beyond.kn-bremen.de>
|
|
|
|
| | Ingo Wilken <Ingo.Wilken@informatik.uni-oldenburg.de>
|
|
|
|
+-------------------+ Stefan Reich <reich@halbling.de>
|
|
|
|
|
|
|
|
This program may not be used, modified or distributed
|
|
|
|
without prior permission by the authors of Eressea.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <platform.h>
|
|
|
|
#include "message.h"
|
|
|
|
|
|
|
|
#include "goodies.h"
|
|
|
|
#include "log.h"
|
2011-02-25 17:04:25 +01:00
|
|
|
#include "quicklist.h"
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
|
|
/* libc includes */
|
|
|
|
#include <assert.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
void (*msg_log_create) (const struct message * msg) = 0;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
const char *mt_name(const message_type * mtype)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2011-02-25 17:04:25 +01:00
|
|
|
return mtype->name;
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
message_type *mt_new(const char *name, const char *args[])
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
|
|
|
int i, nparameters = 0;
|
2011-03-07 08:02:35 +01:00
|
|
|
message_type *mtype = (message_type *) malloc(sizeof(message_type));
|
|
|
|
|
|
|
|
assert(name != NULL);
|
|
|
|
if (name == NULL) {
|
2012-05-17 01:52:01 +02:00
|
|
|
log_error("Trying to create message_type with name=0x0\n");
|
2010-08-08 10:06:34 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
2014-01-05 21:50:13 +01:00
|
|
|
if (args != NULL) {
|
|
|
|
/* count the number of parameters */
|
|
|
|
while (args[nparameters]) ++nparameters;
|
|
|
|
}
|
|
|
|
mtype->key = 0;
|
2013-12-29 14:38:58 +01:00
|
|
|
mtype->name = _strdup(name);
|
2010-08-08 10:06:34 +02:00
|
|
|
mtype->nparameters = nparameters;
|
|
|
|
if (nparameters > 0) {
|
2011-03-07 08:02:35 +01:00
|
|
|
mtype->pnames = (const char **)malloc(sizeof(char *) * nparameters);
|
|
|
|
mtype->types = (const arg_type **)malloc(sizeof(arg_type *) * nparameters);
|
2010-08-08 10:06:34 +02:00
|
|
|
} else {
|
|
|
|
mtype->pnames = NULL;
|
|
|
|
mtype->types = NULL;
|
|
|
|
}
|
2011-03-07 08:02:35 +01:00
|
|
|
if (args != NULL)
|
|
|
|
for (i = 0; args[i]; ++i) {
|
|
|
|
const char *x = args[i];
|
|
|
|
const char *spos = strchr(x, ':');
|
|
|
|
if (spos == NULL) {
|
2013-12-29 14:38:58 +01:00
|
|
|
mtype->pnames[i] = _strdup(x);
|
2011-03-07 08:02:35 +01:00
|
|
|
mtype->types[i] = NULL;
|
|
|
|
} else {
|
|
|
|
char *cp = strncpy((char *)malloc(spos - x + 1), x, spos - x);
|
|
|
|
cp[spos - x] = '\0';
|
|
|
|
mtype->pnames[i] = cp;
|
|
|
|
mtype->types[i] = find_argtype(spos + 1);
|
|
|
|
if (mtype->types[i] == NULL) {
|
2012-05-17 01:52:01 +02:00
|
|
|
log_error("unknown argument type %s for message type %s\n", spos + 1, mtype->name);
|
2011-03-07 08:02:35 +01:00
|
|
|
}
|
|
|
|
assert(mtype->types[i]);
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return mtype;
|
|
|
|
}
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
message_type *mt_new_va(const char *name, ...)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2011-03-07 08:02:35 +01:00
|
|
|
const char *args[16];
|
2011-02-25 17:04:25 +01:00
|
|
|
int i = 0;
|
|
|
|
va_list marker;
|
|
|
|
|
|
|
|
va_start(marker, name);
|
|
|
|
for (;;) {
|
2011-03-07 08:02:35 +01:00
|
|
|
const char *c = va_arg(marker, const char *);
|
2011-02-25 17:04:25 +01:00
|
|
|
args[i++] = c;
|
2011-03-07 08:02:35 +01:00
|
|
|
if (c == NULL)
|
|
|
|
break;
|
2011-02-25 17:04:25 +01:00
|
|
|
}
|
|
|
|
va_end(marker);
|
|
|
|
return mt_new(name, args);
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
arg_type *argtypes = NULL;
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
|
|
void
|
2011-03-07 08:02:35 +01:00
|
|
|
register_argtype(const char *name, void (*free_arg) (variant),
|
|
|
|
variant(*copy_arg) (variant), variant_type type)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2011-03-07 08:02:35 +01:00
|
|
|
arg_type *atype = (arg_type *) malloc(sizeof(arg_type));
|
2010-08-08 10:06:34 +02:00
|
|
|
atype->name = name;
|
|
|
|
atype->next = argtypes;
|
|
|
|
atype->release = free_arg;
|
|
|
|
atype->copy = copy_arg;
|
|
|
|
atype->vtype = type;
|
|
|
|
argtypes = atype;
|
|
|
|
}
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
const arg_type *find_argtype(const char *name)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2011-03-07 08:02:35 +01:00
|
|
|
arg_type *atype = argtypes;
|
|
|
|
while (atype != NULL) {
|
|
|
|
if (strcmp(atype->name, name) == 0)
|
|
|
|
return atype;
|
2010-08-08 10:06:34 +02:00
|
|
|
atype = atype->next;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
static variant copy_arg(const arg_type * atype, variant data)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2011-03-07 08:02:35 +01:00
|
|
|
assert(atype != NULL);
|
|
|
|
if (atype->copy == NULL)
|
|
|
|
return data;
|
2010-08-08 10:06:34 +02:00
|
|
|
return atype->copy(data);
|
|
|
|
}
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
static void free_arg(const arg_type * atype, variant data)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2011-03-07 08:02:35 +01:00
|
|
|
assert(atype != NULL);
|
|
|
|
if (atype->release)
|
|
|
|
atype->release(data);
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
message *msg_create(const struct message_type *mtype, variant args[])
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
|
|
|
int i;
|
2011-03-07 08:02:35 +01:00
|
|
|
message *msg = (message *) malloc(sizeof(message));
|
|
|
|
|
|
|
|
assert(mtype != NULL);
|
|
|
|
if (mtype == NULL) {
|
2012-05-17 01:52:01 +02:00
|
|
|
log_error("Trying to create message with type=0x0\n");
|
2010-08-08 10:06:34 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
msg->type = mtype;
|
2015-01-15 17:17:32 +01:00
|
|
|
msg->parameters = (variant *)(mtype->nparameters ? calloc(mtype->nparameters, sizeof(variant)) : NULL);
|
2011-03-07 08:02:35 +01:00
|
|
|
msg->refcount = 1;
|
|
|
|
for (i = 0; i != mtype->nparameters; ++i) {
|
2010-08-08 10:06:34 +02:00
|
|
|
msg->parameters[i] = copy_arg(mtype->types[i], args[i]);
|
|
|
|
}
|
2011-03-07 08:02:35 +01:00
|
|
|
if (msg_log_create)
|
|
|
|
msg_log_create(msg);
|
2010-08-08 10:06:34 +02:00
|
|
|
return msg;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define MT_MAXHASH 1021
|
2011-03-07 08:02:35 +01:00
|
|
|
static quicklist *messagetypes[MT_MAXHASH];
|
2010-08-08 10:06:34 +02:00
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
const message_type *mt_find(const char *name)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
|
|
|
unsigned int hash = hashstring(name) % MT_MAXHASH;
|
2011-03-07 08:02:35 +01:00
|
|
|
quicklist *ql = messagetypes[hash];
|
2011-02-25 17:04:25 +01:00
|
|
|
int qi;
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
for (qi = 0; ql; ql_advance(&ql, &qi, 1)) {
|
|
|
|
message_type *data = (message_type *) ql_get(ql, qi);
|
|
|
|
if (strcmp(data->name, name) == 0) {
|
2011-02-25 17:04:25 +01:00
|
|
|
return data;
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
}
|
2011-02-25 17:04:25 +01:00
|
|
|
return 0;
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
static unsigned int mt_id(const message_type * mtype)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
|
|
|
unsigned int key = 0;
|
|
|
|
size_t i = strlen(mtype->name);
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
while (i > 0) {
|
|
|
|
key = (mtype->name[--i] + key * 37);
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
return key % 0x7FFFFFFF;
|
|
|
|
}
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
const message_type *mt_register(message_type * type)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
|
|
|
unsigned int hash = hashstring(type->name) % MT_MAXHASH;
|
2011-03-07 08:02:35 +01:00
|
|
|
quicklist **qlp = messagetypes + hash;
|
|
|
|
|
2014-01-05 21:50:13 +01:00
|
|
|
if (ql_set_insert(qlp, type)) {
|
2010-08-08 10:06:34 +02:00
|
|
|
type->key = mt_id(type);
|
|
|
|
}
|
|
|
|
return type;
|
|
|
|
}
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
void msg_free(message * msg)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
|
|
|
int i;
|
2011-03-07 08:02:35 +01:00
|
|
|
assert(msg->refcount == 0);
|
|
|
|
for (i = 0; i != msg->type->nparameters; ++i) {
|
2010-08-08 10:06:34 +02:00
|
|
|
free_arg(msg->type->types[i], msg->parameters[i]);
|
|
|
|
}
|
2011-03-07 08:02:35 +01:00
|
|
|
free((void *)msg->parameters);
|
2010-08-08 10:06:34 +02:00
|
|
|
free(msg);
|
|
|
|
}
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
void msg_release(struct message *msg)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2011-03-07 08:02:35 +01:00
|
|
|
assert(msg->refcount > 0);
|
|
|
|
if (--msg->refcount > 0)
|
|
|
|
return;
|
2010-08-08 10:06:34 +02:00
|
|
|
msg_free(msg);
|
|
|
|
}
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
struct message *msg_addref(struct message *msg)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2011-03-07 08:02:35 +01:00
|
|
|
assert(msg->refcount > 0);
|
2010-08-08 10:06:34 +02:00
|
|
|
++msg->refcount;
|
|
|
|
return msg;
|
|
|
|
}
|