message parsing from exparse is working, but allocates too much.

This commit is contained in:
Enno Rehling 2018-05-18 20:42:22 +02:00
parent 19b3b5b35a
commit 6b0f75339f
5 changed files with 97 additions and 42 deletions

View File

@ -17,6 +17,8 @@
#include "util/functions.h"
#include "util/log.h"
#include "util/message.h"
#include "util/crmessage.h"
#include "util/nrmessage.h"
#include "util/strings.h"
#include <expat.h>
@ -285,8 +287,56 @@ static void handle_weapon(parseinfo *pi, const XML_Char *el, const XML_Char **at
wtype->flags = flags;
}
static void XMLCALL start_messages(parseinfo *pi, const XML_Char *el, const XML_Char **attr) {
static int msg_nargs;
static char * msg_args[MSG_MAXARGS];
static void end_messages(parseinfo *pi, const XML_Char *el) {
if (xml_strcmp(el, "message") == 0) {
int i;
struct message_type *mtype = (struct message_type *)pi->object;
assert(mtype);
assert(msg_nargs < MSG_MAXARGS);
mt_create(mtype, (const char **)msg_args, msg_nargs);
/* register the type for CR and NR */
crt_register(mtype);
nrt_register(mtype);
for (i = 0; i != msg_nargs; ++i) {
free(msg_args[i]);
msg_args[i] = NULL;
}
msg_nargs = 0;
}
else if (xml_strcmp(el, "messages") == 0) {
pi->type = EXP_UNKNOWN;
}
}
static void start_messages(parseinfo *pi, const XML_Char *el, const XML_Char **attr) {
if (xml_strcmp(el, "arg") == 0) {
int i;
const XML_Char *name = NULL, *type = NULL;
assert(msg_nargs < MSG_MAXARGS);
for (i = 0; attr[i]; i += 2) {
const XML_Char *key = attr[i], *val = attr[i + 1];
if (xml_strcmp(key, "name") == 0) {
name = val;
}
else if (xml_strcmp(key, "type") == 0) {
type = val;
}
else {
handle_bad_input(pi, el, key);
}
}
if (name && type) {
char zBuffer[128];
sprintf(zBuffer, "%s:%s", name, type);
msg_args[msg_nargs++] = str_strdup(zBuffer);
}
}
else if (xml_strcmp(el, "message") == 0) {
const XML_Char *name = NULL, *section = NULL;
int i;
for (i = 0; attr[i]; i += 2) {
@ -297,18 +347,24 @@ static void XMLCALL start_messages(parseinfo *pi, const XML_Char *el, const XML_
else if (xml_strcmp(key, "section") == 0) {
section = val;
}
else {
handle_bad_input(pi, el, key);
}
}
if (name) {
pi->object = mt_new(name, NULL);
pi->object = mt_new(name, section);
}
}
else if (xml_strcmp(el, "type") != 0 && xml_strcmp(el, "text") != 0) {
handle_bad_input(pi, el, NULL);
}
}
#define MAX_COMPONENTS 8
static spell_component components[MAX_COMPONENTS];
static int ncomponents;
static void XMLCALL start_spells(parseinfo *pi, const XML_Char *el, const XML_Char **attr) {
static void start_spells(parseinfo *pi, const XML_Char *el, const XML_Char **attr) {
const char *flag_names[] = {
"far", "variable", "ocean", "ship", "los",
"unittarget", "shiptarget", "buildingtarget", "regiontarget", "globaltarget", NULL };
@ -390,7 +446,7 @@ static void XMLCALL start_spells(parseinfo *pi, const XML_Char *el, const XML_Ch
}
}
static void XMLCALL start_spellbooks(parseinfo *pi, const XML_Char *el, const XML_Char **attr) {
static void start_spellbooks(parseinfo *pi, const XML_Char *el, const XML_Char **attr) {
spellbook * sb = (spellbook *)pi->object;
if (xml_strcmp(el, "spellbook") == 0) {
const XML_Char *name = attr_get(attr, "name");
@ -430,7 +486,7 @@ static void XMLCALL start_spellbooks(parseinfo *pi, const XML_Char *el, const XM
}
}
static void XMLCALL start_weapon(parseinfo *pi, const XML_Char *el, const XML_Char **attr) {
static void start_weapon(parseinfo *pi, const XML_Char *el, const XML_Char **attr) {
resource_type *rtype = (resource_type *)pi->object;
assert(rtype && rtype->wtype);
@ -791,7 +847,7 @@ static void start_resources(parseinfo *pi, const XML_Char *el, const XML_Char **
}
}
static void XMLCALL start_ships(parseinfo *pi, const XML_Char *el, const XML_Char **attr) {
static void start_ships(parseinfo *pi, const XML_Char *el, const XML_Char **attr) {
const char *flag_names[] = { "opensea", "fly", "nocoast", "speedy", NULL };
if (xml_strcmp(el, "ship") == 0) {
const XML_Char *name;
@ -899,7 +955,7 @@ static void XMLCALL start_ships(parseinfo *pi, const XML_Char *el, const XML_Cha
static int nattacks;
static int nfamiliars;
static void XMLCALL start_races(parseinfo *pi, const XML_Char *el, const XML_Char **attr) {
static void start_races(parseinfo *pi, const XML_Char *el, const XML_Char **attr) {
race *rc = (race *)pi->object;
const char *flag_names[] = {
"playerrace", "killpeasants", "scarepeasants", "!cansteal",
@ -1116,7 +1172,7 @@ static void XMLCALL start_races(parseinfo *pi, const XML_Char *el, const XML_Cha
}
}
static void XMLCALL start_buildings(parseinfo *pi, const XML_Char *el, const XML_Char **attr) {
static void start_buildings(parseinfo *pi, const XML_Char *el, const XML_Char **attr) {
const char *flag_names[] = { "nodestroy", "nobuild", "unique", "decay", "magic", "namechange", "fort", "oneperturn", NULL };
if (xml_strcmp(el, "building") == 0) {
const XML_Char *name;
@ -1427,6 +1483,9 @@ static void XMLCALL handle_end(void *data, const XML_Char *el) {
case EXP_SPELLS:
end_spells(pi, el);
break;
case EXP_MESSAGES:
end_messages(pi, el);
break;
default:
if (pi->depth == 1) {
pi->object = NULL;
@ -1444,18 +1503,6 @@ static void XMLCALL handle_end(void *data, const XML_Char *el) {
}
}
static void XMLCALL handle_data(void *data, const XML_Char *xs, int len) {
parseinfo *pi = (parseinfo *)data;
if (len > 0) {
if (pi->type == EXP_MESSAGES && pi->depth == 4) {
size_t bytes = (size_t)len;
pi->cdata = realloc(pi->cdata, pi->clength + bytes);
memcpy(pi->cdata + pi->clength, xs, bytes);
pi->clength = pi->clength + bytes;
}
}
}
int exparse_readfile(const char * filename) {
XML_Parser xp;
FILE *F;
@ -1469,7 +1516,6 @@ int exparse_readfile(const char * filename) {
}
xp = XML_ParserCreate("UTF-8");
XML_SetElementHandler(xp, handle_start, handle_end);
XML_SetCharacterDataHandler(xp, handle_data);
XML_SetUserData(xp, &pi);
memset(&pi, 0, sizeof(pi));
for (;;) {

View File

@ -25,7 +25,7 @@ void test_message(CuTest *tc) {
message_type *mtype;
test_setup();
mtype = mt_create(mt_new("custom", NULL), NULL);
mtype = mt_create(mt_new("custom", NULL), NULL, 0);
CuAssertPtrEquals(tc, mtype, (void *)mt_find("custom"));
CuAssertIntEquals(tc, 0, mtype->nparameters);
CuAssertPtrEquals(tc, NULL, (void *)mtype->pnames);
@ -51,7 +51,7 @@ static void test_merge_split(CuTest *tc) {
message *msg;
test_setup();
mtype = mt_create(mt_new("custom", NULL), NULL);
mtype = mt_create(mt_new("custom", NULL), NULL, 0);
add_message(&mlist, msg = msg_message(mtype->name, ""));
msg_release(msg);
add_message(&append, msg = msg_message(mtype->name, ""));

View File

@ -75,15 +75,22 @@ static unsigned int mt_id(const message_type * mtype)
#define MT_MAXHASH 1021
static selist *messagetypes[MT_MAXHASH];
message_type *mt_create(message_type * mtype, const char *args[])
{
int nparameters = 0;
static void mt_register(message_type * mtype) {
unsigned int hash = str_hash(mtype->name) % MT_MAXHASH;
selist **qlp = messagetypes + hash;
if (args != NULL) {
if (selist_set_insert(qlp, mtype, NULL)) {
mtype->key = mt_id(mtype);
}
}
message_type *mt_create(message_type * mtype, const char *args[], int nparameters)
{
if (args != NULL && args[nparameters]) {
/* count the number of parameters */
while (args[nparameters]) ++nparameters;
do {
++nparameters;
} while (args[nparameters]);
}
if (nparameters > 0) {
int i;
@ -111,9 +118,7 @@ message_type *mt_create(message_type * mtype, const char *args[])
}
}
}
if (selist_set_insert(qlp, mtype, NULL)) {
mtype->key = mt_id(mtype);
}
mt_register(mtype);
return mtype;
}
@ -151,7 +156,7 @@ message_type *mt_create_va(message_type *mtype, ...)
}
va_end(marker);
args[i] = NULL;
return mt_create(mtype, args);
return mt_create(mtype, args, i - 1);
}
static variant copy_arg(const arg_type * atype, variant data)

View File

@ -18,6 +18,9 @@
extern "C" {
#endif
#define MSG_MAXARGS 8
#define MT_NEW_END ((const char *)0)
typedef struct arg_type {
struct arg_type *next;
variant_type vtype;
@ -44,9 +47,6 @@ extern "C" {
void message_done(void);
void mt_clear(void);
#define MT_NEW_END ((const char *)0)
/* mt_new("simple_sentence", "subject:string", "predicate:string",
* "object:string", "lang:locale", MT_NEW_END); */
struct message *msg_create(const struct message_type *type,
variant args[]);
@ -60,7 +60,7 @@ extern "C" {
struct message_type *mt_new(const char *name, const char *section);
/** message_type registry (optional): **/
struct message_type *mt_create(struct message_type *, const char *args[]);
struct message_type *mt_create(struct message_type *, const char *args[], int nargs);
struct message_type *mt_create_va(struct message_type *, ...);
const struct message_type *mt_find(const char *);

View File

@ -1277,7 +1277,7 @@ static int parse_messages(xmlDocPtr doc)
xmlChar *propSection;
xmlChar *propValue;
xmlXPathObjectPtr result;
int k;
int nargs = 0;
char **argv = NULL;
const message_type *mtype;
@ -1285,8 +1285,10 @@ static int parse_messages(xmlDocPtr doc)
xpath->node = node;
result = xmlXPathEvalExpression(BAD_CAST "type/arg", xpath);
if (result->nodesetval && result->nodesetval->nodeNr > 0) {
argv = malloc(sizeof(char *) * (result->nodesetval->nodeNr + 1));
for (k = 0; k != result->nodesetval->nodeNr; ++k) {
int k;
nargs = result->nodesetval->nodeNr;
argv = malloc(sizeof(char *) * (nargs + 1));
for (k = 0; k != nargs; ++k) {
xmlNodePtr node = result->nodesetval->nodeTab[k];
char zBuffer[128];
xmlChar *propName, *propType;
@ -1299,7 +1301,7 @@ static int parse_messages(xmlDocPtr doc)
xmlFree(propType);
argv[k] = str_strdup(zBuffer);
}
argv[result->nodesetval->nodeNr] = NULL;
argv[nargs] = NULL;
}
xmlXPathFreeObject(result);
@ -1312,7 +1314,7 @@ static int parse_messages(xmlDocPtr doc)
propValue = xmlGetProp(node, BAD_CAST "name");
mtype = mt_find((const char *)propValue);
if (mtype == NULL) {
mtype = mt_create(mt_new((const char *)propValue, (const char *)propSection), (const char **)argv);
mtype = mt_create(mt_new((const char *)propValue, (const char *)propSection), (const char **)argv, nargs);
}
else {
assert(argv != NULL || !"cannot redefine arguments of message now");
@ -1329,8 +1331,10 @@ static int parse_messages(xmlDocPtr doc)
/* let's clean up the mess */
if (argv != NULL) {
for (k = 0; argv[k] != NULL; ++k)
int k;
for (k = 0; argv[k] != NULL; ++k) {
free(argv[k]);
}
free(argv);
}
}