From 6b0f75339f0c31402277d59eaea5b94e9fc11015 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 18 May 2018 20:42:22 +0200 Subject: [PATCH] message parsing from exparse is working, but allocates too much. --- src/exparse.c | 88 +++++++++++++++++++++++++++++--------- src/kernel/messages.test.c | 4 +- src/util/message.c | 23 ++++++---- src/util/message.h | 8 ++-- src/xmlreader.c | 16 ++++--- 5 files changed, 97 insertions(+), 42 deletions(-) diff --git a/src/exparse.c b/src/exparse.c index e323bb74c..271443c05 100644 --- a/src/exparse.c +++ b/src/exparse.c @@ -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 @@ -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 (;;) { diff --git a/src/kernel/messages.test.c b/src/kernel/messages.test.c index 961d2e63a..c017f6ec1 100644 --- a/src/kernel/messages.test.c +++ b/src/kernel/messages.test.c @@ -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, "")); diff --git a/src/util/message.c b/src/util/message.c index 0f8b7cc36..b01993098 100644 --- a/src/util/message.c +++ b/src/util/message.c @@ -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) diff --git a/src/util/message.h b/src/util/message.h index 41d58b448..40cc09086 100644 --- a/src/util/message.h +++ b/src/util/message.h @@ -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 *); diff --git a/src/xmlreader.c b/src/xmlreader.c index 8ba33db84..2decd9cb5 100644 --- a/src/xmlreader.c +++ b/src/xmlreader.c @@ -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); } }