From 828ca5f5f6c7b109c5e3c2eae05360e46a7b2d18 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 8 Oct 2017 12:39:41 +0200 Subject: [PATCH 01/43] refactor: split order_data from order, force use of ids (to be replaced with db backend). --- src/kernel/order.c | 79 +++++++++++++++++++++++++++++++++-------- src/kernel/order.h | 4 +-- src/kernel/order.test.c | 10 +++--- src/laws.test.c | 2 +- 4 files changed, 72 insertions(+), 23 deletions(-) diff --git a/src/kernel/order.c b/src/kernel/order.c index a48825333..2f209da24 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -31,8 +31,8 @@ #include # define ORD_KEYWORD(ord) (keyword_t)((ord)->command & 0xFFFF) -# define ORD_LOCALE(ord) locale_array[(ord)->data->_lindex]->lang -# define ORD_STRING(ord) (ord)->data->_str +# define OD_LOCALE(odata) locale_array[(odata)->_lindex]->lang +# define OD_STRING(odata) (odata)->_str typedef struct locale_data { struct order_data *short_orders; @@ -48,6 +48,22 @@ typedef struct order_data { int _lindex; } order_data; +#include + +static selist * orders; + +order_data *load_data(int id) { + order_data * od = (order_data *)selist_get(orders, id - 1); + ++od->_refcount; + return od; +} + +int add_data(order_data *od) { + ++od->_refcount; + selist_push(&orders, od); + return selist_length(orders); +} + static void release_data(order_data * data) { if (data) { @@ -57,6 +73,20 @@ static void release_data(order_data * data) } } +void free_data_cb(void *entry) { + order_data *od = (order_data *)entry; + if (od->_refcount > 1) { + log_error("refcount=%d for order %s", od->_refcount, od->_str); + } + release_data(od); +} + +void free_data(void) { + selist_foreach(orders, free_data_cb); + selist_free(orders); + orders = NULL; +} + void replace_order(order ** dlist, order * orig, const order * src) { assert(src); @@ -64,7 +94,7 @@ void replace_order(order ** dlist, order * orig, const order * src) assert(dlist); while (*dlist != NULL) { order *dst = *dlist; - if (dst->data == orig->data) { + if (dst->id == orig->id) { order *cpy = copy_order(src); *dlist = cpy; cpy->next = dst->next; @@ -89,7 +119,8 @@ keyword_t getkeyword(const order * ord) */ char* get_command(const order *ord, char *sbuffer, size_t size) { char *bufp = sbuffer; - const char *text = ORD_STRING(ord); + order_data *od; + const char * text; keyword_t kwd = ORD_KEYWORD(ord); int bytes; @@ -111,8 +142,11 @@ char* get_command(const order *ord, char *sbuffer, size_t size) { WARN_STATIC_BUFFER(); } } + + od = load_data(ord->id); + text = OD_STRING(od); if (kwd != NOKEYWORD) { - const struct locale *lang = ORD_LOCALE(ord); + const struct locale *lang = OD_LOCALE(od); if (size > 0) { const char *str = (const char *)LOC(lang, keyword(kwd)); assert(str); @@ -142,6 +176,7 @@ char* get_command(const order *ord, char *sbuffer, size_t size) { } } } + release_data(od); if (size > 0) *bufp = 0; return sbuffer; } @@ -150,8 +185,6 @@ void free_order(order * ord) { if (ord != NULL) { assert(ord->next == 0); - - release_data(ord->data); free(ord); } } @@ -162,8 +195,7 @@ order *copy_order(const order * src) order *ord = (order *)malloc(sizeof(order)); ord->next = NULL; ord->command = src->command; - ord->data = src->data; - ++ord->data->_refcount; + ord->id = src->id; return ord; } return NULL; @@ -277,12 +309,14 @@ void close_orders(void) { locale_array[i] = 0; } } + free_data(); } static order *create_order_i(order *ord, keyword_t kwd, const char *sptr, bool persistent, bool noerror, const struct locale *lang) { int lindex; + order_data *od; assert(ord); if (kwd == NOKEYWORD || keyword_disabled(kwd)) { @@ -317,7 +351,10 @@ static order *create_order_i(order *ord, keyword_t kwd, const char *sptr, bool p ord->next = NULL; while (isspace(*(unsigned char *)sptr)) ++sptr; - ord->data = create_data(kwd, sptr, lindex); + + od = create_data(kwd, sptr, lindex); + ord->id = add_data(od); + release_data(od); return ord; } @@ -573,9 +610,11 @@ char *write_order(const order * ord, char *buffer, size_t size) else { keyword_t kwd = ORD_KEYWORD(ord); if (kwd == NOKEYWORD) { - const char *text = ORD_STRING(ord); + order_data *od = load_data(ord->id); + const char *text = OD_STRING(od); if (text) strlcpy(buffer, (const char *)text, size); else buffer[0] = 0; + release_data(od); } else { get_command(ord, buffer, size); @@ -593,7 +632,19 @@ void push_order(order ** ordp, order * ord) keyword_t init_order(const struct order *ord) { - assert(ord && ord->data); - init_tokens_str(ord->data->_str); - return ORD_KEYWORD(ord); + static order_data *od; + + if (!ord) { + release_data(od); + return NOKEYWORD; + } + else { + if (od) { + // TODO: warning + release_data(od); + } + od = load_data(ord->id); + init_tokens_str(od->_str); + return ORD_KEYWORD(ord); + } } diff --git a/src/kernel/order.h b/src/kernel/order.h index b9d235c88..f26174ee4 100644 --- a/src/kernel/order.h +++ b/src/kernel/order.h @@ -30,8 +30,6 @@ extern "C" { * implemented yet) saving approx. 50% of all string-related memory. */ - struct order_data; - #define CMD_QUIET 0x010000 #define CMD_PERSIST 0x020000 #define CMD_DEFAULT 0x040000 @@ -39,7 +37,7 @@ extern "C" { typedef struct order { struct order *next; /* do not access this data: */ - struct order_data *data; + int id; int command; } order; diff --git a/src/kernel/order.test.c b/src/kernel/order.test.c index 71938ca7e..e1656efc9 100644 --- a/src/kernel/order.test.c +++ b/src/kernel/order.test.c @@ -48,35 +48,35 @@ static void test_parse_order(CuTest *tc) { ord = parse_order("!MOVE NORTH", lang); CuAssertPtrNotNull(tc, ord); - CuAssertPtrNotNull(tc, ord->data); + CuAssertTrue(tc, ord->id > 0); CuAssertIntEquals(tc, K_MOVE, getkeyword(ord)); CuAssertIntEquals(tc, K_MOVE | CMD_QUIET, ord->command); free_order(ord); ord = parse_order("@MOVE NORTH", lang); CuAssertPtrNotNull(tc, ord); - CuAssertPtrNotNull(tc, ord->data); + CuAssertTrue(tc, ord->id > 0); CuAssertIntEquals(tc, K_MOVE, getkeyword(ord)); CuAssertIntEquals(tc, K_MOVE | CMD_PERSIST, ord->command); free_order(ord); ord = parse_order("!@MOVE NORTH", lang); CuAssertPtrNotNull(tc, ord); - CuAssertPtrNotNull(tc, ord->data); + CuAssertTrue(tc, ord->id > 0); CuAssertIntEquals(tc, K_MOVE, getkeyword(ord)); CuAssertIntEquals(tc, K_MOVE | CMD_PERSIST | CMD_QUIET, ord->command); free_order(ord); ord = parse_order("@!MOVE NORTH", lang); CuAssertPtrNotNull(tc, ord); - CuAssertPtrNotNull(tc, ord->data); + CuAssertTrue(tc, ord->id > 0); CuAssertIntEquals(tc, K_MOVE, getkeyword(ord)); CuAssertIntEquals(tc, K_MOVE | CMD_PERSIST | CMD_QUIET, ord->command); free_order(ord); ord = parse_order(" !@MOVE NORTH", lang); CuAssertPtrNotNull(tc, ord); - CuAssertPtrNotNull(tc, ord->data); + CuAssertTrue(tc, ord->id > 0); CuAssertIntEquals(tc, K_MOVE, getkeyword(ord)); CuAssertIntEquals(tc, K_MOVE | CMD_PERSIST | CMD_QUIET, ord->command); free_order(ord); diff --git a/src/laws.test.c b/src/laws.test.c index ee5c55f19..f11ca458d 100644 --- a/src/laws.test.c +++ b/src/laws.test.c @@ -1005,7 +1005,7 @@ static void test_long_order_normal(CuTest *tc) { fset(u, UFL_LONGACTION); unit_addorder(u, ord = create_order(K_MOVE, u->faction->locale, 0)); update_long_order(u); - CuAssertPtrEquals(tc, ord->data, u->thisorder->data); + CuAssertIntEquals(tc, ord->id, u->thisorder->id); CuAssertIntEquals(tc, 0, fval(u, UFL_MOVED)); CuAssertIntEquals(tc, 0, fval(u, UFL_LONGACTION)); CuAssertPtrNotNull(tc, u->orders); From 97ff152f1722d9f543671c58f4891e8c0e7afaa9 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 8 Oct 2017 15:34:40 +0200 Subject: [PATCH 02/43] remove order de-duplication for short and study orders. --- src/kernel/order.c | 144 +++++++++++++-------------------------------- src/spy.c | 2 +- src/study.c | 3 +- 3 files changed, 43 insertions(+), 106 deletions(-) diff --git a/src/kernel/order.c b/src/kernel/order.c index 2f209da24..bbb211cb3 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -31,21 +31,13 @@ #include # define ORD_KEYWORD(ord) (keyword_t)((ord)->command & 0xFFFF) -# define OD_LOCALE(odata) locale_array[(odata)->_lindex]->lang -# define OD_STRING(odata) (odata)->_str - -typedef struct locale_data { - struct order_data *short_orders; - struct order_data *study_orders[MAXSKILLS]; - const struct locale *lang; -} locale_data; - -static struct locale_data *locale_array[MAXLOCALES]; +# define OD_LOCALE(odata) ((odata) ? (odata)->lang : NULL) +# define OD_STRING(odata) ((odata) ? (odata)->_str : NULL) typedef struct order_data { const char *_str; int _refcount; - int _lindex; + const struct locale *lang; } order_data; #include @@ -53,15 +45,21 @@ typedef struct order_data { static selist * orders; order_data *load_data(int id) { - order_data * od = (order_data *)selist_get(orders, id - 1); - ++od->_refcount; - return od; + if (id > 0) { + order_data * od = (order_data *)selist_get(orders, id - 1); + ++od->_refcount; + return od; + } + return NULL; } int add_data(order_data *od) { - ++od->_refcount; - selist_push(&orders, od); - return selist_length(orders); + if (od->_str) { + ++od->_refcount; + selist_push(&orders, od); + return selist_length(orders); + } + return 0; } static void release_data(order_data * data) @@ -219,103 +217,42 @@ void free_orders(order ** olist) } } -static char *mkdata(order_data **pdata, size_t len, int lindex, const char *str) +static char *mkdata(order_data **pdata, size_t len, const struct locale *lang, const char *str) { order_data *data; char *result; data = malloc(sizeof(order_data) + len + 1); result = (char *)(data + 1); - data->_lindex = lindex; + data->lang = lang; data->_refcount = 0; - data->_str = 0; - data->_str = (len > 0) ? result : 0; + data->_str = (len > 0) ? result : NULL; if (str) strcpy(result, str); if (pdata) *pdata = data; return result; } -static order_data *create_data(keyword_t kwd, const char *sptr, int lindex) +static order_data *create_data(keyword_t kwd, const char *sptr, const struct locale *lang) { const char *s = sptr; order_data *data; - const struct locale *lang = locale_array[lindex]->lang; if (kwd != NOKEYWORD) s = (*sptr) ? sptr : NULL; - /* learning, only one order_data per skill required */ - if (kwd == K_STUDY) { - skill_t sk = get_skill(parse_token_depr(&sptr), lang); - switch (sk) { - case NOSKILL: /* fehler */ - break; - case SK_MAGIC: /* kann parameter haben */ - if (*sptr != 0) - break; - default: /* nur skill als Parameter, keine extras */ - data = locale_array[lindex]->study_orders[sk]; - if (data == NULL) { - const char *skname = skillname(sk, lang); - const char *spc = strchr(skname, ' '); - size_t len = strlen(skname); - char *dst = mkdata(&data, len + (spc ? 3 : 0), lindex, spc ? 0 : skname); - locale_array[lindex]->study_orders[sk] = data; - if (spc) { - dst[0] = '\"'; - memcpy(dst + 1, skname, len); - dst[len + 1] = '\"'; - dst[len + 2] = '\0'; - } - data->_refcount = 1; - } - ++data->_refcount; - return data; - } - } - /* orders with no parameter, only one order_data per order required */ - else if (kwd != NOKEYWORD && *sptr == 0) { - data = locale_array[lindex]->short_orders; - if (data == NULL) { - mkdata(&data, 0, lindex, 0); - data->_refcount = 1; - locale_array[lindex]->short_orders = data; - } - ++data->_refcount; + if (kwd != NOKEYWORD && *sptr == 0) { + mkdata(&data, 0, lang, NULL); + data->_refcount = 1; return data; } - mkdata(&data, s ? strlen(s) : 0, lindex, s); + mkdata(&data, s ? strlen(s) : 0, lang, s); data->_refcount = 1; return data; } -static void clear_localedata(int lindex) { - int i; - release_data(locale_array[lindex]->short_orders); - locale_array[lindex]->short_orders = NULL; - for (i = 0; i != MAXSKILLS; ++i) { - release_data(locale_array[lindex]->study_orders[i]); - locale_array[lindex]->study_orders[i] = 0; - } - locale_array[lindex]->lang = 0; -} - -void close_orders(void) { - int i; - for (i = 0; i != MAXLOCALES; ++i) { - if (locale_array[i]){ - clear_localedata(i); - free(locale_array[i]); - locale_array[i] = 0; - } - } - free_data(); -} - static order *create_order_i(order *ord, keyword_t kwd, const char *sptr, bool persistent, bool noerror, const struct locale *lang) { - int lindex; order_data *od; assert(ord); @@ -335,16 +272,6 @@ static order *create_order_i(order *ord, keyword_t kwd, const char *sptr, bool p } } - lindex = locale_index(lang); - assert(lindex < MAXLOCALES); - if (!locale_array[lindex]) { - locale_array[lindex] = (locale_data *)calloc(1, sizeof(locale_data)); - } - else if (locale_array[lindex]->lang != lang) { - clear_localedata(lindex); - } - locale_array[lindex]->lang = lang; - ord->command = (int)kwd; if (persistent) ord->command |= CMD_PERSIST; if (noerror) ord->command |= CMD_QUIET; @@ -352,7 +279,7 @@ static order *create_order_i(order *ord, keyword_t kwd, const char *sptr, bool p while (isspace(*(unsigned char *)sptr)) ++sptr; - od = create_data(kwd, sptr, lindex); + od = create_data(kwd, sptr, lang); ord->id = add_data(od); release_data(od); @@ -630,21 +557,30 @@ void push_order(order ** ordp, order * ord) *ordp = ord; } +static order_data *parser_od; + keyword_t init_order(const struct order *ord) { - static order_data *od; - if (!ord) { - release_data(od); + release_data(parser_od); + parser_od = NULL; return NOKEYWORD; } else { - if (od) { + if (parser_od) { // TODO: warning - release_data(od); + release_data(parser_od); } - od = load_data(ord->id); - init_tokens_str(od->_str); + parser_od = load_data(ord->id); + init_tokens_str(OD_STRING(parser_od)); return ORD_KEYWORD(ord); } } + +void close_orders(void) { + if (parser_od) { + init_order(NULL); + } + free_data(); +} + diff --git a/src/spy.c b/src/spy.c index 210be63e4..ae01656bf 100644 --- a/src/spy.c +++ b/src/spy.c @@ -496,8 +496,8 @@ int sabotage_cmd(unit * u, struct order *ord) init_order(ord); s = getstrtoken(); - p = findparam(s, u->faction->locale); + init_order(NULL); switch (p) { case P_SHIP: diff --git a/src/study.c b/src/study.c index 9d37a7648..a66efd662 100644 --- a/src/study.c +++ b/src/study.c @@ -448,6 +448,7 @@ int teach_cmd(unit * teacher, struct order *ord) if (academy_students > 0 && sk_academy!=NOSKILL) { academy_teaching_bonus(teacher, sk_academy, academy_students); } + init_order(NULL); return 0; } @@ -784,7 +785,7 @@ int study_cmd(unit * u, order * ord) mage = create_mage(u, u->faction->magiegebiet); } } - + init_order(NULL); return 0; } From 28d75f7cfc30cd556f00b7e9f7b21600b0fa82a1 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 8 Oct 2017 17:07:42 +0200 Subject: [PATCH 03/43] remove the locale from orders. --- scripts/tests/orders.lua | 3 +- src/bind_unit.c | 121 +++++++++++++++++++++---------------- src/bindings.c | 14 ----- src/bindings.h | 1 - src/creport.c | 35 +++++------ src/kernel/command.c | 3 +- src/kernel/jsonconf.test.c | 2 +- src/kernel/order.c | 26 ++++---- src/kernel/order.h | 8 ++- src/kernel/order.test.c | 18 +++--- src/kernel/save.c | 2 +- src/keyword.test.c | 2 +- src/laws.c | 2 +- src/monsters.test.c | 6 +- src/report.c | 21 ++++--- src/reports.c | 53 ++++++++-------- 16 files changed, 163 insertions(+), 154 deletions(-) diff --git a/scripts/tests/orders.lua b/scripts/tests/orders.lua index af0919640..63abaed00 100644 --- a/scripts/tests/orders.lua +++ b/scripts/tests/orders.lua @@ -47,7 +47,8 @@ function test_give() assert_not_equal(5, u2:get_item("money")) end -function test_make_temp() +function disable_test_make_temp() + -- disabled because of TOLUA_ORDERS_CLOSURE u:add_order("MACHE TEMP 123 'Herpderp'") u:add_order("// this comment will be copied") u:add_order("ENDE") diff --git a/src/bind_unit.c b/src/bind_unit.c index 1e1aee00e..00c2b9e09 100644 --- a/src/bind_unit.c +++ b/src/bind_unit.c @@ -763,6 +763,22 @@ static int tolua_unit_get_spells(lua_State * L) return tolua_selist_push(L, "spellbook", "spell_entry", slist); } +#ifdef TOLUA_ORDERS_CLOSURE +/* TODO: this requires that the locale for write_order is included in the closure */ +static int tolua_orderlist_next(lua_State * L) +{ + order **order_ptr = (order **)lua_touserdata(L, lua_upvalueindex(1)); + order *ord = *order_ptr; + if (ord != NULL) { + char cmd[8192]; + write_order(ord, cmd, sizeof(cmd)); + tolua_pushstring(L, cmd); + *order_ptr = ord->next; + return 1; + } + return 0; +} + static int tolua_unit_get_orders(lua_State * L) { unit *self = (unit *)tolua_tousertype(L, 1, 0); @@ -778,7 +794,7 @@ static int tolua_unit_get_orders(lua_State * L) return 1; } - +#endif static int tolua_unit_get_curse(lua_State *L) { unit *self = (unit *)tolua_tousertype(L, 1, 0); const char *name = tolua_tostring(L, 2, 0); @@ -960,95 +976,96 @@ void tolua_unit_open(lua_State * L) NULL); tolua_beginmodule(L, TOLUA_CAST "event"); { - tolua_function(L, TOLUA_CAST "get_type", &tolua_event_gettype); - tolua_function(L, TOLUA_CAST "get", &tolua_event_get); + tolua_function(L, TOLUA_CAST "get_type", tolua_event_gettype); + tolua_function(L, TOLUA_CAST "get", tolua_event_get); } tolua_endmodule(L); tolua_cclass(L, TOLUA_CAST "unit", TOLUA_CAST "unit", TOLUA_CAST "", NULL); tolua_beginmodule(L, TOLUA_CAST "unit"); { - tolua_function(L, TOLUA_CAST "__tostring", &tolua_unit_tostring); - tolua_function(L, TOLUA_CAST "create", &tolua_unit_create); - tolua_function(L, TOLUA_CAST "destroy", &tolua_unit_destroy); + tolua_function(L, TOLUA_CAST "__tostring", tolua_unit_tostring); + tolua_function(L, TOLUA_CAST "create", tolua_unit_create); + tolua_function(L, TOLUA_CAST "destroy", tolua_unit_destroy); - tolua_variable(L, TOLUA_CAST "name", &tolua_unit_get_name, + tolua_variable(L, TOLUA_CAST "name", tolua_unit_get_name, tolua_unit_set_name); - tolua_variable(L, TOLUA_CAST "faction", &tolua_unit_get_faction, + tolua_variable(L, TOLUA_CAST "faction", tolua_unit_get_faction, tolua_unit_set_faction); tolua_variable(L, TOLUA_CAST "id", tolua_unit_get_id, tolua_unit_set_id); tolua_variable(L, TOLUA_CAST "group", tolua_unit_get_group, tolua_unit_set_group); tolua_variable(L, TOLUA_CAST "info", tolua_unit_get_info, tolua_unit_set_info); - tolua_variable(L, TOLUA_CAST "hp", &tolua_unit_get_hp, tolua_unit_set_hp); - tolua_variable(L, TOLUA_CAST "status", &tolua_unit_get_status, + tolua_variable(L, TOLUA_CAST "hp", tolua_unit_get_hp, tolua_unit_set_hp); + tolua_variable(L, TOLUA_CAST "status", tolua_unit_get_status, tolua_unit_set_status); - tolua_variable(L, TOLUA_CAST "familiar", &tolua_unit_get_familiar, + tolua_variable(L, TOLUA_CAST "familiar", tolua_unit_get_familiar, tolua_unit_set_familiar); - tolua_variable(L, TOLUA_CAST "weight", &tolua_unit_get_weight, 0); - tolua_variable(L, TOLUA_CAST "capacity", &tolua_unit_get_capacity, 0); + tolua_variable(L, TOLUA_CAST "weight", tolua_unit_get_weight, 0); + tolua_variable(L, TOLUA_CAST "capacity", tolua_unit_get_capacity, 0); - tolua_function(L, TOLUA_CAST "add_order", &tolua_unit_add_order); - tolua_function(L, TOLUA_CAST "clear_orders", &tolua_unit_clear_orders); - tolua_variable(L, TOLUA_CAST "orders", &tolua_unit_get_orders, 0); - - tolua_function(L, TOLUA_CAST "get_curse", &tolua_unit_get_curse); - tolua_function(L, TOLUA_CAST "has_attrib", &tolua_unit_has_attrib); + tolua_function(L, TOLUA_CAST "add_order", tolua_unit_add_order); + tolua_function(L, TOLUA_CAST "clear_orders", tolua_unit_clear_orders); +#ifdef TOLUA_ORDERS_CLOSURE + tolua_variable(L, TOLUA_CAST "orders", tolua_unit_get_orders, 0); +#endif + tolua_function(L, TOLUA_CAST "get_curse", tolua_unit_get_curse); + tolua_function(L, TOLUA_CAST "has_attrib", tolua_unit_has_attrib); /* key-attributes for named flags: */ - tolua_function(L, TOLUA_CAST "set_flag", &tolua_unit_set_flag); - tolua_function(L, TOLUA_CAST "get_flag", &tolua_unit_get_flag); - tolua_variable(L, TOLUA_CAST "guard", &tolua_unit_get_guard, - &tolua_unit_set_guard); - tolua_variable(L, TOLUA_CAST "flags", &tolua_unit_get_flags, - &tolua_unit_set_flags); - tolua_variable(L, TOLUA_CAST "age", &tolua_unit_get_age, + tolua_function(L, TOLUA_CAST "set_flag", tolua_unit_set_flag); + tolua_function(L, TOLUA_CAST "get_flag", tolua_unit_get_flag); + tolua_variable(L, TOLUA_CAST "guard", tolua_unit_get_guard, + tolua_unit_set_guard); + tolua_variable(L, TOLUA_CAST "flags", tolua_unit_get_flags, + tolua_unit_set_flags); + tolua_variable(L, TOLUA_CAST "age", tolua_unit_get_age, tolua_unit_set_age); /* items: */ - tolua_function(L, TOLUA_CAST "get_item", &tolua_unit_get_item); - tolua_function(L, TOLUA_CAST "add_item", &tolua_unit_add_item); - tolua_variable(L, TOLUA_CAST "items", &tolua_unit_get_items, 0); - tolua_function(L, TOLUA_CAST "get_pooled", &tolua_unit_get_pooled); - tolua_function(L, TOLUA_CAST "use_pooled", &tolua_unit_use_pooled); + tolua_function(L, TOLUA_CAST "get_item", tolua_unit_get_item); + tolua_function(L, TOLUA_CAST "add_item", tolua_unit_add_item); + tolua_variable(L, TOLUA_CAST "items", tolua_unit_get_items, 0); + tolua_function(L, TOLUA_CAST "get_pooled", tolua_unit_get_pooled); + tolua_function(L, TOLUA_CAST "use_pooled", tolua_unit_use_pooled); /* effects */ - tolua_function(L, TOLUA_CAST "get_potion", &tolua_unit_get_effect); + tolua_function(L, TOLUA_CAST "get_potion", tolua_unit_get_effect); /* skills: */ - tolua_function(L, TOLUA_CAST "get_skill", &tolua_unit_getskill); - tolua_function(L, TOLUA_CAST "eff_skill", &tolua_unit_effskill); - tolua_function(L, TOLUA_CAST "set_skill", &tolua_unit_setskill); + tolua_function(L, TOLUA_CAST "get_skill", tolua_unit_getskill); + tolua_function(L, TOLUA_CAST "eff_skill", tolua_unit_effskill); + tolua_function(L, TOLUA_CAST "set_skill", tolua_unit_setskill); - tolua_function(L, TOLUA_CAST "add_notice", &tolua_unit_addnotice); + tolua_function(L, TOLUA_CAST "add_notice", tolua_unit_addnotice); /* npc logic: */ - tolua_function(L, TOLUA_CAST "add_handler", &tolua_unit_addhandler); + tolua_function(L, TOLUA_CAST "add_handler", tolua_unit_addhandler); - tolua_variable(L, TOLUA_CAST "race_name", &tolua_unit_get_racename, - &tolua_unit_set_racename); - tolua_function(L, TOLUA_CAST "add_spell", &tolua_unit_addspell); - tolua_variable(L, TOLUA_CAST "spells", &tolua_unit_get_spells, 0); - tolua_function(L, TOLUA_CAST "cast_spell", &tolua_unit_castspell); + tolua_variable(L, TOLUA_CAST "race_name", tolua_unit_get_racename, + tolua_unit_set_racename); + tolua_function(L, TOLUA_CAST "add_spell", tolua_unit_addspell); + tolua_variable(L, TOLUA_CAST "spells", tolua_unit_get_spells, 0); + tolua_function(L, TOLUA_CAST "cast_spell", tolua_unit_castspell); - tolua_variable(L, TOLUA_CAST "magic", &tolua_unit_get_magic, + tolua_variable(L, TOLUA_CAST "magic", tolua_unit_get_magic, tolua_unit_set_magic); - tolua_variable(L, TOLUA_CAST "aura", &tolua_unit_get_aura, + tolua_variable(L, TOLUA_CAST "aura", tolua_unit_get_aura, tolua_unit_set_aura); - tolua_variable(L, TOLUA_CAST "building", &tolua_unit_get_building, + tolua_variable(L, TOLUA_CAST "building", tolua_unit_get_building, tolua_unit_set_building); - tolua_variable(L, TOLUA_CAST "ship", &tolua_unit_get_ship, + tolua_variable(L, TOLUA_CAST "ship", tolua_unit_get_ship, tolua_unit_set_ship); - tolua_variable(L, TOLUA_CAST "region", &tolua_unit_get_region, + tolua_variable(L, TOLUA_CAST "region", tolua_unit_get_region, tolua_unit_set_region); - tolua_variable(L, TOLUA_CAST "number", &tolua_unit_get_number, + tolua_variable(L, TOLUA_CAST "number", tolua_unit_get_number, tolua_unit_set_number); - tolua_variable(L, TOLUA_CAST "race", &tolua_unit_get_race, + tolua_variable(L, TOLUA_CAST "race", tolua_unit_get_race, tolua_unit_set_race); - tolua_variable(L, TOLUA_CAST "hp_max", &tolua_unit_get_hpmax, 0); - tolua_variable(L, TOLUA_CAST "aura_max", &tolua_unit_get_auramax, 0); + tolua_variable(L, TOLUA_CAST "hp_max", tolua_unit_get_hpmax, 0); + tolua_variable(L, TOLUA_CAST "aura_max", tolua_unit_get_auramax, 0); - tolua_function(L, TOLUA_CAST "show", &tolua_bufunit); + tolua_function(L, TOLUA_CAST "show", tolua_bufunit); } tolua_endmodule(L); } diff --git a/src/bindings.c b/src/bindings.c index 33d609ee0..7a24a3d07 100755 --- a/src/bindings.c +++ b/src/bindings.c @@ -114,20 +114,6 @@ int log_lua_error(lua_State * L) return 1; } -int tolua_orderlist_next(lua_State * L) -{ - order **order_ptr = (order **)lua_touserdata(L, lua_upvalueindex(1)); - order *ord = *order_ptr; - if (ord != NULL) { - char cmd[8192]; - write_order(ord, cmd, sizeof(cmd)); - tolua_pushstring(L, cmd); - *order_ptr = ord->next; - return 1; - } - return 0; -} - static int tolua_selist_iter(lua_State * L) { selist **qlp = (selist **)lua_touserdata(L, lua_upvalueindex(1)); diff --git a/src/bindings.h b/src/bindings.h index 5cb64a038..b5ebf916b 100755 --- a/src/bindings.h +++ b/src/bindings.h @@ -22,7 +22,6 @@ extern "C" { int tolua_sqlite_open(struct lua_State *L); int tolua_bindings_open(struct lua_State *L, const struct _dictionary_ *d); int tolua_itemlist_next(struct lua_State *L); - int tolua_orderlist_next(struct lua_State *L); int tolua_selist_push(struct lua_State *L, const char *list_type, const char *elem_type, struct selist *list); diff --git a/src/creport.c b/src/creport.c index 4ec7f9b0b..6b3c2cdca 100644 --- a/src/creport.c +++ b/src/creport.c @@ -376,13 +376,13 @@ static int cr_alliance(variant var, char *buffer, const void *userdata) static int cr_skill(variant var, char *buffer, const void *userdata) { - const faction *report = (const faction *)userdata; + const faction *f = (const faction *)userdata; skill_t sk = (skill_t)var.i; UNUSED_ARG(userdata); if (sk != NOSKILL) sprintf(buffer, "\"%s\"", translate(mkname("skill", skillnames[sk]), skillname(sk, - report->locale))); + f->locale))); else strcpy(buffer, "\"\""); return 0; @@ -391,13 +391,14 @@ static int cr_skill(variant var, char *buffer, const void *userdata) static int cr_order(variant var, char *buffer, const void *userdata) { order *ord = (order *)var.v; - UNUSED_ARG(userdata); + const faction *f = (const faction *)userdata; + if (ord != NULL) { char cmd[ORDERSIZE]; char *wp = buffer; const char *rp; - get_command(ord, cmd, sizeof(cmd)); + get_command(ord, f->locale, cmd, sizeof(cmd)); *wp++ = '\"'; for (rp = cmd; *rp;) { @@ -722,11 +723,11 @@ static void cr_output_ship_compat(FILE *F, const ship *sh, const unit *u, cr_output_ship(&strm, sh, u, fcaptain, f, r); } -static int stream_order(stream *out, const struct order *ord) { +static int stream_order(stream *out, const struct order *ord, const struct locale *lang) { const char *str; char ebuf[1025]; char obuf[1024]; - write_order(ord, obuf, sizeof(obuf)); + write_order(ord, lang, obuf, sizeof(obuf)); str = escape_string(obuf, ebuf, sizeof(ebuf)); if (str == ebuf) { ebuf[1024] = 0; @@ -779,6 +780,7 @@ void cr_output_unit(stream *out, const region * r, const faction * f, const faction *fother; const char *prefix; bool allied; + const struct locale *lang = f->locale; assert(u && u->number); assert(u->region == r); /* TODO: if this holds true, then why did we pass in r? */ @@ -787,7 +789,7 @@ void cr_output_unit(stream *out, const region * r, const faction * f, stream_printf(out, "EINHEIT %d\n", u->no); stream_printf(out, "\"%s\";Name\n", unit_getname(u)); - str = u_description(u, f->locale); + str = u_description(u, lang); if (str) { stream_printf(out, "\"%s\";Beschr\n", str); } @@ -833,7 +835,7 @@ void cr_output_unit(stream *out, const region * r, const faction * f, prefix = raceprefix(u); if (prefix) { prefix = mkname("prefix", prefix); - stream_printf(out, "\"%s\";typprefix\n", translate(prefix, LOC(f->locale, + stream_printf(out, "\"%s\";typprefix\n", translate(prefix, LOC(lang, prefix))); } stream_printf(out, "%d;Anzahl\n", u->number); @@ -844,20 +846,20 @@ void cr_output_unit(stream *out, const region * r, const faction * f, if (u->faction == f && fval(u_race(u), RCF_SHAPESHIFTANY)) { const char *zRace = rc_name_s(u_race(u), NAME_PLURAL); stream_printf(out, "\"%s\";wahrerTyp\n", - translate(zRace, LOC(f->locale, zRace))); + translate(zRace, LOC(lang, zRace))); } } else { const race *irace = u_irace(u); const char *zRace = rc_name_s(irace, NAME_PLURAL); stream_printf(out, "\"%s\";Typ\n", - translate(zRace, LOC(f->locale, zRace))); + translate(zRace, LOC(lang, zRace))); if (u->faction == f && irace != u_race(u)) { assert(skill_enabled(SK_STEALTH) || !"we're resetting this on load, so.. ircase should never be used"); zRace = rc_name_s(u_race(u), NAME_PLURAL); stream_printf(out, "\"%s\";wahrerTyp\n", - translate(zRace, LOC(f->locale, zRace))); + translate(zRace, LOC(lang, zRace))); } } @@ -925,7 +927,7 @@ void cr_output_unit(stream *out, const region * r, const faction * f, for (ord = u->old_orders; ord; ord = ord->next) { /* this new order will replace the old defaults */ if (is_persistent(ord)) { - stream_order(out, ord); + stream_order(out, ord, lang); } } for (ord = u->orders; ord; ord = ord->next) { @@ -933,7 +935,7 @@ void cr_output_unit(stream *out, const region * r, const faction * f, if (u->old_orders && is_repeated(kwd)) continue; /* unit has defaults */ if (is_persistent(ord)) { - stream_order(out, ord); + stream_order(out, ord, lang); } } @@ -949,7 +951,7 @@ void cr_output_unit(stream *out, const region * r, const faction * f, } stream_printf(out, "%d %d;%s\n", u->number * level_days(sv->level), esk, translate(mkname("skill", skillnames[sk]), skillname(sk, - f->locale))); + lang))); } } @@ -963,8 +965,7 @@ void cr_output_unit(stream *out, const region * r, const faction * f, const spell *sp = mage->combatspells[i].sp; if (sp) { const char *name = - translate(mkname("spell", sp->sname), spell_name(sp, - f->locale)); + translate(mkname("spell", sp->sname), spell_name(sp, lang)); stream_printf(out, "KAMPFZAUBER %d\n", i); stream_printf(out, "\"%s\";name\n", name); stream_printf(out, "%d;level\n", mage->combatspells[i].level); @@ -999,7 +1000,7 @@ void cr_output_unit(stream *out, const region * r, const faction * f, pr = 1; stream_printf(out, "GEGENSTAENDE\n"); } - stream_printf(out, "%d;%s\n", in, translate(ic, LOC(f->locale, ic))); + stream_printf(out, "%d;%s\n", in, translate(ic, LOC(lang, ic))); } cr_output_curses(out, f, u, TYP_UNIT); diff --git a/src/kernel/command.c b/src/kernel/command.c index 912f21f7d..a6a036fe9 100644 --- a/src/kernel/command.c +++ b/src/kernel/command.c @@ -14,6 +14,7 @@ #include #include "command.h" +#include #include #include @@ -107,7 +108,7 @@ void do_command(const struct tnode *keys, struct unit *u, struct order *ord) init_order(ord); if (do_command_i(keys, u, ord) != E_TOK_SUCCESS) { char cmd[ORDERSIZE]; - get_command(ord, cmd, sizeof(cmd)); + get_command(ord, u->faction->locale, cmd, sizeof(cmd)); log_warning("%s failed command '%s'\n", unitname(u), cmd); } } diff --git a/src/kernel/jsonconf.test.c b/src/kernel/jsonconf.test.c index cb79cafc4..5408f8fb3 100644 --- a/src/kernel/jsonconf.test.c +++ b/src/kernel/jsonconf.test.c @@ -637,7 +637,7 @@ static void test_infinitive_from_config(CuTest *tc) { CuAssertIntEquals(tc, K_STUDY, get_keyword("LERNEN", lang)); ord = create_order(K_STUDY, lang, ""); - CuAssertStrEquals(tc, "LERNE", get_command(ord, buffer, sizeof(buffer))); + CuAssertStrEquals(tc, "LERNE", get_command(ord, lang, buffer, sizeof(buffer))); free_order(ord); cJSON_Delete(json); test_cleanup(); diff --git a/src/kernel/order.c b/src/kernel/order.c index bbb211cb3..154b3f451 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -31,13 +31,11 @@ #include # define ORD_KEYWORD(ord) (keyword_t)((ord)->command & 0xFFFF) -# define OD_LOCALE(odata) ((odata) ? (odata)->lang : NULL) # define OD_STRING(odata) ((odata) ? (odata)->_str : NULL) typedef struct order_data { const char *_str; int _refcount; - const struct locale *lang; } order_data; #include @@ -115,7 +113,7 @@ keyword_t getkeyword(const order * ord) * This is the inverse function to the parse_order command. Note that * keywords are expanded to their full length. */ -char* get_command(const order *ord, char *sbuffer, size_t size) { +char* get_command(const order *ord, const struct locale *lang, char *sbuffer, size_t size) { char *bufp = sbuffer; order_data *od; const char * text; @@ -144,7 +142,6 @@ char* get_command(const order *ord, char *sbuffer, size_t size) { od = load_data(ord->id); text = OD_STRING(od); if (kwd != NOKEYWORD) { - const struct locale *lang = OD_LOCALE(od); if (size > 0) { const char *str = (const char *)LOC(lang, keyword(kwd)); assert(str); @@ -217,13 +214,12 @@ void free_orders(order ** olist) } } -static char *mkdata(order_data **pdata, size_t len, const struct locale *lang, const char *str) +static char *mkdata(order_data **pdata, size_t len, const char *str) { order_data *data; char *result; data = malloc(sizeof(order_data) + len + 1); result = (char *)(data + 1); - data->lang = lang; data->_refcount = 0; data->_str = (len > 0) ? result : NULL; if (str) strcpy(result, str); @@ -231,7 +227,7 @@ static char *mkdata(order_data **pdata, size_t len, const struct locale *lang, c return result; } -static order_data *create_data(keyword_t kwd, const char *sptr, const struct locale *lang) +static order_data *create_data(keyword_t kwd, const char *sptr) { const char *s = sptr; order_data *data; @@ -241,17 +237,17 @@ static order_data *create_data(keyword_t kwd, const char *sptr, const struct loc /* orders with no parameter, only one order_data per order required */ if (kwd != NOKEYWORD && *sptr == 0) { - mkdata(&data, 0, lang, NULL); + mkdata(&data, 0, NULL); data->_refcount = 1; return data; } - mkdata(&data, s ? strlen(s) : 0, lang, s); + mkdata(&data, s ? strlen(s) : 0, s); data->_refcount = 1; return data; } static order *create_order_i(order *ord, keyword_t kwd, const char *sptr, bool persistent, - bool noerror, const struct locale *lang) + bool noerror) { order_data *od; @@ -279,7 +275,7 @@ static order *create_order_i(order *ord, keyword_t kwd, const char *sptr, bool p while (isspace(*(unsigned char *)sptr)) ++sptr; - od = create_data(kwd, sptr, lang); + od = create_data(kwd, sptr); ord->id = add_data(od); release_data(od); @@ -341,7 +337,7 @@ order *create_order(keyword_t kwd, const struct locale * lang, zBuffer[0] = 0; } ord = (order *)malloc(sizeof(order)); - return create_order_i(ord, kwd, zBuffer, false, false, lang); + return create_order_i(ord, kwd, zBuffer, false, false); } order *parse_order(const char *s, const struct locale * lang) @@ -373,7 +369,7 @@ order *parse_order(const char *s, const struct locale * lang) } if (kwd != NOKEYWORD) { order *ord = (order *)malloc(sizeof(order)); - return create_order_i(ord, kwd, sptr, persistent, noerror, lang); + return create_order_i(ord, kwd, sptr, persistent, noerror); } } return NULL; @@ -529,7 +525,7 @@ bool is_silent(const order * ord) return (ord->command & CMD_QUIET) != 0; } -char *write_order(const order * ord, char *buffer, size_t size) +char *write_order(const order * ord, const struct locale *lang, char *buffer, size_t size) { if (ord == 0) { buffer[0] = 0; @@ -544,7 +540,7 @@ char *write_order(const order * ord, char *buffer, size_t size) release_data(od); } else { - get_command(ord, buffer, size); + get_command(ord, lang, buffer, size); } } return buffer; diff --git a/src/kernel/order.h b/src/kernel/order.h index f26174ee4..916055379 100644 --- a/src/kernel/order.h +++ b/src/kernel/order.h @@ -21,6 +21,8 @@ extern "C" { #endif + struct locale; + /* Encapsulation of an order * * This structure contains one order given by a unit. These used to be @@ -57,14 +59,16 @@ extern "C" { /* access functions for orders */ keyword_t getkeyword(const order * ord); void set_order(order ** destp, order * src); - char* get_command(const order *ord, char *buffer, size_t size); + char* get_command(const order *ord, const struct locale *lang, + char *buffer, size_t size); bool is_persistent(const order * ord); bool is_silent(const order * ord); bool is_exclusive(const order * ord); bool is_repeated(keyword_t kwd); bool is_long(keyword_t kwd); - char *write_order(const order * ord, char *buffer, size_t size); + char *write_order(const order * ord, const struct locale *lang, + char *buffer, size_t size); keyword_t init_order(const struct order *ord); void close_orders(void); diff --git a/src/kernel/order.test.c b/src/kernel/order.test.c index e1656efc9..675cd90cf 100644 --- a/src/kernel/order.test.c +++ b/src/kernel/order.test.c @@ -20,7 +20,7 @@ static void test_create_order(CuTest *tc) { ord = create_order(K_MOVE, lang, "NORTH"); CuAssertPtrNotNull(tc, ord); CuAssertIntEquals(tc, K_MOVE, getkeyword(ord)); - CuAssertStrEquals(tc, "move NORTH", get_command(ord, cmd, sizeof(cmd))); + CuAssertStrEquals(tc, "move NORTH", get_command(ord, lang, cmd, sizeof(cmd))); CuAssertIntEquals(tc, K_MOVE, init_order(ord)); CuAssertStrEquals(tc, "NORTH", getstrtoken()); @@ -40,7 +40,7 @@ static void test_parse_order(CuTest *tc) { CuAssertPtrNotNull(tc, ord); CuAssertIntEquals(tc, K_MOVE, ord->command); CuAssertIntEquals(tc, K_MOVE, getkeyword(ord)); - CuAssertStrEquals(tc, "move NORTH", get_command(ord, cmd, sizeof(cmd))); + CuAssertStrEquals(tc, "move NORTH", get_command(ord, lang, cmd, sizeof(cmd))); CuAssertIntEquals(tc, K_MOVE, init_order(ord)); CuAssertStrEquals(tc, "NORTH", getstrtoken()); @@ -98,7 +98,7 @@ static void test_parse_make(CuTest *tc) { ord = parse_order("M hurrdurr", lang); CuAssertPtrNotNull(tc, ord); CuAssertIntEquals(tc, K_MAKE, getkeyword(ord)); - CuAssertStrEquals(tc, "MAKE hurrdurr", get_command(ord, cmd, sizeof(cmd))); + CuAssertStrEquals(tc, "MAKE hurrdurr", get_command(ord, lang, cmd, sizeof(cmd))); CuAssertIntEquals(tc, K_MAKE, init_order(ord)); CuAssertStrEquals(tc, "hurrdurr", getstrtoken()); @@ -121,7 +121,7 @@ static void test_parse_make_temp(CuTest *tc) { ord = parse_order("M T herp", lang); CuAssertPtrNotNull(tc, ord); CuAssertIntEquals(tc, K_MAKETEMP, getkeyword(ord)); - CuAssertStrEquals(tc, "MAKETEMP herp", get_command(ord, cmd, sizeof(cmd))); + CuAssertStrEquals(tc, "MAKETEMP herp", get_command(ord, lang, cmd, sizeof(cmd))); CuAssertIntEquals(tc, K_MAKETEMP, init_order(ord)); CuAssertStrEquals(tc, "herp", getstrtoken()); @@ -144,7 +144,7 @@ static void test_parse_maketemp(CuTest *tc) { ord = parse_order("MAKET herp", lang); CuAssertPtrNotNull(tc, ord); - CuAssertStrEquals(tc, "MAKETEMP herp", get_command(ord, cmd, sizeof(cmd))); + CuAssertStrEquals(tc, "MAKETEMP herp", get_command(ord, lang, cmd, sizeof(cmd))); CuAssertIntEquals(tc, K_MAKETEMP, getkeyword(ord)); CuAssertIntEquals(tc, K_MAKETEMP, init_order(ord)); CuAssertStrEquals(tc, "herp", getstrtoken()); @@ -213,13 +213,13 @@ static void test_get_command(CuTest *tc) { test_setup(); lang = test_create_locale(); ord = create_order(K_MAKE, lang, "iron"); - CuAssertStrEquals(tc, "make iron", get_command(ord, buf, sizeof(buf))); + CuAssertStrEquals(tc, "make iron", get_command(ord, lang, buf, sizeof(buf))); ord->command |= CMD_QUIET; - CuAssertStrEquals(tc, "!make iron", get_command(ord, buf, sizeof(buf))); + CuAssertStrEquals(tc, "!make iron", get_command(ord, lang, buf, sizeof(buf))); ord->command |= CMD_PERSIST; - CuAssertStrEquals(tc, "!@make iron", get_command(ord, buf, sizeof(buf))); + CuAssertStrEquals(tc, "!@make iron", get_command(ord, lang, buf, sizeof(buf))); ord->command = K_MAKE | CMD_PERSIST; - CuAssertStrEquals(tc, "@make iron", get_command(ord, buf, sizeof(buf))); + CuAssertStrEquals(tc, "@make iron", get_command(ord, lang, buf, sizeof(buf))); free_order(ord); test_cleanup(); } diff --git a/src/kernel/save.c b/src/kernel/save.c index aa09a27be..133472d4f 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -379,7 +379,7 @@ static void writeorder(gamedata *data, const struct order *ord, const struct locale *lang) { char obuf[1024]; - write_order(ord, obuf, sizeof(obuf)); + write_order(ord, lang, obuf, sizeof(obuf)); if (obuf[0]) WRITE_STR(data->store, obuf); } diff --git a/src/keyword.test.c b/src/keyword.test.c index 75c31904a..68858367a 100644 --- a/src/keyword.test.c +++ b/src/keyword.test.c @@ -36,7 +36,7 @@ static void test_infinitive(CuTest *tc) { CuAssertIntEquals(tc, K_STUDY, get_keyword("LERNEN", lang)); ord = create_order(K_STUDY, lang, ""); - CuAssertStrEquals(tc, "LERNE", get_command(ord, buffer, sizeof(buffer))); + CuAssertStrEquals(tc, "LERNE", get_command(ord, lang, buffer, sizeof(buffer))); free_order(ord); test_cleanup(); } diff --git a/src/laws.c b/src/laws.c index f60af7f15..7da40f83f 100644 --- a/src/laws.c +++ b/src/laws.c @@ -968,7 +968,7 @@ int quit_cmd(unit * u, struct order *ord) } else { char buffer[64]; - write_order(ord, buffer, sizeof(buffer)); + write_order(ord, f->locale, buffer, sizeof(buffer)); cmistake(u, ord, 86, MSG_EVENT); log_warning("QUIT with illegal password for faction %s: %s\n", itoa36(f->no), buffer); } diff --git a/src/monsters.test.c b/src/monsters.test.c index 51f122b87..e43ed65cc 100644 --- a/src/monsters.test.c +++ b/src/monsters.test.c @@ -31,12 +31,12 @@ extern void plan_monsters(struct faction *f); extern int monster_attacks(unit * monster, bool rich_only); -static order *find_order(const char *expected, const unit *unit) +static order *find_order(const char *expected, const unit *u) { char cmd[32]; order *ord; - for (ord = unit->orders; ord; ord = ord->next) { - if (strcmp(expected, get_command(ord, cmd, sizeof(cmd))) == 0) { + for (ord = u->orders; ord; ord = ord->next) { + if (strcmp(expected, get_command(ord, u->faction->locale, cmd, sizeof(cmd))) == 0) { return ord; } } diff --git a/src/report.c b/src/report.c index c23a9466c..68e75661e 100644 --- a/src/report.c +++ b/src/report.c @@ -1389,7 +1389,8 @@ static int report_template(const char *filename, report_context * ctx, const char *bom) { const resource_type *rsilver = get_resourcetype(R_SILVER); - faction *f = ctx->f; + const faction *f = ctx->f; + const struct locale *lang = f->locale; region *r; FILE *F = fopen(filename, "w"); stream strm = { 0 }, *out = &strm; @@ -1408,11 +1409,11 @@ report_template(const char *filename, report_context * ctx, const char *bom) } newline(out); - rps_nowrap(out, LOC(f->locale, "nr_template")); + rps_nowrap(out, LOC(lang, "nr_template")); newline(out); newline(out); - sprintf(buf, "%s %s \"password\"", LOC(f->locale, parameters[P_FACTION]), itoa36(f->no)); + sprintf(buf, "%s %s \"password\"", LOC(lang, parameters[P_FACTION]), itoa36(f->no)); rps_nowrap(out, buf); newline(out); newline(out); @@ -1439,12 +1440,12 @@ report_template(const char *filename, report_context * ctx, const char *bom) adjust_coordinates(f, &nx, &ny, pl); newline(out); if (pl && pl->id != 0) { - sprintf(buf, "%s %d,%d,%d ; %s", LOC(f->locale, - parameters[P_REGION]), nx, ny, pl->id, rname(r, f->locale)); + sprintf(buf, "%s %d,%d,%d ; %s", LOC(lang, + parameters[P_REGION]), nx, ny, pl->id, rname(r, lang)); } else { - sprintf(buf, "%s %d,%d ; %s", LOC(f->locale, parameters[P_REGION]), - nx, ny, rname(r, f->locale)); + sprintf(buf, "%s %d,%d ; %s", LOC(lang, parameters[P_REGION]), + nx, ny, rname(r, lang)); } rps_nowrap(out, buf); newline(out); @@ -1505,7 +1506,7 @@ report_template(const char *filename, report_context * ctx, const char *bom) for (ord = u->old_orders; ord; ord = ord->next) { /* this new order will replace the old defaults */ strcpy(buf, " "); - write_order(ord, buf + 2, sizeof(buf) - 2); + write_order(ord, lang, buf + 2, sizeof(buf) - 2); rps_nowrap(out, buf); newline(out); } @@ -1515,7 +1516,7 @@ report_template(const char *filename, report_context * ctx, const char *bom) continue; /* unit has defaults */ if (is_persistent(ord)) { strcpy(buf, " "); - write_order(ord, buf + 2, sizeof(buf) - 2); + write_order(ord, lang, buf + 2, sizeof(buf) - 2); rps_nowrap(out, buf); newline(out); } @@ -1527,7 +1528,7 @@ report_template(const char *filename, report_context * ctx, const char *bom) } } newline(out); - strlcpy(buf, LOC(f->locale, parameters[P_NEXT]), sizeof(buf)); + strlcpy(buf, LOC(lang, parameters[P_NEXT]), sizeof(buf)); rps_nowrap(out, buf); newline(out); fstream_done(&strm); diff --git a/src/reports.c b/src/reports.c index 1182f89c9..cbc534162 100644 --- a/src/reports.c +++ b/src/reports.c @@ -266,14 +266,14 @@ report_item(const unit * owner, const item * i, const faction * viewer, } #define ORDERS_IN_NR 1 -static size_t buforder(char *buffer, size_t size, const order * ord, int mode) +static size_t buforder(char *buffer, size_t size, const order * ord, const struct locale *lang, int mode) { char *bufp = buffer; bufp = STRLCPY(bufp, ", \"", size); if (mode < ORDERS_IN_NR) { char cmd[ORDERSIZE]; - get_command(ord, cmd, sizeof(cmd)); + get_command(ord, lang, cmd, sizeof(cmd)); bufp = STRLCPY(bufp, cmd, size); } else { @@ -498,6 +498,7 @@ bufunit(const faction * f, const unit * u, unsigned int indent, seen_mode mode, char *bufp = buf; int result = 0; item results[MAX_INVENTORY]; + const struct locale *lang = f->locale; assert(f); bufp = STRLCPY(bufp, unitname(u), size); @@ -514,7 +515,7 @@ bufunit(const faction * f, const unit * u, unsigned int indent, seen_mode mode, } if (getarnt) { bufp = STRLCPY(bufp, ", ", size); - bufp = STRLCPY(bufp, LOC(f->locale, "anonymous"), size); + bufp = STRLCPY(bufp, LOC(lang, "anonymous"), size); } else if (u->attribs) { faction *otherf = get_otherfaction(u); @@ -527,7 +528,7 @@ bufunit(const faction * f, const unit * u, unsigned int indent, seen_mode mode, else { if (getarnt) { bufp = STRLCPY(bufp, ", ", size); - bufp = STRLCPY(bufp, LOC(f->locale, "anonymous"), size); + bufp = STRLCPY(bufp, LOC(lang, "anonymous"), size); } else { if (u->attribs && alliedunit(u, f, HELP_FSTEALTH)) { @@ -562,7 +563,7 @@ bufunit(const faction * f, const unit * u, unsigned int indent, seen_mode mode, bufp = STRLCPY(bufp, pzTmp, size); if (u->faction == f && fval(u_race(u), RCF_SHAPESHIFTANY)) { bufp = STRLCPY(bufp, " (", size); - bufp = STRLCPY(bufp, racename(f->locale, u, u_race(u)), size); + bufp = STRLCPY(bufp, racename(lang, u, u_race(u)), size); if (size > 1) { strcpy(bufp++, ")"); --size; @@ -571,10 +572,10 @@ bufunit(const faction * f, const unit * u, unsigned int indent, seen_mode mode, } else { const race *irace = u_irace(u); - bufp = STRLCPY(bufp, racename(f->locale, u, irace), size); + bufp = STRLCPY(bufp, racename(lang, u, irace), size); if (u->faction == f && irace != u_race(u)) { bufp = STRLCPY(bufp, " (", size); - bufp = STRLCPY(bufp, racename(f->locale, u, u_race(u)), size); + bufp = STRLCPY(bufp, racename(lang, u, u_race(u)), size); if (size > 1) { strcpy(bufp++, ")"); --size; @@ -584,15 +585,15 @@ bufunit(const faction * f, const unit * u, unsigned int indent, seen_mode mode, if (fval(u, UFL_HERO) && (u->faction == f || omniscient(f))) { bufp = STRLCPY(bufp, ", ", size); - bufp = STRLCPY(bufp, LOC(f->locale, "hero"), size); + bufp = STRLCPY(bufp, LOC(lang, "hero"), size); } /* status */ if (u->number && (u->faction == f || isbattle)) { const char *c = hp_status(u); - c = c ? LOC(f->locale, c) : 0; + c = c ? LOC(lang, c) : 0; bufp = STRLCPY(bufp, ", ", size); - bufp += report_status(u, f->locale, bufp, size); + bufp += report_status(u, lang, bufp, size); if (c || fval(u, UFL_HUNGER)) { bufp = STRLCPY(bufp, " (", size); if (c) { @@ -602,7 +603,7 @@ bufunit(const faction * f, const unit * u, unsigned int indent, seen_mode mode, if (c) { bufp = STRLCPY(bufp, ", ", size); } - bufp = STRLCPY(bufp, LOC(f->locale, "unit_hungers"), size); + bufp = STRLCPY(bufp, LOC(lang, "unit_hungers"), size); } if (size > 1) { strcpy(bufp++, ")"); @@ -612,7 +613,7 @@ bufunit(const faction * f, const unit * u, unsigned int indent, seen_mode mode, } if (is_guard(u)) { bufp = STRLCPY(bufp, ", ", size); - bufp = STRLCPY(bufp, LOC(f->locale, "unit_guards"), size); + bufp = STRLCPY(bufp, LOC(lang, "unit_guards"), size); } if ((b = usiege(u)) != NULL) { @@ -624,7 +625,7 @@ bufunit(const faction * f, const unit * u, unsigned int indent, seen_mode mode, if (u->faction == f) { skill *sv; for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { - size_t bytes = spskill(bufp, size, f->locale, u, sv, &dh, 1); + size_t bytes = spskill(bufp, size, lang, u, sv, &dh, 1); assert(bytes <= INT_MAX); if (wrptr(&bufp, &size, (int)bytes) != 0) WARN_STATIC_BUFFER(); @@ -651,7 +652,7 @@ bufunit(const faction * f, const unit * u, unsigned int indent, seen_mode mode, bufp = STRLCPY(bufp, ", ", size); if (!dh) { - result = snprintf(bufp, size, "%s: ", LOC(f->locale, "nr_inventory")); + result = snprintf(bufp, size, "%s: ", LOC(lang, "nr_inventory")); if (wrptr(&bufp, &size, result) != 0) WARN_STATIC_BUFFER(); dh = 1; @@ -681,7 +682,7 @@ bufunit(const faction * f, const unit * u, unsigned int indent, seen_mode mode, if (sbe->level <= maxlevel) { int result = 0; if (!header) { - result = snprintf(bufp, size, ", %s: ", LOC(f->locale, "nr_spells")); + result = snprintf(bufp, size, ", %s: ", LOC(lang, "nr_spells")); header = 1; } else { @@ -691,7 +692,7 @@ bufunit(const faction * f, const unit * u, unsigned int indent, seen_mode mode, WARN_STATIC_BUFFER(); } /* TODO: no need to deref the spellref here (spref->name is good) */ - bufp = STRLCPY(bufp, spell_name(sbe->sp, f->locale), size); + bufp = STRLCPY(bufp, spell_name(sbe->sp, lang), size); } } @@ -701,7 +702,7 @@ bufunit(const faction * f, const unit * u, unsigned int indent, seen_mode mode, } if (i != MAXCOMBATSPELLS) { int result = - snprintf(bufp, size, ", %s: ", LOC(f->locale, "nr_combatspells")); + snprintf(bufp, size, ", %s: ", LOC(lang, "nr_combatspells")); if (wrptr(&bufp, &size, result) != 0) WARN_STATIC_BUFFER(); @@ -717,7 +718,7 @@ bufunit(const faction * f, const unit * u, unsigned int indent, seen_mode mode, sp = get_combatspell(u, i); if (sp) { int sl = get_combatspelllevel(u, i); - bufp = STRLCPY(bufp, spell_name(sp, u->faction->locale), size); + bufp = STRLCPY(bufp, spell_name(sp, lang), size); if (sl > 0) { result = snprintf(bufp, size, " (%d)", sl); if (wrptr(&bufp, &size, result) != 0) @@ -725,7 +726,7 @@ bufunit(const faction * f, const unit * u, unsigned int indent, seen_mode mode, } } else { - bufp = STRLCPY(bufp, LOC(f->locale, "nr_nospells"), size); + bufp = STRLCPY(bufp, LOC(lang, "nr_nospells"), size); } } } @@ -737,7 +738,7 @@ bufunit(const faction * f, const unit * u, unsigned int indent, seen_mode mode, keyword_t kwd = getkeyword(ord); if (is_repeated(kwd)) { if (printed < ORDERS_IN_NR) { - int result = (int)buforder(bufp, size, ord, printed++); + int result = (int)buforder(bufp, size, ord, u->faction->locale, printed++); if (wrptr(&bufp, &size, result) != 0) WARN_STATIC_BUFFER(); } @@ -750,7 +751,7 @@ bufunit(const faction * f, const unit * u, unsigned int indent, seen_mode mode, keyword_t kwd = getkeyword(ord); if (is_repeated(kwd)) { if (printed < ORDERS_IN_NR) { - int result = (int)buforder(bufp, size, ord, printed++); + int result = (int)buforder(bufp, size, ord, lang, printed++); if (wrptr(&bufp, &size, result) != 0) WARN_STATIC_BUFFER(); } @@ -762,7 +763,7 @@ bufunit(const faction * f, const unit * u, unsigned int indent, seen_mode mode, } i = 0; - str = u_description(u, f->locale); + str = u_description(u, lang); if (str) { bufp = STRLCPY(bufp, "; ", size); bufp = STRLCPY(bufp, str, size); @@ -1979,13 +1980,15 @@ static void eval_race(struct opstack **stack, const void *userdata) static void eval_order(struct opstack **stack, const void *userdata) { /* order -> string */ + const faction *f = (const faction *)userdata; const struct order *ord = (const struct order *)opop(stack).v; char buf[4096]; size_t len; variant var; + const struct locale *lang = f ? f->locale : default_locale; UNUSED_ARG(userdata); - write_order(ord, buf, sizeof(buf)); + write_order(ord, lang, buf, sizeof(buf)); len = strlen(buf); var.v = strcpy(balloc(len + 1), buf); opush(stack, var); @@ -1993,8 +1996,8 @@ static void eval_order(struct opstack **stack, const void *userdata) static void eval_resources(struct opstack **stack, const void *userdata) { /* order -> string */ - const faction *report = (const faction *)userdata; - const struct locale *lang = report ? report->locale : default_locale; + const faction *f = (const faction *)userdata; + const struct locale *lang = f ? f->locale : default_locale; const struct resource *res = (const struct resource *)opop(stack).v; char buf[1024]; /* but we only use about half of this */ size_t size = sizeof(buf) - 1; From 710fcd0a08866ca94d2b3f5b2f75fe2ffb7a765c Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 8 Oct 2017 18:41:59 +0200 Subject: [PATCH 04/43] do not use a list to store several million entries. --- clibs | 2 +- src/kernel/order.c | 46 +++++++++++++++++++++++++++++++--------------- 2 files changed, 32 insertions(+), 16 deletions(-) diff --git a/clibs b/clibs index 147584ad7..7eb6713ff 160000 --- a/clibs +++ b/clibs @@ -1 +1 @@ -Subproject commit 147584ad70b220abf6a4e97ca76e785729b9ac32 +Subproject commit 7eb6713ff73d29e67d2bc87fb037a9c738c2c512 diff --git a/src/kernel/order.c b/src/kernel/order.c index 154b3f451..36211ccc4 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -38,24 +38,39 @@ typedef struct order_data { int _refcount; } order_data; -#include +#include -static selist * orders; +static critbit_tree cb_orders = { 0 }; +static int auto_id = 0; + +struct cb_entry { + int id; + order_data *data; +}; order_data *load_data(int id) { + void * match; + if (id > 0) { - order_data * od = (order_data *)selist_get(orders, id - 1); - ++od->_refcount; - return od; + if (cb_find_prefix(&cb_orders, &id, sizeof(id), &match, 1, 0) > 0) { + struct cb_entry *ent = (struct cb_entry *)match; + order_data * od = ent->data; + ++od->_refcount; + return od; + } } return NULL; } -int add_data(order_data *od) { +int save_data(order_data *od) { if (od->_str) { + struct cb_entry ent; + ++od->_refcount; - selist_push(&orders, od); - return selist_length(orders); + ent.id = ++auto_id; + ent.data = od; + cb_insert(&cb_orders, &ent, sizeof(ent)); + return ent.id; } return 0; } @@ -69,18 +84,19 @@ static void release_data(order_data * data) } } -void free_data_cb(void *entry) { - order_data *od = (order_data *)entry; +int free_data_cb(const void *match, const void *key, size_t keylen, void *udata) { + struct cb_entry * ent = (struct cb_entry *)match; + order_data *od = ent->data; if (od->_refcount > 1) { - log_error("refcount=%d for order %s", od->_refcount, od->_str); + log_error("refcount=%d for order %d, %s", od->_refcount, ent->id, od->_str); } release_data(od); + return 0; } void free_data(void) { - selist_foreach(orders, free_data_cb); - selist_free(orders); - orders = NULL; + cb_foreach(&cb_orders, NULL, 0, free_data_cb, NULL); + cb_clear(&cb_orders); } void replace_order(order ** dlist, order * orig, const order * src) @@ -276,7 +292,7 @@ static order *create_order_i(order *ord, keyword_t kwd, const char *sptr, bool p while (isspace(*(unsigned char *)sptr)) ++sptr; od = create_data(kwd, sptr); - ord->id = add_data(od); + ord->id = save_data(od); release_data(od); return ord; From 905873e48bd5d181bb73694764c408fd35b2ce69 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 8 Oct 2017 18:49:14 +0200 Subject: [PATCH 05/43] fix gcc build --- src/kernel/order.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernel/order.c b/src/kernel/order.c index 36211ccc4..e11b652ae 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -580,7 +580,7 @@ keyword_t init_order(const struct order *ord) } else { if (parser_od) { - // TODO: warning + /* TODO: warning */ release_data(parser_od); } parser_od = load_data(ord->id); From f62c0866e395d5c5eb165e749d2a4e57b35b337d Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 9 Oct 2017 18:25:57 +0200 Subject: [PATCH 06/43] WIP: optimized study orders, failing 15 study tests --- src/kernel/order.c | 76 ++++++++++++++++++++++------------------------ 1 file changed, 37 insertions(+), 39 deletions(-) diff --git a/src/kernel/order.c b/src/kernel/order.c index e11b652ae..4124651c9 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -62,10 +62,9 @@ order_data *load_data(int id) { return NULL; } -int save_data(order_data *od) { +int save_data(keyword_t kwd, order_data *od) { if (od->_str) { struct cb_entry ent; - ++od->_refcount; ent.id = ++auto_id; ent.data = od; @@ -131,7 +130,7 @@ keyword_t getkeyword(const order * ord) */ char* get_command(const order *ord, const struct locale *lang, char *sbuffer, size_t size) { char *bufp = sbuffer; - order_data *od; + order_data *od = NULL; const char * text; keyword_t kwd = ORD_KEYWORD(ord); int bytes; @@ -155,8 +154,14 @@ char* get_command(const order *ord, const struct locale *lang, char *sbuffer, si } } - od = load_data(ord->id); - text = OD_STRING(od); + if (ord->id < 0) { + skill_t sk = (skill_t)(100-ord->id); + assert(kwd == K_STUDY && sk != SK_MAGIC); + text = skillname(sk, lang); + } else { + od = load_data(ord->id); + text = OD_STRING(od); + } if (kwd != NOKEYWORD) { if (size > 0) { const char *str = (const char *)LOC(lang, keyword(kwd)); @@ -187,7 +192,9 @@ char* get_command(const order *ord, const struct locale *lang, char *sbuffer, si } } } - release_data(od); + if (od) { + release_data(od); + } if (size > 0) *bufp = 0; return sbuffer; } @@ -236,54 +243,48 @@ static char *mkdata(order_data **pdata, size_t len, const char *str) char *result; data = malloc(sizeof(order_data) + len + 1); result = (char *)(data + 1); - data->_refcount = 0; + data->_refcount = 1; data->_str = (len > 0) ? result : NULL; if (str) strcpy(result, str); if (pdata) *pdata = data; return result; } -static order_data *create_data(keyword_t kwd, const char *sptr) +static int create_data(keyword_t kwd, const char *s, + const struct locale *lang) { - const char *s = sptr; order_data *data; + int id; - if (kwd != NOKEYWORD) - s = (*sptr) ? sptr : NULL; + assert(kwd!=NOKEYWORD); - /* orders with no parameter, only one order_data per order required */ - if (kwd != NOKEYWORD && *sptr == 0) { - mkdata(&data, 0, NULL); - data->_refcount = 1; - return data; + if (!s || *s == 0) { + return 0; } + if (kwd==K_STUDY) { + const char * sptr = s; + skill_t sk = get_skill(parse_token_depr(&sptr), lang); + if (sk != SK_MAGIC && sk != NOSKILL) { + return ((int)sk)-100; + } + } + /* TODO: between mkdata and release_data, this object is very + * short-lived. */ mkdata(&data, s ? strlen(s) : 0, s); - data->_refcount = 1; - return data; + id = save_data(kwd, data); + release_data(data); + return id; } -static order *create_order_i(order *ord, keyword_t kwd, const char *sptr, bool persistent, - bool noerror) +static order *create_order_i(order *ord, const struct locale *lang, + keyword_t kwd, const char *sptr, bool persistent, bool noerror) { - order_data *od; - assert(ord); if (kwd == NOKEYWORD || keyword_disabled(kwd)) { log_error("trying to create an order for disabled keyword %s.", keyword(kwd)); return NULL; } - /* if this is just nonsense, then we skip it. */ - if (lomem) { - switch (kwd) { - case K_KOMMENTAR: - case NOKEYWORD: - return NULL; - default: - break; - } - } - ord->command = (int)kwd; if (persistent) ord->command |= CMD_PERSIST; if (noerror) ord->command |= CMD_QUIET; @@ -291,10 +292,7 @@ static order *create_order_i(order *ord, keyword_t kwd, const char *sptr, bool p while (isspace(*(unsigned char *)sptr)) ++sptr; - od = create_data(kwd, sptr); - ord->id = save_data(od); - release_data(od); - + ord->id = create_data(kwd, sptr, lang); return ord; } @@ -353,7 +351,7 @@ order *create_order(keyword_t kwd, const struct locale * lang, zBuffer[0] = 0; } ord = (order *)malloc(sizeof(order)); - return create_order_i(ord, kwd, zBuffer, false, false); + return create_order_i(ord, lang, kwd, zBuffer, false, false); } order *parse_order(const char *s, const struct locale * lang) @@ -385,7 +383,7 @@ order *parse_order(const char *s, const struct locale * lang) } if (kwd != NOKEYWORD) { order *ord = (order *)malloc(sizeof(order)); - return create_order_i(ord, kwd, sptr, persistent, noerror); + return create_order_i(ord, lang, kwd, sptr, persistent, noerror); } } return NULL; From fc80f2bd8c5c6e05df7270ff8bab6a6445c3192e Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 9 Oct 2017 20:33:47 +0200 Subject: [PATCH 07/43] hackish optimization for STUDY orders --- src/battle.c | 2 +- src/bind_order.c | 2 +- src/economy.c | 24 +++++++++--------- src/give.c | 2 +- src/items.c | 2 +- src/kernel/alliance.c | 10 ++++---- src/kernel/build.c | 2 +- src/kernel/command.c | 2 +- src/kernel/config.test.c | 24 +++++++++--------- src/kernel/order.c | 31 ++++++++++++++++++----- src/kernel/order.h | 3 ++- src/kernel/order.test.c | 52 +++++++++++++++++++++++++++++++++----- src/laws.c | 54 ++++++++++++++++++++-------------------- src/magic.c | 2 +- src/move.c | 22 ++++++++-------- src/move.test.c | 2 +- src/piracy.c | 4 +-- src/renumber.c | 2 +- src/spy.c | 8 +++--- src/study.c | 18 +++++++------- 20 files changed, 164 insertions(+), 104 deletions(-) diff --git a/src/battle.c b/src/battle.c index ad1c0f8da..8139456cc 100644 --- a/src/battle.c +++ b/src/battle.c @@ -3841,7 +3841,7 @@ static bool start_battle(region * r, battle ** bp) /* Ende Fehlerbehandlung Angreifer */ - init_order(ord); + init_order_depr(ord); /* attackierte Einheit ermitteln */ getunit(r, u->faction, &u2); diff --git a/src/bind_order.c b/src/bind_order.c index 84399deec..cfbe51d16 100644 --- a/src/bind_order.c +++ b/src/bind_order.c @@ -13,7 +13,7 @@ static int tolua_order_get_token(lua_State *L) { order *ord = (order *)tolua_tousertype(L, 1, 0); int n = (int)tolua_tonumber(L, 2, 0); const char * str = 0; - init_order(ord); + init_order_depr(ord); while (n-->0) { str = getstrtoken(); if (!str) { diff --git a/src/economy.c b/src/economy.c index 7c4b0efd3..1de4f7e4e 100644 --- a/src/economy.c +++ b/src/economy.c @@ -441,7 +441,7 @@ static void recruit(unit * u, struct order *ord, request ** recruitorders) const char *str; int n; - init_order(ord); + init_order_depr(ord); n = getint(); if (n <= 0) { syntax_error(u, ord); @@ -598,7 +598,7 @@ int give_control_cmd(unit * u, order * ord) unit *u2; const char *s; - init_order(ord); + init_order_depr(ord); getunit(r, u->faction, &u2); s = gettoken(token, sizeof(token)); @@ -657,7 +657,7 @@ static int forget_cmd(unit * u, order * ord) return 0; } - init_order(ord); + init_order_depr(ord); s = gettoken(token, sizeof(token)); sk = get_skill(s, u->faction->locale); @@ -1303,7 +1303,7 @@ int make_cmd(unit * u, struct order *ord) char ibuf[16]; keyword_t kwd; - kwd = init_order(ord); + kwd = init_order_depr(ord); assert(kwd == K_MAKE); s = gettoken(token, sizeof(token)); @@ -1582,7 +1582,7 @@ static void buy(unit * u, request ** buyorders, struct order *ord) /* Im Augenblick kann man nur 1 Produkt kaufen. expandbuying ist aber * schon daf�r ausger�stet, mehrere Produkte zu kaufen. */ - kwd = init_order(ord); + kwd = init_order_depr(ord); assert(kwd == K_BUY); n = getint(); if (n <= 0) { @@ -1896,7 +1896,7 @@ static bool sell(unit * u, request ** sellorders, struct order *ord) /* sellorders sind KEIN array, weil f�r alle items DIE SELBE resource * (das geld der region) aufgebraucht wird. */ - kwd = init_order(ord); + kwd = init_order_depr(ord); assert(kwd == K_SELL); s = gettoken(token, sizeof(token)); @@ -2287,7 +2287,7 @@ static void breed_cmd(unit * u, struct order *ord) } /* z�chte [] */ - (void)init_order(ord); + (void)init_order_depr(ord); s = gettoken(token, sizeof(token)); m = s ? atoip(s) : 0; @@ -2354,7 +2354,7 @@ static void research_cmd(unit * u, struct order *ord) region *r = u->region; keyword_t kwd; - kwd = init_order(ord); + kwd = init_order_depr(ord); assert(kwd == K_RESEARCH); if (effskill(u, SK_HERBALISM, 0) < 7) { @@ -2430,7 +2430,7 @@ static void steal_cmd(unit * u, struct order *ord, request ** stealorders) message * msg; keyword_t kwd; - kwd = init_order(ord); + kwd = init_order_depr(ord); assert(kwd == K_STEAL); assert(skill_enabled(SK_PERCEPTION) && skill_enabled(SK_STEALTH)); @@ -2568,7 +2568,7 @@ void entertain_cmd(unit * u, struct order *ord) static int entertainperlevel = 0; keyword_t kwd; - kwd = init_order(ord); + kwd = init_order_depr(ord); assert(kwd == K_ENTERTAIN); if (!entertainbase) { const char *str = config_get("entertain.base"); @@ -2778,7 +2778,7 @@ void tax_cmd(unit * u, struct order *ord, request ** taxorders) taxperlevel = config_get_int("taxing.perlevel", 0); } - kwd = init_order(ord); + kwd = init_order_depr(ord); assert(kwd == K_TAX); if (!humanoidrace(u_race(u)) && !is_monsters(u->faction)) { @@ -2847,7 +2847,7 @@ void loot_cmd(unit * u, struct order *ord, request ** lootorders) request *o; keyword_t kwd; - kwd = init_order(ord); + kwd = init_order_depr(ord); assert(kwd == K_LOOT); if (config_get_int("rules.enable_loot", 0) == 0 && !is_monsters(u->faction)) { diff --git a/src/give.c b/src/give.c index da75e56c5..84e2765a6 100644 --- a/src/give.c +++ b/src/give.c @@ -634,7 +634,7 @@ void give_cmd(unit * u, order * ord) message *msg; keyword_t kwd; - kwd = init_order(ord); + kwd = init_order_depr(ord); assert(kwd == K_GIVE); err = getunit(r, u->faction, &u2); s = gettoken(token, sizeof(token)); diff --git a/src/items.c b/src/items.c index 8a6328d91..fe59ffa15 100644 --- a/src/items.c +++ b/src/items.c @@ -47,7 +47,7 @@ static int use_studypotion(struct unit *u, const struct item_type *itype, int amount, struct order *ord) { - if (u->thisorder && init_order(u->thisorder) == K_STUDY) { + if (u->thisorder && init_order(u->thisorder, u->faction->locale) == K_STUDY) { char token[128]; skill_t sk = NOSKILL; skill *sv = 0; diff --git a/src/kernel/alliance.c b/src/kernel/alliance.c index 910670d10..e4fd7c3b5 100644 --- a/src/kernel/alliance.c +++ b/src/kernel/alliance.c @@ -171,7 +171,7 @@ static void perform_kick(void) if (al && alliance_get_leader(al) == ta->u->faction) { faction *f; - init_order(ta->ord); + init_order_depr(ta->ord); skip_token(); f = getfaction(); if (f && f_get_alliance(f) == al) { @@ -192,7 +192,7 @@ static void perform_new(void) int id; faction *f = ta->u->faction; - init_order(ta->ord); + init_order_depr(ta->ord); skip_token(); id = getid(); @@ -227,7 +227,7 @@ static void perform_transfer(void) if (al && alliance_get_leader(al) == ta->u->faction) { faction *f; - init_order(ta->ord); + init_order_depr(ta->ord); skip_token(); f = getfaction(); if (f && f_get_alliance(f) == al) { @@ -264,7 +264,7 @@ static void perform_join(void) faction *fj = ta->u->faction; int aid; - init_order(ta->ord); + init_order_depr(ta->ord); skip_token(); aid = getid(); if (aid) { @@ -276,7 +276,7 @@ static void perform_join(void) faction *fi = ti->u->faction; if (fi && f_get_alliance(fi) == al) { int fid; - init_order(ti->ord); + init_order_depr(ti->ord); skip_token(); fid = getid(); if (fid == fj->no) { diff --git a/src/kernel/build.c b/src/kernel/build.c index 1f4e143df..2746fa406 100644 --- a/src/kernel/build.c +++ b/src/kernel/build.c @@ -161,7 +161,7 @@ int destroy_cmd(unit * u, struct order *ord) return 52; } - init_order(ord); + init_order_depr(ord); s = gettoken(token, sizeof(token)); if (s && *s) { diff --git a/src/kernel/command.c b/src/kernel/command.c index a6a036fe9..8b2a7e5e8 100644 --- a/src/kernel/command.c +++ b/src/kernel/command.c @@ -105,7 +105,7 @@ static int do_command_i(const struct tnode *keys, struct unit *u, struct order * void do_command(const struct tnode *keys, struct unit *u, struct order *ord) { - init_order(ord); + init_order_depr(ord); if (do_command_i(keys, u, ord) != E_TOK_SUCCESS) { char cmd[ORDERSIZE]; get_command(ord, u->faction->locale, cmd, sizeof(cmd)); diff --git a/src/kernel/config.test.c b/src/kernel/config.test.c index ac35b85a3..610c2d4b3 100644 --- a/src/kernel/config.test.c +++ b/src/kernel/config.test.c @@ -32,28 +32,28 @@ static void test_read_unitid(CuTest *tc) { a->data.i = atoi36("42"); /* this unit is also TEMP 42 */ ord = create_order(K_GIVE, lang, "TEMP 42"); - init_order(ord); + init_order_depr(ord); CuAssertIntEquals(tc, u->no, read_unitid(u->faction, u->region)); free_order(ord); ord = create_order(K_GIVE, lang, "8"); - init_order(ord); + init_order_depr(ord); CuAssertIntEquals(tc, 8, read_unitid(u->faction, u->region)); free_order(ord); ord = create_order(K_GIVE, lang, ""); - init_order(ord); + init_order_depr(ord); CuAssertIntEquals(tc, -1, read_unitid(u->faction, u->region)); free_order(ord); ord = create_order(K_GIVE, lang, "TEMP"); - init_order(ord); + init_order_depr(ord); CuAssertIntEquals(tc, -1, read_unitid(u->faction, u->region)); free_order(ord); /* bug https://bugs.eressea.de/view.php?id=1685 */ ord = create_order(K_GIVE, lang, "##"); - init_order(ord); + init_order_depr(ord); CuAssertIntEquals(tc, -1, read_unitid(u->faction, u->region)); free_order(ord); @@ -78,42 +78,42 @@ static void test_getunit(CuTest *tc) { r = test_create_region(1, 0, t_plain); ord = create_order(K_GIVE, lang, itoa36(u->no)); - init_order(ord); + init_order_depr(ord); CuAssertIntEquals(tc, GET_UNIT, getunit(u->region, u->faction, &u2)); CuAssertPtrEquals(tc, u, u2); - init_order(ord); + init_order_depr(ord); CuAssertIntEquals(tc, GET_NOTFOUND, getunit(r, u->faction, &u2)); CuAssertPtrEquals(tc, NULL, u2); free_order(ord); ord = create_order(K_GIVE, lang, itoa36(u->no + 1)); - init_order(ord); + init_order_depr(ord); CuAssertIntEquals(tc, GET_NOTFOUND, getunit(u->region, u->faction, &u2)); CuAssertPtrEquals(tc, NULL, u2); free_order(ord); ord = create_order(K_GIVE, lang, "0"); - init_order(ord); + init_order_depr(ord); CuAssertIntEquals(tc, GET_PEASANTS, getunit(u->region, u->faction, &u2)); CuAssertPtrEquals(tc, NULL, u2); free_order(ord); /* bug https://bugs.eressea.de/view.php?id=1685 */ ord = create_order(K_GIVE, lang, "TEMP ##"); - init_order(ord); + init_order_depr(ord); CuAssertIntEquals(tc, GET_NOTFOUND, getunit(u->region, u->faction, &u2)); CuAssertPtrEquals(tc, NULL, u2); free_order(ord); /* bug https://bugs.eressea.de/view.php?id=1685 */ ord = create_order(K_GIVE, lang, "##"); - init_order(ord); + init_order_depr(ord); CuAssertIntEquals(tc, GET_NOTFOUND, getunit(u->region, u->faction, &u2)); CuAssertPtrEquals(tc, NULL, u2); free_order(ord); ord = create_order(K_GIVE, lang, "TEMP 42"); - init_order(ord); + init_order_depr(ord); CuAssertIntEquals(tc, GET_UNIT, getunit(u->region, u->faction, &u2)); CuAssertPtrEquals(tc, u, u2); free_order(ord); diff --git a/src/kernel/order.c b/src/kernel/order.c index 4124651c9..7cdb2961d 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -155,7 +155,7 @@ char* get_command(const order *ord, const struct locale *lang, char *sbuffer, si } if (ord->id < 0) { - skill_t sk = (skill_t)(100-ord->id); + skill_t sk = (skill_t)(100+ord->id); assert(kwd == K_STUDY && sk != SK_MAGIC); text = skillname(sk, lang); } else { @@ -569,7 +569,7 @@ void push_order(order ** ordp, order * ord) static order_data *parser_od; -keyword_t init_order(const struct order *ord) +keyword_t init_order(const struct order *ord, const struct locale *lang) { if (!ord) { release_data(parser_od); @@ -577,19 +577,38 @@ keyword_t init_order(const struct order *ord) return NOKEYWORD; } else { + keyword_t kwd = ORD_KEYWORD(ord); if (parser_od) { /* TODO: warning */ release_data(parser_od); + parser_od = NULL; } - parser_od = load_data(ord->id); - init_tokens_str(OD_STRING(parser_od)); - return ORD_KEYWORD(ord); + if (ord->id < 0) { + skill_t sk = (skill_t)(100 + ord->id); + assert(lang); + assert(kwd == K_STUDY); + init_tokens_str(skillname(sk, lang)); + } + else { + parser_od = load_data(ord->id); + init_tokens_str(OD_STRING(parser_od)); + } + return kwd; } } +keyword_t init_order_depr(const struct order *ord) +{ + if (ord) { + keyword_t kwd = ORD_KEYWORD(ord); + assert(kwd != K_STUDY); + } + return init_order(ord, NULL); +} + void close_orders(void) { if (parser_od) { - init_order(NULL); + (void)init_order(NULL, NULL); } free_data(); } diff --git a/src/kernel/order.h b/src/kernel/order.h index 916055379..0cbe4989c 100644 --- a/src/kernel/order.h +++ b/src/kernel/order.h @@ -69,7 +69,8 @@ extern "C" { char *write_order(const order * ord, const struct locale *lang, char *buffer, size_t size); - keyword_t init_order(const struct order *ord); + keyword_t init_order_depr(const struct order *ord); + keyword_t init_order(const struct order *ord, const struct locale *lang); void close_orders(void); diff --git a/src/kernel/order.test.c b/src/kernel/order.test.c index 675cd90cf..c892e7e54 100644 --- a/src/kernel/order.test.c +++ b/src/kernel/order.test.c @@ -2,6 +2,8 @@ #include #include "order.h" +#include + #include #include @@ -22,7 +24,7 @@ static void test_create_order(CuTest *tc) { CuAssertIntEquals(tc, K_MOVE, getkeyword(ord)); CuAssertStrEquals(tc, "move NORTH", get_command(ord, lang, cmd, sizeof(cmd))); - CuAssertIntEquals(tc, K_MOVE, init_order(ord)); + CuAssertIntEquals(tc, K_MOVE, init_order_depr(ord)); CuAssertStrEquals(tc, "NORTH", getstrtoken()); free_order(ord); test_cleanup(); @@ -42,7 +44,7 @@ static void test_parse_order(CuTest *tc) { CuAssertIntEquals(tc, K_MOVE, getkeyword(ord)); CuAssertStrEquals(tc, "move NORTH", get_command(ord, lang, cmd, sizeof(cmd))); - CuAssertIntEquals(tc, K_MOVE, init_order(ord)); + CuAssertIntEquals(tc, K_MOVE, init_order_depr(ord)); CuAssertStrEquals(tc, "NORTH", getstrtoken()); free_order(ord); @@ -100,7 +102,7 @@ static void test_parse_make(CuTest *tc) { CuAssertIntEquals(tc, K_MAKE, getkeyword(ord)); CuAssertStrEquals(tc, "MAKE hurrdurr", get_command(ord, lang, cmd, sizeof(cmd))); - CuAssertIntEquals(tc, K_MAKE, init_order(ord)); + CuAssertIntEquals(tc, K_MAKE, init_order_depr(ord)); CuAssertStrEquals(tc, "hurrdurr", getstrtoken()); free_order(ord); test_cleanup(); @@ -123,7 +125,7 @@ static void test_parse_make_temp(CuTest *tc) { CuAssertIntEquals(tc, K_MAKETEMP, getkeyword(ord)); CuAssertStrEquals(tc, "MAKETEMP herp", get_command(ord, lang, cmd, sizeof(cmd))); - CuAssertIntEquals(tc, K_MAKETEMP, init_order(ord)); + CuAssertIntEquals(tc, K_MAKETEMP, init_order_depr(ord)); CuAssertStrEquals(tc, "herp", getstrtoken()); free_order(ord); test_cleanup(); @@ -146,7 +148,7 @@ static void test_parse_maketemp(CuTest *tc) { CuAssertPtrNotNull(tc, ord); CuAssertStrEquals(tc, "MAKETEMP herp", get_command(ord, lang, cmd, sizeof(cmd))); CuAssertIntEquals(tc, K_MAKETEMP, getkeyword(ord)); - CuAssertIntEquals(tc, K_MAKETEMP, init_order(ord)); + CuAssertIntEquals(tc, K_MAKETEMP, init_order_depr(ord)); CuAssertStrEquals(tc, "herp", getstrtoken()); free_order(ord); test_cleanup(); @@ -160,7 +162,7 @@ static void test_init_order(CuTest *tc) { lang = get_or_create_locale("en"); ord = create_order(K_MAKETEMP, lang, "hurr durr"); - CuAssertIntEquals(tc, K_MAKETEMP, init_order(ord)); + CuAssertIntEquals(tc, K_MAKETEMP, init_order_depr(ord)); CuAssertStrEquals(tc, "hurr", getstrtoken()); CuAssertStrEquals(tc, "durr", getstrtoken()); free_order(ord); @@ -292,10 +294,48 @@ static void test_is_silent(CuTest *tc) { test_cleanup(); } + +static void test_study_orders(CuTest *tc) { + order *ord; + struct locale *lang; + const char *s; + char token[16]; + + test_setup(); + lang = test_create_locale(); + + ord = create_order(K_STUDY, lang, skillname(SK_CROSSBOW, lang)); + CuAssertIntEquals(tc, K_STUDY, getkeyword(ord)); + CuAssertIntEquals(tc, K_STUDY, init_order(ord, lang)); + s = gettoken(token, sizeof(token)); + CuAssertStrEquals(tc, skillname(SK_CROSSBOW, lang), s); + CuAssertPtrEquals(tc, NULL, (void *)getstrtoken()); + free_order(ord); + + ord = create_order(K_STUDY, lang, skillname(SK_MAGIC, lang)); + CuAssertIntEquals(tc, K_STUDY, getkeyword(ord)); + CuAssertIntEquals(tc, K_STUDY, init_order(ord, lang)); + s = gettoken(token, sizeof(token)); + CuAssertStrEquals(tc, skillname(SK_MAGIC, lang), s); + CuAssertPtrEquals(tc, NULL, (void *)getstrtoken()); + free_order(ord); + + ord = create_order(K_STUDY, lang, "%s 100", skillname(SK_MAGIC, lang)); + CuAssertIntEquals(tc, K_STUDY, getkeyword(ord)); + CuAssertIntEquals(tc, K_STUDY, init_order(ord, lang)); + s = gettoken(token, sizeof(token)); + CuAssertStrEquals(tc, skillname(SK_MAGIC, lang), s); + CuAssertIntEquals(tc, 100, getint()); + free_order(ord); + + test_cleanup(); +} + CuSuite *get_order_suite(void) { CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_create_order); + SUITE_ADD_TEST(suite, test_study_orders); SUITE_ADD_TEST(suite, test_parse_order); SUITE_ADD_TEST(suite, test_parse_make); SUITE_ADD_TEST(suite, test_parse_make_temp); diff --git a/src/laws.c b/src/laws.c index 7da40f83f..dec35ef8c 100644 --- a/src/laws.c +++ b/src/laws.c @@ -910,7 +910,7 @@ int contact_cmd(unit * u, order * ord) unit *u2; int n; - init_order(ord); + init_order_depr(ord); n = read_unitid(u->faction, u->region); u2 = findunit(n); @@ -960,7 +960,7 @@ int quit_cmd(unit * u, struct order *ord) const char *passwd; keyword_t kwd; - kwd = init_order(ord); + kwd = init_order_depr(ord); assert(kwd == K_QUIT); passwd = gettoken(token, sizeof(token)); if (checkpasswd(f, (const char *)passwd)) { @@ -1146,7 +1146,7 @@ void do_enter(struct region *r, bool is_final_attempt) unit *ulast = NULL; const char * s; - init_order(ord); + init_order_depr(ord); s = gettoken(token, sizeof(token)); p = findparam_ex(s, u->faction->locale); id = getid(); @@ -1306,7 +1306,7 @@ int ally_cmd(unit * u, struct order *ord) int keyword, not_kw; const char *s; - init_order(ord); + init_order_depr(ord); f = getfaction(); if (f == NULL || is_monsters(f)) { @@ -1473,7 +1473,7 @@ int prefix_cmd(unit * u, struct order *ord) for (in = pnames; in->lang != lang; in = in->next); } - init_order(ord); + init_order_depr(ord); s = gettoken(token, sizeof(token)); if (!s || !*s) { @@ -1517,7 +1517,7 @@ int display_cmd(unit * u, struct order *ord) const char *str; region *r = u->region; - init_order(ord); + init_order_depr(ord); str = gettoken(token, sizeof(token)); switch (findparam_ex(str, u->faction->locale)) { @@ -1690,7 +1690,7 @@ int name_cmd(struct unit *u, struct order *ord) bool foreign = false; const char *str; - init_order(ord); + init_order_depr(ord); str = gettoken(token, sizeof(token)); p = findparam_ex(str, u->faction->locale); @@ -1948,7 +1948,7 @@ int mail_cmd(unit * u, struct order *ord) const char *s; int n, cont; - init_order(ord); + init_order_depr(ord); s = gettoken(token, sizeof(token)); /* Falls kein Parameter, ist das eine Einheitsnummer; @@ -2105,7 +2105,7 @@ int banner_cmd(unit * u, struct order *ord) const char * s; free(u->faction->banner); - init_order(ord); + init_order_depr(ord); s = getstrtoken(); u->faction->banner = s ? strdup(s) : 0; add_message(&u->faction->msgs, msg_message("changebanner", "value", @@ -2118,7 +2118,7 @@ int email_cmd(unit * u, struct order *ord) { const char *s; - init_order(ord); + init_order_depr(ord); s = getstrtoken(); if (!s || !s[0]) { @@ -2144,7 +2144,7 @@ int password_cmd(unit * u, struct order *ord) const char *s; bool pwok = true; - init_order(ord); + init_order_depr(ord); s = gettoken(pwbuf, sizeof(pwbuf)); if (!s || !*s) { @@ -2177,7 +2177,7 @@ int send_cmd(unit * u, struct order *ord) const char *s; int option; - init_order(ord); + init_order_depr(ord); s = gettoken(token, sizeof(token)); option = findoption(s, u->faction->locale); @@ -2512,7 +2512,7 @@ int group_cmd(unit * u, struct order *ord) { keyword_t kwd; - kwd = init_order(ord); + kwd = init_order_depr(ord); assert(kwd == K_GROUP); join_group(u, getstrtoken()); return 0; @@ -2522,7 +2522,7 @@ int origin_cmd(unit * u, struct order *ord) { short px, py; - init_order(ord); + init_order_depr(ord); px = (short)getint(); py = (short)getint(); @@ -2534,7 +2534,7 @@ int origin_cmd(unit * u, struct order *ord) int guard_off_cmd(unit * u, struct order *ord) { assert(getkeyword(ord) == K_GUARD); - init_order(ord); + init_order_depr(ord); if (getparam(u->faction->locale) == P_NOT) { setguard(u, false); @@ -2548,7 +2548,7 @@ int reshow_cmd(unit * u, struct order *ord) const char *s; param_t p = NOPARAM; - init_order(ord); + init_order_depr(ord); s = gettoken(lbuf, sizeof(lbuf)); if (s && isparam(s, u->faction->locale, P_ANY)) { @@ -2565,7 +2565,7 @@ int status_cmd(unit * u, struct order *ord) char token[128]; const char *s; - init_order(ord); + init_order_depr(ord); s = gettoken(token, sizeof(token)); switch (findparam(s, u->faction->locale)) { case P_NOT: @@ -2613,7 +2613,7 @@ int combatspell_cmd(unit * u, struct order *ord) int level = 0; spell *sp = 0; - init_order(ord); + init_order_depr(ord); s = gettoken(token, sizeof(token)); /* KAMPFZAUBER [NICHT] löscht alle gesetzten Kampfzauber */ @@ -2658,7 +2658,7 @@ int guard_on_cmd(unit * u, struct order *ord) assert(u); assert(u->faction); - init_order(ord); + init_order_depr(ord); /* GUARD NOT is handled in goard_off_cmd earlier in the turn */ if (getparam(u->faction->locale) == P_NOT) { @@ -2739,7 +2739,7 @@ void restack_units(void) int id; unit *v; - init_order(ord); + init_order_depr(ord); s = gettoken(token, sizeof(token)); p = findparam(s, u->faction->locale); id = getid(); @@ -3049,7 +3049,7 @@ void maketemp_cmd(unit *u, order **olist) unit *u2; order **ordp, **oinsert; #ifndef NDEBUG - keyword_t kwd = init_order(makeord); + keyword_t kwd = init_order_depr(makeord); assert(kwd == K_MAKETEMP); #endif alias = getid(); @@ -3347,7 +3347,7 @@ void defaultorders(void) char lbuf[8192]; order *new_order = 0; const char *s; - init_order(ord); + init_order_depr(ord); s = gettoken(lbuf, sizeof(lbuf)); if (s) { new_order = parse_order(s, u->faction->locale); @@ -3463,7 +3463,7 @@ int use_cmd(unit * u, struct order *ord) int n, err = ENOITEM; const item_type *itype; - init_order(ord); + init_order_depr(ord); t = gettoken(token, sizeof(token)); if (!t) { @@ -3518,7 +3518,7 @@ int pay_cmd(unit * u, struct order *ord) param_t p; int id; - init_order(ord); + init_order_depr(ord); p = getparam(u->faction->locale); id = getid(); if (p == P_NOT) { @@ -3572,7 +3572,7 @@ static int reserve_i(unit * u, struct order *ord, int flags) const item_type *itype; const char *s; - init_order(ord); + init_order_depr(ord); s = gettoken(token, sizeof(token)); count = s ? atoip(s) : 0; para = findparam(s, u->faction->locale); @@ -3615,7 +3615,7 @@ int claim_cmd(unit * u, struct order *ord) int n = 1; const item_type *itype = 0; - init_order(ord); + init_order_depr(ord); t = gettoken(token, sizeof(token)); if (t) { @@ -3909,7 +3909,7 @@ int siege_cmd(unit * u, order * ord) resource_type *rt_catapultammo = NULL; resource_type *rt_catapult = NULL; - init_order(ord); + init_order_depr(ord); b = getbuilding(r); if (!b) { diff --git a/src/magic.c b/src/magic.c index f83e31a7d..c8f1b83c3 100644 --- a/src/magic.c +++ b/src/magic.c @@ -2514,7 +2514,7 @@ static castorder *cast_cmd(unit * u, order * ord) } level = effskill(u, SK_MAGIC, 0); - init_order(ord); + init_order_depr(ord); s = gettoken(token, sizeof(token)); param = findparam(s, u->faction->locale); /* für Syntax ' STUFE x REGION y z ' */ diff --git a/src/move.c b/src/move.c index 3f899ac22..5a9e51b43 100644 --- a/src/move.c +++ b/src/move.c @@ -1067,7 +1067,7 @@ static void cycle_route(order * ord, unit * u, int gereist) return; tail[0] = '\0'; - init_order(ord); + init_order_depr(ord); neworder[0] = 0; for (cm = 0;; ++cm) { @@ -1144,7 +1144,7 @@ static bool transport(unit * ut, unit * u) for (ord = ut->orders; ord; ord = ord->next) { if (getkeyword(ord) == K_TRANSPORT) { unit *u2; - init_order(ord); + init_order_depr(ord); getunit(ut->region, ut->faction, &u2); if (u2 == u) { return true; @@ -1178,7 +1178,7 @@ static void init_transportation(void) && !fval(u, UFL_NOTMOVING) && !LongHunger(u)) { unit *ut = 0; - init_order(u->thisorder); + init_order_depr(u->thisorder); if (getunit(r, u->faction, &ut) != GET_UNIT) { ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "feedback_unit_not_found", "")); @@ -1207,7 +1207,7 @@ static void init_transportation(void) for (ord = u->orders; ord; ord = ord->next) { if (getkeyword(ord) == K_TRANSPORT) { - init_order(ord); + init_order_depr(ord); for (;;) { unit *ut = 0; @@ -1218,7 +1218,7 @@ static void init_transportation(void) can_move(ut) && !fval(ut, UFL_NOTMOVING) && !LongHunger(ut)) { unit *u2; - init_order(ut->thisorder); + init_order_depr(ut->thisorder); getunit(r, ut->faction, &u2); if (u2 == u) { w += weight(ut); @@ -2062,7 +2062,7 @@ static const region_list *travel_i(unit * u, const region_list * route_begin, if (getkeyword(ord) != K_TRANSPORT) continue; - init_order(ord); + init_order_depr(ord); if (getunit(r, u->faction, &ut) == GET_UNIT) { if (getkeyword(ut->thisorder) == K_DRIVE) { if (ut->building && !can_leave(ut)) { @@ -2077,7 +2077,7 @@ static const region_list *travel_i(unit * u, const region_list * route_begin, if (!fval(ut, UFL_NOTMOVING) && !LongHunger(ut)) { unit *u2; - init_order(ut->thisorder); + init_order_depr(ut->thisorder); getunit(u->region, ut->faction, &u2); if (u2 == u) { const region_list *route_to = @@ -2363,7 +2363,7 @@ static void move_hunters(void) if (getkeyword(ord) == K_FOLLOW) { param_t p; - init_order(ord); + init_order_depr(ord); p = getparam(u->faction->locale); if (p != P_SHIP) { if (p != P_UNIT) { @@ -2485,13 +2485,13 @@ void movement(void) else { if (ships) { if (u->ship && ship_owner(u->ship) == u) { - init_order(u->thisorder); + init_order_depr(u->thisorder); move_cmd(u, u->thisorder); } } else { if (!u->ship || ship_owner(u->ship) != u) { - init_order(u->thisorder); + init_order_depr(u->thisorder); move_cmd(u, u->thisorder); } } @@ -2548,7 +2548,7 @@ void follow_unit(unit * u) if (getkeyword(ord) == K_FOLLOW) { int id; param_t p; - init_order(ord); + init_order_depr(ord); p = getparam(lang); if (p == P_UNIT) { id = read_unitid(u->faction, r); diff --git a/src/move.test.c b/src/move.test.c index c8fdb2436..908da0bb7 100644 --- a/src/move.test.c +++ b/src/move.test.c @@ -462,7 +462,7 @@ static void test_follow_ship_msg(CuTest * tc) { mt_register(mt_new_va("error18", "unit:unit", "region:region", "command:order", 0)); - init_order(ord); + init_order_depr(ord); getstrtoken(); follow_ship(u, ord); diff --git a/src/piracy.c b/src/piracy.c index 3025d484c..b74a0b363 100644 --- a/src/piracy.c +++ b/src/piracy.c @@ -86,7 +86,7 @@ int *parse_ids(const order *ord) { const char *s; int *il = NULL; - init_order(ord); + init_order_depr(ord); s = getstrtoken(); if (s != NULL && *s) { il = intlist_init(); @@ -211,7 +211,7 @@ void piracy_cmd(unit * u) ord = create_order(K_MOVE, u->faction->locale, "%s", LOC(u->faction->locale, directions[target_dir])); /* Bewegung ausführen */ - init_order(ord); + init_order_depr(ord); move_cmd(u, ord); free_order(ord); } diff --git a/src/renumber.c b/src/renumber.c index 30769403f..ec9d61c66 100644 --- a/src/renumber.c +++ b/src/renumber.c @@ -80,7 +80,7 @@ int renumber_cmd(unit * u, order * ord) int i = 0; faction *f = u->faction; - init_order(ord); + init_order_depr(ord); s = gettoken(token, sizeof(token)); switch (findparam_ex(s, u->faction->locale)) { diff --git a/src/spy.c b/src/spy.c index ae01656bf..ff1f6da4e 100644 --- a/src/spy.c +++ b/src/spy.c @@ -126,7 +126,7 @@ int spy_cmd(unit * u, struct order *ord) double spychance, observechance; region *r = u->region; - init_order(ord); + init_order_depr(ord); getunit(r, u->faction, &target); if (!target) { @@ -219,7 +219,7 @@ int setstealth_cmd(unit * u, struct order *ord) const char *s; int level; - init_order(ord); + init_order_depr(ord); s = gettoken(token, sizeof(token)); /* Tarne ohne Parameter: Setzt maximale Tarnung */ @@ -494,10 +494,10 @@ int sabotage_cmd(unit * u, struct order *ord) assert(u); assert(ord); - init_order(ord); + init_order_depr(ord); s = getstrtoken(); p = findparam(s, u->faction->locale); - init_order(NULL); + init_order_depr(NULL); switch (p) { case P_SHIP: diff --git a/src/study.c b/src/study.c index a66efd662..9264f9060 100644 --- a/src/study.c +++ b/src/study.c @@ -283,7 +283,7 @@ int teach_cmd(unit * teacher, struct order *ord) count = 0; - init_order(ord); + init_order_depr(ord); #if TEACH_ALL if (getparam(teacher->faction->locale) == P_ANY) { @@ -304,7 +304,7 @@ int teach_cmd(unit * teacher, struct order *ord) else if (student->faction == teacher->faction) { if (getkeyword(student->thisorder) == K_STUDY) { /* Input ist nun von student->thisorder !! */ - init_order(student->thisorder); + init_order(student->thisorder, student->faction->locale); sk = getskill(student->faction->locale); if (sk != NOSKILL && teachskill[0] != NOSKILL) { for (t = 0; teachskill[t] != NOSKILL; ++t) { @@ -324,7 +324,7 @@ int teach_cmd(unit * teacher, struct order *ord) else if (alliedunit(teacher, student->faction, HELP_GUARD)) { if (getkeyword(student->thisorder) == K_STUDY) { /* Input ist nun von student->thisorder !! */ - init_order(student->thisorder); + init_order(student->thisorder, student->faction->locale); sk = getskill(student->faction->locale); if (sk != NOSKILL && effskill_study(teacher, sk, 0) - TEACHDIFFERENCE >= effskill(student, sk, 0)) { @@ -343,7 +343,7 @@ int teach_cmd(unit * teacher, struct order *ord) order *new_order; zOrder[0] = '\0'; - init_order(ord); + init_order_depr(ord); while (!parser_end()) { skill_t sk; @@ -361,7 +361,7 @@ int teach_cmd(unit * teacher, struct order *ord) const char *token; /* Finde den string, der den Fehler verursacht hat */ parser_pushstate(); - init_order(ord); + init_order_depr(ord); for (j = 0; j != count - 1; ++j) { /* skip over the first 'count' units */ @@ -406,7 +406,7 @@ int teach_cmd(unit * teacher, struct order *ord) /* Input ist nun von student->thisorder !! */ parser_pushstate(); - init_order(student->thisorder); + init_order(student->thisorder, student->faction->locale); sk = getskill(student->faction->locale); parser_popstate(); @@ -448,7 +448,7 @@ int teach_cmd(unit * teacher, struct order *ord) if (academy_students > 0 && sk_academy!=NOSKILL) { academy_teaching_bonus(teacher, sk_academy, academy_students); } - init_order(NULL); + init_order_depr(NULL); return 0; } @@ -557,7 +557,7 @@ int study_cmd(unit * u, order * ord) return 0; } - init_order(ord); + (void)init_order(ord, u->faction->locale); sk = getskill(u->faction->locale); if (sk < 0) { @@ -785,7 +785,7 @@ int study_cmd(unit * u, order * ord) mage = create_mage(u, u->faction->magiegebiet); } } - init_order(NULL); + init_order_depr(NULL); return 0; } From 0a0806a181c1eb26b3cbea6bdeda08ebb13e2886 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 10 Oct 2017 09:29:32 +0200 Subject: [PATCH 08/43] try fixing coverity complaints --- src/kernel/order.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/kernel/order.c b/src/kernel/order.c index 7cdb2961d..88f6313fa 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -156,7 +156,7 @@ char* get_command(const order *ord, const struct locale *lang, char *sbuffer, si if (ord->id < 0) { skill_t sk = (skill_t)(100+ord->id); - assert(kwd == K_STUDY && sk != SK_MAGIC); + assert(kwd == K_STUDY && sk != SK_MAGIC && sk < MAXSKILLS); text = skillname(sk, lang); } else { od = load_data(ord->id); @@ -270,7 +270,7 @@ static int create_data(keyword_t kwd, const char *s, } /* TODO: between mkdata and release_data, this object is very * short-lived. */ - mkdata(&data, s ? strlen(s) : 0, s); + mkdata(&data, strlen(s), s); id = save_data(kwd, data); release_data(data); return id; @@ -351,7 +351,11 @@ order *create_order(keyword_t kwd, const struct locale * lang, zBuffer[0] = 0; } ord = (order *)malloc(sizeof(order)); - return create_order_i(ord, lang, kwd, zBuffer, false, false); + if (create_order_i(ord, lang, kwd, zBuffer, false, false) == NULL) { + free(ord); + return NULL; + } + return ord; } order *parse_order(const char *s, const struct locale * lang) @@ -383,7 +387,12 @@ order *parse_order(const char *s, const struct locale * lang) } if (kwd != NOKEYWORD) { order *ord = (order *)malloc(sizeof(order)); - return create_order_i(ord, lang, kwd, sptr, persistent, noerror); + if (create_order_i(ord, lang, kwd, sptr, persistent, noerror) + == NULL) { + free(ord); + return NULL; + } + return ord; } } return NULL; @@ -585,6 +594,7 @@ keyword_t init_order(const struct order *ord, const struct locale *lang) } if (ord->id < 0) { skill_t sk = (skill_t)(100 + ord->id); + assert(sk < MAXSKILLS); assert(lang); assert(kwd == K_STUDY); init_tokens_str(skillname(sk, lang)); From cbaf4bfd044272cedd1c8c4ce28698d852893d35 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 12 Oct 2017 18:11:21 +0200 Subject: [PATCH 09/43] refactoring: move order_data to orderdb module. --- src/CMakeLists.txt | 1 + src/eressea.c | 3 ++ src/kernel/order.c | 87 ++++++---------------------------------------- src/orderdb.c | 78 +++++++++++++++++++++++++++++++++++++++++ src/orderdb.h | 23 ++++++++++++ 5 files changed, 116 insertions(+), 76 deletions(-) create mode 100644 src/orderdb.c create mode 100644 src/orderdb.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e5ae8de7a..c8a4c4783 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -116,6 +116,7 @@ set (ERESSEA_SRC magic.c market.c morale.c + orderdb.c orderfile.c randenc.c renumber.c diff --git a/src/eressea.c b/src/eressea.c index 2174450eb..b4ae7890f 100755 --- a/src/eressea.c +++ b/src/eressea.c @@ -8,6 +8,7 @@ #include "creport.h" #include "report.h" #include "names.h" +#include "orderdb.h" #include "reports.h" #include "spells.h" #include "vortex.h" @@ -57,10 +58,12 @@ void game_done(void) free_special_directions(); free_locales(); kernel_done(); + orderdb_close(); } void game_init(void) { + orderdb_open(); kernel_init(); register_triggers(); register_xmas(); diff --git a/src/kernel/order.c b/src/kernel/order.c index 7cdb2961d..b8cf4bc4b 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -14,6 +14,7 @@ #include #include "order.h" +#include "orderdb.h" #include "skill.h" #include "keyword.h" @@ -33,71 +34,6 @@ # define ORD_KEYWORD(ord) (keyword_t)((ord)->command & 0xFFFF) # define OD_STRING(odata) ((odata) ? (odata)->_str : NULL) -typedef struct order_data { - const char *_str; - int _refcount; -} order_data; - -#include - -static critbit_tree cb_orders = { 0 }; -static int auto_id = 0; - -struct cb_entry { - int id; - order_data *data; -}; - -order_data *load_data(int id) { - void * match; - - if (id > 0) { - if (cb_find_prefix(&cb_orders, &id, sizeof(id), &match, 1, 0) > 0) { - struct cb_entry *ent = (struct cb_entry *)match; - order_data * od = ent->data; - ++od->_refcount; - return od; - } - } - return NULL; -} - -int save_data(keyword_t kwd, order_data *od) { - if (od->_str) { - struct cb_entry ent; - ++od->_refcount; - ent.id = ++auto_id; - ent.data = od; - cb_insert(&cb_orders, &ent, sizeof(ent)); - return ent.id; - } - return 0; -} - -static void release_data(order_data * data) -{ - if (data) { - if (--data->_refcount == 0) { - free(data); - } - } -} - -int free_data_cb(const void *match, const void *key, size_t keylen, void *udata) { - struct cb_entry * ent = (struct cb_entry *)match; - order_data *od = ent->data; - if (od->_refcount > 1) { - log_error("refcount=%d for order %d, %s", od->_refcount, ent->id, od->_str); - } - release_data(od); - return 0; -} - -void free_data(void) { - cb_foreach(&cb_orders, NULL, 0, free_data_cb, NULL); - cb_clear(&cb_orders); -} - void replace_order(order ** dlist, order * orig, const order * src) { assert(src); @@ -159,7 +95,7 @@ char* get_command(const order *ord, const struct locale *lang, char *sbuffer, si assert(kwd == K_STUDY && sk != SK_MAGIC); text = skillname(sk, lang); } else { - od = load_data(ord->id); + od = odata_load(ord->id); text = OD_STRING(od); } if (kwd != NOKEYWORD) { @@ -193,7 +129,7 @@ char* get_command(const order *ord, const struct locale *lang, char *sbuffer, si } } if (od) { - release_data(od); + odata_release(od); } if (size > 0) *bufp = 0; return sbuffer; @@ -268,11 +204,11 @@ static int create_data(keyword_t kwd, const char *s, return ((int)sk)-100; } } - /* TODO: between mkdata and release_data, this object is very + /* TODO: between mkdata and odata_release, this object is very * short-lived. */ mkdata(&data, s ? strlen(s) : 0, s); - id = save_data(kwd, data); - release_data(data); + id = odata_save(data); + odata_release(data); return id; } @@ -547,11 +483,11 @@ char *write_order(const order * ord, const struct locale *lang, char *buffer, si else { keyword_t kwd = ORD_KEYWORD(ord); if (kwd == NOKEYWORD) { - order_data *od = load_data(ord->id); + order_data *od = odata_load(ord->id); const char *text = OD_STRING(od); if (text) strlcpy(buffer, (const char *)text, size); else buffer[0] = 0; - release_data(od); + odata_release(od); } else { get_command(ord, lang, buffer, size); @@ -572,7 +508,7 @@ static order_data *parser_od; keyword_t init_order(const struct order *ord, const struct locale *lang) { if (!ord) { - release_data(parser_od); + odata_release(parser_od); parser_od = NULL; return NOKEYWORD; } @@ -580,7 +516,7 @@ keyword_t init_order(const struct order *ord, const struct locale *lang) keyword_t kwd = ORD_KEYWORD(ord); if (parser_od) { /* TODO: warning */ - release_data(parser_od); + odata_release(parser_od); parser_od = NULL; } if (ord->id < 0) { @@ -590,7 +526,7 @@ keyword_t init_order(const struct order *ord, const struct locale *lang) init_tokens_str(skillname(sk, lang)); } else { - parser_od = load_data(ord->id); + parser_od = odata_load(ord->id); init_tokens_str(OD_STRING(parser_od)); } return kwd; @@ -610,6 +546,5 @@ void close_orders(void) { if (parser_od) { (void)init_order(NULL, NULL); } - free_data(); } diff --git a/src/orderdb.c b/src/orderdb.c new file mode 100644 index 000000000..37faeacc4 --- /dev/null +++ b/src/orderdb.c @@ -0,0 +1,78 @@ +#include +#include "orderdb.h" + +#include + +#include + +#include + +static critbit_tree cb_orders = { 0 }; +static int auto_id = 0; + +struct cb_entry { + int id; + order_data *data; +}; + +order_data *odata_load(int id) +{ + void * match; + + if (id > 0) { + if (cb_find_prefix(&cb_orders, &id, sizeof(id), &match, 1, 0) > 0) { + struct cb_entry *ent = (struct cb_entry *)match; + order_data * od = ent->data; + ++od->_refcount; + return od; + } + } + return NULL; +} + +int odata_save(order_data *od) +{ + if (od->_str) { + struct cb_entry ent; + ++od->_refcount; + ent.id = ++auto_id; + ent.data = od; + cb_insert(&cb_orders, &ent, sizeof(ent)); + return ent.id; + } + return 0; +} + +void odata_release(order_data * od) +{ + if (od) { + if (--od->_refcount == 0) { + free(od); + } + } +} + +int free_data_cb(const void *match, const void *key, size_t keylen, void *udata) { + struct cb_entry * ent = (struct cb_entry *)match; + order_data *od = ent->data; + if (od->_refcount > 1) { + log_error("refcount=%d for order %d, %s", od->_refcount, ent->id, od->_str); + } + odata_release(od); + return 0; +} + +void free_data(void) { + cb_foreach(&cb_orders, NULL, 0, free_data_cb, NULL); + cb_clear(&cb_orders); +} + +void orderdb_open(void) +{ + auto_id = 0; +} + +void orderdb_close(void) +{ + free_data(); +} diff --git a/src/orderdb.h b/src/orderdb.h new file mode 100644 index 000000000..be39a642e --- /dev/null +++ b/src/orderdb.h @@ -0,0 +1,23 @@ +#ifndef H_ORDERDB +#define H_ORDERDB + +#ifdef __cplusplus +extern "C" { +#endif + + typedef struct order_data { + const char *_str; + int _refcount; + } order_data; + + void orderdb_open(void); + void orderdb_close(void); + + order_data *odata_load(int id); + int odata_save(order_data *od); + void odata_release(order_data * od); + +#ifdef __cplusplus +} +#endif +#endif From db0bd8d4dbb5d4265c57fdce2a152718de255b97 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 8 Oct 2017 12:39:41 +0200 Subject: [PATCH 10/43] refactor: split order_data from order, force use of ids (to be replaced with db backend). --- src/kernel/order.c | 79 +++++++++++++++++++++++++++++++++-------- src/kernel/order.h | 4 +-- src/kernel/order.test.c | 10 +++--- src/laws.test.c | 2 +- 4 files changed, 72 insertions(+), 23 deletions(-) diff --git a/src/kernel/order.c b/src/kernel/order.c index a48825333..2f209da24 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -31,8 +31,8 @@ #include # define ORD_KEYWORD(ord) (keyword_t)((ord)->command & 0xFFFF) -# define ORD_LOCALE(ord) locale_array[(ord)->data->_lindex]->lang -# define ORD_STRING(ord) (ord)->data->_str +# define OD_LOCALE(odata) locale_array[(odata)->_lindex]->lang +# define OD_STRING(odata) (odata)->_str typedef struct locale_data { struct order_data *short_orders; @@ -48,6 +48,22 @@ typedef struct order_data { int _lindex; } order_data; +#include + +static selist * orders; + +order_data *load_data(int id) { + order_data * od = (order_data *)selist_get(orders, id - 1); + ++od->_refcount; + return od; +} + +int add_data(order_data *od) { + ++od->_refcount; + selist_push(&orders, od); + return selist_length(orders); +} + static void release_data(order_data * data) { if (data) { @@ -57,6 +73,20 @@ static void release_data(order_data * data) } } +void free_data_cb(void *entry) { + order_data *od = (order_data *)entry; + if (od->_refcount > 1) { + log_error("refcount=%d for order %s", od->_refcount, od->_str); + } + release_data(od); +} + +void free_data(void) { + selist_foreach(orders, free_data_cb); + selist_free(orders); + orders = NULL; +} + void replace_order(order ** dlist, order * orig, const order * src) { assert(src); @@ -64,7 +94,7 @@ void replace_order(order ** dlist, order * orig, const order * src) assert(dlist); while (*dlist != NULL) { order *dst = *dlist; - if (dst->data == orig->data) { + if (dst->id == orig->id) { order *cpy = copy_order(src); *dlist = cpy; cpy->next = dst->next; @@ -89,7 +119,8 @@ keyword_t getkeyword(const order * ord) */ char* get_command(const order *ord, char *sbuffer, size_t size) { char *bufp = sbuffer; - const char *text = ORD_STRING(ord); + order_data *od; + const char * text; keyword_t kwd = ORD_KEYWORD(ord); int bytes; @@ -111,8 +142,11 @@ char* get_command(const order *ord, char *sbuffer, size_t size) { WARN_STATIC_BUFFER(); } } + + od = load_data(ord->id); + text = OD_STRING(od); if (kwd != NOKEYWORD) { - const struct locale *lang = ORD_LOCALE(ord); + const struct locale *lang = OD_LOCALE(od); if (size > 0) { const char *str = (const char *)LOC(lang, keyword(kwd)); assert(str); @@ -142,6 +176,7 @@ char* get_command(const order *ord, char *sbuffer, size_t size) { } } } + release_data(od); if (size > 0) *bufp = 0; return sbuffer; } @@ -150,8 +185,6 @@ void free_order(order * ord) { if (ord != NULL) { assert(ord->next == 0); - - release_data(ord->data); free(ord); } } @@ -162,8 +195,7 @@ order *copy_order(const order * src) order *ord = (order *)malloc(sizeof(order)); ord->next = NULL; ord->command = src->command; - ord->data = src->data; - ++ord->data->_refcount; + ord->id = src->id; return ord; } return NULL; @@ -277,12 +309,14 @@ void close_orders(void) { locale_array[i] = 0; } } + free_data(); } static order *create_order_i(order *ord, keyword_t kwd, const char *sptr, bool persistent, bool noerror, const struct locale *lang) { int lindex; + order_data *od; assert(ord); if (kwd == NOKEYWORD || keyword_disabled(kwd)) { @@ -317,7 +351,10 @@ static order *create_order_i(order *ord, keyword_t kwd, const char *sptr, bool p ord->next = NULL; while (isspace(*(unsigned char *)sptr)) ++sptr; - ord->data = create_data(kwd, sptr, lindex); + + od = create_data(kwd, sptr, lindex); + ord->id = add_data(od); + release_data(od); return ord; } @@ -573,9 +610,11 @@ char *write_order(const order * ord, char *buffer, size_t size) else { keyword_t kwd = ORD_KEYWORD(ord); if (kwd == NOKEYWORD) { - const char *text = ORD_STRING(ord); + order_data *od = load_data(ord->id); + const char *text = OD_STRING(od); if (text) strlcpy(buffer, (const char *)text, size); else buffer[0] = 0; + release_data(od); } else { get_command(ord, buffer, size); @@ -593,7 +632,19 @@ void push_order(order ** ordp, order * ord) keyword_t init_order(const struct order *ord) { - assert(ord && ord->data); - init_tokens_str(ord->data->_str); - return ORD_KEYWORD(ord); + static order_data *od; + + if (!ord) { + release_data(od); + return NOKEYWORD; + } + else { + if (od) { + // TODO: warning + release_data(od); + } + od = load_data(ord->id); + init_tokens_str(od->_str); + return ORD_KEYWORD(ord); + } } diff --git a/src/kernel/order.h b/src/kernel/order.h index b9d235c88..f26174ee4 100644 --- a/src/kernel/order.h +++ b/src/kernel/order.h @@ -30,8 +30,6 @@ extern "C" { * implemented yet) saving approx. 50% of all string-related memory. */ - struct order_data; - #define CMD_QUIET 0x010000 #define CMD_PERSIST 0x020000 #define CMD_DEFAULT 0x040000 @@ -39,7 +37,7 @@ extern "C" { typedef struct order { struct order *next; /* do not access this data: */ - struct order_data *data; + int id; int command; } order; diff --git a/src/kernel/order.test.c b/src/kernel/order.test.c index 71938ca7e..e1656efc9 100644 --- a/src/kernel/order.test.c +++ b/src/kernel/order.test.c @@ -48,35 +48,35 @@ static void test_parse_order(CuTest *tc) { ord = parse_order("!MOVE NORTH", lang); CuAssertPtrNotNull(tc, ord); - CuAssertPtrNotNull(tc, ord->data); + CuAssertTrue(tc, ord->id > 0); CuAssertIntEquals(tc, K_MOVE, getkeyword(ord)); CuAssertIntEquals(tc, K_MOVE | CMD_QUIET, ord->command); free_order(ord); ord = parse_order("@MOVE NORTH", lang); CuAssertPtrNotNull(tc, ord); - CuAssertPtrNotNull(tc, ord->data); + CuAssertTrue(tc, ord->id > 0); CuAssertIntEquals(tc, K_MOVE, getkeyword(ord)); CuAssertIntEquals(tc, K_MOVE | CMD_PERSIST, ord->command); free_order(ord); ord = parse_order("!@MOVE NORTH", lang); CuAssertPtrNotNull(tc, ord); - CuAssertPtrNotNull(tc, ord->data); + CuAssertTrue(tc, ord->id > 0); CuAssertIntEquals(tc, K_MOVE, getkeyword(ord)); CuAssertIntEquals(tc, K_MOVE | CMD_PERSIST | CMD_QUIET, ord->command); free_order(ord); ord = parse_order("@!MOVE NORTH", lang); CuAssertPtrNotNull(tc, ord); - CuAssertPtrNotNull(tc, ord->data); + CuAssertTrue(tc, ord->id > 0); CuAssertIntEquals(tc, K_MOVE, getkeyword(ord)); CuAssertIntEquals(tc, K_MOVE | CMD_PERSIST | CMD_QUIET, ord->command); free_order(ord); ord = parse_order(" !@MOVE NORTH", lang); CuAssertPtrNotNull(tc, ord); - CuAssertPtrNotNull(tc, ord->data); + CuAssertTrue(tc, ord->id > 0); CuAssertIntEquals(tc, K_MOVE, getkeyword(ord)); CuAssertIntEquals(tc, K_MOVE | CMD_PERSIST | CMD_QUIET, ord->command); free_order(ord); diff --git a/src/laws.test.c b/src/laws.test.c index ec14ac4cc..4881300b4 100644 --- a/src/laws.test.c +++ b/src/laws.test.c @@ -1005,7 +1005,7 @@ static void test_long_order_normal(CuTest *tc) { fset(u, UFL_LONGACTION); unit_addorder(u, ord = create_order(K_MOVE, u->faction->locale, 0)); update_long_order(u); - CuAssertPtrEquals(tc, ord->data, u->thisorder->data); + CuAssertIntEquals(tc, ord->id, u->thisorder->id); CuAssertIntEquals(tc, 0, fval(u, UFL_MOVED)); CuAssertIntEquals(tc, 0, fval(u, UFL_LONGACTION)); CuAssertPtrNotNull(tc, u->orders); From 2b546050802de16946e13c84b9ace3db1e4e7472 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 8 Oct 2017 15:34:40 +0200 Subject: [PATCH 11/43] remove order de-duplication for short and study orders. --- src/kernel/order.c | 144 +++++++++++++-------------------------------- src/spy.c | 2 +- src/study.c | 3 +- 3 files changed, 43 insertions(+), 106 deletions(-) diff --git a/src/kernel/order.c b/src/kernel/order.c index 2f209da24..bbb211cb3 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -31,21 +31,13 @@ #include # define ORD_KEYWORD(ord) (keyword_t)((ord)->command & 0xFFFF) -# define OD_LOCALE(odata) locale_array[(odata)->_lindex]->lang -# define OD_STRING(odata) (odata)->_str - -typedef struct locale_data { - struct order_data *short_orders; - struct order_data *study_orders[MAXSKILLS]; - const struct locale *lang; -} locale_data; - -static struct locale_data *locale_array[MAXLOCALES]; +# define OD_LOCALE(odata) ((odata) ? (odata)->lang : NULL) +# define OD_STRING(odata) ((odata) ? (odata)->_str : NULL) typedef struct order_data { const char *_str; int _refcount; - int _lindex; + const struct locale *lang; } order_data; #include @@ -53,15 +45,21 @@ typedef struct order_data { static selist * orders; order_data *load_data(int id) { - order_data * od = (order_data *)selist_get(orders, id - 1); - ++od->_refcount; - return od; + if (id > 0) { + order_data * od = (order_data *)selist_get(orders, id - 1); + ++od->_refcount; + return od; + } + return NULL; } int add_data(order_data *od) { - ++od->_refcount; - selist_push(&orders, od); - return selist_length(orders); + if (od->_str) { + ++od->_refcount; + selist_push(&orders, od); + return selist_length(orders); + } + return 0; } static void release_data(order_data * data) @@ -219,103 +217,42 @@ void free_orders(order ** olist) } } -static char *mkdata(order_data **pdata, size_t len, int lindex, const char *str) +static char *mkdata(order_data **pdata, size_t len, const struct locale *lang, const char *str) { order_data *data; char *result; data = malloc(sizeof(order_data) + len + 1); result = (char *)(data + 1); - data->_lindex = lindex; + data->lang = lang; data->_refcount = 0; - data->_str = 0; - data->_str = (len > 0) ? result : 0; + data->_str = (len > 0) ? result : NULL; if (str) strcpy(result, str); if (pdata) *pdata = data; return result; } -static order_data *create_data(keyword_t kwd, const char *sptr, int lindex) +static order_data *create_data(keyword_t kwd, const char *sptr, const struct locale *lang) { const char *s = sptr; order_data *data; - const struct locale *lang = locale_array[lindex]->lang; if (kwd != NOKEYWORD) s = (*sptr) ? sptr : NULL; - /* learning, only one order_data per skill required */ - if (kwd == K_STUDY) { - skill_t sk = get_skill(parse_token_depr(&sptr), lang); - switch (sk) { - case NOSKILL: /* fehler */ - break; - case SK_MAGIC: /* kann parameter haben */ - if (*sptr != 0) - break; - default: /* nur skill als Parameter, keine extras */ - data = locale_array[lindex]->study_orders[sk]; - if (data == NULL) { - const char *skname = skillname(sk, lang); - const char *spc = strchr(skname, ' '); - size_t len = strlen(skname); - char *dst = mkdata(&data, len + (spc ? 3 : 0), lindex, spc ? 0 : skname); - locale_array[lindex]->study_orders[sk] = data; - if (spc) { - dst[0] = '\"'; - memcpy(dst + 1, skname, len); - dst[len + 1] = '\"'; - dst[len + 2] = '\0'; - } - data->_refcount = 1; - } - ++data->_refcount; - return data; - } - } - /* orders with no parameter, only one order_data per order required */ - else if (kwd != NOKEYWORD && *sptr == 0) { - data = locale_array[lindex]->short_orders; - if (data == NULL) { - mkdata(&data, 0, lindex, 0); - data->_refcount = 1; - locale_array[lindex]->short_orders = data; - } - ++data->_refcount; + if (kwd != NOKEYWORD && *sptr == 0) { + mkdata(&data, 0, lang, NULL); + data->_refcount = 1; return data; } - mkdata(&data, s ? strlen(s) : 0, lindex, s); + mkdata(&data, s ? strlen(s) : 0, lang, s); data->_refcount = 1; return data; } -static void clear_localedata(int lindex) { - int i; - release_data(locale_array[lindex]->short_orders); - locale_array[lindex]->short_orders = NULL; - for (i = 0; i != MAXSKILLS; ++i) { - release_data(locale_array[lindex]->study_orders[i]); - locale_array[lindex]->study_orders[i] = 0; - } - locale_array[lindex]->lang = 0; -} - -void close_orders(void) { - int i; - for (i = 0; i != MAXLOCALES; ++i) { - if (locale_array[i]){ - clear_localedata(i); - free(locale_array[i]); - locale_array[i] = 0; - } - } - free_data(); -} - static order *create_order_i(order *ord, keyword_t kwd, const char *sptr, bool persistent, bool noerror, const struct locale *lang) { - int lindex; order_data *od; assert(ord); @@ -335,16 +272,6 @@ static order *create_order_i(order *ord, keyword_t kwd, const char *sptr, bool p } } - lindex = locale_index(lang); - assert(lindex < MAXLOCALES); - if (!locale_array[lindex]) { - locale_array[lindex] = (locale_data *)calloc(1, sizeof(locale_data)); - } - else if (locale_array[lindex]->lang != lang) { - clear_localedata(lindex); - } - locale_array[lindex]->lang = lang; - ord->command = (int)kwd; if (persistent) ord->command |= CMD_PERSIST; if (noerror) ord->command |= CMD_QUIET; @@ -352,7 +279,7 @@ static order *create_order_i(order *ord, keyword_t kwd, const char *sptr, bool p while (isspace(*(unsigned char *)sptr)) ++sptr; - od = create_data(kwd, sptr, lindex); + od = create_data(kwd, sptr, lang); ord->id = add_data(od); release_data(od); @@ -630,21 +557,30 @@ void push_order(order ** ordp, order * ord) *ordp = ord; } +static order_data *parser_od; + keyword_t init_order(const struct order *ord) { - static order_data *od; - if (!ord) { - release_data(od); + release_data(parser_od); + parser_od = NULL; return NOKEYWORD; } else { - if (od) { + if (parser_od) { // TODO: warning - release_data(od); + release_data(parser_od); } - od = load_data(ord->id); - init_tokens_str(od->_str); + parser_od = load_data(ord->id); + init_tokens_str(OD_STRING(parser_od)); return ORD_KEYWORD(ord); } } + +void close_orders(void) { + if (parser_od) { + init_order(NULL); + } + free_data(); +} + diff --git a/src/spy.c b/src/spy.c index 4039e8a8a..39d60c416 100644 --- a/src/spy.c +++ b/src/spy.c @@ -496,8 +496,8 @@ int sabotage_cmd(unit * u, struct order *ord) init_order(ord); s = getstrtoken(); - p = findparam(s, u->faction->locale); + init_order(NULL); switch (p) { case P_SHIP: diff --git a/src/study.c b/src/study.c index 9d37a7648..a66efd662 100644 --- a/src/study.c +++ b/src/study.c @@ -448,6 +448,7 @@ int teach_cmd(unit * teacher, struct order *ord) if (academy_students > 0 && sk_academy!=NOSKILL) { academy_teaching_bonus(teacher, sk_academy, academy_students); } + init_order(NULL); return 0; } @@ -784,7 +785,7 @@ int study_cmd(unit * u, order * ord) mage = create_mage(u, u->faction->magiegebiet); } } - + init_order(NULL); return 0; } From 34cd692c2d8ecae456c44ada541248b546adbbf8 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 8 Oct 2017 17:07:42 +0200 Subject: [PATCH 12/43] remove the locale from orders. --- scripts/tests/orders.lua | 3 +- src/bind_unit.c | 121 +++++++++++++++++++++---------------- src/bindings.c | 14 ----- src/bindings.h | 1 - src/creport.c | 35 +++++------ src/kernel/command.c | 3 +- src/kernel/jsonconf.test.c | 2 +- src/kernel/order.c | 26 ++++---- src/kernel/order.h | 8 ++- src/kernel/order.test.c | 18 +++--- src/kernel/save.c | 2 +- src/keyword.test.c | 2 +- src/laws.c | 2 +- src/monsters.test.c | 6 +- src/report.c | 21 ++++--- src/reports.c | 53 ++++++++-------- 16 files changed, 163 insertions(+), 154 deletions(-) diff --git a/scripts/tests/orders.lua b/scripts/tests/orders.lua index af0919640..63abaed00 100644 --- a/scripts/tests/orders.lua +++ b/scripts/tests/orders.lua @@ -47,7 +47,8 @@ function test_give() assert_not_equal(5, u2:get_item("money")) end -function test_make_temp() +function disable_test_make_temp() + -- disabled because of TOLUA_ORDERS_CLOSURE u:add_order("MACHE TEMP 123 'Herpderp'") u:add_order("// this comment will be copied") u:add_order("ENDE") diff --git a/src/bind_unit.c b/src/bind_unit.c index 1e1aee00e..00c2b9e09 100644 --- a/src/bind_unit.c +++ b/src/bind_unit.c @@ -763,6 +763,22 @@ static int tolua_unit_get_spells(lua_State * L) return tolua_selist_push(L, "spellbook", "spell_entry", slist); } +#ifdef TOLUA_ORDERS_CLOSURE +/* TODO: this requires that the locale for write_order is included in the closure */ +static int tolua_orderlist_next(lua_State * L) +{ + order **order_ptr = (order **)lua_touserdata(L, lua_upvalueindex(1)); + order *ord = *order_ptr; + if (ord != NULL) { + char cmd[8192]; + write_order(ord, cmd, sizeof(cmd)); + tolua_pushstring(L, cmd); + *order_ptr = ord->next; + return 1; + } + return 0; +} + static int tolua_unit_get_orders(lua_State * L) { unit *self = (unit *)tolua_tousertype(L, 1, 0); @@ -778,7 +794,7 @@ static int tolua_unit_get_orders(lua_State * L) return 1; } - +#endif static int tolua_unit_get_curse(lua_State *L) { unit *self = (unit *)tolua_tousertype(L, 1, 0); const char *name = tolua_tostring(L, 2, 0); @@ -960,95 +976,96 @@ void tolua_unit_open(lua_State * L) NULL); tolua_beginmodule(L, TOLUA_CAST "event"); { - tolua_function(L, TOLUA_CAST "get_type", &tolua_event_gettype); - tolua_function(L, TOLUA_CAST "get", &tolua_event_get); + tolua_function(L, TOLUA_CAST "get_type", tolua_event_gettype); + tolua_function(L, TOLUA_CAST "get", tolua_event_get); } tolua_endmodule(L); tolua_cclass(L, TOLUA_CAST "unit", TOLUA_CAST "unit", TOLUA_CAST "", NULL); tolua_beginmodule(L, TOLUA_CAST "unit"); { - tolua_function(L, TOLUA_CAST "__tostring", &tolua_unit_tostring); - tolua_function(L, TOLUA_CAST "create", &tolua_unit_create); - tolua_function(L, TOLUA_CAST "destroy", &tolua_unit_destroy); + tolua_function(L, TOLUA_CAST "__tostring", tolua_unit_tostring); + tolua_function(L, TOLUA_CAST "create", tolua_unit_create); + tolua_function(L, TOLUA_CAST "destroy", tolua_unit_destroy); - tolua_variable(L, TOLUA_CAST "name", &tolua_unit_get_name, + tolua_variable(L, TOLUA_CAST "name", tolua_unit_get_name, tolua_unit_set_name); - tolua_variable(L, TOLUA_CAST "faction", &tolua_unit_get_faction, + tolua_variable(L, TOLUA_CAST "faction", tolua_unit_get_faction, tolua_unit_set_faction); tolua_variable(L, TOLUA_CAST "id", tolua_unit_get_id, tolua_unit_set_id); tolua_variable(L, TOLUA_CAST "group", tolua_unit_get_group, tolua_unit_set_group); tolua_variable(L, TOLUA_CAST "info", tolua_unit_get_info, tolua_unit_set_info); - tolua_variable(L, TOLUA_CAST "hp", &tolua_unit_get_hp, tolua_unit_set_hp); - tolua_variable(L, TOLUA_CAST "status", &tolua_unit_get_status, + tolua_variable(L, TOLUA_CAST "hp", tolua_unit_get_hp, tolua_unit_set_hp); + tolua_variable(L, TOLUA_CAST "status", tolua_unit_get_status, tolua_unit_set_status); - tolua_variable(L, TOLUA_CAST "familiar", &tolua_unit_get_familiar, + tolua_variable(L, TOLUA_CAST "familiar", tolua_unit_get_familiar, tolua_unit_set_familiar); - tolua_variable(L, TOLUA_CAST "weight", &tolua_unit_get_weight, 0); - tolua_variable(L, TOLUA_CAST "capacity", &tolua_unit_get_capacity, 0); + tolua_variable(L, TOLUA_CAST "weight", tolua_unit_get_weight, 0); + tolua_variable(L, TOLUA_CAST "capacity", tolua_unit_get_capacity, 0); - tolua_function(L, TOLUA_CAST "add_order", &tolua_unit_add_order); - tolua_function(L, TOLUA_CAST "clear_orders", &tolua_unit_clear_orders); - tolua_variable(L, TOLUA_CAST "orders", &tolua_unit_get_orders, 0); - - tolua_function(L, TOLUA_CAST "get_curse", &tolua_unit_get_curse); - tolua_function(L, TOLUA_CAST "has_attrib", &tolua_unit_has_attrib); + tolua_function(L, TOLUA_CAST "add_order", tolua_unit_add_order); + tolua_function(L, TOLUA_CAST "clear_orders", tolua_unit_clear_orders); +#ifdef TOLUA_ORDERS_CLOSURE + tolua_variable(L, TOLUA_CAST "orders", tolua_unit_get_orders, 0); +#endif + tolua_function(L, TOLUA_CAST "get_curse", tolua_unit_get_curse); + tolua_function(L, TOLUA_CAST "has_attrib", tolua_unit_has_attrib); /* key-attributes for named flags: */ - tolua_function(L, TOLUA_CAST "set_flag", &tolua_unit_set_flag); - tolua_function(L, TOLUA_CAST "get_flag", &tolua_unit_get_flag); - tolua_variable(L, TOLUA_CAST "guard", &tolua_unit_get_guard, - &tolua_unit_set_guard); - tolua_variable(L, TOLUA_CAST "flags", &tolua_unit_get_flags, - &tolua_unit_set_flags); - tolua_variable(L, TOLUA_CAST "age", &tolua_unit_get_age, + tolua_function(L, TOLUA_CAST "set_flag", tolua_unit_set_flag); + tolua_function(L, TOLUA_CAST "get_flag", tolua_unit_get_flag); + tolua_variable(L, TOLUA_CAST "guard", tolua_unit_get_guard, + tolua_unit_set_guard); + tolua_variable(L, TOLUA_CAST "flags", tolua_unit_get_flags, + tolua_unit_set_flags); + tolua_variable(L, TOLUA_CAST "age", tolua_unit_get_age, tolua_unit_set_age); /* items: */ - tolua_function(L, TOLUA_CAST "get_item", &tolua_unit_get_item); - tolua_function(L, TOLUA_CAST "add_item", &tolua_unit_add_item); - tolua_variable(L, TOLUA_CAST "items", &tolua_unit_get_items, 0); - tolua_function(L, TOLUA_CAST "get_pooled", &tolua_unit_get_pooled); - tolua_function(L, TOLUA_CAST "use_pooled", &tolua_unit_use_pooled); + tolua_function(L, TOLUA_CAST "get_item", tolua_unit_get_item); + tolua_function(L, TOLUA_CAST "add_item", tolua_unit_add_item); + tolua_variable(L, TOLUA_CAST "items", tolua_unit_get_items, 0); + tolua_function(L, TOLUA_CAST "get_pooled", tolua_unit_get_pooled); + tolua_function(L, TOLUA_CAST "use_pooled", tolua_unit_use_pooled); /* effects */ - tolua_function(L, TOLUA_CAST "get_potion", &tolua_unit_get_effect); + tolua_function(L, TOLUA_CAST "get_potion", tolua_unit_get_effect); /* skills: */ - tolua_function(L, TOLUA_CAST "get_skill", &tolua_unit_getskill); - tolua_function(L, TOLUA_CAST "eff_skill", &tolua_unit_effskill); - tolua_function(L, TOLUA_CAST "set_skill", &tolua_unit_setskill); + tolua_function(L, TOLUA_CAST "get_skill", tolua_unit_getskill); + tolua_function(L, TOLUA_CAST "eff_skill", tolua_unit_effskill); + tolua_function(L, TOLUA_CAST "set_skill", tolua_unit_setskill); - tolua_function(L, TOLUA_CAST "add_notice", &tolua_unit_addnotice); + tolua_function(L, TOLUA_CAST "add_notice", tolua_unit_addnotice); /* npc logic: */ - tolua_function(L, TOLUA_CAST "add_handler", &tolua_unit_addhandler); + tolua_function(L, TOLUA_CAST "add_handler", tolua_unit_addhandler); - tolua_variable(L, TOLUA_CAST "race_name", &tolua_unit_get_racename, - &tolua_unit_set_racename); - tolua_function(L, TOLUA_CAST "add_spell", &tolua_unit_addspell); - tolua_variable(L, TOLUA_CAST "spells", &tolua_unit_get_spells, 0); - tolua_function(L, TOLUA_CAST "cast_spell", &tolua_unit_castspell); + tolua_variable(L, TOLUA_CAST "race_name", tolua_unit_get_racename, + tolua_unit_set_racename); + tolua_function(L, TOLUA_CAST "add_spell", tolua_unit_addspell); + tolua_variable(L, TOLUA_CAST "spells", tolua_unit_get_spells, 0); + tolua_function(L, TOLUA_CAST "cast_spell", tolua_unit_castspell); - tolua_variable(L, TOLUA_CAST "magic", &tolua_unit_get_magic, + tolua_variable(L, TOLUA_CAST "magic", tolua_unit_get_magic, tolua_unit_set_magic); - tolua_variable(L, TOLUA_CAST "aura", &tolua_unit_get_aura, + tolua_variable(L, TOLUA_CAST "aura", tolua_unit_get_aura, tolua_unit_set_aura); - tolua_variable(L, TOLUA_CAST "building", &tolua_unit_get_building, + tolua_variable(L, TOLUA_CAST "building", tolua_unit_get_building, tolua_unit_set_building); - tolua_variable(L, TOLUA_CAST "ship", &tolua_unit_get_ship, + tolua_variable(L, TOLUA_CAST "ship", tolua_unit_get_ship, tolua_unit_set_ship); - tolua_variable(L, TOLUA_CAST "region", &tolua_unit_get_region, + tolua_variable(L, TOLUA_CAST "region", tolua_unit_get_region, tolua_unit_set_region); - tolua_variable(L, TOLUA_CAST "number", &tolua_unit_get_number, + tolua_variable(L, TOLUA_CAST "number", tolua_unit_get_number, tolua_unit_set_number); - tolua_variable(L, TOLUA_CAST "race", &tolua_unit_get_race, + tolua_variable(L, TOLUA_CAST "race", tolua_unit_get_race, tolua_unit_set_race); - tolua_variable(L, TOLUA_CAST "hp_max", &tolua_unit_get_hpmax, 0); - tolua_variable(L, TOLUA_CAST "aura_max", &tolua_unit_get_auramax, 0); + tolua_variable(L, TOLUA_CAST "hp_max", tolua_unit_get_hpmax, 0); + tolua_variable(L, TOLUA_CAST "aura_max", tolua_unit_get_auramax, 0); - tolua_function(L, TOLUA_CAST "show", &tolua_bufunit); + tolua_function(L, TOLUA_CAST "show", tolua_bufunit); } tolua_endmodule(L); } diff --git a/src/bindings.c b/src/bindings.c index 33d609ee0..7a24a3d07 100755 --- a/src/bindings.c +++ b/src/bindings.c @@ -114,20 +114,6 @@ int log_lua_error(lua_State * L) return 1; } -int tolua_orderlist_next(lua_State * L) -{ - order **order_ptr = (order **)lua_touserdata(L, lua_upvalueindex(1)); - order *ord = *order_ptr; - if (ord != NULL) { - char cmd[8192]; - write_order(ord, cmd, sizeof(cmd)); - tolua_pushstring(L, cmd); - *order_ptr = ord->next; - return 1; - } - return 0; -} - static int tolua_selist_iter(lua_State * L) { selist **qlp = (selist **)lua_touserdata(L, lua_upvalueindex(1)); diff --git a/src/bindings.h b/src/bindings.h index 5cb64a038..b5ebf916b 100755 --- a/src/bindings.h +++ b/src/bindings.h @@ -22,7 +22,6 @@ extern "C" { int tolua_sqlite_open(struct lua_State *L); int tolua_bindings_open(struct lua_State *L, const struct _dictionary_ *d); int tolua_itemlist_next(struct lua_State *L); - int tolua_orderlist_next(struct lua_State *L); int tolua_selist_push(struct lua_State *L, const char *list_type, const char *elem_type, struct selist *list); diff --git a/src/creport.c b/src/creport.c index c26d28963..74e32505c 100644 --- a/src/creport.c +++ b/src/creport.c @@ -376,13 +376,13 @@ static int cr_alliance(variant var, char *buffer, const void *userdata) static int cr_skill(variant var, char *buffer, const void *userdata) { - const faction *report = (const faction *)userdata; + const faction *f = (const faction *)userdata; skill_t sk = (skill_t)var.i; UNUSED_ARG(userdata); if (sk != NOSKILL) sprintf(buffer, "\"%s\"", translate(mkname("skill", skillnames[sk]), skillname(sk, - report->locale))); + f->locale))); else strcpy(buffer, "\"\""); return 0; @@ -391,13 +391,14 @@ static int cr_skill(variant var, char *buffer, const void *userdata) static int cr_order(variant var, char *buffer, const void *userdata) { order *ord = (order *)var.v; - UNUSED_ARG(userdata); + const faction *f = (const faction *)userdata; + if (ord != NULL) { char cmd[ORDERSIZE]; char *wp = buffer; const char *rp; - get_command(ord, cmd, sizeof(cmd)); + get_command(ord, f->locale, cmd, sizeof(cmd)); *wp++ = '\"'; for (rp = cmd; *rp;) { @@ -722,11 +723,11 @@ static void cr_output_ship_compat(FILE *F, const ship *sh, const unit *u, cr_output_ship(&strm, sh, u, fcaptain, f, r); } -static int stream_order(stream *out, const struct order *ord) { +static int stream_order(stream *out, const struct order *ord, const struct locale *lang) { const char *str; char ebuf[1025]; char obuf[1024]; - write_order(ord, obuf, sizeof(obuf)); + write_order(ord, lang, obuf, sizeof(obuf)); str = escape_string(obuf, ebuf, sizeof(ebuf)); if (str == ebuf) { ebuf[1024] = 0; @@ -779,6 +780,7 @@ void cr_output_unit(stream *out, const region * r, const faction * f, const faction *fother; const char *prefix; bool allied; + const struct locale *lang = f->locale; assert(u && u->number); assert(u->region == r); /* TODO: if this holds true, then why did we pass in r? */ @@ -787,7 +789,7 @@ void cr_output_unit(stream *out, const region * r, const faction * f, stream_printf(out, "EINHEIT %d\n", u->no); stream_printf(out, "\"%s\";Name\n", unit_getname(u)); - str = u_description(u, f->locale); + str = u_description(u, lang); if (str) { stream_printf(out, "\"%s\";Beschr\n", str); } @@ -833,7 +835,7 @@ void cr_output_unit(stream *out, const region * r, const faction * f, prefix = raceprefix(u); if (prefix) { prefix = mkname("prefix", prefix); - stream_printf(out, "\"%s\";typprefix\n", translate(prefix, LOC(f->locale, + stream_printf(out, "\"%s\";typprefix\n", translate(prefix, LOC(lang, prefix))); } stream_printf(out, "%d;Anzahl\n", u->number); @@ -844,20 +846,20 @@ void cr_output_unit(stream *out, const region * r, const faction * f, if (u->faction == f && fval(u_race(u), RCF_SHAPESHIFTANY)) { const char *zRace = rc_name_s(u_race(u), NAME_PLURAL); stream_printf(out, "\"%s\";wahrerTyp\n", - translate(zRace, LOC(f->locale, zRace))); + translate(zRace, LOC(lang, zRace))); } } else { const race *irace = u_irace(u); const char *zRace = rc_name_s(irace, NAME_PLURAL); stream_printf(out, "\"%s\";Typ\n", - translate(zRace, LOC(f->locale, zRace))); + translate(zRace, LOC(lang, zRace))); if (u->faction == f && irace != u_race(u)) { assert(skill_enabled(SK_STEALTH) || !"we're resetting this on load, so.. ircase should never be used"); zRace = rc_name_s(u_race(u), NAME_PLURAL); stream_printf(out, "\"%s\";wahrerTyp\n", - translate(zRace, LOC(f->locale, zRace))); + translate(zRace, LOC(lang, zRace))); } } @@ -925,7 +927,7 @@ void cr_output_unit(stream *out, const region * r, const faction * f, for (ord = u->old_orders; ord; ord = ord->next) { /* this new order will replace the old defaults */ if (is_persistent(ord)) { - stream_order(out, ord); + stream_order(out, ord, lang); } } for (ord = u->orders; ord; ord = ord->next) { @@ -933,7 +935,7 @@ void cr_output_unit(stream *out, const region * r, const faction * f, if (u->old_orders && is_repeated(kwd)) continue; /* unit has defaults */ if (is_persistent(ord)) { - stream_order(out, ord); + stream_order(out, ord, lang); } } @@ -949,7 +951,7 @@ void cr_output_unit(stream *out, const region * r, const faction * f, } stream_printf(out, "%d %d;%s\n", u->number * level_days(sv->level), esk, translate(mkname("skill", skillnames[sk]), skillname(sk, - f->locale))); + lang))); } } @@ -963,8 +965,7 @@ void cr_output_unit(stream *out, const region * r, const faction * f, const spell *sp = mage->combatspells[i].sp; if (sp) { const char *name = - translate(mkname("spell", sp->sname), spell_name(sp, - f->locale)); + translate(mkname("spell", sp->sname), spell_name(sp, lang)); stream_printf(out, "KAMPFZAUBER %d\n", i); stream_printf(out, "\"%s\";name\n", name); stream_printf(out, "%d;level\n", mage->combatspells[i].level); @@ -999,7 +1000,7 @@ void cr_output_unit(stream *out, const region * r, const faction * f, pr = 1; stream_printf(out, "GEGENSTAENDE\n"); } - stream_printf(out, "%d;%s\n", in, translate(ic, LOC(f->locale, ic))); + stream_printf(out, "%d;%s\n", in, translate(ic, LOC(lang, ic))); } cr_output_curses(out, f, u, TYP_UNIT); diff --git a/src/kernel/command.c b/src/kernel/command.c index 912f21f7d..a6a036fe9 100644 --- a/src/kernel/command.c +++ b/src/kernel/command.c @@ -14,6 +14,7 @@ #include #include "command.h" +#include #include #include @@ -107,7 +108,7 @@ void do_command(const struct tnode *keys, struct unit *u, struct order *ord) init_order(ord); if (do_command_i(keys, u, ord) != E_TOK_SUCCESS) { char cmd[ORDERSIZE]; - get_command(ord, cmd, sizeof(cmd)); + get_command(ord, u->faction->locale, cmd, sizeof(cmd)); log_warning("%s failed command '%s'\n", unitname(u), cmd); } } diff --git a/src/kernel/jsonconf.test.c b/src/kernel/jsonconf.test.c index cb79cafc4..5408f8fb3 100644 --- a/src/kernel/jsonconf.test.c +++ b/src/kernel/jsonconf.test.c @@ -637,7 +637,7 @@ static void test_infinitive_from_config(CuTest *tc) { CuAssertIntEquals(tc, K_STUDY, get_keyword("LERNEN", lang)); ord = create_order(K_STUDY, lang, ""); - CuAssertStrEquals(tc, "LERNE", get_command(ord, buffer, sizeof(buffer))); + CuAssertStrEquals(tc, "LERNE", get_command(ord, lang, buffer, sizeof(buffer))); free_order(ord); cJSON_Delete(json); test_cleanup(); diff --git a/src/kernel/order.c b/src/kernel/order.c index bbb211cb3..154b3f451 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -31,13 +31,11 @@ #include # define ORD_KEYWORD(ord) (keyword_t)((ord)->command & 0xFFFF) -# define OD_LOCALE(odata) ((odata) ? (odata)->lang : NULL) # define OD_STRING(odata) ((odata) ? (odata)->_str : NULL) typedef struct order_data { const char *_str; int _refcount; - const struct locale *lang; } order_data; #include @@ -115,7 +113,7 @@ keyword_t getkeyword(const order * ord) * This is the inverse function to the parse_order command. Note that * keywords are expanded to their full length. */ -char* get_command(const order *ord, char *sbuffer, size_t size) { +char* get_command(const order *ord, const struct locale *lang, char *sbuffer, size_t size) { char *bufp = sbuffer; order_data *od; const char * text; @@ -144,7 +142,6 @@ char* get_command(const order *ord, char *sbuffer, size_t size) { od = load_data(ord->id); text = OD_STRING(od); if (kwd != NOKEYWORD) { - const struct locale *lang = OD_LOCALE(od); if (size > 0) { const char *str = (const char *)LOC(lang, keyword(kwd)); assert(str); @@ -217,13 +214,12 @@ void free_orders(order ** olist) } } -static char *mkdata(order_data **pdata, size_t len, const struct locale *lang, const char *str) +static char *mkdata(order_data **pdata, size_t len, const char *str) { order_data *data; char *result; data = malloc(sizeof(order_data) + len + 1); result = (char *)(data + 1); - data->lang = lang; data->_refcount = 0; data->_str = (len > 0) ? result : NULL; if (str) strcpy(result, str); @@ -231,7 +227,7 @@ static char *mkdata(order_data **pdata, size_t len, const struct locale *lang, c return result; } -static order_data *create_data(keyword_t kwd, const char *sptr, const struct locale *lang) +static order_data *create_data(keyword_t kwd, const char *sptr) { const char *s = sptr; order_data *data; @@ -241,17 +237,17 @@ static order_data *create_data(keyword_t kwd, const char *sptr, const struct loc /* orders with no parameter, only one order_data per order required */ if (kwd != NOKEYWORD && *sptr == 0) { - mkdata(&data, 0, lang, NULL); + mkdata(&data, 0, NULL); data->_refcount = 1; return data; } - mkdata(&data, s ? strlen(s) : 0, lang, s); + mkdata(&data, s ? strlen(s) : 0, s); data->_refcount = 1; return data; } static order *create_order_i(order *ord, keyword_t kwd, const char *sptr, bool persistent, - bool noerror, const struct locale *lang) + bool noerror) { order_data *od; @@ -279,7 +275,7 @@ static order *create_order_i(order *ord, keyword_t kwd, const char *sptr, bool p while (isspace(*(unsigned char *)sptr)) ++sptr; - od = create_data(kwd, sptr, lang); + od = create_data(kwd, sptr); ord->id = add_data(od); release_data(od); @@ -341,7 +337,7 @@ order *create_order(keyword_t kwd, const struct locale * lang, zBuffer[0] = 0; } ord = (order *)malloc(sizeof(order)); - return create_order_i(ord, kwd, zBuffer, false, false, lang); + return create_order_i(ord, kwd, zBuffer, false, false); } order *parse_order(const char *s, const struct locale * lang) @@ -373,7 +369,7 @@ order *parse_order(const char *s, const struct locale * lang) } if (kwd != NOKEYWORD) { order *ord = (order *)malloc(sizeof(order)); - return create_order_i(ord, kwd, sptr, persistent, noerror, lang); + return create_order_i(ord, kwd, sptr, persistent, noerror); } } return NULL; @@ -529,7 +525,7 @@ bool is_silent(const order * ord) return (ord->command & CMD_QUIET) != 0; } -char *write_order(const order * ord, char *buffer, size_t size) +char *write_order(const order * ord, const struct locale *lang, char *buffer, size_t size) { if (ord == 0) { buffer[0] = 0; @@ -544,7 +540,7 @@ char *write_order(const order * ord, char *buffer, size_t size) release_data(od); } else { - get_command(ord, buffer, size); + get_command(ord, lang, buffer, size); } } return buffer; diff --git a/src/kernel/order.h b/src/kernel/order.h index f26174ee4..916055379 100644 --- a/src/kernel/order.h +++ b/src/kernel/order.h @@ -21,6 +21,8 @@ extern "C" { #endif + struct locale; + /* Encapsulation of an order * * This structure contains one order given by a unit. These used to be @@ -57,14 +59,16 @@ extern "C" { /* access functions for orders */ keyword_t getkeyword(const order * ord); void set_order(order ** destp, order * src); - char* get_command(const order *ord, char *buffer, size_t size); + char* get_command(const order *ord, const struct locale *lang, + char *buffer, size_t size); bool is_persistent(const order * ord); bool is_silent(const order * ord); bool is_exclusive(const order * ord); bool is_repeated(keyword_t kwd); bool is_long(keyword_t kwd); - char *write_order(const order * ord, char *buffer, size_t size); + char *write_order(const order * ord, const struct locale *lang, + char *buffer, size_t size); keyword_t init_order(const struct order *ord); void close_orders(void); diff --git a/src/kernel/order.test.c b/src/kernel/order.test.c index e1656efc9..675cd90cf 100644 --- a/src/kernel/order.test.c +++ b/src/kernel/order.test.c @@ -20,7 +20,7 @@ static void test_create_order(CuTest *tc) { ord = create_order(K_MOVE, lang, "NORTH"); CuAssertPtrNotNull(tc, ord); CuAssertIntEquals(tc, K_MOVE, getkeyword(ord)); - CuAssertStrEquals(tc, "move NORTH", get_command(ord, cmd, sizeof(cmd))); + CuAssertStrEquals(tc, "move NORTH", get_command(ord, lang, cmd, sizeof(cmd))); CuAssertIntEquals(tc, K_MOVE, init_order(ord)); CuAssertStrEquals(tc, "NORTH", getstrtoken()); @@ -40,7 +40,7 @@ static void test_parse_order(CuTest *tc) { CuAssertPtrNotNull(tc, ord); CuAssertIntEquals(tc, K_MOVE, ord->command); CuAssertIntEquals(tc, K_MOVE, getkeyword(ord)); - CuAssertStrEquals(tc, "move NORTH", get_command(ord, cmd, sizeof(cmd))); + CuAssertStrEquals(tc, "move NORTH", get_command(ord, lang, cmd, sizeof(cmd))); CuAssertIntEquals(tc, K_MOVE, init_order(ord)); CuAssertStrEquals(tc, "NORTH", getstrtoken()); @@ -98,7 +98,7 @@ static void test_parse_make(CuTest *tc) { ord = parse_order("M hurrdurr", lang); CuAssertPtrNotNull(tc, ord); CuAssertIntEquals(tc, K_MAKE, getkeyword(ord)); - CuAssertStrEquals(tc, "MAKE hurrdurr", get_command(ord, cmd, sizeof(cmd))); + CuAssertStrEquals(tc, "MAKE hurrdurr", get_command(ord, lang, cmd, sizeof(cmd))); CuAssertIntEquals(tc, K_MAKE, init_order(ord)); CuAssertStrEquals(tc, "hurrdurr", getstrtoken()); @@ -121,7 +121,7 @@ static void test_parse_make_temp(CuTest *tc) { ord = parse_order("M T herp", lang); CuAssertPtrNotNull(tc, ord); CuAssertIntEquals(tc, K_MAKETEMP, getkeyword(ord)); - CuAssertStrEquals(tc, "MAKETEMP herp", get_command(ord, cmd, sizeof(cmd))); + CuAssertStrEquals(tc, "MAKETEMP herp", get_command(ord, lang, cmd, sizeof(cmd))); CuAssertIntEquals(tc, K_MAKETEMP, init_order(ord)); CuAssertStrEquals(tc, "herp", getstrtoken()); @@ -144,7 +144,7 @@ static void test_parse_maketemp(CuTest *tc) { ord = parse_order("MAKET herp", lang); CuAssertPtrNotNull(tc, ord); - CuAssertStrEquals(tc, "MAKETEMP herp", get_command(ord, cmd, sizeof(cmd))); + CuAssertStrEquals(tc, "MAKETEMP herp", get_command(ord, lang, cmd, sizeof(cmd))); CuAssertIntEquals(tc, K_MAKETEMP, getkeyword(ord)); CuAssertIntEquals(tc, K_MAKETEMP, init_order(ord)); CuAssertStrEquals(tc, "herp", getstrtoken()); @@ -213,13 +213,13 @@ static void test_get_command(CuTest *tc) { test_setup(); lang = test_create_locale(); ord = create_order(K_MAKE, lang, "iron"); - CuAssertStrEquals(tc, "make iron", get_command(ord, buf, sizeof(buf))); + CuAssertStrEquals(tc, "make iron", get_command(ord, lang, buf, sizeof(buf))); ord->command |= CMD_QUIET; - CuAssertStrEquals(tc, "!make iron", get_command(ord, buf, sizeof(buf))); + CuAssertStrEquals(tc, "!make iron", get_command(ord, lang, buf, sizeof(buf))); ord->command |= CMD_PERSIST; - CuAssertStrEquals(tc, "!@make iron", get_command(ord, buf, sizeof(buf))); + CuAssertStrEquals(tc, "!@make iron", get_command(ord, lang, buf, sizeof(buf))); ord->command = K_MAKE | CMD_PERSIST; - CuAssertStrEquals(tc, "@make iron", get_command(ord, buf, sizeof(buf))); + CuAssertStrEquals(tc, "@make iron", get_command(ord, lang, buf, sizeof(buf))); free_order(ord); test_cleanup(); } diff --git a/src/kernel/save.c b/src/kernel/save.c index aa09a27be..133472d4f 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -379,7 +379,7 @@ static void writeorder(gamedata *data, const struct order *ord, const struct locale *lang) { char obuf[1024]; - write_order(ord, obuf, sizeof(obuf)); + write_order(ord, lang, obuf, sizeof(obuf)); if (obuf[0]) WRITE_STR(data->store, obuf); } diff --git a/src/keyword.test.c b/src/keyword.test.c index 75c31904a..68858367a 100644 --- a/src/keyword.test.c +++ b/src/keyword.test.c @@ -36,7 +36,7 @@ static void test_infinitive(CuTest *tc) { CuAssertIntEquals(tc, K_STUDY, get_keyword("LERNEN", lang)); ord = create_order(K_STUDY, lang, ""); - CuAssertStrEquals(tc, "LERNE", get_command(ord, buffer, sizeof(buffer))); + CuAssertStrEquals(tc, "LERNE", get_command(ord, lang, buffer, sizeof(buffer))); free_order(ord); test_cleanup(); } diff --git a/src/laws.c b/src/laws.c index 6b27e7816..df6c70b89 100644 --- a/src/laws.c +++ b/src/laws.c @@ -968,7 +968,7 @@ int quit_cmd(unit * u, struct order *ord) } else { char buffer[64]; - write_order(ord, buffer, sizeof(buffer)); + write_order(ord, f->locale, buffer, sizeof(buffer)); cmistake(u, ord, 86, MSG_EVENT); log_warning("QUIT with illegal password for faction %s: %s\n", itoa36(f->no), buffer); } diff --git a/src/monsters.test.c b/src/monsters.test.c index 51f122b87..e43ed65cc 100644 --- a/src/monsters.test.c +++ b/src/monsters.test.c @@ -31,12 +31,12 @@ extern void plan_monsters(struct faction *f); extern int monster_attacks(unit * monster, bool rich_only); -static order *find_order(const char *expected, const unit *unit) +static order *find_order(const char *expected, const unit *u) { char cmd[32]; order *ord; - for (ord = unit->orders; ord; ord = ord->next) { - if (strcmp(expected, get_command(ord, cmd, sizeof(cmd))) == 0) { + for (ord = u->orders; ord; ord = ord->next) { + if (strcmp(expected, get_command(ord, u->faction->locale, cmd, sizeof(cmd))) == 0) { return ord; } } diff --git a/src/report.c b/src/report.c index 311cd98b2..3b2dd1d9f 100644 --- a/src/report.c +++ b/src/report.c @@ -1389,7 +1389,8 @@ static int report_template(const char *filename, report_context * ctx, const char *bom) { const resource_type *rsilver = get_resourcetype(R_SILVER); - faction *f = ctx->f; + const faction *f = ctx->f; + const struct locale *lang = f->locale; region *r; FILE *F = fopen(filename, "w"); stream strm = { 0 }, *out = &strm; @@ -1408,11 +1409,11 @@ report_template(const char *filename, report_context * ctx, const char *bom) } newline(out); - rps_nowrap(out, LOC(f->locale, "nr_template")); + rps_nowrap(out, LOC(lang, "nr_template")); newline(out); newline(out); - sprintf(buf, "%s %s \"password\"", LOC(f->locale, parameters[P_FACTION]), itoa36(f->no)); + sprintf(buf, "%s %s \"password\"", LOC(lang, parameters[P_FACTION]), itoa36(f->no)); rps_nowrap(out, buf); newline(out); newline(out); @@ -1439,12 +1440,12 @@ report_template(const char *filename, report_context * ctx, const char *bom) adjust_coordinates(f, &nx, &ny, pl); newline(out); if (pl && pl->id != 0) { - sprintf(buf, "%s %d,%d,%d ; %s", LOC(f->locale, - parameters[P_REGION]), nx, ny, pl->id, rname(r, f->locale)); + sprintf(buf, "%s %d,%d,%d ; %s", LOC(lang, + parameters[P_REGION]), nx, ny, pl->id, rname(r, lang)); } else { - sprintf(buf, "%s %d,%d ; %s", LOC(f->locale, parameters[P_REGION]), - nx, ny, rname(r, f->locale)); + sprintf(buf, "%s %d,%d ; %s", LOC(lang, parameters[P_REGION]), + nx, ny, rname(r, lang)); } rps_nowrap(out, buf); newline(out); @@ -1505,7 +1506,7 @@ report_template(const char *filename, report_context * ctx, const char *bom) for (ord = u->old_orders; ord; ord = ord->next) { /* this new order will replace the old defaults */ strcpy(buf, " "); - write_order(ord, buf + 2, sizeof(buf) - 2); + write_order(ord, lang, buf + 2, sizeof(buf) - 2); rps_nowrap(out, buf); newline(out); } @@ -1515,7 +1516,7 @@ report_template(const char *filename, report_context * ctx, const char *bom) continue; /* unit has defaults */ if (is_persistent(ord)) { strcpy(buf, " "); - write_order(ord, buf + 2, sizeof(buf) - 2); + write_order(ord, lang, buf + 2, sizeof(buf) - 2); rps_nowrap(out, buf); newline(out); } @@ -1527,7 +1528,7 @@ report_template(const char *filename, report_context * ctx, const char *bom) } } newline(out); - strlcpy(buf, LOC(f->locale, parameters[P_NEXT]), sizeof(buf)); + strlcpy(buf, LOC(lang, parameters[P_NEXT]), sizeof(buf)); rps_nowrap(out, buf); newline(out); fstream_done(&strm); diff --git a/src/reports.c b/src/reports.c index e6021134a..265c2ab90 100644 --- a/src/reports.c +++ b/src/reports.c @@ -266,14 +266,14 @@ report_item(const unit * owner, const item * i, const faction * viewer, } #define ORDERS_IN_NR 1 -static size_t buforder(char *buffer, size_t size, const order * ord, int mode) +static size_t buforder(char *buffer, size_t size, const order * ord, const struct locale *lang, int mode) { char *bufp = buffer; bufp = STRLCPY(bufp, ", \"", size); if (mode < ORDERS_IN_NR) { char cmd[ORDERSIZE]; - get_command(ord, cmd, sizeof(cmd)); + get_command(ord, lang, cmd, sizeof(cmd)); bufp = STRLCPY(bufp, cmd, size); } else { @@ -498,6 +498,7 @@ bufunit(const faction * f, const unit * u, unsigned int indent, seen_mode mode, char *bufp = buf; int result = 0; item results[MAX_INVENTORY]; + const struct locale *lang = f->locale; assert(f); bufp = STRLCPY(bufp, unitname(u), size); @@ -514,7 +515,7 @@ bufunit(const faction * f, const unit * u, unsigned int indent, seen_mode mode, } if (getarnt) { bufp = STRLCPY(bufp, ", ", size); - bufp = STRLCPY(bufp, LOC(f->locale, "anonymous"), size); + bufp = STRLCPY(bufp, LOC(lang, "anonymous"), size); } else if (u->attribs) { faction *otherf = get_otherfaction(u); @@ -527,7 +528,7 @@ bufunit(const faction * f, const unit * u, unsigned int indent, seen_mode mode, else { if (getarnt) { bufp = STRLCPY(bufp, ", ", size); - bufp = STRLCPY(bufp, LOC(f->locale, "anonymous"), size); + bufp = STRLCPY(bufp, LOC(lang, "anonymous"), size); } else { if (u->attribs && alliedunit(u, f, HELP_FSTEALTH)) { @@ -562,7 +563,7 @@ bufunit(const faction * f, const unit * u, unsigned int indent, seen_mode mode, bufp = STRLCPY(bufp, pzTmp, size); if (u->faction == f && fval(u_race(u), RCF_SHAPESHIFTANY)) { bufp = STRLCPY(bufp, " (", size); - bufp = STRLCPY(bufp, racename(f->locale, u, u_race(u)), size); + bufp = STRLCPY(bufp, racename(lang, u, u_race(u)), size); if (size > 1) { strcpy(bufp++, ")"); --size; @@ -571,10 +572,10 @@ bufunit(const faction * f, const unit * u, unsigned int indent, seen_mode mode, } else { const race *irace = u_irace(u); - bufp = STRLCPY(bufp, racename(f->locale, u, irace), size); + bufp = STRLCPY(bufp, racename(lang, u, irace), size); if (u->faction == f && irace != u_race(u)) { bufp = STRLCPY(bufp, " (", size); - bufp = STRLCPY(bufp, racename(f->locale, u, u_race(u)), size); + bufp = STRLCPY(bufp, racename(lang, u, u_race(u)), size); if (size > 1) { strcpy(bufp++, ")"); --size; @@ -584,15 +585,15 @@ bufunit(const faction * f, const unit * u, unsigned int indent, seen_mode mode, if (fval(u, UFL_HERO) && (u->faction == f || omniscient(f))) { bufp = STRLCPY(bufp, ", ", size); - bufp = STRLCPY(bufp, LOC(f->locale, "hero"), size); + bufp = STRLCPY(bufp, LOC(lang, "hero"), size); } /* status */ if (u->number && (u->faction == f || isbattle)) { const char *c = hp_status(u); - c = c ? LOC(f->locale, c) : 0; + c = c ? LOC(lang, c) : 0; bufp = STRLCPY(bufp, ", ", size); - bufp += report_status(u, f->locale, bufp, size); + bufp += report_status(u, lang, bufp, size); if (c || fval(u, UFL_HUNGER)) { bufp = STRLCPY(bufp, " (", size); if (c) { @@ -602,7 +603,7 @@ bufunit(const faction * f, const unit * u, unsigned int indent, seen_mode mode, if (c) { bufp = STRLCPY(bufp, ", ", size); } - bufp = STRLCPY(bufp, LOC(f->locale, "unit_hungers"), size); + bufp = STRLCPY(bufp, LOC(lang, "unit_hungers"), size); } if (size > 1) { strcpy(bufp++, ")"); @@ -612,7 +613,7 @@ bufunit(const faction * f, const unit * u, unsigned int indent, seen_mode mode, } if (is_guard(u)) { bufp = STRLCPY(bufp, ", ", size); - bufp = STRLCPY(bufp, LOC(f->locale, "unit_guards"), size); + bufp = STRLCPY(bufp, LOC(lang, "unit_guards"), size); } if ((b = usiege(u)) != NULL) { @@ -624,7 +625,7 @@ bufunit(const faction * f, const unit * u, unsigned int indent, seen_mode mode, if (u->faction == f) { skill *sv; for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { - size_t bytes = spskill(bufp, size, f->locale, u, sv, &dh, 1); + size_t bytes = spskill(bufp, size, lang, u, sv, &dh, 1); assert(bytes <= INT_MAX); if (wrptr(&bufp, &size, (int)bytes) != 0) WARN_STATIC_BUFFER(); @@ -651,7 +652,7 @@ bufunit(const faction * f, const unit * u, unsigned int indent, seen_mode mode, bufp = STRLCPY(bufp, ", ", size); if (!dh) { - result = snprintf(bufp, size, "%s: ", LOC(f->locale, "nr_inventory")); + result = snprintf(bufp, size, "%s: ", LOC(lang, "nr_inventory")); if (wrptr(&bufp, &size, result) != 0) WARN_STATIC_BUFFER(); dh = 1; @@ -681,7 +682,7 @@ bufunit(const faction * f, const unit * u, unsigned int indent, seen_mode mode, if (sbe->level <= maxlevel) { int result = 0; if (!header) { - result = snprintf(bufp, size, ", %s: ", LOC(f->locale, "nr_spells")); + result = snprintf(bufp, size, ", %s: ", LOC(lang, "nr_spells")); header = 1; } else { @@ -691,7 +692,7 @@ bufunit(const faction * f, const unit * u, unsigned int indent, seen_mode mode, WARN_STATIC_BUFFER(); } /* TODO: no need to deref the spellref here (spref->name is good) */ - bufp = STRLCPY(bufp, spell_name(sbe->sp, f->locale), size); + bufp = STRLCPY(bufp, spell_name(sbe->sp, lang), size); } } @@ -701,7 +702,7 @@ bufunit(const faction * f, const unit * u, unsigned int indent, seen_mode mode, } if (i != MAXCOMBATSPELLS) { int result = - snprintf(bufp, size, ", %s: ", LOC(f->locale, "nr_combatspells")); + snprintf(bufp, size, ", %s: ", LOC(lang, "nr_combatspells")); if (wrptr(&bufp, &size, result) != 0) WARN_STATIC_BUFFER(); @@ -717,7 +718,7 @@ bufunit(const faction * f, const unit * u, unsigned int indent, seen_mode mode, sp = get_combatspell(u, i); if (sp) { int sl = get_combatspelllevel(u, i); - bufp = STRLCPY(bufp, spell_name(sp, u->faction->locale), size); + bufp = STRLCPY(bufp, spell_name(sp, lang), size); if (sl > 0) { result = snprintf(bufp, size, " (%d)", sl); if (wrptr(&bufp, &size, result) != 0) @@ -725,7 +726,7 @@ bufunit(const faction * f, const unit * u, unsigned int indent, seen_mode mode, } } else { - bufp = STRLCPY(bufp, LOC(f->locale, "nr_nospells"), size); + bufp = STRLCPY(bufp, LOC(lang, "nr_nospells"), size); } } } @@ -737,7 +738,7 @@ bufunit(const faction * f, const unit * u, unsigned int indent, seen_mode mode, keyword_t kwd = getkeyword(ord); if (is_repeated(kwd)) { if (printed < ORDERS_IN_NR) { - int result = (int)buforder(bufp, size, ord, printed++); + int result = (int)buforder(bufp, size, ord, u->faction->locale, printed++); if (wrptr(&bufp, &size, result) != 0) WARN_STATIC_BUFFER(); } @@ -750,7 +751,7 @@ bufunit(const faction * f, const unit * u, unsigned int indent, seen_mode mode, keyword_t kwd = getkeyword(ord); if (is_repeated(kwd)) { if (printed < ORDERS_IN_NR) { - int result = (int)buforder(bufp, size, ord, printed++); + int result = (int)buforder(bufp, size, ord, lang, printed++); if (wrptr(&bufp, &size, result) != 0) WARN_STATIC_BUFFER(); } @@ -762,7 +763,7 @@ bufunit(const faction * f, const unit * u, unsigned int indent, seen_mode mode, } i = 0; - str = u_description(u, f->locale); + str = u_description(u, lang); if (str) { bufp = STRLCPY(bufp, "; ", size); bufp = STRLCPY(bufp, str, size); @@ -1980,13 +1981,15 @@ static void eval_race(struct opstack **stack, const void *userdata) static void eval_order(struct opstack **stack, const void *userdata) { /* order -> string */ + const faction *f = (const faction *)userdata; const struct order *ord = (const struct order *)opop(stack).v; char buf[4096]; size_t len; variant var; + const struct locale *lang = f ? f->locale : default_locale; UNUSED_ARG(userdata); - write_order(ord, buf, sizeof(buf)); + write_order(ord, lang, buf, sizeof(buf)); len = strlen(buf); var.v = strcpy(balloc(len + 1), buf); opush(stack, var); @@ -1994,8 +1997,8 @@ static void eval_order(struct opstack **stack, const void *userdata) static void eval_resources(struct opstack **stack, const void *userdata) { /* order -> string */ - const faction *report = (const faction *)userdata; - const struct locale *lang = report ? report->locale : default_locale; + const faction *f = (const faction *)userdata; + const struct locale *lang = f ? f->locale : default_locale; const struct resource *res = (const struct resource *)opop(stack).v; char buf[1024]; /* but we only use about half of this */ size_t size = sizeof(buf) - 1; From 42f7be4bb9458d66b02686579dc06fceeb9967f8 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 8 Oct 2017 18:41:59 +0200 Subject: [PATCH 13/43] do not use a list to store several million entries. --- src/kernel/order.c | 46 +++++++++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/src/kernel/order.c b/src/kernel/order.c index 154b3f451..36211ccc4 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -38,24 +38,39 @@ typedef struct order_data { int _refcount; } order_data; -#include +#include -static selist * orders; +static critbit_tree cb_orders = { 0 }; +static int auto_id = 0; + +struct cb_entry { + int id; + order_data *data; +}; order_data *load_data(int id) { + void * match; + if (id > 0) { - order_data * od = (order_data *)selist_get(orders, id - 1); - ++od->_refcount; - return od; + if (cb_find_prefix(&cb_orders, &id, sizeof(id), &match, 1, 0) > 0) { + struct cb_entry *ent = (struct cb_entry *)match; + order_data * od = ent->data; + ++od->_refcount; + return od; + } } return NULL; } -int add_data(order_data *od) { +int save_data(order_data *od) { if (od->_str) { + struct cb_entry ent; + ++od->_refcount; - selist_push(&orders, od); - return selist_length(orders); + ent.id = ++auto_id; + ent.data = od; + cb_insert(&cb_orders, &ent, sizeof(ent)); + return ent.id; } return 0; } @@ -69,18 +84,19 @@ static void release_data(order_data * data) } } -void free_data_cb(void *entry) { - order_data *od = (order_data *)entry; +int free_data_cb(const void *match, const void *key, size_t keylen, void *udata) { + struct cb_entry * ent = (struct cb_entry *)match; + order_data *od = ent->data; if (od->_refcount > 1) { - log_error("refcount=%d for order %s", od->_refcount, od->_str); + log_error("refcount=%d for order %d, %s", od->_refcount, ent->id, od->_str); } release_data(od); + return 0; } void free_data(void) { - selist_foreach(orders, free_data_cb); - selist_free(orders); - orders = NULL; + cb_foreach(&cb_orders, NULL, 0, free_data_cb, NULL); + cb_clear(&cb_orders); } void replace_order(order ** dlist, order * orig, const order * src) @@ -276,7 +292,7 @@ static order *create_order_i(order *ord, keyword_t kwd, const char *sptr, bool p while (isspace(*(unsigned char *)sptr)) ++sptr; od = create_data(kwd, sptr); - ord->id = add_data(od); + ord->id = save_data(od); release_data(od); return ord; From 10331434113c0eab4a150a59531a34c9d8f18143 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 8 Oct 2017 18:49:14 +0200 Subject: [PATCH 14/43] fix gcc build --- src/kernel/order.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernel/order.c b/src/kernel/order.c index 36211ccc4..e11b652ae 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -580,7 +580,7 @@ keyword_t init_order(const struct order *ord) } else { if (parser_od) { - // TODO: warning + /* TODO: warning */ release_data(parser_od); } parser_od = load_data(ord->id); From 394839f7a4015c18fb6a7e627d566d7d92c7debc Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 9 Oct 2017 18:25:57 +0200 Subject: [PATCH 15/43] WIP: optimized study orders, failing 15 study tests --- src/kernel/order.c | 76 ++++++++++++++++++++++------------------------ 1 file changed, 37 insertions(+), 39 deletions(-) diff --git a/src/kernel/order.c b/src/kernel/order.c index e11b652ae..4124651c9 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -62,10 +62,9 @@ order_data *load_data(int id) { return NULL; } -int save_data(order_data *od) { +int save_data(keyword_t kwd, order_data *od) { if (od->_str) { struct cb_entry ent; - ++od->_refcount; ent.id = ++auto_id; ent.data = od; @@ -131,7 +130,7 @@ keyword_t getkeyword(const order * ord) */ char* get_command(const order *ord, const struct locale *lang, char *sbuffer, size_t size) { char *bufp = sbuffer; - order_data *od; + order_data *od = NULL; const char * text; keyword_t kwd = ORD_KEYWORD(ord); int bytes; @@ -155,8 +154,14 @@ char* get_command(const order *ord, const struct locale *lang, char *sbuffer, si } } - od = load_data(ord->id); - text = OD_STRING(od); + if (ord->id < 0) { + skill_t sk = (skill_t)(100-ord->id); + assert(kwd == K_STUDY && sk != SK_MAGIC); + text = skillname(sk, lang); + } else { + od = load_data(ord->id); + text = OD_STRING(od); + } if (kwd != NOKEYWORD) { if (size > 0) { const char *str = (const char *)LOC(lang, keyword(kwd)); @@ -187,7 +192,9 @@ char* get_command(const order *ord, const struct locale *lang, char *sbuffer, si } } } - release_data(od); + if (od) { + release_data(od); + } if (size > 0) *bufp = 0; return sbuffer; } @@ -236,54 +243,48 @@ static char *mkdata(order_data **pdata, size_t len, const char *str) char *result; data = malloc(sizeof(order_data) + len + 1); result = (char *)(data + 1); - data->_refcount = 0; + data->_refcount = 1; data->_str = (len > 0) ? result : NULL; if (str) strcpy(result, str); if (pdata) *pdata = data; return result; } -static order_data *create_data(keyword_t kwd, const char *sptr) +static int create_data(keyword_t kwd, const char *s, + const struct locale *lang) { - const char *s = sptr; order_data *data; + int id; - if (kwd != NOKEYWORD) - s = (*sptr) ? sptr : NULL; + assert(kwd!=NOKEYWORD); - /* orders with no parameter, only one order_data per order required */ - if (kwd != NOKEYWORD && *sptr == 0) { - mkdata(&data, 0, NULL); - data->_refcount = 1; - return data; + if (!s || *s == 0) { + return 0; } + if (kwd==K_STUDY) { + const char * sptr = s; + skill_t sk = get_skill(parse_token_depr(&sptr), lang); + if (sk != SK_MAGIC && sk != NOSKILL) { + return ((int)sk)-100; + } + } + /* TODO: between mkdata and release_data, this object is very + * short-lived. */ mkdata(&data, s ? strlen(s) : 0, s); - data->_refcount = 1; - return data; + id = save_data(kwd, data); + release_data(data); + return id; } -static order *create_order_i(order *ord, keyword_t kwd, const char *sptr, bool persistent, - bool noerror) +static order *create_order_i(order *ord, const struct locale *lang, + keyword_t kwd, const char *sptr, bool persistent, bool noerror) { - order_data *od; - assert(ord); if (kwd == NOKEYWORD || keyword_disabled(kwd)) { log_error("trying to create an order for disabled keyword %s.", keyword(kwd)); return NULL; } - /* if this is just nonsense, then we skip it. */ - if (lomem) { - switch (kwd) { - case K_KOMMENTAR: - case NOKEYWORD: - return NULL; - default: - break; - } - } - ord->command = (int)kwd; if (persistent) ord->command |= CMD_PERSIST; if (noerror) ord->command |= CMD_QUIET; @@ -291,10 +292,7 @@ static order *create_order_i(order *ord, keyword_t kwd, const char *sptr, bool p while (isspace(*(unsigned char *)sptr)) ++sptr; - od = create_data(kwd, sptr); - ord->id = save_data(od); - release_data(od); - + ord->id = create_data(kwd, sptr, lang); return ord; } @@ -353,7 +351,7 @@ order *create_order(keyword_t kwd, const struct locale * lang, zBuffer[0] = 0; } ord = (order *)malloc(sizeof(order)); - return create_order_i(ord, kwd, zBuffer, false, false); + return create_order_i(ord, lang, kwd, zBuffer, false, false); } order *parse_order(const char *s, const struct locale * lang) @@ -385,7 +383,7 @@ order *parse_order(const char *s, const struct locale * lang) } if (kwd != NOKEYWORD) { order *ord = (order *)malloc(sizeof(order)); - return create_order_i(ord, kwd, sptr, persistent, noerror); + return create_order_i(ord, lang, kwd, sptr, persistent, noerror); } } return NULL; From 333ef06fefcd69c061b409596adf8ace1cce1cfd Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 9 Oct 2017 20:33:47 +0200 Subject: [PATCH 16/43] hackish optimization for STUDY orders --- src/battle.c | 2 +- src/bind_order.c | 2 +- src/economy.c | 24 +++++++++--------- src/give.c | 2 +- src/items.c | 2 +- src/kernel/alliance.c | 10 ++++---- src/kernel/build.c | 2 +- src/kernel/command.c | 2 +- src/kernel/config.test.c | 24 +++++++++--------- src/kernel/order.c | 31 ++++++++++++++++++----- src/kernel/order.h | 3 ++- src/kernel/order.test.c | 52 +++++++++++++++++++++++++++++++++----- src/laws.c | 54 ++++++++++++++++++++-------------------- src/magic.c | 2 +- src/move.c | 22 ++++++++-------- src/move.test.c | 2 +- src/piracy.c | 4 +-- src/renumber.c | 2 +- src/spy.c | 8 +++--- src/study.c | 18 +++++++------- 20 files changed, 164 insertions(+), 104 deletions(-) diff --git a/src/battle.c b/src/battle.c index a60eeebb2..79e3c7a32 100644 --- a/src/battle.c +++ b/src/battle.c @@ -3841,7 +3841,7 @@ static bool start_battle(region * r, battle ** bp) /* Ende Fehlerbehandlung Angreifer */ - init_order(ord); + init_order_depr(ord); /* attackierte Einheit ermitteln */ getunit(r, u->faction, &u2); diff --git a/src/bind_order.c b/src/bind_order.c index 84399deec..cfbe51d16 100644 --- a/src/bind_order.c +++ b/src/bind_order.c @@ -13,7 +13,7 @@ static int tolua_order_get_token(lua_State *L) { order *ord = (order *)tolua_tousertype(L, 1, 0); int n = (int)tolua_tonumber(L, 2, 0); const char * str = 0; - init_order(ord); + init_order_depr(ord); while (n-->0) { str = getstrtoken(); if (!str) { diff --git a/src/economy.c b/src/economy.c index 73007b750..54fccd005 100644 --- a/src/economy.c +++ b/src/economy.c @@ -441,7 +441,7 @@ static void recruit(unit * u, struct order *ord, request ** recruitorders) const char *str; int n; - init_order(ord); + init_order_depr(ord); n = getint(); if (n <= 0) { syntax_error(u, ord); @@ -598,7 +598,7 @@ int give_control_cmd(unit * u, order * ord) unit *u2; const char *s; - init_order(ord); + init_order_depr(ord); getunit(r, u->faction, &u2); s = gettoken(token, sizeof(token)); @@ -657,7 +657,7 @@ static int forget_cmd(unit * u, order * ord) return 0; } - init_order(ord); + init_order_depr(ord); s = gettoken(token, sizeof(token)); sk = get_skill(s, u->faction->locale); @@ -1303,7 +1303,7 @@ int make_cmd(unit * u, struct order *ord) char ibuf[16]; keyword_t kwd; - kwd = init_order(ord); + kwd = init_order_depr(ord); assert(kwd == K_MAKE); s = gettoken(token, sizeof(token)); @@ -1582,7 +1582,7 @@ static void buy(unit * u, request ** buyorders, struct order *ord) /* Im Augenblick kann man nur 1 Produkt kaufen. expandbuying ist aber * schon daf�r ausger�stet, mehrere Produkte zu kaufen. */ - kwd = init_order(ord); + kwd = init_order_depr(ord); assert(kwd == K_BUY); n = getint(); if (n <= 0) { @@ -1896,7 +1896,7 @@ static bool sell(unit * u, request ** sellorders, struct order *ord) /* sellorders sind KEIN array, weil f�r alle items DIE SELBE resource * (das geld der region) aufgebraucht wird. */ - kwd = init_order(ord); + kwd = init_order_depr(ord); assert(kwd == K_SELL); s = gettoken(token, sizeof(token)); @@ -2287,7 +2287,7 @@ static void breed_cmd(unit * u, struct order *ord) } /* z�chte [] */ - (void)init_order(ord); + (void)init_order_depr(ord); s = gettoken(token, sizeof(token)); m = s ? atoip(s) : 0; @@ -2354,7 +2354,7 @@ static void research_cmd(unit * u, struct order *ord) region *r = u->region; keyword_t kwd; - kwd = init_order(ord); + kwd = init_order_depr(ord); assert(kwd == K_RESEARCH); if (effskill(u, SK_HERBALISM, 0) < 7) { @@ -2430,7 +2430,7 @@ static void steal_cmd(unit * u, struct order *ord, request ** stealorders) message * msg; keyword_t kwd; - kwd = init_order(ord); + kwd = init_order_depr(ord); assert(kwd == K_STEAL); assert(skill_enabled(SK_PERCEPTION) && skill_enabled(SK_STEALTH)); @@ -2568,7 +2568,7 @@ void entertain_cmd(unit * u, struct order *ord) static int entertainperlevel = 0; keyword_t kwd; - kwd = init_order(ord); + kwd = init_order_depr(ord); assert(kwd == K_ENTERTAIN); if (!entertainbase) { const char *str = config_get("entertain.base"); @@ -2778,7 +2778,7 @@ void tax_cmd(unit * u, struct order *ord, request ** taxorders) taxperlevel = config_get_int("taxing.perlevel", 0); } - kwd = init_order(ord); + kwd = init_order_depr(ord); assert(kwd == K_TAX); if (!humanoidrace(u_race(u)) && !is_monsters(u->faction)) { @@ -2847,7 +2847,7 @@ void loot_cmd(unit * u, struct order *ord, request ** lootorders) request *o; keyword_t kwd; - kwd = init_order(ord); + kwd = init_order_depr(ord); assert(kwd == K_LOOT); if (config_get_int("rules.enable_loot", 0) == 0 && !is_monsters(u->faction)) { diff --git a/src/give.c b/src/give.c index 0dab27f2f..6d9137522 100644 --- a/src/give.c +++ b/src/give.c @@ -634,7 +634,7 @@ void give_cmd(unit * u, order * ord) message *msg; keyword_t kwd; - kwd = init_order(ord); + kwd = init_order_depr(ord); assert(kwd == K_GIVE); err = getunit(r, u->faction, &u2); s = gettoken(token, sizeof(token)); diff --git a/src/items.c b/src/items.c index 8a6328d91..fe59ffa15 100644 --- a/src/items.c +++ b/src/items.c @@ -47,7 +47,7 @@ static int use_studypotion(struct unit *u, const struct item_type *itype, int amount, struct order *ord) { - if (u->thisorder && init_order(u->thisorder) == K_STUDY) { + if (u->thisorder && init_order(u->thisorder, u->faction->locale) == K_STUDY) { char token[128]; skill_t sk = NOSKILL; skill *sv = 0; diff --git a/src/kernel/alliance.c b/src/kernel/alliance.c index 910670d10..e4fd7c3b5 100644 --- a/src/kernel/alliance.c +++ b/src/kernel/alliance.c @@ -171,7 +171,7 @@ static void perform_kick(void) if (al && alliance_get_leader(al) == ta->u->faction) { faction *f; - init_order(ta->ord); + init_order_depr(ta->ord); skip_token(); f = getfaction(); if (f && f_get_alliance(f) == al) { @@ -192,7 +192,7 @@ static void perform_new(void) int id; faction *f = ta->u->faction; - init_order(ta->ord); + init_order_depr(ta->ord); skip_token(); id = getid(); @@ -227,7 +227,7 @@ static void perform_transfer(void) if (al && alliance_get_leader(al) == ta->u->faction) { faction *f; - init_order(ta->ord); + init_order_depr(ta->ord); skip_token(); f = getfaction(); if (f && f_get_alliance(f) == al) { @@ -264,7 +264,7 @@ static void perform_join(void) faction *fj = ta->u->faction; int aid; - init_order(ta->ord); + init_order_depr(ta->ord); skip_token(); aid = getid(); if (aid) { @@ -276,7 +276,7 @@ static void perform_join(void) faction *fi = ti->u->faction; if (fi && f_get_alliance(fi) == al) { int fid; - init_order(ti->ord); + init_order_depr(ti->ord); skip_token(); fid = getid(); if (fid == fj->no) { diff --git a/src/kernel/build.c b/src/kernel/build.c index 2de25938e..52228d4b9 100644 --- a/src/kernel/build.c +++ b/src/kernel/build.c @@ -161,7 +161,7 @@ int destroy_cmd(unit * u, struct order *ord) return 52; } - init_order(ord); + init_order_depr(ord); s = gettoken(token, sizeof(token)); if (s && *s) { diff --git a/src/kernel/command.c b/src/kernel/command.c index a6a036fe9..8b2a7e5e8 100644 --- a/src/kernel/command.c +++ b/src/kernel/command.c @@ -105,7 +105,7 @@ static int do_command_i(const struct tnode *keys, struct unit *u, struct order * void do_command(const struct tnode *keys, struct unit *u, struct order *ord) { - init_order(ord); + init_order_depr(ord); if (do_command_i(keys, u, ord) != E_TOK_SUCCESS) { char cmd[ORDERSIZE]; get_command(ord, u->faction->locale, cmd, sizeof(cmd)); diff --git a/src/kernel/config.test.c b/src/kernel/config.test.c index ac35b85a3..610c2d4b3 100644 --- a/src/kernel/config.test.c +++ b/src/kernel/config.test.c @@ -32,28 +32,28 @@ static void test_read_unitid(CuTest *tc) { a->data.i = atoi36("42"); /* this unit is also TEMP 42 */ ord = create_order(K_GIVE, lang, "TEMP 42"); - init_order(ord); + init_order_depr(ord); CuAssertIntEquals(tc, u->no, read_unitid(u->faction, u->region)); free_order(ord); ord = create_order(K_GIVE, lang, "8"); - init_order(ord); + init_order_depr(ord); CuAssertIntEquals(tc, 8, read_unitid(u->faction, u->region)); free_order(ord); ord = create_order(K_GIVE, lang, ""); - init_order(ord); + init_order_depr(ord); CuAssertIntEquals(tc, -1, read_unitid(u->faction, u->region)); free_order(ord); ord = create_order(K_GIVE, lang, "TEMP"); - init_order(ord); + init_order_depr(ord); CuAssertIntEquals(tc, -1, read_unitid(u->faction, u->region)); free_order(ord); /* bug https://bugs.eressea.de/view.php?id=1685 */ ord = create_order(K_GIVE, lang, "##"); - init_order(ord); + init_order_depr(ord); CuAssertIntEquals(tc, -1, read_unitid(u->faction, u->region)); free_order(ord); @@ -78,42 +78,42 @@ static void test_getunit(CuTest *tc) { r = test_create_region(1, 0, t_plain); ord = create_order(K_GIVE, lang, itoa36(u->no)); - init_order(ord); + init_order_depr(ord); CuAssertIntEquals(tc, GET_UNIT, getunit(u->region, u->faction, &u2)); CuAssertPtrEquals(tc, u, u2); - init_order(ord); + init_order_depr(ord); CuAssertIntEquals(tc, GET_NOTFOUND, getunit(r, u->faction, &u2)); CuAssertPtrEquals(tc, NULL, u2); free_order(ord); ord = create_order(K_GIVE, lang, itoa36(u->no + 1)); - init_order(ord); + init_order_depr(ord); CuAssertIntEquals(tc, GET_NOTFOUND, getunit(u->region, u->faction, &u2)); CuAssertPtrEquals(tc, NULL, u2); free_order(ord); ord = create_order(K_GIVE, lang, "0"); - init_order(ord); + init_order_depr(ord); CuAssertIntEquals(tc, GET_PEASANTS, getunit(u->region, u->faction, &u2)); CuAssertPtrEquals(tc, NULL, u2); free_order(ord); /* bug https://bugs.eressea.de/view.php?id=1685 */ ord = create_order(K_GIVE, lang, "TEMP ##"); - init_order(ord); + init_order_depr(ord); CuAssertIntEquals(tc, GET_NOTFOUND, getunit(u->region, u->faction, &u2)); CuAssertPtrEquals(tc, NULL, u2); free_order(ord); /* bug https://bugs.eressea.de/view.php?id=1685 */ ord = create_order(K_GIVE, lang, "##"); - init_order(ord); + init_order_depr(ord); CuAssertIntEquals(tc, GET_NOTFOUND, getunit(u->region, u->faction, &u2)); CuAssertPtrEquals(tc, NULL, u2); free_order(ord); ord = create_order(K_GIVE, lang, "TEMP 42"); - init_order(ord); + init_order_depr(ord); CuAssertIntEquals(tc, GET_UNIT, getunit(u->region, u->faction, &u2)); CuAssertPtrEquals(tc, u, u2); free_order(ord); diff --git a/src/kernel/order.c b/src/kernel/order.c index 4124651c9..7cdb2961d 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -155,7 +155,7 @@ char* get_command(const order *ord, const struct locale *lang, char *sbuffer, si } if (ord->id < 0) { - skill_t sk = (skill_t)(100-ord->id); + skill_t sk = (skill_t)(100+ord->id); assert(kwd == K_STUDY && sk != SK_MAGIC); text = skillname(sk, lang); } else { @@ -569,7 +569,7 @@ void push_order(order ** ordp, order * ord) static order_data *parser_od; -keyword_t init_order(const struct order *ord) +keyword_t init_order(const struct order *ord, const struct locale *lang) { if (!ord) { release_data(parser_od); @@ -577,19 +577,38 @@ keyword_t init_order(const struct order *ord) return NOKEYWORD; } else { + keyword_t kwd = ORD_KEYWORD(ord); if (parser_od) { /* TODO: warning */ release_data(parser_od); + parser_od = NULL; } - parser_od = load_data(ord->id); - init_tokens_str(OD_STRING(parser_od)); - return ORD_KEYWORD(ord); + if (ord->id < 0) { + skill_t sk = (skill_t)(100 + ord->id); + assert(lang); + assert(kwd == K_STUDY); + init_tokens_str(skillname(sk, lang)); + } + else { + parser_od = load_data(ord->id); + init_tokens_str(OD_STRING(parser_od)); + } + return kwd; } } +keyword_t init_order_depr(const struct order *ord) +{ + if (ord) { + keyword_t kwd = ORD_KEYWORD(ord); + assert(kwd != K_STUDY); + } + return init_order(ord, NULL); +} + void close_orders(void) { if (parser_od) { - init_order(NULL); + (void)init_order(NULL, NULL); } free_data(); } diff --git a/src/kernel/order.h b/src/kernel/order.h index 916055379..0cbe4989c 100644 --- a/src/kernel/order.h +++ b/src/kernel/order.h @@ -69,7 +69,8 @@ extern "C" { char *write_order(const order * ord, const struct locale *lang, char *buffer, size_t size); - keyword_t init_order(const struct order *ord); + keyword_t init_order_depr(const struct order *ord); + keyword_t init_order(const struct order *ord, const struct locale *lang); void close_orders(void); diff --git a/src/kernel/order.test.c b/src/kernel/order.test.c index 675cd90cf..c892e7e54 100644 --- a/src/kernel/order.test.c +++ b/src/kernel/order.test.c @@ -2,6 +2,8 @@ #include #include "order.h" +#include + #include #include @@ -22,7 +24,7 @@ static void test_create_order(CuTest *tc) { CuAssertIntEquals(tc, K_MOVE, getkeyword(ord)); CuAssertStrEquals(tc, "move NORTH", get_command(ord, lang, cmd, sizeof(cmd))); - CuAssertIntEquals(tc, K_MOVE, init_order(ord)); + CuAssertIntEquals(tc, K_MOVE, init_order_depr(ord)); CuAssertStrEquals(tc, "NORTH", getstrtoken()); free_order(ord); test_cleanup(); @@ -42,7 +44,7 @@ static void test_parse_order(CuTest *tc) { CuAssertIntEquals(tc, K_MOVE, getkeyword(ord)); CuAssertStrEquals(tc, "move NORTH", get_command(ord, lang, cmd, sizeof(cmd))); - CuAssertIntEquals(tc, K_MOVE, init_order(ord)); + CuAssertIntEquals(tc, K_MOVE, init_order_depr(ord)); CuAssertStrEquals(tc, "NORTH", getstrtoken()); free_order(ord); @@ -100,7 +102,7 @@ static void test_parse_make(CuTest *tc) { CuAssertIntEquals(tc, K_MAKE, getkeyword(ord)); CuAssertStrEquals(tc, "MAKE hurrdurr", get_command(ord, lang, cmd, sizeof(cmd))); - CuAssertIntEquals(tc, K_MAKE, init_order(ord)); + CuAssertIntEquals(tc, K_MAKE, init_order_depr(ord)); CuAssertStrEquals(tc, "hurrdurr", getstrtoken()); free_order(ord); test_cleanup(); @@ -123,7 +125,7 @@ static void test_parse_make_temp(CuTest *tc) { CuAssertIntEquals(tc, K_MAKETEMP, getkeyword(ord)); CuAssertStrEquals(tc, "MAKETEMP herp", get_command(ord, lang, cmd, sizeof(cmd))); - CuAssertIntEquals(tc, K_MAKETEMP, init_order(ord)); + CuAssertIntEquals(tc, K_MAKETEMP, init_order_depr(ord)); CuAssertStrEquals(tc, "herp", getstrtoken()); free_order(ord); test_cleanup(); @@ -146,7 +148,7 @@ static void test_parse_maketemp(CuTest *tc) { CuAssertPtrNotNull(tc, ord); CuAssertStrEquals(tc, "MAKETEMP herp", get_command(ord, lang, cmd, sizeof(cmd))); CuAssertIntEquals(tc, K_MAKETEMP, getkeyword(ord)); - CuAssertIntEquals(tc, K_MAKETEMP, init_order(ord)); + CuAssertIntEquals(tc, K_MAKETEMP, init_order_depr(ord)); CuAssertStrEquals(tc, "herp", getstrtoken()); free_order(ord); test_cleanup(); @@ -160,7 +162,7 @@ static void test_init_order(CuTest *tc) { lang = get_or_create_locale("en"); ord = create_order(K_MAKETEMP, lang, "hurr durr"); - CuAssertIntEquals(tc, K_MAKETEMP, init_order(ord)); + CuAssertIntEquals(tc, K_MAKETEMP, init_order_depr(ord)); CuAssertStrEquals(tc, "hurr", getstrtoken()); CuAssertStrEquals(tc, "durr", getstrtoken()); free_order(ord); @@ -292,10 +294,48 @@ static void test_is_silent(CuTest *tc) { test_cleanup(); } + +static void test_study_orders(CuTest *tc) { + order *ord; + struct locale *lang; + const char *s; + char token[16]; + + test_setup(); + lang = test_create_locale(); + + ord = create_order(K_STUDY, lang, skillname(SK_CROSSBOW, lang)); + CuAssertIntEquals(tc, K_STUDY, getkeyword(ord)); + CuAssertIntEquals(tc, K_STUDY, init_order(ord, lang)); + s = gettoken(token, sizeof(token)); + CuAssertStrEquals(tc, skillname(SK_CROSSBOW, lang), s); + CuAssertPtrEquals(tc, NULL, (void *)getstrtoken()); + free_order(ord); + + ord = create_order(K_STUDY, lang, skillname(SK_MAGIC, lang)); + CuAssertIntEquals(tc, K_STUDY, getkeyword(ord)); + CuAssertIntEquals(tc, K_STUDY, init_order(ord, lang)); + s = gettoken(token, sizeof(token)); + CuAssertStrEquals(tc, skillname(SK_MAGIC, lang), s); + CuAssertPtrEquals(tc, NULL, (void *)getstrtoken()); + free_order(ord); + + ord = create_order(K_STUDY, lang, "%s 100", skillname(SK_MAGIC, lang)); + CuAssertIntEquals(tc, K_STUDY, getkeyword(ord)); + CuAssertIntEquals(tc, K_STUDY, init_order(ord, lang)); + s = gettoken(token, sizeof(token)); + CuAssertStrEquals(tc, skillname(SK_MAGIC, lang), s); + CuAssertIntEquals(tc, 100, getint()); + free_order(ord); + + test_cleanup(); +} + CuSuite *get_order_suite(void) { CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_create_order); + SUITE_ADD_TEST(suite, test_study_orders); SUITE_ADD_TEST(suite, test_parse_order); SUITE_ADD_TEST(suite, test_parse_make); SUITE_ADD_TEST(suite, test_parse_make_temp); diff --git a/src/laws.c b/src/laws.c index df6c70b89..033dfbcd0 100644 --- a/src/laws.c +++ b/src/laws.c @@ -910,7 +910,7 @@ int contact_cmd(unit * u, order * ord) unit *u2; int n; - init_order(ord); + init_order_depr(ord); n = read_unitid(u->faction, u->region); u2 = findunit(n); @@ -960,7 +960,7 @@ int quit_cmd(unit * u, struct order *ord) const char *passwd; keyword_t kwd; - kwd = init_order(ord); + kwd = init_order_depr(ord); assert(kwd == K_QUIT); passwd = gettoken(token, sizeof(token)); if (checkpasswd(f, (const char *)passwd)) { @@ -1146,7 +1146,7 @@ void do_enter(struct region *r, bool is_final_attempt) unit *ulast = NULL; const char * s; - init_order(ord); + init_order_depr(ord); s = gettoken(token, sizeof(token)); p = findparam_ex(s, u->faction->locale); id = getid(); @@ -1306,7 +1306,7 @@ int ally_cmd(unit * u, struct order *ord) int keyword, not_kw; const char *s; - init_order(ord); + init_order_depr(ord); f = getfaction(); if (f == NULL || is_monsters(f)) { @@ -1473,7 +1473,7 @@ int prefix_cmd(unit * u, struct order *ord) for (in = pnames; in->lang != lang; in = in->next); } - init_order(ord); + init_order_depr(ord); s = gettoken(token, sizeof(token)); if (!s || !*s) { @@ -1517,7 +1517,7 @@ int display_cmd(unit * u, struct order *ord) const char *str; region *r = u->region; - init_order(ord); + init_order_depr(ord); str = gettoken(token, sizeof(token)); switch (findparam_ex(str, u->faction->locale)) { @@ -1690,7 +1690,7 @@ int name_cmd(struct unit *u, struct order *ord) bool foreign = false; const char *str; - init_order(ord); + init_order_depr(ord); str = gettoken(token, sizeof(token)); p = findparam_ex(str, u->faction->locale); @@ -1948,7 +1948,7 @@ int mail_cmd(unit * u, struct order *ord) const char *s; int n, cont; - init_order(ord); + init_order_depr(ord); s = gettoken(token, sizeof(token)); /* Falls kein Parameter, ist das eine Einheitsnummer; @@ -2105,7 +2105,7 @@ int banner_cmd(unit * u, struct order *ord) const char * s; free(u->faction->banner); - init_order(ord); + init_order_depr(ord); s = getstrtoken(); u->faction->banner = s ? strdup(s) : 0; add_message(&u->faction->msgs, msg_message("changebanner", "value", @@ -2118,7 +2118,7 @@ int email_cmd(unit * u, struct order *ord) { const char *s; - init_order(ord); + init_order_depr(ord); s = getstrtoken(); if (!s || !s[0]) { @@ -2144,7 +2144,7 @@ int password_cmd(unit * u, struct order *ord) const char *s; bool pwok = true; - init_order(ord); + init_order_depr(ord); s = gettoken(pwbuf, sizeof(pwbuf)); if (!s || !*s) { @@ -2177,7 +2177,7 @@ int send_cmd(unit * u, struct order *ord) const char *s; int option; - init_order(ord); + init_order_depr(ord); s = gettoken(token, sizeof(token)); option = findoption(s, u->faction->locale); @@ -2512,7 +2512,7 @@ int group_cmd(unit * u, struct order *ord) { keyword_t kwd; - kwd = init_order(ord); + kwd = init_order_depr(ord); assert(kwd == K_GROUP); join_group(u, getstrtoken()); return 0; @@ -2522,7 +2522,7 @@ int origin_cmd(unit * u, struct order *ord) { short px, py; - init_order(ord); + init_order_depr(ord); px = (short)getint(); py = (short)getint(); @@ -2534,7 +2534,7 @@ int origin_cmd(unit * u, struct order *ord) int guard_off_cmd(unit * u, struct order *ord) { assert(getkeyword(ord) == K_GUARD); - init_order(ord); + init_order_depr(ord); if (getparam(u->faction->locale) == P_NOT) { setguard(u, false); @@ -2548,7 +2548,7 @@ int reshow_cmd(unit * u, struct order *ord) const char *s; param_t p = NOPARAM; - init_order(ord); + init_order_depr(ord); s = gettoken(lbuf, sizeof(lbuf)); if (s && isparam(s, u->faction->locale, P_ANY)) { @@ -2565,7 +2565,7 @@ int status_cmd(unit * u, struct order *ord) char token[128]; const char *s; - init_order(ord); + init_order_depr(ord); s = gettoken(token, sizeof(token)); switch (findparam(s, u->faction->locale)) { case P_NOT: @@ -2613,7 +2613,7 @@ int combatspell_cmd(unit * u, struct order *ord) int level = 0; spell *sp = 0; - init_order(ord); + init_order_depr(ord); s = gettoken(token, sizeof(token)); /* KAMPFZAUBER [NICHT] löscht alle gesetzten Kampfzauber */ @@ -2658,7 +2658,7 @@ int guard_on_cmd(unit * u, struct order *ord) assert(u); assert(u->faction); - init_order(ord); + init_order_depr(ord); /* GUARD NOT is handled in goard_off_cmd earlier in the turn */ if (getparam(u->faction->locale) == P_NOT) { @@ -2739,7 +2739,7 @@ void restack_units(void) int id; unit *v; - init_order(ord); + init_order_depr(ord); s = gettoken(token, sizeof(token)); p = findparam(s, u->faction->locale); id = getid(); @@ -3049,7 +3049,7 @@ void maketemp_cmd(unit *u, order **olist) unit *u2; order **ordp, **oinsert; #ifndef NDEBUG - keyword_t kwd = init_order(makeord); + keyword_t kwd = init_order_depr(makeord); assert(kwd == K_MAKETEMP); #endif alias = getid(); @@ -3347,7 +3347,7 @@ void defaultorders(void) char lbuf[8192]; order *new_order = 0; const char *s; - init_order(ord); + init_order_depr(ord); s = gettoken(lbuf, sizeof(lbuf)); if (s) { new_order = parse_order(s, u->faction->locale); @@ -3463,7 +3463,7 @@ int use_cmd(unit * u, struct order *ord) int n, err = ENOITEM; const item_type *itype; - init_order(ord); + init_order_depr(ord); t = gettoken(token, sizeof(token)); if (!t) { @@ -3518,7 +3518,7 @@ int pay_cmd(unit * u, struct order *ord) param_t p; int id; - init_order(ord); + init_order_depr(ord); p = getparam(u->faction->locale); id = getid(); if (p == P_NOT) { @@ -3572,7 +3572,7 @@ static int reserve_i(unit * u, struct order *ord, int flags) const item_type *itype; const char *s; - init_order(ord); + init_order_depr(ord); s = gettoken(token, sizeof(token)); count = s ? atoip(s) : 0; para = findparam(s, u->faction->locale); @@ -3615,7 +3615,7 @@ int claim_cmd(unit * u, struct order *ord) int n = 1; const item_type *itype = 0; - init_order(ord); + init_order_depr(ord); t = gettoken(token, sizeof(token)); if (t) { @@ -3909,7 +3909,7 @@ int siege_cmd(unit * u, order * ord) resource_type *rt_catapultammo = NULL; resource_type *rt_catapult = NULL; - init_order(ord); + init_order_depr(ord); b = getbuilding(r); if (!b) { diff --git a/src/magic.c b/src/magic.c index d05c87b80..7e321a700 100644 --- a/src/magic.c +++ b/src/magic.c @@ -2514,7 +2514,7 @@ static castorder *cast_cmd(unit * u, order * ord) } level = effskill(u, SK_MAGIC, 0); - init_order(ord); + init_order_depr(ord); s = gettoken(token, sizeof(token)); param = findparam(s, u->faction->locale); /* für Syntax ' STUFE x REGION y z ' */ diff --git a/src/move.c b/src/move.c index eec5c74df..f95728305 100644 --- a/src/move.c +++ b/src/move.c @@ -1067,7 +1067,7 @@ static void cycle_route(order * ord, unit * u, int gereist) return; tail[0] = '\0'; - init_order(ord); + init_order_depr(ord); neworder[0] = 0; for (cm = 0;; ++cm) { @@ -1144,7 +1144,7 @@ static bool transport(unit * ut, unit * u) for (ord = ut->orders; ord; ord = ord->next) { if (getkeyword(ord) == K_TRANSPORT) { unit *u2; - init_order(ord); + init_order_depr(ord); getunit(ut->region, ut->faction, &u2); if (u2 == u) { return true; @@ -1178,7 +1178,7 @@ static void init_transportation(void) && !fval(u, UFL_NOTMOVING) && !LongHunger(u)) { unit *ut = 0; - init_order(u->thisorder); + init_order_depr(u->thisorder); if (getunit(r, u->faction, &ut) != GET_UNIT) { ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "feedback_unit_not_found", "")); @@ -1207,7 +1207,7 @@ static void init_transportation(void) for (ord = u->orders; ord; ord = ord->next) { if (getkeyword(ord) == K_TRANSPORT) { - init_order(ord); + init_order_depr(ord); for (;;) { unit *ut = 0; @@ -1218,7 +1218,7 @@ static void init_transportation(void) can_move(ut) && !fval(ut, UFL_NOTMOVING) && !LongHunger(ut)) { unit *u2; - init_order(ut->thisorder); + init_order_depr(ut->thisorder); getunit(r, ut->faction, &u2); if (u2 == u) { w += weight(ut); @@ -2062,7 +2062,7 @@ static const region_list *travel_i(unit * u, const region_list * route_begin, if (getkeyword(ord) != K_TRANSPORT) continue; - init_order(ord); + init_order_depr(ord); if (getunit(r, u->faction, &ut) == GET_UNIT) { if (getkeyword(ut->thisorder) == K_DRIVE) { if (ut->building && !can_leave(ut)) { @@ -2077,7 +2077,7 @@ static const region_list *travel_i(unit * u, const region_list * route_begin, if (!fval(ut, UFL_NOTMOVING) && !LongHunger(ut)) { unit *u2; - init_order(ut->thisorder); + init_order_depr(ut->thisorder); getunit(u->region, ut->faction, &u2); if (u2 == u) { const region_list *route_to = @@ -2363,7 +2363,7 @@ static void move_hunters(void) if (getkeyword(ord) == K_FOLLOW) { param_t p; - init_order(ord); + init_order_depr(ord); p = getparam(u->faction->locale); if (p != P_SHIP) { if (p != P_UNIT) { @@ -2485,13 +2485,13 @@ void movement(void) else { if (ships) { if (u->ship && ship_owner(u->ship) == u) { - init_order(u->thisorder); + init_order_depr(u->thisorder); move_cmd(u, u->thisorder); } } else { if (!u->ship || ship_owner(u->ship) != u) { - init_order(u->thisorder); + init_order_depr(u->thisorder); move_cmd(u, u->thisorder); } } @@ -2548,7 +2548,7 @@ void follow_unit(unit * u) if (getkeyword(ord) == K_FOLLOW) { int id; param_t p; - init_order(ord); + init_order_depr(ord); p = getparam(lang); if (p == P_UNIT) { id = read_unitid(u->faction, r); diff --git a/src/move.test.c b/src/move.test.c index c8fdb2436..908da0bb7 100644 --- a/src/move.test.c +++ b/src/move.test.c @@ -462,7 +462,7 @@ static void test_follow_ship_msg(CuTest * tc) { mt_register(mt_new_va("error18", "unit:unit", "region:region", "command:order", 0)); - init_order(ord); + init_order_depr(ord); getstrtoken(); follow_ship(u, ord); diff --git a/src/piracy.c b/src/piracy.c index 3025d484c..b74a0b363 100644 --- a/src/piracy.c +++ b/src/piracy.c @@ -86,7 +86,7 @@ int *parse_ids(const order *ord) { const char *s; int *il = NULL; - init_order(ord); + init_order_depr(ord); s = getstrtoken(); if (s != NULL && *s) { il = intlist_init(); @@ -211,7 +211,7 @@ void piracy_cmd(unit * u) ord = create_order(K_MOVE, u->faction->locale, "%s", LOC(u->faction->locale, directions[target_dir])); /* Bewegung ausführen */ - init_order(ord); + init_order_depr(ord); move_cmd(u, ord); free_order(ord); } diff --git a/src/renumber.c b/src/renumber.c index 30769403f..ec9d61c66 100644 --- a/src/renumber.c +++ b/src/renumber.c @@ -80,7 +80,7 @@ int renumber_cmd(unit * u, order * ord) int i = 0; faction *f = u->faction; - init_order(ord); + init_order_depr(ord); s = gettoken(token, sizeof(token)); switch (findparam_ex(s, u->faction->locale)) { diff --git a/src/spy.c b/src/spy.c index 39d60c416..54d8f9c70 100644 --- a/src/spy.c +++ b/src/spy.c @@ -126,7 +126,7 @@ int spy_cmd(unit * u, struct order *ord) double spychance, observechance; region *r = u->region; - init_order(ord); + init_order_depr(ord); getunit(r, u->faction, &target); if (!target) { @@ -219,7 +219,7 @@ int setstealth_cmd(unit * u, struct order *ord) const char *s; int level; - init_order(ord); + init_order_depr(ord); s = gettoken(token, sizeof(token)); /* Tarne ohne Parameter: Setzt maximale Tarnung */ @@ -494,10 +494,10 @@ int sabotage_cmd(unit * u, struct order *ord) assert(u); assert(ord); - init_order(ord); + init_order_depr(ord); s = getstrtoken(); p = findparam(s, u->faction->locale); - init_order(NULL); + init_order_depr(NULL); switch (p) { case P_SHIP: diff --git a/src/study.c b/src/study.c index a66efd662..9264f9060 100644 --- a/src/study.c +++ b/src/study.c @@ -283,7 +283,7 @@ int teach_cmd(unit * teacher, struct order *ord) count = 0; - init_order(ord); + init_order_depr(ord); #if TEACH_ALL if (getparam(teacher->faction->locale) == P_ANY) { @@ -304,7 +304,7 @@ int teach_cmd(unit * teacher, struct order *ord) else if (student->faction == teacher->faction) { if (getkeyword(student->thisorder) == K_STUDY) { /* Input ist nun von student->thisorder !! */ - init_order(student->thisorder); + init_order(student->thisorder, student->faction->locale); sk = getskill(student->faction->locale); if (sk != NOSKILL && teachskill[0] != NOSKILL) { for (t = 0; teachskill[t] != NOSKILL; ++t) { @@ -324,7 +324,7 @@ int teach_cmd(unit * teacher, struct order *ord) else if (alliedunit(teacher, student->faction, HELP_GUARD)) { if (getkeyword(student->thisorder) == K_STUDY) { /* Input ist nun von student->thisorder !! */ - init_order(student->thisorder); + init_order(student->thisorder, student->faction->locale); sk = getskill(student->faction->locale); if (sk != NOSKILL && effskill_study(teacher, sk, 0) - TEACHDIFFERENCE >= effskill(student, sk, 0)) { @@ -343,7 +343,7 @@ int teach_cmd(unit * teacher, struct order *ord) order *new_order; zOrder[0] = '\0'; - init_order(ord); + init_order_depr(ord); while (!parser_end()) { skill_t sk; @@ -361,7 +361,7 @@ int teach_cmd(unit * teacher, struct order *ord) const char *token; /* Finde den string, der den Fehler verursacht hat */ parser_pushstate(); - init_order(ord); + init_order_depr(ord); for (j = 0; j != count - 1; ++j) { /* skip over the first 'count' units */ @@ -406,7 +406,7 @@ int teach_cmd(unit * teacher, struct order *ord) /* Input ist nun von student->thisorder !! */ parser_pushstate(); - init_order(student->thisorder); + init_order(student->thisorder, student->faction->locale); sk = getskill(student->faction->locale); parser_popstate(); @@ -448,7 +448,7 @@ int teach_cmd(unit * teacher, struct order *ord) if (academy_students > 0 && sk_academy!=NOSKILL) { academy_teaching_bonus(teacher, sk_academy, academy_students); } - init_order(NULL); + init_order_depr(NULL); return 0; } @@ -557,7 +557,7 @@ int study_cmd(unit * u, order * ord) return 0; } - init_order(ord); + (void)init_order(ord, u->faction->locale); sk = getskill(u->faction->locale); if (sk < 0) { @@ -785,7 +785,7 @@ int study_cmd(unit * u, order * ord) mage = create_mage(u, u->faction->magiegebiet); } } - init_order(NULL); + init_order_depr(NULL); return 0; } From 8a5164806b06dd97b778e76ac029fd3ab0ee235b Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 10 Oct 2017 09:29:32 +0200 Subject: [PATCH 17/43] try fixing coverity complaints --- src/kernel/order.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/kernel/order.c b/src/kernel/order.c index 7cdb2961d..88f6313fa 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -156,7 +156,7 @@ char* get_command(const order *ord, const struct locale *lang, char *sbuffer, si if (ord->id < 0) { skill_t sk = (skill_t)(100+ord->id); - assert(kwd == K_STUDY && sk != SK_MAGIC); + assert(kwd == K_STUDY && sk != SK_MAGIC && sk < MAXSKILLS); text = skillname(sk, lang); } else { od = load_data(ord->id); @@ -270,7 +270,7 @@ static int create_data(keyword_t kwd, const char *s, } /* TODO: between mkdata and release_data, this object is very * short-lived. */ - mkdata(&data, s ? strlen(s) : 0, s); + mkdata(&data, strlen(s), s); id = save_data(kwd, data); release_data(data); return id; @@ -351,7 +351,11 @@ order *create_order(keyword_t kwd, const struct locale * lang, zBuffer[0] = 0; } ord = (order *)malloc(sizeof(order)); - return create_order_i(ord, lang, kwd, zBuffer, false, false); + if (create_order_i(ord, lang, kwd, zBuffer, false, false) == NULL) { + free(ord); + return NULL; + } + return ord; } order *parse_order(const char *s, const struct locale * lang) @@ -383,7 +387,12 @@ order *parse_order(const char *s, const struct locale * lang) } if (kwd != NOKEYWORD) { order *ord = (order *)malloc(sizeof(order)); - return create_order_i(ord, lang, kwd, sptr, persistent, noerror); + if (create_order_i(ord, lang, kwd, sptr, persistent, noerror) + == NULL) { + free(ord); + return NULL; + } + return ord; } } return NULL; @@ -585,6 +594,7 @@ keyword_t init_order(const struct order *ord, const struct locale *lang) } if (ord->id < 0) { skill_t sk = (skill_t)(100 + ord->id); + assert(sk < MAXSKILLS); assert(lang); assert(kwd == K_STUDY); init_tokens_str(skillname(sk, lang)); From 78360b1466974c2f1fdd440107760e9db33fdbc5 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 12 Oct 2017 18:11:21 +0200 Subject: [PATCH 18/43] refactoring: move order_data to orderdb module. --- src/CMakeLists.txt | 1 + src/eressea.c | 3 ++ src/kernel/order.c | 85 ++++++---------------------------------------- src/orderdb.c | 78 ++++++++++++++++++++++++++++++++++++++++++ src/orderdb.h | 23 +++++++++++++ 5 files changed, 115 insertions(+), 75 deletions(-) create mode 100644 src/orderdb.c create mode 100644 src/orderdb.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e5ae8de7a..c8a4c4783 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -116,6 +116,7 @@ set (ERESSEA_SRC magic.c market.c morale.c + orderdb.c orderfile.c randenc.c renumber.c diff --git a/src/eressea.c b/src/eressea.c index 2174450eb..b4ae7890f 100755 --- a/src/eressea.c +++ b/src/eressea.c @@ -8,6 +8,7 @@ #include "creport.h" #include "report.h" #include "names.h" +#include "orderdb.h" #include "reports.h" #include "spells.h" #include "vortex.h" @@ -57,10 +58,12 @@ void game_done(void) free_special_directions(); free_locales(); kernel_done(); + orderdb_close(); } void game_init(void) { + orderdb_open(); kernel_init(); register_triggers(); register_xmas(); diff --git a/src/kernel/order.c b/src/kernel/order.c index 88f6313fa..873169493 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -14,6 +14,7 @@ #include #include "order.h" +#include "orderdb.h" #include "skill.h" #include "keyword.h" @@ -33,71 +34,6 @@ # define ORD_KEYWORD(ord) (keyword_t)((ord)->command & 0xFFFF) # define OD_STRING(odata) ((odata) ? (odata)->_str : NULL) -typedef struct order_data { - const char *_str; - int _refcount; -} order_data; - -#include - -static critbit_tree cb_orders = { 0 }; -static int auto_id = 0; - -struct cb_entry { - int id; - order_data *data; -}; - -order_data *load_data(int id) { - void * match; - - if (id > 0) { - if (cb_find_prefix(&cb_orders, &id, sizeof(id), &match, 1, 0) > 0) { - struct cb_entry *ent = (struct cb_entry *)match; - order_data * od = ent->data; - ++od->_refcount; - return od; - } - } - return NULL; -} - -int save_data(keyword_t kwd, order_data *od) { - if (od->_str) { - struct cb_entry ent; - ++od->_refcount; - ent.id = ++auto_id; - ent.data = od; - cb_insert(&cb_orders, &ent, sizeof(ent)); - return ent.id; - } - return 0; -} - -static void release_data(order_data * data) -{ - if (data) { - if (--data->_refcount == 0) { - free(data); - } - } -} - -int free_data_cb(const void *match, const void *key, size_t keylen, void *udata) { - struct cb_entry * ent = (struct cb_entry *)match; - order_data *od = ent->data; - if (od->_refcount > 1) { - log_error("refcount=%d for order %d, %s", od->_refcount, ent->id, od->_str); - } - release_data(od); - return 0; -} - -void free_data(void) { - cb_foreach(&cb_orders, NULL, 0, free_data_cb, NULL); - cb_clear(&cb_orders); -} - void replace_order(order ** dlist, order * orig, const order * src) { assert(src); @@ -159,7 +95,7 @@ char* get_command(const order *ord, const struct locale *lang, char *sbuffer, si assert(kwd == K_STUDY && sk != SK_MAGIC && sk < MAXSKILLS); text = skillname(sk, lang); } else { - od = load_data(ord->id); + od = odata_load(ord->id); text = OD_STRING(od); } if (kwd != NOKEYWORD) { @@ -193,7 +129,7 @@ char* get_command(const order *ord, const struct locale *lang, char *sbuffer, si } } if (od) { - release_data(od); + odata_release(od); } if (size > 0) *bufp = 0; return sbuffer; @@ -268,10 +204,10 @@ static int create_data(keyword_t kwd, const char *s, return ((int)sk)-100; } } - /* TODO: between mkdata and release_data, this object is very + /* TODO: between mkdata and odata_release, this object is very * short-lived. */ mkdata(&data, strlen(s), s); - id = save_data(kwd, data); + id = odata_save(kwd, data); release_data(data); return id; } @@ -556,11 +492,11 @@ char *write_order(const order * ord, const struct locale *lang, char *buffer, si else { keyword_t kwd = ORD_KEYWORD(ord); if (kwd == NOKEYWORD) { - order_data *od = load_data(ord->id); + order_data *od = odata_load(ord->id); const char *text = OD_STRING(od); if (text) strlcpy(buffer, (const char *)text, size); else buffer[0] = 0; - release_data(od); + odata_release(od); } else { get_command(ord, lang, buffer, size); @@ -581,7 +517,7 @@ static order_data *parser_od; keyword_t init_order(const struct order *ord, const struct locale *lang) { if (!ord) { - release_data(parser_od); + odata_release(parser_od); parser_od = NULL; return NOKEYWORD; } @@ -589,7 +525,7 @@ keyword_t init_order(const struct order *ord, const struct locale *lang) keyword_t kwd = ORD_KEYWORD(ord); if (parser_od) { /* TODO: warning */ - release_data(parser_od); + odata_release(parser_od); parser_od = NULL; } if (ord->id < 0) { @@ -600,7 +536,7 @@ keyword_t init_order(const struct order *ord, const struct locale *lang) init_tokens_str(skillname(sk, lang)); } else { - parser_od = load_data(ord->id); + parser_od = odata_load(ord->id); init_tokens_str(OD_STRING(parser_od)); } return kwd; @@ -620,6 +556,5 @@ void close_orders(void) { if (parser_od) { (void)init_order(NULL, NULL); } - free_data(); } diff --git a/src/orderdb.c b/src/orderdb.c new file mode 100644 index 000000000..37faeacc4 --- /dev/null +++ b/src/orderdb.c @@ -0,0 +1,78 @@ +#include +#include "orderdb.h" + +#include + +#include + +#include + +static critbit_tree cb_orders = { 0 }; +static int auto_id = 0; + +struct cb_entry { + int id; + order_data *data; +}; + +order_data *odata_load(int id) +{ + void * match; + + if (id > 0) { + if (cb_find_prefix(&cb_orders, &id, sizeof(id), &match, 1, 0) > 0) { + struct cb_entry *ent = (struct cb_entry *)match; + order_data * od = ent->data; + ++od->_refcount; + return od; + } + } + return NULL; +} + +int odata_save(order_data *od) +{ + if (od->_str) { + struct cb_entry ent; + ++od->_refcount; + ent.id = ++auto_id; + ent.data = od; + cb_insert(&cb_orders, &ent, sizeof(ent)); + return ent.id; + } + return 0; +} + +void odata_release(order_data * od) +{ + if (od) { + if (--od->_refcount == 0) { + free(od); + } + } +} + +int free_data_cb(const void *match, const void *key, size_t keylen, void *udata) { + struct cb_entry * ent = (struct cb_entry *)match; + order_data *od = ent->data; + if (od->_refcount > 1) { + log_error("refcount=%d for order %d, %s", od->_refcount, ent->id, od->_str); + } + odata_release(od); + return 0; +} + +void free_data(void) { + cb_foreach(&cb_orders, NULL, 0, free_data_cb, NULL); + cb_clear(&cb_orders); +} + +void orderdb_open(void) +{ + auto_id = 0; +} + +void orderdb_close(void) +{ + free_data(); +} diff --git a/src/orderdb.h b/src/orderdb.h new file mode 100644 index 000000000..be39a642e --- /dev/null +++ b/src/orderdb.h @@ -0,0 +1,23 @@ +#ifndef H_ORDERDB +#define H_ORDERDB + +#ifdef __cplusplus +extern "C" { +#endif + + typedef struct order_data { + const char *_str; + int _refcount; + } order_data; + + void orderdb_open(void); + void orderdb_close(void); + + order_data *odata_load(int id); + int odata_save(order_data *od); + void odata_release(order_data * od); + +#ifdef __cplusplus +} +#endif +#endif From 5a40ff9e628425ba663ff3eaddda58a3f85d916c Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 13 Oct 2017 19:35:12 +0200 Subject: [PATCH 19/43] merge conflict fix --- src/kernel/order.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/kernel/order.c b/src/kernel/order.c index 873169493..810f09dee 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -207,8 +207,8 @@ static int create_data(keyword_t kwd, const char *s, /* TODO: between mkdata and odata_release, this object is very * short-lived. */ mkdata(&data, strlen(s), s); - id = odata_save(kwd, data); - release_data(data); + id = odata_save(data); + odata_release(data); return id; } From 6d79f8562894574b95edd97b9a332472c025d0f8 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 14 Oct 2017 08:43:01 +0200 Subject: [PATCH 20/43] orderdb backend choices and first tests. --- src/CMakeLists.txt | 1 + src/eressea.c | 7 ++++++- src/orderdb.c | 14 ++++++++++++-- src/orderdb.h | 10 +++++++++- src/orderdb.test.c | 27 +++++++++++++++++++++++++++ src/test_eressea.c | 1 + src/util/log.c | 1 + 7 files changed, 57 insertions(+), 4 deletions(-) create mode 100644 src/orderdb.test.c diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c8a4c4783..cfce6e1a2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -219,6 +219,7 @@ set(TESTS_SRC monsters.test.c move.test.c names.test.c + orderdb.test.c orderfile.test.c piracy.test.c prefix.test.c diff --git a/src/eressea.c b/src/eressea.c index b4ae7890f..857c309f6 100755 --- a/src/eressea.c +++ b/src/eressea.c @@ -37,6 +37,8 @@ #include #include +#include + void game_done(void) { #ifdef CLEANUP_CODE @@ -63,7 +65,10 @@ void game_done(void) void game_init(void) { - orderdb_open(); + db_backend choices[] = { DB_MEMORY, DB_NONE }; + if (orderdb_open(choices) == DB_NONE) { + log_fatal("no orderdb backend available"); + } kernel_init(); register_triggers(); register_xmas(); diff --git a/src/orderdb.c b/src/orderdb.c index 37faeacc4..37ae35978 100644 --- a/src/orderdb.c +++ b/src/orderdb.c @@ -15,6 +15,8 @@ struct cb_entry { order_data *data; }; +static db_backend odata_backend = DB_NONE; + order_data *odata_load(int id) { void * match; @@ -67,9 +69,17 @@ void free_data(void) { cb_clear(&cb_orders); } -void orderdb_open(void) +db_backend orderdb_open(db_backend choices[]) { - auto_id = 0; + int i; + for (i = 0; choices[i] != DB_NONE; ++i) { + db_backend choice = choices[i]; + if (choice == DB_MEMORY) { + auto_id = 0; + return odata_backend = choice; + } + } + return DB_NONE; } void orderdb_close(void) diff --git a/src/orderdb.h b/src/orderdb.h index be39a642e..eb92850d0 100644 --- a/src/orderdb.h +++ b/src/orderdb.h @@ -5,12 +5,20 @@ extern "C" { #endif + typedef enum { + DB_NONE, + DB_MEMORY, + DB_MMAP, + DB_BDB, + DB_SQLITE + } db_backend; + typedef struct order_data { const char *_str; int _refcount; } order_data; - void orderdb_open(void); + db_backend orderdb_open(db_backend choices[]); void orderdb_close(void); order_data *odata_load(int id); diff --git a/src/orderdb.test.c b/src/orderdb.test.c new file mode 100644 index 000000000..5336c540d --- /dev/null +++ b/src/orderdb.test.c @@ -0,0 +1,27 @@ +#include +#include + +#include "orderdb.h" + +#include +#include + +static void test_orderdb_open_close(CuTest *tc) { + db_backend choices[] = { DB_MEMORY, DB_NONE }; + db_backend nochoice[] = { DB_SQLITE, DB_NONE }; + + CuAssertIntEquals(tc, DB_MEMORY, orderdb_open(choices)); + orderdb_close(); + + CuAssertIntEquals(tc, DB_NONE, orderdb_open(nochoice)); + + orderdb_close(); +} + +CuSuite *get_orderdb_suite(void) +{ + CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_orderdb_open_close); + + return suite; +} diff --git a/src/test_eressea.c b/src/test_eressea.c index 38c5cf026..c21a1cf5e 100644 --- a/src/test_eressea.c +++ b/src/test_eressea.c @@ -132,6 +132,7 @@ int RunAllTests(int argc, char *argv[]) ADD_SUITE(monsters); ADD_SUITE(move); ADD_SUITE(names); + ADD_SUITE(orderdb); ADD_SUITE(orderfile); ADD_SUITE(otherfaction); ADD_SUITE(piracy); diff --git a/src/util/log.c b/src/util/log.c index 24ddce757..cacd3d36e 100644 --- a/src/util/log.c +++ b/src/util/log.c @@ -218,6 +218,7 @@ void log_fatal(const char *format, ...) va_start(args, format); log_write(LOG_CPERROR, NULL, format, args); va_end(args); + abort(); } void log_error(const char *format, ...) /*-V524 */ From 4257a9891c16dff3defe4831a3d5b767e6749c5a Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 14 Oct 2017 09:01:14 +0200 Subject: [PATCH 21/43] another test. moving some deckchairs around. --- src/kernel/order.c | 15 +-------------- src/orderdb.c | 14 ++++++++++++++ src/orderdb.h | 6 +++++- src/orderdb.test.c | 26 ++++++++++++++++++++++++++ src/sqlite.c | 42 ------------------------------------------ 5 files changed, 46 insertions(+), 57 deletions(-) diff --git a/src/kernel/order.c b/src/kernel/order.c index 810f09dee..51cefd791 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -173,19 +173,6 @@ void free_orders(order ** olist) } } -static char *mkdata(order_data **pdata, size_t len, const char *str) -{ - order_data *data; - char *result; - data = malloc(sizeof(order_data) + len + 1); - result = (char *)(data + 1); - data->_refcount = 1; - data->_str = (len > 0) ? result : NULL; - if (str) strcpy(result, str); - if (pdata) *pdata = data; - return result; -} - static int create_data(keyword_t kwd, const char *s, const struct locale *lang) { @@ -206,7 +193,7 @@ static int create_data(keyword_t kwd, const char *s, } /* TODO: between mkdata and odata_release, this object is very * short-lived. */ - mkdata(&data, strlen(s), s); + odata_create(&data, strlen(s), s); id = odata_save(data); odata_release(data); return id; diff --git a/src/orderdb.c b/src/orderdb.c index 37ae35978..7c60a64a3 100644 --- a/src/orderdb.c +++ b/src/orderdb.c @@ -6,6 +6,7 @@ #include #include +#include static critbit_tree cb_orders = { 0 }; static int auto_id = 0; @@ -32,6 +33,19 @@ order_data *odata_load(int id) return NULL; } +void odata_create(order_data **pdata, size_t len, const char *str) +{ + order_data *data; + char *result; + + data = malloc(sizeof(order_data) + len + 1); + data->_refcount = 1; + result = (char *)(data + 1); + data->_str = (len > 0) ? result : NULL; + if (str) strcpy(result, str); + if (pdata) *pdata = data; +} + int odata_save(order_data *od) { if (od->_str) { diff --git a/src/orderdb.h b/src/orderdb.h index eb92850d0..6c1c470cf 100644 --- a/src/orderdb.h +++ b/src/orderdb.h @@ -1,6 +1,8 @@ #ifndef H_ORDERDB #define H_ORDERDB +#include + #ifdef __cplusplus extern "C" { #endif @@ -21,9 +23,11 @@ extern "C" { db_backend orderdb_open(db_backend choices[]); void orderdb_close(void); + void odata_create(order_data **pdata, size_t len, const char *str); + void odata_release(order_data * od); + order_data *odata_load(int id); int odata_save(order_data *od); - void odata_release(order_data * od); #ifdef __cplusplus } diff --git a/src/orderdb.test.c b/src/orderdb.test.c index 5336c540d..36bc13b53 100644 --- a/src/orderdb.test.c +++ b/src/orderdb.test.c @@ -6,6 +6,8 @@ #include #include +#include + static void test_orderdb_open_close(CuTest *tc) { db_backend choices[] = { DB_MEMORY, DB_NONE }; db_backend nochoice[] = { DB_SQLITE, DB_NONE }; @@ -18,10 +20,34 @@ static void test_orderdb_open_close(CuTest *tc) { orderdb_close(); } +static void test_odata_save_load(CuTest *tc) { + db_backend choices[] = { DB_MEMORY, DB_NONE }; + order_data *od; + int id; + const char * s = "GIB enno 1 Hodor"; + + CuAssertIntEquals(tc, DB_MEMORY, orderdb_open(choices)); + + odata_create(&od, strlen(s) + 1, s); + CuAssertTrue(tc, od->_refcount >= 1); + id = odata_save(od); + odata_release(od); + CuAssertTrue(tc, id != 0); + + od = odata_load(id); + CuAssertPtrNotNull(tc, od); + CuAssertTrue(tc, od->_refcount >= 1); + CuAssertStrEquals(tc, s, od->_str); + odata_release(od); + + orderdb_close(); +} + CuSuite *get_orderdb_suite(void) { CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_orderdb_open_close); + SUITE_ADD_TEST(suite, test_odata_save_load); return suite; } diff --git a/src/sqlite.c b/src/sqlite.c index edb5bfc62..498f0da70 100644 --- a/src/sqlite.c +++ b/src/sqlite.c @@ -23,48 +23,6 @@ faction *get_faction_by_id(int uid) return NULL; } -/* -typedef struct stmt_cache { -sqlite3 *db; -sqlite3_stmt *stmt; -const char *sql; -int inuse; -} stmt_cache; - -#define MAX_STMT_CACHE 64 -static stmt_cache cache[MAX_STMT_CACHE]; -static int cache_insert; - -static sqlite3_stmt *stmt_cache_get(sqlite3 * db, const char *sql) -{ -int i; -sqlite3_stmt *stmt; - -for (i = 0; i != MAX_STMT_CACHE && cache[i].db; ++i) { -if (cache[i].sql == sql && cache[i].db == db) { -cache[i].inuse = 1; -stmt = cache[i].stmt; -sqlite3_reset(stmt); -sqlite3_clear_bindings(stmt); -return stmt; -} -} -if (i == MAX_STMT_CACHE) { -while (cache[cache_insert].inuse) { -cache[cache_insert].inuse = 0; -cache_insert = (cache_insert + 1) & (MAX_STMT_CACHE - 1); -} -i = cache_insert; -stmt = cache[i].stmt; -sqlite3_finalize(stmt); -} -cache[i].inuse = 1; -cache[i].db = db; -cache[i].sql = sql; -sqlite3_prepare_v2(db, sql, -1, &cache[i].stmt, NULL); -return cache[i].stmt; -} -*/ typedef struct db_faction { int uid; int no; From fee9b6d0a8fdd20d38f077767c757844d6098db5 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 9 Nov 2017 19:55:28 +0100 Subject: [PATCH 22/43] separate database logic from order_data. laying groundwork for different database backends. --- src/CMakeLists.txt | 2 -- src/eressea.c | 9 ++--- src/kernel/CMakeLists.txt | 6 ++++ src/kernel/db.h | 21 +++++++++++ src/kernel/db.test.c | 40 +++++++++++++++++++++ src/{orderdb.c => kernel/dbtrie.c} | 57 +++++++----------------------- src/kernel/orderdb.c | 42 ++++++++++++++++++++++ src/{ => kernel}/orderdb.h | 11 ------ src/kernel/orderdb.test.c | 28 +++++++++++++++ src/orderdb.test.c | 53 --------------------------- src/test_eressea.c | 1 + tests/drmemory.bat | 1 + 12 files changed, 154 insertions(+), 117 deletions(-) create mode 100644 src/kernel/db.h create mode 100644 src/kernel/db.test.c rename src/{orderdb.c => kernel/dbtrie.c} (52%) create mode 100644 src/kernel/orderdb.c rename src/{ => kernel}/orderdb.h (66%) create mode 100644 src/kernel/orderdb.test.c delete mode 100644 src/orderdb.test.c diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cfce6e1a2..e5ae8de7a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -116,7 +116,6 @@ set (ERESSEA_SRC magic.c market.c morale.c - orderdb.c orderfile.c randenc.c renumber.c @@ -219,7 +218,6 @@ set(TESTS_SRC monsters.test.c move.test.c names.test.c - orderdb.test.c orderfile.test.c piracy.test.c prefix.test.c diff --git a/src/eressea.c b/src/eressea.c index 857c309f6..e1c81f8db 100755 --- a/src/eressea.c +++ b/src/eressea.c @@ -8,7 +8,6 @@ #include "creport.h" #include "report.h" #include "names.h" -#include "orderdb.h" #include "reports.h" #include "spells.h" #include "vortex.h" @@ -25,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -60,15 +60,12 @@ void game_done(void) free_special_directions(); free_locales(); kernel_done(); - orderdb_close(); + db_close(); } void game_init(void) { - db_backend choices[] = { DB_MEMORY, DB_NONE }; - if (orderdb_open(choices) == DB_NONE) { - log_fatal("no orderdb backend available"); - } + db_open(); kernel_init(); register_triggers(); register_xmas(); diff --git a/src/kernel/CMakeLists.txt b/src/kernel/CMakeLists.txt index fe560af7a..f4af301db 100644 --- a/src/kernel/CMakeLists.txt +++ b/src/kernel/CMakeLists.txt @@ -11,12 +11,14 @@ command.test.c config.test.c # connection.test.c curse.test.c +db.test.c equipment.test.c faction.test.c group.test.c item.test.c messages.test.c order.test.c +orderdb.test.c # pathfinder.test.c plane.test.c pool.test.c @@ -34,7 +36,10 @@ jsonconf.test.c # xmlreader.test.c ) +SET(_DBFILES dbtrie.c) + SET(_FILES +${_DBFILES} alliance.c ally.c build.c @@ -50,6 +55,7 @@ group.c item.c messages.c order.c +orderdb.c pathfinder.c plane.c pool.c diff --git a/src/kernel/db.h b/src/kernel/db.h new file mode 100644 index 000000000..052d28aad --- /dev/null +++ b/src/kernel/db.h @@ -0,0 +1,21 @@ +#ifndef H_DB +#define H_DB + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + struct order_data; + + void db_open(void); + void db_close(void); + + struct order_data *db_load_order(int id); + int db_save_order(struct order_data *od); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/db.test.c b/src/kernel/db.test.c new file mode 100644 index 000000000..5ec81b568 --- /dev/null +++ b/src/kernel/db.test.c @@ -0,0 +1,40 @@ +#include +#include + +#include "db.h" +#include "orderdb.h" + +#include +#include + +#include + +static void test_save_load_order(CuTest *tc) { + order_data *od; + int id; + const char * s = "GIB enno 1 Hodor"; + + db_open(); + + odata_create(&od, strlen(s) + 1, s); + CuAssertTrue(tc, od->_refcount >= 1); + id = odata_save(od); + odata_release(od); + CuAssertTrue(tc, id != 0); + + od = odata_load(id); + CuAssertPtrNotNull(tc, od); + CuAssertTrue(tc, od->_refcount >= 1); + CuAssertStrEquals(tc, s, od->_str); + odata_release(od); + + db_close(); +} + +CuSuite *get_db_suite(void) +{ + CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_save_load_order); + + return suite; +} diff --git a/src/orderdb.c b/src/kernel/dbtrie.c similarity index 52% rename from src/orderdb.c rename to src/kernel/dbtrie.c index 7c60a64a3..78ffaee61 100644 --- a/src/orderdb.c +++ b/src/kernel/dbtrie.c @@ -1,4 +1,5 @@ #include +#include "db.h" #include "orderdb.h" #include @@ -16,9 +17,7 @@ struct cb_entry { order_data *data; }; -static db_backend odata_backend = DB_NONE; - -order_data *odata_load(int id) +order_data *db_load_order(int id) { void * match; @@ -33,20 +32,7 @@ order_data *odata_load(int id) return NULL; } -void odata_create(order_data **pdata, size_t len, const char *str) -{ - order_data *data; - char *result; - - data = malloc(sizeof(order_data) + len + 1); - data->_refcount = 1; - result = (char *)(data + 1); - data->_str = (len > 0) ? result : NULL; - if (str) strcpy(result, str); - if (pdata) *pdata = data; -} - -int odata_save(order_data *od) +int db_save_order(order_data *od) { if (od->_str) { struct cb_entry ent; @@ -59,16 +45,9 @@ int odata_save(order_data *od) return 0; } -void odata_release(order_data * od) +static int free_data_cb(const void *match, const void *key, size_t keylen, + void *udata) { - if (od) { - if (--od->_refcount == 0) { - free(od); - } - } -} - -int free_data_cb(const void *match, const void *key, size_t keylen, void *udata) { struct cb_entry * ent = (struct cb_entry *)match; order_data *od = ent->data; if (od->_refcount > 1) { @@ -78,25 +57,13 @@ int free_data_cb(const void *match, const void *key, size_t keylen, void *udata) return 0; } -void free_data(void) { +void db_open(void) +{ + auto_id = 0; +} + +void db_close(void) +{ cb_foreach(&cb_orders, NULL, 0, free_data_cb, NULL); cb_clear(&cb_orders); } - -db_backend orderdb_open(db_backend choices[]) -{ - int i; - for (i = 0; choices[i] != DB_NONE; ++i) { - db_backend choice = choices[i]; - if (choice == DB_MEMORY) { - auto_id = 0; - return odata_backend = choice; - } - } - return DB_NONE; -} - -void orderdb_close(void) -{ - free_data(); -} diff --git a/src/kernel/orderdb.c b/src/kernel/orderdb.c new file mode 100644 index 000000000..a20bcf1e7 --- /dev/null +++ b/src/kernel/orderdb.c @@ -0,0 +1,42 @@ +#include +#include "db.h" +#include "orderdb.h" + +#include + +#include + +#include +#include + +void odata_create(order_data **pdata, size_t len, const char *str) +{ + order_data *data; + char *result; + + data = malloc(sizeof(order_data) + len + 1); + data->_refcount = 1; + result = (char *)(data + 1); + data->_str = (len > 0) ? result : NULL; + if (str) strcpy(result, str); + if (pdata) *pdata = data; +} + +void odata_release(order_data * od) +{ + if (od) { + if (--od->_refcount == 0) { + free(od); + } + } +} + +order_data *odata_load(int id) +{ + return db_load_order(id); +} + +int odata_save(order_data *od) +{ + return db_save_order(od); +} diff --git a/src/orderdb.h b/src/kernel/orderdb.h similarity index 66% rename from src/orderdb.h rename to src/kernel/orderdb.h index 6c1c470cf..d25fcb3cf 100644 --- a/src/orderdb.h +++ b/src/kernel/orderdb.h @@ -7,22 +7,11 @@ extern "C" { #endif - typedef enum { - DB_NONE, - DB_MEMORY, - DB_MMAP, - DB_BDB, - DB_SQLITE - } db_backend; - typedef struct order_data { const char *_str; int _refcount; } order_data; - db_backend orderdb_open(db_backend choices[]); - void orderdb_close(void); - void odata_create(order_data **pdata, size_t len, const char *str); void odata_release(order_data * od); diff --git a/src/kernel/orderdb.test.c b/src/kernel/orderdb.test.c new file mode 100644 index 000000000..bdb6f0a95 --- /dev/null +++ b/src/kernel/orderdb.test.c @@ -0,0 +1,28 @@ +#include +#include + +#include "orderdb.h" + +#include +#include + +#include + +static void test_orderdb(CuTest *tc) { + order_data *od = NULL; + const char * s = "GIB enno 1 Hodor"; + + odata_create(&od, strlen(s) + 1, s); + CuAssertPtrNotNull(tc, od); + CuAssertStrEquals(tc, s, od->_str); + CuAssertTrue(tc, od->_refcount >= 1); + odata_release(od); +} + +CuSuite *get_orderdb_suite(void) +{ + CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_orderdb); + + return suite; +} diff --git a/src/orderdb.test.c b/src/orderdb.test.c deleted file mode 100644 index 36bc13b53..000000000 --- a/src/orderdb.test.c +++ /dev/null @@ -1,53 +0,0 @@ -#include -#include - -#include "orderdb.h" - -#include -#include - -#include - -static void test_orderdb_open_close(CuTest *tc) { - db_backend choices[] = { DB_MEMORY, DB_NONE }; - db_backend nochoice[] = { DB_SQLITE, DB_NONE }; - - CuAssertIntEquals(tc, DB_MEMORY, orderdb_open(choices)); - orderdb_close(); - - CuAssertIntEquals(tc, DB_NONE, orderdb_open(nochoice)); - - orderdb_close(); -} - -static void test_odata_save_load(CuTest *tc) { - db_backend choices[] = { DB_MEMORY, DB_NONE }; - order_data *od; - int id; - const char * s = "GIB enno 1 Hodor"; - - CuAssertIntEquals(tc, DB_MEMORY, orderdb_open(choices)); - - odata_create(&od, strlen(s) + 1, s); - CuAssertTrue(tc, od->_refcount >= 1); - id = odata_save(od); - odata_release(od); - CuAssertTrue(tc, id != 0); - - od = odata_load(id); - CuAssertPtrNotNull(tc, od); - CuAssertTrue(tc, od->_refcount >= 1); - CuAssertStrEquals(tc, s, od->_str); - odata_release(od); - - orderdb_close(); -} - -CuSuite *get_orderdb_suite(void) -{ - CuSuite *suite = CuSuiteNew(); - SUITE_ADD_TEST(suite, test_orderdb_open_close); - SUITE_ADD_TEST(suite, test_odata_save_load); - - return suite; -} diff --git a/src/test_eressea.c b/src/test_eressea.c index c21a1cf5e..0bd8a455f 100644 --- a/src/test_eressea.c +++ b/src/test_eressea.c @@ -93,6 +93,7 @@ int RunAllTests(int argc, char *argv[]) /* kernel */ ADD_SUITE(alliance); ADD_SUITE(command); + ADD_SUITE(db); ADD_SUITE(plane); ADD_SUITE(unit); ADD_SUITE(faction); diff --git a/tests/drmemory.bat b/tests/drmemory.bat index 66ca98c38..2a2874f1d 100644 --- a/tests/drmemory.bat +++ b/tests/drmemory.bat @@ -1,6 +1,7 @@ cd c:\users\enno\documents\eressea\git\tests "C:\Program Files (x86)\Dr. Memory\bin64\drmemory.exe" ..\build-vs14\eressea\Debug\eressea.exe -t184 test-turn.lua +REM "C:\Program Files (x86)\Dr. Memory\bin64\drmemory.exe" ..\build-vs14\eressea\Debug\test_eressea.exe -t184 test-turn.lua del /q reports del /q datum htpasswd parteien parteien.full passwd score turn From 9f778c0ae98a936de8395c6153ad11741dc9be42 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 9 Nov 2017 20:17:06 +0100 Subject: [PATCH 23/43] fix symetric db_open and db_close calls. --- src/kernel/command.test.c | 2 +- src/kernel/db.test.c | 4 ++-- src/kernel/dbtrie.c | 8 ++++---- src/kernel/plane.test.c | 5 +++-- src/main.c | 1 + src/test_eressea.c | 1 + 6 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/kernel/command.test.c b/src/kernel/command.test.c index 25e75fdc3..8fd7374bf 100644 --- a/src/kernel/command.test.c +++ b/src/kernel/command.test.c @@ -32,7 +32,7 @@ static void test_command(CuTest * tc) { struct locale * loc; unit *u; - test_cleanup(); + test_setup(); loc = test_create_locale(); st = stree_create(); CuAssertPtrNotNull(tc, st); diff --git a/src/kernel/db.test.c b/src/kernel/db.test.c index 5ec81b568..81f6f51c4 100644 --- a/src/kernel/db.test.c +++ b/src/kernel/db.test.c @@ -14,7 +14,7 @@ static void test_save_load_order(CuTest *tc) { int id; const char * s = "GIB enno 1 Hodor"; - db_open(); + test_setup(); odata_create(&od, strlen(s) + 1, s); CuAssertTrue(tc, od->_refcount >= 1); @@ -28,7 +28,7 @@ static void test_save_load_order(CuTest *tc) { CuAssertStrEquals(tc, s, od->_str); odata_release(od); - db_close(); + test_cleanup(); } CuSuite *get_db_suite(void) diff --git a/src/kernel/dbtrie.c b/src/kernel/dbtrie.c index 78ffaee61..3cca71af8 100644 --- a/src/kernel/dbtrie.c +++ b/src/kernel/dbtrie.c @@ -6,11 +6,12 @@ #include +#include #include #include static critbit_tree cb_orders = { 0 }; -static int auto_id = 0; +static int auto_id = -1; struct cb_entry { int id; @@ -50,15 +51,13 @@ static int free_data_cb(const void *match, const void *key, size_t keylen, { struct cb_entry * ent = (struct cb_entry *)match; order_data *od = ent->data; - if (od->_refcount > 1) { - log_error("refcount=%d for order %d, %s", od->_refcount, ent->id, od->_str); - } odata_release(od); return 0; } void db_open(void) { + assert(auto_id == -1); auto_id = 0; } @@ -66,4 +65,5 @@ void db_close(void) { cb_foreach(&cb_orders, NULL, 0, free_data_cb, NULL); cb_clear(&cb_orders); + auto_id = -1; } diff --git a/src/kernel/plane.test.c b/src/kernel/plane.test.c index a479a34be..16ec065f7 100644 --- a/src/kernel/plane.test.c +++ b/src/kernel/plane.test.c @@ -9,7 +9,7 @@ static void test_plane(CuTest *tc) { struct region *r; plane *pl; - test_cleanup(); + test_setup(); r = test_create_region(0, 0, 0); CuAssertPtrEquals(tc, 0, findplane(0, 0)); CuAssertPtrEquals(tc, 0, getplane(r)); @@ -38,13 +38,14 @@ static void test_plane(CuTest *tc) { CuAssertIntEquals(tc, 60, plane_center_y(pl)); CuAssertIntEquals(tc, 5, plane_width(pl)); CuAssertIntEquals(tc, 41, plane_height(pl)); + test_cleanup(); } static void test_origin(CuTest *tc) { struct faction *f; int x, y; - test_cleanup(); + test_setup(); f = test_create_faction(0); x = 0; y = 0; diff --git a/src/main.c b/src/main.c index 0c171f219..8b613789d 100644 --- a/src/main.c +++ b/src/main.c @@ -20,6 +20,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include +#include #include #include #include diff --git a/src/test_eressea.c b/src/test_eressea.c index 0bd8a455f..c5ba24abb 100644 --- a/src/test_eressea.c +++ b/src/test_eressea.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include From 0cd965169019490bc91a53d89670e86854300521 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 9 Nov 2017 21:12:25 +0100 Subject: [PATCH 24/43] fix sqlite linking for tests. implement save_order for sqlite. --- src/CMakeLists.txt | 1 + src/kernel/CMakeLists.txt | 3 ++ src/kernel/dbsqlite.c | 63 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+) create mode 100644 src/kernel/dbsqlite.c diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e5ae8de7a..cfbe6c474 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -267,6 +267,7 @@ install(TARGETS eressea DESTINATION "bin") if (SQLITE3_FOUND) target_link_libraries(eressea ${SQLITE3_LIBRARIES}) +target_link_libraries(test_eressea ${SQLITE3_LIBRARIES}) add_definitions(-DUSE_SQLITE) endif(SQLITE3_FOUND) diff --git a/src/kernel/CMakeLists.txt b/src/kernel/CMakeLists.txt index f4af301db..cbd8a6296 100644 --- a/src/kernel/CMakeLists.txt +++ b/src/kernel/CMakeLists.txt @@ -37,6 +37,9 @@ jsonconf.test.c ) SET(_DBFILES dbtrie.c) +IF(SQLITE3_FOUND) +SET(_DBFILES dbsqlite.c) +ENDIF(SQLITE3_FOUND) SET(_FILES ${_DBFILES} diff --git a/src/kernel/dbsqlite.c b/src/kernel/dbsqlite.c new file mode 100644 index 000000000..ac970ce4a --- /dev/null +++ b/src/kernel/dbsqlite.c @@ -0,0 +1,63 @@ +#include +#include "db.h" +#include "orderdb.h" + +#include + +#include + +#include +#include +#include + + +#define DBNAME ":memory:" +static sqlite3 *g_db; +static sqlite3_stmt * g_stmt_insert; +static sqlite3_stmt * g_stmt_select; + +order_data *db_load_order(int id) +{ + if (id > 0) { + order_data * od = NULL; + odata_create(&od, 0, NULL); + return od; + } + return NULL; +} + +int db_save_order(order_data *od) +{ + if (od->_str) { + int err; + err = sqlite3_reset(g_stmt_insert); + assert(err == SQLITE_OK); + err = sqlite3_bind_text(g_stmt_insert, 1, od->_str, -1, SQLITE_STATIC); + assert(err == SQLITE_OK); + err = sqlite3_step(g_stmt_insert); + assert(err == SQLITE_DONE); + } + return 0; +} + +void db_open(void) +{ + int err; + + err = sqlite3_open(DBNAME, &g_db); + assert(err == SQLITE_OK); + err = sqlite3_exec(g_db, "CREATE TABLE IF NOT EXISTS orders (id INTEGER PRIMARY KEY, data TEXT NOT NULL)", NULL, NULL, NULL); + assert(err == SQLITE_OK); + err = sqlite3_prepare_v2(g_db, "INSERT INTO orders (data) VALUES (?)", -1, &g_stmt_insert, NULL); + assert(err == SQLITE_OK); +} + +void db_close(void) +{ + int err; + + err = sqlite3_finalize(g_stmt_insert); + assert(err == SQLITE_OK); + err = sqlite3_close(g_db); + assert(err == SQLITE_OK); +} From 89bf17cdca63a19df2e02949f9bd274da2c3d36d Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 9 Nov 2017 21:33:42 +0100 Subject: [PATCH 25/43] almost have sqlite storage working (in memory, not file). but test_teach_magic crashes. --- src/kernel/dbsqlite.c | 30 ++++++++++++++++++++++++++++-- src/study.c | 2 +- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/kernel/dbsqlite.c b/src/kernel/dbsqlite.c index ac970ce4a..2dd249c65 100644 --- a/src/kernel/dbsqlite.c +++ b/src/kernel/dbsqlite.c @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -20,8 +21,25 @@ order_data *db_load_order(int id) { if (id > 0) { order_data * od = NULL; - odata_create(&od, 0, NULL); - return od; + int err; + + err = sqlite3_reset(g_stmt_select); + assert(err == SQLITE_OK); + err = sqlite3_bind_int(g_stmt_select, 1, id); + assert(err == SQLITE_OK); + do { + err = sqlite3_step(g_stmt_select); + if (err == SQLITE_ROW) { + const unsigned char *text; + int bytes; + bytes = sqlite3_column_bytes(g_stmt_select, 0); + assert(bytes > 0); + text = sqlite3_column_text(g_stmt_select, 0); + odata_create(&od, (size_t)bytes, (const char *)text); + return od; + } + } while (err == SQLITE_ROW); + assert(err == SQLITE_DONE); } return NULL; } @@ -30,12 +48,16 @@ int db_save_order(order_data *od) { if (od->_str) { int err; + sqlite3_int64 id; err = sqlite3_reset(g_stmt_insert); assert(err == SQLITE_OK); err = sqlite3_bind_text(g_stmt_insert, 1, od->_str, -1, SQLITE_STATIC); assert(err == SQLITE_OK); err = sqlite3_step(g_stmt_insert); assert(err == SQLITE_DONE); + id = sqlite3_last_insert_rowid(g_db); + assert(id <= INT_MAX); + return (int)id; } return 0; } @@ -50,12 +72,16 @@ void db_open(void) assert(err == SQLITE_OK); err = sqlite3_prepare_v2(g_db, "INSERT INTO orders (data) VALUES (?)", -1, &g_stmt_insert, NULL); assert(err == SQLITE_OK); + err = sqlite3_prepare_v2(g_db, "SELECT data FROM orders WHERE id = ?", -1, &g_stmt_select, NULL); + assert(err == SQLITE_OK); } void db_close(void) { int err; + err = sqlite3_finalize(g_stmt_select); + assert(err == SQLITE_OK); err = sqlite3_finalize(g_stmt_insert); assert(err == SQLITE_OK); err = sqlite3_close(g_db); diff --git a/src/study.c b/src/study.c index 9264f9060..a80fa932f 100644 --- a/src/study.c +++ b/src/study.c @@ -371,7 +371,7 @@ int teach_cmd(unit * teacher, struct order *ord) token = getstrtoken(); /* Beginne die Fehlermeldung */ - if (isparam(token, teacher->faction->locale, P_TEMP)) { + if (token && isparam(token, teacher->faction->locale, P_TEMP)) { token = getstrtoken(); sprintf(tbuf, "%s %s", LOC(teacher->faction->locale, parameters[P_TEMP]), token); From add9d24f52545dbf63945d9186a5621b92b0fcf2 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 10 Nov 2017 07:45:15 +0100 Subject: [PATCH 26/43] convert needs sqlite3 now (because libgame does). --- src/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cfbe6c474..c5b1b40b2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -267,6 +267,7 @@ install(TARGETS eressea DESTINATION "bin") if (SQLITE3_FOUND) target_link_libraries(eressea ${SQLITE3_LIBRARIES}) +target_link_libraries(convert ${SQLITE3_LIBRARIES}) target_link_libraries(test_eressea ${SQLITE3_LIBRARIES}) add_definitions(-DUSE_SQLITE) endif(SQLITE3_FOUND) From df4cc70abf8fcefe672a1f165ba5c9cf369370fe Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 10 Nov 2017 07:45:41 +0100 Subject: [PATCH 27/43] add nul terminator to loaded string. --- src/kernel/dbsqlite.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernel/dbsqlite.c b/src/kernel/dbsqlite.c index 2dd249c65..7c1af1146 100644 --- a/src/kernel/dbsqlite.c +++ b/src/kernel/dbsqlite.c @@ -35,7 +35,7 @@ order_data *db_load_order(int id) bytes = sqlite3_column_bytes(g_stmt_select, 0); assert(bytes > 0); text = sqlite3_column_text(g_stmt_select, 0); - odata_create(&od, (size_t)bytes, (const char *)text); + odata_create(&od, 1+(size_t)bytes, (const char *)text); return od; } } while (err == SQLITE_ROW); From 05b7837070d928d9dc96e854d3ca39ec86929c29 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 10 Nov 2017 07:56:56 +0100 Subject: [PATCH 28/43] fix parser to keep a reference to the order it is parsing. make push/popstate not crash. pass unit tests. --- src/kernel/order.c | 7 ++++++- src/kernel/orderdb.c | 5 +++++ src/kernel/orderdb.h | 1 + src/study.c | 2 +- src/util/parser.c | 22 ++++++++++++++++++---- src/util/parser.h | 1 + 6 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/kernel/order.c b/src/kernel/order.c index 51cefd791..c4571cea1 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -523,8 +523,13 @@ keyword_t init_order(const struct order *ord, const struct locale *lang) init_tokens_str(skillname(sk, lang)); } else { + const char *str; parser_od = odata_load(ord->id); - init_tokens_str(OD_STRING(parser_od)); + if (parser_od) { + odata_addref(parser_od); + } + str = OD_STRING(parser_od); + init_tokens_ex(str, parser_od, odata_release); } return kwd; } diff --git a/src/kernel/orderdb.c b/src/kernel/orderdb.c index a20bcf1e7..ee23993e6 100644 --- a/src/kernel/orderdb.c +++ b/src/kernel/orderdb.c @@ -31,6 +31,11 @@ void odata_release(order_data * od) } } +void odata_addref(order_data *od) +{ + ++od->_refcount; +} + order_data *odata_load(int id) { return db_load_order(id); diff --git a/src/kernel/orderdb.h b/src/kernel/orderdb.h index d25fcb3cf..800732c5e 100644 --- a/src/kernel/orderdb.h +++ b/src/kernel/orderdb.h @@ -14,6 +14,7 @@ extern "C" { void odata_create(order_data **pdata, size_t len, const char *str); void odata_release(order_data * od); + void odata_addref(order_data *od); order_data *odata_load(int id); int odata_save(order_data *od); diff --git a/src/study.c b/src/study.c index a80fa932f..9264f9060 100644 --- a/src/study.c +++ b/src/study.c @@ -371,7 +371,7 @@ int teach_cmd(unit * teacher, struct order *ord) token = getstrtoken(); /* Beginne die Fehlermeldung */ - if (token && isparam(token, teacher->faction->locale, P_TEMP)) { + if (isparam(token, teacher->faction->locale, P_TEMP)) { token = getstrtoken(); sprintf(tbuf, "%s %s", LOC(teacher->faction->locale, parameters[P_TEMP]), token); diff --git a/src/util/parser.c b/src/util/parser.c index 46a9d3a28..5a322005f 100644 --- a/src/util/parser.c +++ b/src/util/parser.c @@ -16,6 +16,8 @@ typedef struct parser_state { const char *current_token; struct parser_state *next; + void *data; + void(*dtor)(void *); } parser_state; static parser_state *states; @@ -50,17 +52,26 @@ static int eatwhitespace_c(const char **str_p) return ret; } -void init_tokens_str(const char *initstr) +void init_tokens_ex(const char *initstr, void *data, void (*dtor)(void *)) { if (states == NULL) { - states = malloc(sizeof(parser_state)); + states = calloc(1, sizeof(parser_state)); } + else if (states->dtor) { + states->dtor(states->data); + } + states->dtor = dtor; + states->data = data; states->current_token = initstr; } +void init_tokens_str(const char *initstr) { + init_tokens_ex(initstr, NULL, NULL); +} + void parser_pushstate(void) { - parser_state *new_state = malloc(sizeof(parser_state)); + parser_state *new_state = calloc(1, sizeof(parser_state)); new_state->current_token = NULL; new_state->next = states; states = new_state; @@ -69,6 +80,9 @@ void parser_pushstate(void) void parser_popstate(void) { parser_state *new_state = states->next; + if (states->dtor) { + states->dtor(states->data); + } free(states); states = new_state; } @@ -254,7 +268,7 @@ unsigned int atoip(const char *s) int n; assert(s); - n = (s[0] >='0' && s[0]<='9'); + n = (s[0] >= '0' && s[0] <= '9'); n = n ? atoi(s) : 0; if (n < 0) diff --git a/src/util/parser.h b/src/util/parser.h index 0c8306931..52fdbc4f4 100644 --- a/src/util/parser.h +++ b/src/util/parser.h @@ -18,6 +18,7 @@ extern "C" { #endif + void init_tokens_ex(const char *initstr, void *data, void(*dtor)(void *)); void init_tokens_str(const char *initstr); /* initialize token parsing */ void skip_token(void); const char *parse_token_depr(const char **str); From f8e552ab6eb25e06c43117b9c6dabf01d04e8a87 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 10 Nov 2017 08:02:52 +0100 Subject: [PATCH 29/43] gcc and clang want function pointers to be cast. --- src/kernel/order.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernel/order.c b/src/kernel/order.c index c4571cea1..ed0b93d4a 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -529,7 +529,7 @@ keyword_t init_order(const struct order *ord, const struct locale *lang) odata_addref(parser_od); } str = OD_STRING(parser_od); - init_tokens_ex(str, parser_od, odata_release); + init_tokens_ex(str, parser_od, (void(*)(void *))odata_release); } return kwd; } From 6923fe5c536cec8d3eef1addfdf6747e1d4dad7c Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 10 Nov 2017 16:29:48 +0100 Subject: [PATCH 30/43] fix lua dbupdate write sqlite data to a temporary db by default (configurable). --- scripts/run-turn.lua | 2 +- src/kernel/dbsqlite.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/run-turn.lua b/scripts/run-turn.lua index 83d4045ac..34c1ea4fb 100644 --- a/scripts/run-turn.lua +++ b/scripts/run-turn.lua @@ -29,7 +29,7 @@ local function dbupdate() update_scores() if config.dbname then dbname = config.basepath..'/'..config.dbname - edb = db.open(dbame) + edb = db.open(dbname) if edb~=nil then edb:update_factions() edb:update_scores() diff --git a/src/kernel/dbsqlite.c b/src/kernel/dbsqlite.c index 7c1af1146..b57d65937 100644 --- a/src/kernel/dbsqlite.c +++ b/src/kernel/dbsqlite.c @@ -1,6 +1,7 @@ #include #include "db.h" #include "orderdb.h" +#include "config.h" #include @@ -11,8 +12,6 @@ #include #include - -#define DBNAME ":memory:" static sqlite3 *g_db; static sqlite3_stmt * g_stmt_insert; static sqlite3_stmt * g_stmt_select; @@ -65,8 +64,9 @@ int db_save_order(order_data *od) void db_open(void) { int err; + const char *dbname = config_get("config.dbname", ""); - err = sqlite3_open(DBNAME, &g_db); + err = sqlite3_open(dbname, &g_db); assert(err == SQLITE_OK); err = sqlite3_exec(g_db, "CREATE TABLE IF NOT EXISTS orders (id INTEGER PRIMARY KEY, data TEXT NOT NULL)", NULL, NULL, NULL); assert(err == SQLITE_OK); From 79b397e07f42e71cc9cc87720808f7aa897d5a6d Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 10 Nov 2017 16:32:20 +0100 Subject: [PATCH 31/43] fix config_get, has no default. --- src/kernel/dbsqlite.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/kernel/dbsqlite.c b/src/kernel/dbsqlite.c index b57d65937..602e7071b 100644 --- a/src/kernel/dbsqlite.c +++ b/src/kernel/dbsqlite.c @@ -64,8 +64,12 @@ int db_save_order(order_data *od) void db_open(void) { int err; - const char *dbname = config_get("config.dbname", ""); + const char *dbname; + dbname = config_get("config.dbname"); + if (!dbname) { + dbname = ""; + } err = sqlite3_open(dbname, &g_db); assert(err == SQLITE_OK); err = sqlite3_exec(g_db, "CREATE TABLE IF NOT EXISTS orders (id INTEGER PRIMARY KEY, data TEXT NOT NULL)", NULL, NULL, NULL); From 48a58fc907cb5b27ced11ab8157a03e30cced45e Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 11 Nov 2017 21:46:16 +0100 Subject: [PATCH 32/43] sqlite optimizations: transactions, journal_mode, synchronous. --- src/kernel/dbsqlite.c | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/kernel/dbsqlite.c b/src/kernel/dbsqlite.c index 602e7071b..b1e182ac0 100644 --- a/src/kernel/dbsqlite.c +++ b/src/kernel/dbsqlite.c @@ -16,12 +16,20 @@ static sqlite3 *g_db; static sqlite3_stmt * g_stmt_insert; static sqlite3_stmt * g_stmt_select; +static int g_order_batchsize; +static int g_order_tx_size; + order_data *db_load_order(int id) { if (id > 0) { order_data * od = NULL; int err; + if (g_order_tx_size > 0) { + g_order_tx_size = 0; + err = sqlite3_exec(g_db, "COMMIT", NULL, NULL, NULL); + assert(err == SQLITE_OK); + } err = sqlite3_reset(g_stmt_select); assert(err == SQLITE_OK); err = sqlite3_bind_int(g_stmt_select, 1, id); @@ -48,6 +56,14 @@ int db_save_order(order_data *od) if (od->_str) { int err; sqlite3_int64 id; + + if (g_order_batchsize > 0) { + if (g_order_tx_size == 0) { + err = sqlite3_exec(g_db, "BEGIN TRANSACTION", NULL, NULL, NULL); + assert(err == SQLITE_OK); + } + } + err = sqlite3_reset(g_stmt_insert); assert(err == SQLITE_OK); err = sqlite3_bind_text(g_stmt_insert, 1, od->_str, -1, SQLITE_STATIC); @@ -56,6 +72,15 @@ int db_save_order(order_data *od) assert(err == SQLITE_DONE); id = sqlite3_last_insert_rowid(g_db); assert(id <= INT_MAX); + + if (g_order_batchsize > 0) { + if (++g_order_tx_size >= g_order_batchsize) { + err = sqlite3_exec(g_db, "COMMIT", NULL, NULL, NULL); + assert(err == SQLITE_OK); + g_order_tx_size = 0; + } + } + return (int)id; } return 0; @@ -66,12 +91,17 @@ void db_open(void) int err; const char *dbname; - dbname = config_get("config.dbname"); + g_order_batchsize = config_get_int("config.db_batch", 100); + dbname = config_get("config.db_name"); if (!dbname) { dbname = ""; } err = sqlite3_open(dbname, &g_db); assert(err == SQLITE_OK); + err = sqlite3_exec(g_db, "PRAGMA journal_mode=OFF", NULL, NULL, NULL); + assert(err == SQLITE_OK); + err = sqlite3_exec(g_db, "PRAGMA synchronous=OFF", NULL, NULL, NULL); + assert(err == SQLITE_OK); err = sqlite3_exec(g_db, "CREATE TABLE IF NOT EXISTS orders (id INTEGER PRIMARY KEY, data TEXT NOT NULL)", NULL, NULL, NULL); assert(err == SQLITE_OK); err = sqlite3_prepare_v2(g_db, "INSERT INTO orders (data) VALUES (?)", -1, &g_stmt_insert, NULL); From d2356d9e4f3441b6ca1db5d2ba34739d97ff2b9d Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 12 Nov 2017 14:32:08 +0100 Subject: [PATCH 33/43] fix name of config variables. --- src/kernel/dbsqlite.c | 4 ++-- src/main.c | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/kernel/dbsqlite.c b/src/kernel/dbsqlite.c index b1e182ac0..055e0f9cf 100644 --- a/src/kernel/dbsqlite.c +++ b/src/kernel/dbsqlite.c @@ -91,8 +91,8 @@ void db_open(void) int err; const char *dbname; - g_order_batchsize = config_get_int("config.db_batch", 100); - dbname = config_get("config.db_name"); + g_order_batchsize = config_get_int("game.dbbatch", 100); + dbname = config_get("game.dbname"); if (!dbname) { dbname = ""; } diff --git a/src/main.c b/src/main.c index 8b613789d..215015ed0 100644 --- a/src/main.c +++ b/src/main.c @@ -86,6 +86,8 @@ static const char * valid_keys[] = { "game.mailcmd", "game.era", "game.sender", + "game.dbname", + "game.dbbatch", "editor.color", "editor.codepage", "editor.population.", From dbe835e48547ef137957cd49399a057dc058bfed Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 16 Nov 2017 18:30:18 +0100 Subject: [PATCH 34/43] add cmake directives to build with Berkeley DB --- CMakeLists.txt | 1 + cmake/Modules/FindBerkeleyDB.cmake | 50 ++++++++++++++++++++++++++++++ src/CMakeLists.txt | 9 ++++++ 3 files changed, 60 insertions(+) create mode 100644 cmake/Modules/FindBerkeleyDB.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index d9c15fa52..4aa4ca472 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,6 +12,7 @@ include(MSVC) endif (MSVC) find_package (SQLite3) +find_package (BerkeleyDB) find_package (Curses) find_package (LibXml2) find_package (ToLua REQUIRED) diff --git a/cmake/Modules/FindBerkeleyDB.cmake b/cmake/Modules/FindBerkeleyDB.cmake new file mode 100644 index 000000000..88b0621fe --- /dev/null +++ b/cmake/Modules/FindBerkeleyDB.cmake @@ -0,0 +1,50 @@ +# -*- cmake -*- + +# - Find BerkeleyDB +# Find the BerkeleyDB includes and library +# This module defines +# DB_INCLUDE_DIR, where to find db.h, etc. +# DB_LIBRARIES, the libraries needed to use BerkeleyDB. +# DB_FOUND, If false, do not try to use BerkeleyDB. +# also defined, but not for general use are +# DB_LIBRARY, where to find the BerkeleyDB library. + +FIND_PATH(DB_INCLUDE_DIR db.h + /usr/local/include/db4 + /usr/local/include + /usr/include/db4 + /usr/include + ) + +SET(DB_NAMES ${DB_NAMES} db) +FIND_LIBRARY(DB_LIBRARY + NAMES ${DB_NAMES} + PATHS /usr/lib /usr/local/lib + ) + +IF (DB_LIBRARY AND DB_INCLUDE_DIR) + SET(DB_LIBRARIES ${DB_LIBRARY}) + SET(DB_FOUND "YES") +ELSE (DB_LIBRARY AND DB_INCLUDE_DIR) + SET(DB_FOUND "NO") +ENDIF (DB_LIBRARY AND DB_INCLUDE_DIR) + + +IF (DB_FOUND) + IF (NOT DB_FIND_QUIETLY) + MESSAGE(STATUS "Found BerkeleyDB: ${DB_LIBRARIES}") + ENDIF (NOT DB_FIND_QUIETLY) +ELSE (DB_FOUND) + IF (DB_FIND_REQUIRED) + MESSAGE(FATAL_ERROR "Could not find BerkeleyDB library") + ENDIF (DB_FIND_REQUIRED) +ENDIF (DB_FOUND) + +# Deprecated declarations. +SET (NATIVE_DB_INCLUDE_PATH ${DB_INCLUDE_DIR} ) +GET_FILENAME_COMPONENT (NATIVE_DB_LIB_PATH ${DB_LIBRARY} PATH) + +MARK_AS_ADVANCED( + DB_LIBRARY + DB_INCLUDE_DIR + ) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c5b1b40b2..987c6d2be 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -265,7 +265,16 @@ add_test(server test_eressea) install(TARGETS eressea DESTINATION "bin") +if (DB_FOUND) +include_directories (${DB_INCLUDE_DIR}) +target_link_libraries(convert ${DB_LIBRARIES}) +target_link_libraries(eressea ${DB_LIBRARIES}) +target_link_libraries(test_eressea ${DB_LIBRARIES}) +add_definitions(-DUSE_DB) +endif(DB_FOUND) + if (SQLITE3_FOUND) +include_directories (${SQLITE3_INCLUDE_DIR}) target_link_libraries(eressea ${SQLITE3_LIBRARIES}) target_link_libraries(convert ${SQLITE3_LIBRARIES}) target_link_libraries(test_eressea ${SQLITE3_LIBRARIES}) From 2224b59ff913165c01e8bbbd0b9cecf0eb65d606 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 18 Nov 2017 12:54:48 +0100 Subject: [PATCH 35/43] organize database drivers in their own directory --- src/CMakeLists.txt | 1 + src/eressea.c | 2 +- src/kernel/CMakeLists.txt | 7 +- src/kernel/database.c | 58 ++++++++++ src/kernel/{db.h => database.h} | 0 src/kernel/{db.test.c => database.test.c} | 0 src/kernel/{dbtrie.c => db/critbit.c} | 42 ++++---- src/kernel/db/critbit.h | 8 ++ src/kernel/db/sqlite.c | 121 +++++++++++++++++++++ src/kernel/db/sqlite.h | 8 ++ src/kernel/dbsqlite.c | 123 ---------------------- src/kernel/orderdb.c | 2 +- src/main.c | 2 +- src/test_eressea.c | 2 +- 14 files changed, 224 insertions(+), 152 deletions(-) create mode 100644 src/kernel/database.c rename src/kernel/{db.h => database.h} (100%) rename src/kernel/{db.test.c => database.test.c} (100%) rename src/kernel/{dbtrie.c => db/critbit.c} (54%) create mode 100644 src/kernel/db/critbit.h create mode 100644 src/kernel/db/sqlite.c create mode 100644 src/kernel/db/sqlite.h delete mode 100644 src/kernel/dbsqlite.c diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 987c6d2be..2098e2dee 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -134,6 +134,7 @@ set (ERESSEA_SRC ${TRIGGERS_SRC} ${ATTRIBUTES_SRC} ${KERNEL_SRC} + ${DB_SRC} ${UTIL_SRC} ) diff --git a/src/eressea.c b/src/eressea.c index e1c81f8db..bc838136a 100755 --- a/src/eressea.c +++ b/src/eressea.c @@ -24,10 +24,10 @@ #include #include #include -#include #include #include #include +#include #include #include #include diff --git a/src/kernel/CMakeLists.txt b/src/kernel/CMakeLists.txt index cbd8a6296..5619092ad 100644 --- a/src/kernel/CMakeLists.txt +++ b/src/kernel/CMakeLists.txt @@ -11,7 +11,7 @@ command.test.c config.test.c # connection.test.c curse.test.c -db.test.c +database.test.c equipment.test.c faction.test.c group.test.c @@ -36,9 +36,9 @@ jsonconf.test.c # xmlreader.test.c ) -SET(_DBFILES dbtrie.c) +SET(_DBFILES db/critbit.c) IF(SQLITE3_FOUND) -SET(_DBFILES dbsqlite.c) +SET(_DBFILES db/sqlite.c) ENDIF(SQLITE3_FOUND) SET(_FILES @@ -52,6 +52,7 @@ command.c config.c connection.c curse.c +database.c equipment.c faction.c group.c diff --git a/src/kernel/database.c b/src/kernel/database.c new file mode 100644 index 000000000..732f0fc90 --- /dev/null +++ b/src/kernel/database.c @@ -0,0 +1,58 @@ +#include +#include "database.h" + +#include + +#include +#include +#include + +#include + +#ifdef USE_SQLITE +#include "db/sqlite.h" +#else +#include "db/critbit.h" +#endif + +order_data *db_load_order(int id) +{ + if (id > 0) { +#ifdef USE_SQLITE + return db_sqlite_order_load(id); +#else + return db_critbit_order_load(id); +#endif + } + return NULL; +} + +int db_save_order(order_data *od) +{ + if (od->_str) { +#ifdef USE_SQLITE + return db_sqlite_order_save(od); +#else + return db_critbit_order_save(od); +#endif + } + return 0; +} + +void db_open(void) +{ +#ifdef USE_SQLITE + db_sqlite_open(); +#else + db_critbit_open(); +#endif +} + +void db_close(void) +{ +#ifdef USE_SQLITE + db_sqlite_close(); +#else + db_critbit_close(); +#endif +} diff --git a/src/kernel/db.h b/src/kernel/database.h similarity index 100% rename from src/kernel/db.h rename to src/kernel/database.h diff --git a/src/kernel/db.test.c b/src/kernel/database.test.c similarity index 100% rename from src/kernel/db.test.c rename to src/kernel/database.test.c diff --git a/src/kernel/dbtrie.c b/src/kernel/db/critbit.c similarity index 54% rename from src/kernel/dbtrie.c rename to src/kernel/db/critbit.c index 3cca71af8..647c6921b 100644 --- a/src/kernel/dbtrie.c +++ b/src/kernel/db/critbit.c @@ -1,7 +1,7 @@ #include -#include "db.h" -#include "orderdb.h" +#include "critbit.h" +#include #include #include @@ -18,32 +18,30 @@ struct cb_entry { order_data *data; }; -order_data *db_load_order(int id) +order_data *db_critbit_order_load(int id) { void * match; - if (id > 0) { - if (cb_find_prefix(&cb_orders, &id, sizeof(id), &match, 1, 0) > 0) { - struct cb_entry *ent = (struct cb_entry *)match; - order_data * od = ent->data; - ++od->_refcount; - return od; - } + assert(id>0); + if (cb_find_prefix(&cb_orders, &id, sizeof(id), &match, 1, 0) > 0) { + struct cb_entry *ent = (struct cb_entry *)match; + order_data * od = ent->data; + ++od->_refcount; + return od; } return NULL; } -int db_save_order(order_data *od) +int db_critbit_order_save(order_data *od) { - if (od->_str) { - struct cb_entry ent; - ++od->_refcount; - ent.id = ++auto_id; - ent.data = od; - cb_insert(&cb_orders, &ent, sizeof(ent)); - return ent.id; - } - return 0; + struct cb_entry ent; + + assert(od && od->_str); + ++od->_refcount; + ent.id = ++auto_id; + ent.data = od; + cb_insert(&cb_orders, &ent, sizeof(ent)); + return ent.id; } static int free_data_cb(const void *match, const void *key, size_t keylen, @@ -55,13 +53,13 @@ static int free_data_cb(const void *match, const void *key, size_t keylen, return 0; } -void db_open(void) +void db_critbit_open(void) { assert(auto_id == -1); auto_id = 0; } -void db_close(void) +void db_critbit_close(void) { cb_foreach(&cb_orders, NULL, 0, free_data_cb, NULL); cb_clear(&cb_orders); diff --git a/src/kernel/db/critbit.h b/src/kernel/db/critbit.h new file mode 100644 index 000000000..d4140fa08 --- /dev/null +++ b/src/kernel/db/critbit.h @@ -0,0 +1,8 @@ +#pragma once + +struct order_data; + +void db_critbit_open(void); +void db_critbit_close(void); +int db_critbit_order_save(struct order_data *od); +struct order_data *db_critbit_order_load(int id); diff --git a/src/kernel/db/sqlite.c b/src/kernel/db/sqlite.c new file mode 100644 index 000000000..135195ca0 --- /dev/null +++ b/src/kernel/db/sqlite.c @@ -0,0 +1,121 @@ +#include + +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include + +static sqlite3 *g_db; +static sqlite3_stmt * g_stmt_insert; +static sqlite3_stmt * g_stmt_select; + +static int g_order_batchsize; +static int g_order_tx_size; + +order_data *db_sqlite_order_load(int id) +{ + order_data * od = NULL; + int err; + + if (g_order_tx_size > 0) { + g_order_tx_size = 0; + err = sqlite3_exec(g_db, "COMMIT", NULL, NULL, NULL); + assert(err == SQLITE_OK); + } + err = sqlite3_reset(g_stmt_select); + assert(err == SQLITE_OK); + err = sqlite3_bind_int(g_stmt_select, 1, id); + assert(err == SQLITE_OK); + do { + err = sqlite3_step(g_stmt_select); + if (err == SQLITE_ROW) { + const unsigned char *text; + int bytes; + bytes = sqlite3_column_bytes(g_stmt_select, 0); + assert(bytes > 0); + text = sqlite3_column_text(g_stmt_select, 0); + odata_create(&od, 1+(size_t)bytes, (const char *)text); + return od; + } + } while (err == SQLITE_ROW); + assert(err == SQLITE_DONE); + return NULL; +} + +int db_sqlite_order_save(order_data *od) +{ + int err; + sqlite3_int64 id; + + assert(od && od->_str); + + if (g_order_batchsize > 0) { + if (g_order_tx_size == 0) { + err = sqlite3_exec(g_db, "BEGIN TRANSACTION", NULL, NULL, NULL); + assert(err == SQLITE_OK); + } + } + + err = sqlite3_reset(g_stmt_insert); + assert(err == SQLITE_OK); + err = sqlite3_bind_text(g_stmt_insert, 1, od->_str, -1, SQLITE_STATIC); + assert(err == SQLITE_OK); + err = sqlite3_step(g_stmt_insert); + assert(err == SQLITE_DONE); + id = sqlite3_last_insert_rowid(g_db); + assert(id <= INT_MAX); + + if (g_order_batchsize > 0) { + if (++g_order_tx_size >= g_order_batchsize) { + err = sqlite3_exec(g_db, "COMMIT", NULL, NULL, NULL); + assert(err == SQLITE_OK); + g_order_tx_size = 0; + } + } + + return (int)id; +} + +void db_sqlite_open(void) +{ + int err; + const char *dbname; + + g_order_batchsize = config_get_int("game.dbbatch", 100); + dbname = config_get("game.dbname"); + if (!dbname) { + dbname = ""; + } + err = sqlite3_open(dbname, &g_db); + assert(err == SQLITE_OK); + err = sqlite3_exec(g_db, "PRAGMA journal_mode=OFF", NULL, NULL, NULL); + assert(err == SQLITE_OK); + err = sqlite3_exec(g_db, "PRAGMA synchronous=OFF", NULL, NULL, NULL); + assert(err == SQLITE_OK); + err = sqlite3_exec(g_db, "CREATE TABLE IF NOT EXISTS orders (id INTEGER PRIMARY KEY, data TEXT NOT NULL)", NULL, NULL, NULL); + assert(err == SQLITE_OK); + err = sqlite3_prepare_v2(g_db, "INSERT INTO orders (data) VALUES (?)", -1, &g_stmt_insert, NULL); + assert(err == SQLITE_OK); + err = sqlite3_prepare_v2(g_db, "SELECT data FROM orders WHERE id = ?", -1, &g_stmt_select, NULL); + assert(err == SQLITE_OK); +} + +void db_sqlite_close(void) +{ + int err; + + err = sqlite3_finalize(g_stmt_select); + assert(err == SQLITE_OK); + err = sqlite3_finalize(g_stmt_insert); + assert(err == SQLITE_OK); + err = sqlite3_close(g_db); + assert(err == SQLITE_OK); +} diff --git a/src/kernel/db/sqlite.h b/src/kernel/db/sqlite.h new file mode 100644 index 000000000..f0afba6e7 --- /dev/null +++ b/src/kernel/db/sqlite.h @@ -0,0 +1,8 @@ +#pragma once + +struct order_data; + +void db_sqlite_open(void); +void db_sqlite_close(void); +int db_sqlite_order_save(struct order_data *od); +struct order_data *db_sqlite_order_load(int id); diff --git a/src/kernel/dbsqlite.c b/src/kernel/dbsqlite.c deleted file mode 100644 index 055e0f9cf..000000000 --- a/src/kernel/dbsqlite.c +++ /dev/null @@ -1,123 +0,0 @@ -#include -#include "db.h" -#include "orderdb.h" -#include "config.h" - -#include - -#include - -#include -#include -#include -#include - -static sqlite3 *g_db; -static sqlite3_stmt * g_stmt_insert; -static sqlite3_stmt * g_stmt_select; - -static int g_order_batchsize; -static int g_order_tx_size; - -order_data *db_load_order(int id) -{ - if (id > 0) { - order_data * od = NULL; - int err; - - if (g_order_tx_size > 0) { - g_order_tx_size = 0; - err = sqlite3_exec(g_db, "COMMIT", NULL, NULL, NULL); - assert(err == SQLITE_OK); - } - err = sqlite3_reset(g_stmt_select); - assert(err == SQLITE_OK); - err = sqlite3_bind_int(g_stmt_select, 1, id); - assert(err == SQLITE_OK); - do { - err = sqlite3_step(g_stmt_select); - if (err == SQLITE_ROW) { - const unsigned char *text; - int bytes; - bytes = sqlite3_column_bytes(g_stmt_select, 0); - assert(bytes > 0); - text = sqlite3_column_text(g_stmt_select, 0); - odata_create(&od, 1+(size_t)bytes, (const char *)text); - return od; - } - } while (err == SQLITE_ROW); - assert(err == SQLITE_DONE); - } - return NULL; -} - -int db_save_order(order_data *od) -{ - if (od->_str) { - int err; - sqlite3_int64 id; - - if (g_order_batchsize > 0) { - if (g_order_tx_size == 0) { - err = sqlite3_exec(g_db, "BEGIN TRANSACTION", NULL, NULL, NULL); - assert(err == SQLITE_OK); - } - } - - err = sqlite3_reset(g_stmt_insert); - assert(err == SQLITE_OK); - err = sqlite3_bind_text(g_stmt_insert, 1, od->_str, -1, SQLITE_STATIC); - assert(err == SQLITE_OK); - err = sqlite3_step(g_stmt_insert); - assert(err == SQLITE_DONE); - id = sqlite3_last_insert_rowid(g_db); - assert(id <= INT_MAX); - - if (g_order_batchsize > 0) { - if (++g_order_tx_size >= g_order_batchsize) { - err = sqlite3_exec(g_db, "COMMIT", NULL, NULL, NULL); - assert(err == SQLITE_OK); - g_order_tx_size = 0; - } - } - - return (int)id; - } - return 0; -} - -void db_open(void) -{ - int err; - const char *dbname; - - g_order_batchsize = config_get_int("game.dbbatch", 100); - dbname = config_get("game.dbname"); - if (!dbname) { - dbname = ""; - } - err = sqlite3_open(dbname, &g_db); - assert(err == SQLITE_OK); - err = sqlite3_exec(g_db, "PRAGMA journal_mode=OFF", NULL, NULL, NULL); - assert(err == SQLITE_OK); - err = sqlite3_exec(g_db, "PRAGMA synchronous=OFF", NULL, NULL, NULL); - assert(err == SQLITE_OK); - err = sqlite3_exec(g_db, "CREATE TABLE IF NOT EXISTS orders (id INTEGER PRIMARY KEY, data TEXT NOT NULL)", NULL, NULL, NULL); - assert(err == SQLITE_OK); - err = sqlite3_prepare_v2(g_db, "INSERT INTO orders (data) VALUES (?)", -1, &g_stmt_insert, NULL); - assert(err == SQLITE_OK); - err = sqlite3_prepare_v2(g_db, "SELECT data FROM orders WHERE id = ?", -1, &g_stmt_select, NULL); - assert(err == SQLITE_OK); -} - -void db_close(void) -{ - int err; - - err = sqlite3_finalize(g_stmt_select); - assert(err == SQLITE_OK); - err = sqlite3_finalize(g_stmt_insert); - assert(err == SQLITE_OK); - err = sqlite3_close(g_db); - assert(err == SQLITE_OK); -} diff --git a/src/kernel/orderdb.c b/src/kernel/orderdb.c index ee23993e6..e2eed4a0f 100644 --- a/src/kernel/orderdb.c +++ b/src/kernel/orderdb.c @@ -1,5 +1,5 @@ #include -#include "db.h" +#include "database.h" #include "orderdb.h" #include diff --git a/src/main.c b/src/main.c index 215015ed0..ae462c139 100644 --- a/src/main.c +++ b/src/main.c @@ -20,7 +20,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include -#include +#include #include #include #include diff --git a/src/test_eressea.c b/src/test_eressea.c index c5ba24abb..09d6c2cf4 100644 --- a/src/test_eressea.c +++ b/src/test_eressea.c @@ -1,7 +1,7 @@ #include #include #include -#include +#include #include #include #include From 50e242b810f2295909eaf7a41f0b244645253277 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 18 Nov 2017 13:02:12 +0100 Subject: [PATCH 36/43] fix include of renamed header --- src/kernel/database.test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernel/database.test.c b/src/kernel/database.test.c index 81f6f51c4..77f4649c4 100644 --- a/src/kernel/database.test.c +++ b/src/kernel/database.test.c @@ -1,7 +1,7 @@ #include #include -#include "db.h" +#include "database.h" #include "orderdb.h" #include From 2f5f685e551053340ed71f77d70fdb4ae221b65a Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 19 Nov 2017 12:31:50 +0100 Subject: [PATCH 37/43] add berkeley db, rename some files --- src/eressea.c | 8 ++++---- src/kernel/CMakeLists.txt | 5 +++++ src/kernel/database.c | 38 ++++++++-------------------------- src/kernel/database.h | 12 +++++------ src/kernel/db/berkeley.c | 43 +++++++++++++++++++++++++++++++++++++++ src/kernel/db/critbit.c | 10 ++++----- src/kernel/db/critbit.h | 8 -------- src/kernel/db/driver.h | 8 ++++++++ src/kernel/db/sqlite.c | 10 +++++---- src/kernel/db/sqlite.h | 8 -------- src/kernel/orderdb.c | 4 ++-- 11 files changed, 88 insertions(+), 66 deletions(-) create mode 100644 src/kernel/db/berkeley.c delete mode 100644 src/kernel/db/critbit.h create mode 100644 src/kernel/db/driver.h delete mode 100644 src/kernel/db/sqlite.h diff --git a/src/eressea.c b/src/eressea.c index bc838136a..b816fe81d 100755 --- a/src/eressea.c +++ b/src/eressea.c @@ -44,8 +44,8 @@ void game_done(void) #ifdef CLEANUP_CODE /* Diese Routine enfernt allen allokierten Speicher wieder. Das ist nur * zum Debugging interessant, wenn man Leak Detection hat, und nach - * nicht freigegebenem Speicher sucht, der nicht bis zum Ende benötigt - * wird (temporäre Hilsstrukturen) */ + * nicht freigegebenem Speicher sucht, der nicht bis zum Ende ben�tigt + * wird (tempor�re Hilsstrukturen) */ free_game(); @@ -60,12 +60,12 @@ void game_done(void) free_special_directions(); free_locales(); kernel_done(); - db_close(); + dblib_close(); } void game_init(void) { - db_open(); + dblib_open(); kernel_init(); register_triggers(); register_xmas(); diff --git a/src/kernel/CMakeLists.txt b/src/kernel/CMakeLists.txt index 5619092ad..dc8d14abd 100644 --- a/src/kernel/CMakeLists.txt +++ b/src/kernel/CMakeLists.txt @@ -37,10 +37,15 @@ jsonconf.test.c ) SET(_DBFILES db/critbit.c) + IF(SQLITE3_FOUND) SET(_DBFILES db/sqlite.c) ENDIF(SQLITE3_FOUND) +IF(DB_FOUND) +SET(_DBFILES db/berkeley.c) +ENDIF(DB_FOUND) + SET(_FILES ${_DBFILES} alliance.c diff --git a/src/kernel/database.c b/src/kernel/database.c index 732f0fc90..eaf695613 100644 --- a/src/kernel/database.c +++ b/src/kernel/database.c @@ -9,50 +9,30 @@ #include -#ifdef USE_SQLITE -#include "db/sqlite.h" -#else -#include "db/critbit.h" -#endif +#include "db/driver.h" -order_data *db_load_order(int id) +order_data *dblib_load_order(int id) { if (id > 0) { -#ifdef USE_SQLITE - return db_sqlite_order_load(id); -#else - return db_critbit_order_load(id); -#endif + return db_driver_order_load(id); } return NULL; } -int db_save_order(order_data *od) +int dblib_save_order(order_data *od) { if (od->_str) { -#ifdef USE_SQLITE - return db_sqlite_order_save(od); -#else - return db_critbit_order_save(od); -#endif + return db_driver_order_save(od); } return 0; } -void db_open(void) +void dblib_open(void) { -#ifdef USE_SQLITE - db_sqlite_open(); -#else - db_critbit_open(); -#endif + db_driver_open(); } -void db_close(void) +void dblib_close(void) { -#ifdef USE_SQLITE - db_sqlite_close(); -#else - db_critbit_close(); -#endif + db_driver_close(); } diff --git a/src/kernel/database.h b/src/kernel/database.h index 052d28aad..0dd5a70fb 100644 --- a/src/kernel/database.h +++ b/src/kernel/database.h @@ -1,5 +1,5 @@ -#ifndef H_DB -#define H_DB +#ifndef H_DATABASE +#define H_DATABASE #include @@ -9,11 +9,11 @@ extern "C" { struct order_data; - void db_open(void); - void db_close(void); + void dblib_open(void); + void dblib_close(void); - struct order_data *db_load_order(int id); - int db_save_order(struct order_data *od); + struct order_data *dblib_load_order(int id); + int dblib_save_order(struct order_data *od); #ifdef __cplusplus } diff --git a/src/kernel/db/berkeley.c b/src/kernel/db/berkeley.c new file mode 100644 index 000000000..13e7dbb43 --- /dev/null +++ b/src/kernel/db/berkeley.c @@ -0,0 +1,43 @@ +#include +#include "driver.h" + +#ifdef __APPLE__ +#define _DARWIN_C_SOURCE +#include +#endif +#include + +#include + +static DB *g_dbp; + +void db_driver_open(void) +{ + int ret; + u_int32_t flags = DB_CREATE|DB_TRUNCATE; + const char * dbname; + + ret = db_create(&g_dbp, NULL, 0); + assert(ret==0); + + ret = g_dbp->open(g_dbp, NULL, dbname, NULL, DB_BTREE, flags, 0); + assert(ret==0); +} + +void db_driver_close(void) +{ + int ret; + ret = g_dbp->close(g_dbp, 0); + assert(ret==0); +} + +int db_driver_order_save(struct order_data *od) +{ + return 0; +} + +struct order_data *db_driver_order_load(int id) +{ + return NULL; +} + diff --git a/src/kernel/db/critbit.c b/src/kernel/db/critbit.c index 647c6921b..9afb0926d 100644 --- a/src/kernel/db/critbit.c +++ b/src/kernel/db/critbit.c @@ -1,5 +1,5 @@ #include -#include "critbit.h" +#include "driver.h" #include #include @@ -18,7 +18,7 @@ struct cb_entry { order_data *data; }; -order_data *db_critbit_order_load(int id) +order_data *db_driver_order_load(int id) { void * match; @@ -32,7 +32,7 @@ order_data *db_critbit_order_load(int id) return NULL; } -int db_critbit_order_save(order_data *od) +int db_driver_order_save(order_data *od) { struct cb_entry ent; @@ -53,13 +53,13 @@ static int free_data_cb(const void *match, const void *key, size_t keylen, return 0; } -void db_critbit_open(void) +void db_driver_open(void) { assert(auto_id == -1); auto_id = 0; } -void db_critbit_close(void) +void db_driver_close(void) { cb_foreach(&cb_orders, NULL, 0, free_data_cb, NULL); cb_clear(&cb_orders); diff --git a/src/kernel/db/critbit.h b/src/kernel/db/critbit.h deleted file mode 100644 index d4140fa08..000000000 --- a/src/kernel/db/critbit.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -struct order_data; - -void db_critbit_open(void); -void db_critbit_close(void); -int db_critbit_order_save(struct order_data *od); -struct order_data *db_critbit_order_load(int id); diff --git a/src/kernel/db/driver.h b/src/kernel/db/driver.h new file mode 100644 index 000000000..df839b93d --- /dev/null +++ b/src/kernel/db/driver.h @@ -0,0 +1,8 @@ +#pragma once + +struct order_data; + +void db_driver_open(void); +void db_driver_close(void); +int db_driver_order_save(struct order_data *od); +struct order_data *db_driver_order_load(int id); diff --git a/src/kernel/db/sqlite.c b/src/kernel/db/sqlite.c index 135195ca0..965363223 100644 --- a/src/kernel/db/sqlite.c +++ b/src/kernel/db/sqlite.c @@ -6,6 +6,8 @@ #include +#include "driver.h" + #include #include @@ -20,7 +22,7 @@ static sqlite3_stmt * g_stmt_select; static int g_order_batchsize; static int g_order_tx_size; -order_data *db_sqlite_order_load(int id) +order_data *db_driver_order_load(int id) { order_data * od = NULL; int err; @@ -50,7 +52,7 @@ order_data *db_sqlite_order_load(int id) return NULL; } -int db_sqlite_order_save(order_data *od) +int db_driver_order_save(order_data *od) { int err; sqlite3_int64 id; @@ -84,7 +86,7 @@ int db_sqlite_order_save(order_data *od) return (int)id; } -void db_sqlite_open(void) +void db_driver_open(void) { int err; const char *dbname; @@ -108,7 +110,7 @@ void db_sqlite_open(void) assert(err == SQLITE_OK); } -void db_sqlite_close(void) +void db_driver_close(void) { int err; diff --git a/src/kernel/db/sqlite.h b/src/kernel/db/sqlite.h deleted file mode 100644 index f0afba6e7..000000000 --- a/src/kernel/db/sqlite.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -struct order_data; - -void db_sqlite_open(void); -void db_sqlite_close(void); -int db_sqlite_order_save(struct order_data *od); -struct order_data *db_sqlite_order_load(int id); diff --git a/src/kernel/orderdb.c b/src/kernel/orderdb.c index e2eed4a0f..d97c5fae3 100644 --- a/src/kernel/orderdb.c +++ b/src/kernel/orderdb.c @@ -38,10 +38,10 @@ void odata_addref(order_data *od) order_data *odata_load(int id) { - return db_load_order(id); + return dblib_load_order(id); } int odata_save(order_data *od) { - return db_save_order(od); + return dblib_save_order(od); } From 2ff820d1b4c5267aced0dfa5deb770d2a97b4fdc Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 19 Nov 2017 12:50:24 +0100 Subject: [PATCH 38/43] implement get/put for db --- src/kernel/db/berkeley.c | 42 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/src/kernel/db/berkeley.c b/src/kernel/db/berkeley.c index 13e7dbb43..edefbf98d 100644 --- a/src/kernel/db/berkeley.c +++ b/src/kernel/db/berkeley.c @@ -1,6 +1,9 @@ #include #include "driver.h" +#include +#include + #ifdef __APPLE__ #define _DARWIN_C_SOURCE #include @@ -8,8 +11,10 @@ #include #include +#include static DB *g_dbp; +static int order_id = -1; void db_driver_open(void) { @@ -17,11 +22,18 @@ void db_driver_open(void) u_int32_t flags = DB_CREATE|DB_TRUNCATE; const char * dbname; + dbname = config_get("game.dbname"); + if (!dbname) { + dbname = "temporary.db"; + } ret = db_create(&g_dbp, NULL, 0); assert(ret==0); ret = g_dbp->open(g_dbp, NULL, dbname, NULL, DB_BTREE, flags, 0); assert(ret==0); + + assert(order_id == -1); + order_id = 0; } void db_driver_close(void) @@ -29,15 +41,41 @@ void db_driver_close(void) int ret; ret = g_dbp->close(g_dbp, 0); assert(ret==0); + order_id = -1; } int db_driver_order_save(struct order_data *od) { - return 0; + int ret; + DBT key, data; + + assert(od && od->_str); + ++order_id; + key.data = &order_id; + key.size = sizeof(int); + data.data = (void *)od->_str; + data.size = strlen(od->_str) + 1; + data.flags = DB_DBT_USERMEM; + ret = g_dbp->put(g_dbp, NULL, &key, &data, DB_NOOVERWRITE); + assert(ret == 0); + return order_id; } struct order_data *db_driver_order_load(int id) { - return NULL; + int ret; + order_data *od = NULL; + DBT key, data; + + assert(id>0 && id <= order_id); + memset(&key, 0, sizeof(DBT)); + memset(&data, 0, sizeof(DBT)); + key.data = &id; + key.size = sizeof(int); + ret = g_dbp->get(g_dbp, NULL, &key, &data, 0); + if (ret == 0) { + odata_create(&od, data.ulen, data.data); + } + return od; } From 41f20c02b263968b157200b190f97062288eeac4 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 19 Nov 2017 16:19:16 +0100 Subject: [PATCH 39/43] fix bdb load/save, use recno db --- src/CMakeLists.txt | 2 +- src/kernel/db/berkeley.c | 46 ++++++++++++++++++---------------------- 2 files changed, 22 insertions(+), 26 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2098e2dee..07242b312 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -26,7 +26,7 @@ ENDIF() IF (CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang") # SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wconversion -Wno-sign-conversion") SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wsign-compare -Wall -Werror -Wno-unknown-pragmas -Wstrict-prototypes -Wpointer-arith -Wno-char-subscripts -Wno-long-long") - SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c89") +# SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c89") ELSEIF(MSVC) SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Wall /WX /MP") set(CMAKE_EXE_LINKER_FLAGS_DEBUG diff --git a/src/kernel/db/berkeley.c b/src/kernel/db/berkeley.c index edefbf98d..6ccc23b93 100644 --- a/src/kernel/db/berkeley.c +++ b/src/kernel/db/berkeley.c @@ -1,39 +1,32 @@ +#ifdef __APPLE__ +#define _DARWIN_C_SOURCE +#endif +#include +#include + #include #include "driver.h" #include #include -#ifdef __APPLE__ -#define _DARWIN_C_SOURCE -#include -#endif -#include - #include #include static DB *g_dbp; -static int order_id = -1; void db_driver_open(void) { int ret; - u_int32_t flags = DB_CREATE|DB_TRUNCATE; + u_int32_t flags = DB_CREATE; const char * dbname; dbname = config_get("game.dbname"); - if (!dbname) { - dbname = "temporary.db"; - } ret = db_create(&g_dbp, NULL, 0); assert(ret==0); - ret = g_dbp->open(g_dbp, NULL, dbname, NULL, DB_BTREE, flags, 0); + ret = g_dbp->open(g_dbp, NULL, dbname, NULL, DB_RECNO, flags, 0); assert(ret==0); - - assert(order_id == -1); - order_id = 0; } void db_driver_close(void) @@ -41,24 +34,24 @@ void db_driver_close(void) int ret; ret = g_dbp->close(g_dbp, 0); assert(ret==0); - order_id = -1; } int db_driver_order_save(struct order_data *od) { int ret; DBT key, data; + db_recno_t recno; assert(od && od->_str); - ++order_id; - key.data = &order_id; - key.size = sizeof(int); + key.data = &recno; + key.size = sizeof(recno); + key.flags = DB_DBT_USERMEM; data.data = (void *)od->_str; data.size = strlen(od->_str) + 1; data.flags = DB_DBT_USERMEM; - ret = g_dbp->put(g_dbp, NULL, &key, &data, DB_NOOVERWRITE); + ret = g_dbp->put(g_dbp, NULL, &key, &data, DB_APPEND); assert(ret == 0); - return order_id; + return (int)recno; } struct order_data *db_driver_order_load(int id) @@ -66,15 +59,18 @@ struct order_data *db_driver_order_load(int id) int ret; order_data *od = NULL; DBT key, data; + db_recno_t recno; - assert(id>0 && id <= order_id); + assert(id>0); memset(&key, 0, sizeof(DBT)); memset(&data, 0, sizeof(DBT)); - key.data = &id; - key.size = sizeof(int); + recno = (db_recno_t)id; + key.data = &recno; + key.size = sizeof(recno); + key.flags = DB_DBT_USERMEM; ret = g_dbp->get(g_dbp, NULL, &key, &data, 0); if (ret == 0) { - odata_create(&od, data.ulen, data.data); + odata_create(&od, data.size, data.data); } return od; } From 793de9f82a1bfcc73cd727a78393a1110aa65b9a Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 19 Nov 2017 16:32:20 +0100 Subject: [PATCH 40/43] no special apple ifdef required --- src/kernel/db/berkeley.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/kernel/db/berkeley.c b/src/kernel/db/berkeley.c index 6ccc23b93..5a65ee3b0 100644 --- a/src/kernel/db/berkeley.c +++ b/src/kernel/db/berkeley.c @@ -1,6 +1,3 @@ -#ifdef __APPLE__ -#define _DARWIN_C_SOURCE -#endif #include #include From 38922d92057da855b186fcf092abb70c6748f8e6 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 25 Nov 2017 11:29:52 +0100 Subject: [PATCH 41/43] on the Rapsberry Pi, long is only 32 bit --- src/kernel/unit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernel/unit.c b/src/kernel/unit.c index a3e6fc1ac..9b024851b 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -1063,7 +1063,7 @@ void clone_men(const unit * u, unit * dst, int n) transfer_curse(u, dst, n); } set_number(dst, dst->number + n); - dst->hp += (long)u->hp * n / u->number; + dst->hp += (long long)u->hp * n / u->number; assert(dst->hp >= dst->number); /* TODO: Das ist schnarchlahm! und gehoert nicht hierhin */ a = a_find(dst->attribs, &at_effect); From 9188f6fbb62e82f747839e33aaec77b6841b7626 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 26 Nov 2017 15:06:52 +0100 Subject: [PATCH 42/43] scale_number test revised --- src/kernel/unit.test.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/kernel/unit.test.c b/src/kernel/unit.test.c index fcd737ff8..69932afbd 100644 --- a/src/kernel/unit.test.c +++ b/src/kernel/unit.test.c @@ -106,13 +106,22 @@ static void test_scale_number(CuTest *tc) { ptype = new_potiontype(it_get_or_create(rt_get_or_create("hodor")), 1); u = test_create_unit(test_create_faction(test_create_race("human")), findregion(0, 0)); change_effect(u, ptype, 1); + u->hp = 35; CuAssertIntEquals(tc, 1, u->number); - CuAssertIntEquals(tc, 20, u->hp); + CuAssertIntEquals(tc, 35, u->hp); CuAssertIntEquals(tc, 1, get_effect(u, ptype)); scale_number(u, 2); CuAssertIntEquals(tc, 2, u->number); - CuAssertIntEquals(tc, 40, u->hp); - CuAssertIntEquals(tc, 2, get_effect(u, ptype)); + CuAssertIntEquals(tc, 35 * u->number, u->hp); + CuAssertIntEquals(tc, u->number, get_effect(u, ptype)); + scale_number(u, 8237); + CuAssertIntEquals(tc, 8237, u->number); + CuAssertIntEquals(tc, 35 * u->number, u->hp); + CuAssertIntEquals(tc, u->number, get_effect(u, ptype)); + scale_number(u, 8100); + CuAssertIntEquals(tc, 8100, u->number); + CuAssertIntEquals(tc, 35 * u->number, u->hp); + CuAssertIntEquals(tc, u->number, get_effect(u, ptype)); set_level(u, SK_ALCHEMY, 1); scale_number(u, 0); CuAssertIntEquals(tc, 0, get_level(u, SK_ALCHEMY)); From a67b2fa68dc51e0176c3ae4de8e3a2895c927ad4 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 26 Nov 2017 15:15:25 +0100 Subject: [PATCH 43/43] stop using random numbers to scale units. --- src/kernel/unit.c | 40 ++++++++++++---------------------------- src/kernel/unit.h | 2 +- 2 files changed, 13 insertions(+), 29 deletions(-) diff --git a/src/kernel/unit.c b/src/kernel/unit.c index 9b024851b..2e3dab804 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -1733,38 +1733,22 @@ int unit_max_hp(const unit * u) void scale_number(unit * u, int n) { - const attrib *a; - int remain; - - if (n == u->number) + if (n == u->number) { return; - if (n && u->number > 0) { - int full; - remain = ((u->hp % u->number) * (n % u->number)) % u->number; - - full = u->hp / u->number; /* wieviel kriegt jede person mindestens */ - u->hp = full * n + (u->hp - full * u->number) * n / u->number; - assert(u->hp >= 0); - if ((rng_int() % u->number) < remain) - ++u->hp; /* Nachkommastellen */ - } - else { - remain = 0; - u->hp = 0; } if (u->number > 0) { - for (a = a_find(u->attribs, &at_effect); a && a->type == &at_effect; - a = a->next) { - effect_data *data = (effect_data *)a->data.v; - int snew = data->value / u->number * n; - if (n) { - remain = data->value - snew / n * u->number; - snew += remain * n / u->number; - remain = (remain * n) % u->number; - if ((rng_int() % u->number) < remain) - ++snew; /* Nachkommastellen */ + if (n>0) { + const attrib *a = a_find(u->attribs, &at_effect); + + u->hp = (long long)u->hp * n / u->number; + + for (; a && a->type == &at_effect; a = a->next) { + effect_data *data = (effect_data *)a->data.v; + data->value = (long long)data->value * n / u->number; } - data->value = snew; + } + else { + u->hp = 0; } } if (u->number == 0 || n == 0) { diff --git a/src/kernel/unit.h b/src/kernel/unit.h index d80c0ec79..53f9836db 100644 --- a/src/kernel/unit.h +++ b/src/kernel/unit.h @@ -112,7 +112,7 @@ extern "C" { int flags; struct attrib *attribs; status_t status; - int n; /* helper temporariy variable, used in econmy, enno: attribut? */ + int n; /* helper temporary variable, used in economy, enno: attribut? */ int wants; /* enno: attribut? */ } unit;