diff --git a/res/core/common/items.xml b/res/core/common/items.xml index 308a41df2..564e9fafd 100644 --- a/res/core/common/items.xml +++ b/res/core/common/items.xml @@ -46,7 +46,7 @@ - + diff --git a/res/core/de/strings.xml b/res/core/de/strings.xml index 6bf4f5abe..f773be014 100644 --- a/res/core/de/strings.xml +++ b/res/core/de/strings.xml @@ -7331,7 +7331,7 @@ - eine zu $percent%% vollendete Straße + eine zu $percent% vollendete Straße a road that is $percent% complete diff --git a/res/core/messages.xml b/res/core/messages.xml index 5ea0694fd..f09530e0f 100644 --- a/res/core/messages.xml +++ b/res/core/messages.xml @@ -42,6 +42,18 @@ pulled by 8 young dragons flies through the stary night and presents your faction with a $resource($item,1). + + + + + 'Ho ho ho!' Ein dicker Gnom fliegt auf einem von + 8 Jungdrachen gezogenen Schlitten durch die Nacht und vermacht Deiner + Partei einen $resource($item,1). (Um diesen Gegenstand einer Einheit zu geben, gib + ihr den Befehl 'BEANSPRUCHE 1 $resource($item,1)'). + 'Ho ho ho!' A fat little gnome Gnom on a sled + pulled by 8 young dragons flies through the stary night and presents + your faction with a $resource($item,1). + diff --git a/s/travis-build b/s/travis-build index 9ef0fbdd5..a678b1de2 100755 --- a/s/travis-build +++ b/s/travis-build @@ -16,11 +16,23 @@ cd tests ./run-turn.sh } +cppcheck_tests() { + cppcheck --version + DIRS="util kernel modules races attributes triggers items tools spells" + IGNORE="" + for DIR in $DIRS ; do + IGNORE="$IGNORE -i src/$DIR" + echo "cppcheck src/$DIR" + cppcheck --quiet -Isrc -Iclibs -Istorage -IcJSON --error-exitcode=1 "src/$DIR" + done + echo "cppcheck src" + cppcheck --quiet -Isrc -Iclibs -Istorage -IcJSON --error-exitcode=1 $IGNORE src +} + set -e [ -z $BUILD ] && BUILD=Debug ; export BUILD s/cmake-init -cppcheck --version -cppcheck --quiet -Isrc -Iclibs -Istorage -IcJSON --error-exitcode=1 src +# cppcheck_tests s/build cd process make diff --git a/scripts/eressea/xmas.lua b/scripts/eressea/xmas.lua index 6f319a316..9fe368e42 100644 --- a/scripts/eressea/xmas.lua +++ b/scripts/eressea/xmas.lua @@ -2,16 +2,15 @@ if not config.xmas or config.xmas==0 then return nil end local gifts = { e2 = { - { year = 2017, turn = 1057, item = 'snowglobe', msg='santa_f' }, - { year = 2015, turn = 959, item = 'snowglobe', msg='santa_f' }, - { year = 2009, turn = 624, item = 'xmastree' }, - { year = 2006, turn = 468, key = 'xm06', item = 'snowman' }, - { year = 2005, turn = 416, key = 'xm05', item = 'stardust' }, - { year = 2004, turn = 364, key = 'xm04', item = 'speedsail' } + [1057] = { year = 2017, item = 'snowglobe', msg='santa_f' }, + [959] = { year = 2015, item = 'snowglobe', msg='santa_f' }, + [624] = { year = 2009, item = 'xmastree', msg='santa_m' }, + [468] = { year = 2006, item = 'snowman', msg='santa_m' }, + [416] = { year = 2005, item = 'stardust' }, + [364] = { year = 2004, item = 'speedsail' } }, e3 = { - -- { year = 2015, turn = 338, item = 'snowglobe' }, - { year = 2009, turn = 26, key = 'xm09', item = 'xmastree' } + [26] = { year = 2009, item = 'xmastree' } } } @@ -38,13 +37,9 @@ function self.init() local turn = get_turn() local tbl = gifts[config.rules] if tbl then - for _, gift in ipairs(tbl) do - if turn == gift.turn then - give_gifts(gift) - elseif gift.key and not get_key(gift.key) then - give_gifts(gift) - set_key(gift.key) - end + gift = tbl[turn] + if gift then + give_gifts(gift) end end end diff --git a/src/battle.c b/src/battle.c index 837d4a280..da84b2763 100644 --- a/src/battle.c +++ b/src/battle.c @@ -185,7 +185,7 @@ static int army_index(side * s) return s->index; } -static char *sidename(side * s) +const char *sidename(const side * s) { #define SIDENAMEBUFLEN 256 static int bufno; /* STATIC_XCALL: used across calls */ @@ -206,7 +206,7 @@ static const char *sideabkz(side * s, bool truename) return sideabkz_buf; } -static void message_faction(battle * b, faction * f, struct message *m) +void battle_message_faction(battle * b, faction * f, struct message *m) { region *r = b->region; @@ -227,14 +227,14 @@ void message_all(battle * b, message * m) for (bf = b->factions; bf; bf = bf->next) { assert(bf->faction); - message_faction(b, bf->faction, m); + battle_message_faction(b, bf->faction, m); } } static void fbattlerecord(battle * b, faction * f, const char *s) { message *m = msg_message("battle_msg", "string", s); - message_faction(b, f, m); + battle_message_faction(b, f, m); msg_release(m); } @@ -1302,7 +1302,7 @@ terminate(troop dt, troop at, int type, const char *damage, bool missile) if (oldpotiontype[P_HEAL] && !fval(&df->person[dt.index], FL_HEALING_USED)) { if (i_get(du->items, oldpotiontype[P_HEAL]->itype) > 0) { message *m = msg_message("potionsave", "unit", du); - message_faction(b, du->faction, m); + battle_message_faction(b, du->faction, m); msg_release(m); i_change(&du->items, oldpotiontype[P_HEAL]->itype, -1); fset(&df->person[dt.index], FL_HEALING_USED); @@ -2531,7 +2531,7 @@ static void loot_items(fighter * corpse) } } -static bool seematrix(const faction * f, const side * s) +bool seematrix(const faction * f, const side * s) { if (f == s->faction) return true; @@ -2615,7 +2615,7 @@ static void aftermath(battle * b) struct message *m = msg_message("killsandhits", "unit hits kills", du, df->hits, df->kills); - message_faction(b, du->faction, m); + battle_message_faction(b, du->faction, m); msg_release(m); } } @@ -2755,7 +2755,7 @@ static void aftermath(battle * b) faction *f = bf->faction; message *m = seematrix(f, s) ? seen : unseen; - message_faction(b, f, m); + battle_message_faction(b, f, m); } msg_release(seen); @@ -2779,7 +2779,7 @@ static void aftermath(battle * b) message *m = msg_message("battle_loot", "unit amount item", du, l->number, itype->rtype); - message_faction(b, du->faction, m); + battle_message_faction(b, du->faction, m); msg_release(m); i_change(&du->items, itype, l->number); } @@ -2877,54 +2877,6 @@ static void set_attacker(fighter * fig) fset(fig, FIG_ATTACKER); } -static void print_header(battle * b) -{ - bfaction *bf; - char zText[32 * MAXSIDES]; - - for (bf = b->factions; bf; bf = bf->next) { - message *m; - faction *f = bf->faction; - const char *lastf = NULL; - bool first = false; - side *s; - char *bufp = zText; - size_t size = sizeof(zText) - 1; - - for (s = b->sides; s != b->sides + b->nsides; ++s) { - fighter *df; - for (df = s->fighters; df; df = df->next) { - if (is_attacker(df)) { - if (first) { - str_strlcpy(bufp, ", ", size); - } - if (lastf) { - str_strlcpy(bufp, lastf, size); - first = true; - } - if (seematrix(f, s)) - lastf = sidename(s); - else - lastf = LOC(f->locale, "unknown_faction_dative"); - break; - } - } - } - if (first) { - bufp = STRLCPY(bufp, " ", size); - bufp = STRLCPY(bufp, LOC(f->locale, "and"), size); - bufp = STRLCPY(bufp, " ", size); - } - if (lastf) { - bufp = STRLCPY(bufp, lastf, size); - } - - m = msg_message("start_battle", "factions", zText); - message_faction(b, f, m); - msg_release(m); - } -} - static void print_stats(battle * b) { side *s2; @@ -2947,10 +2899,10 @@ static void print_stats(battle * b) message *msg; char buf[1024]; - message_faction(b, f, msg_separator); + battle_message_faction(b, f, msg_separator); msg = msg_message("battle_army", "index name", army_index(s), sname); - message_faction(b, f, msg); + battle_message_faction(b, f, msg); msg_release(msg); bufp = buf; @@ -3569,13 +3521,13 @@ static int battle_report(battle * b) size_t size = sizeof(buf) - 1; message *m; - message_faction(b, fac, msg_separator); + battle_message_faction(b, fac, msg_separator); if (cont) m = msg_message("lineup_battle", "turn", b->turn); else m = msg_message("after_battle", ""); - message_faction(b, fac, m); + battle_message_faction(b, fac, m); msg_release(m); komma = false; @@ -4078,7 +4030,7 @@ void do_battle(region * r) /* Bevor wir die alliierten hineinziehen, sollten wir schauen, * * Ob jemand fliehen kann. Dann er�brigt sich das ganze ja * vielleicht schon. */ - print_header(b); + report_battle_start(b); if (!fighting) { /* Niemand mehr da, Kampf kann nicht stattfinden. */ message *m = msg_message("aborted_battle", ""); diff --git a/src/battle.h b/src/battle.h index f7e84ea6b..6494a6e27 100644 --- a/src/battle.h +++ b/src/battle.h @@ -47,7 +47,6 @@ extern "C" { #define LAST_ROW FLEE_ROW #define MAXSIDES 192 /* if there are ever more than this, we're fucked. */ - typedef struct bfaction { struct bfaction *next; struct side *sides; @@ -266,6 +265,9 @@ extern "C" { const struct faction * stealthfaction); int skilldiff(troop at, troop dt, int dist); void force_leave(struct region *r, struct battle *b); + bool seematrix(const struct faction * f, const struct side * s); + const char *sidename(const struct side * s); + void battle_message_faction(struct battle * b, struct faction * f, struct message *m); #ifdef __cplusplus } diff --git a/src/kernel/faction.c b/src/kernel/faction.c index d49bcd877..f56285b6b 100755 --- a/src/kernel/faction.c +++ b/src/kernel/faction.c @@ -316,7 +316,7 @@ bool checkpasswd(const faction * f, const char *passwd) if (!passwd) return false; if (f->_password && password_verify(f->_password, passwd) == VERIFY_FAIL) { - log_warning("password check failed: %s", factionname(f)); + log_info("password check failed: %s", factionname(f)); return false; } return true; @@ -408,12 +408,8 @@ void save_special_items(unit *usrc) static int cache; static const char *name = NULL; if (rc_changed(&cache)) { - rc_ghost = rc_find("ghost"); - if (!rc_ghost) { - rc_ghost = get_race(RC_TEMPLATE); - name = "ghost"; - } - assert(rc_ghost); + rc_ghost = get_race(RC_TEMPLATE); + name = "ghost"; } for (u = r->units; u; u = u->next) { if (u->faction == fm) { diff --git a/src/kernel/order.c b/src/kernel/order.c index 05a4ac4ba..8defd05c9 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -19,7 +19,6 @@ #include "keyword.h" #include -#include #include #include #include @@ -68,29 +67,17 @@ keyword_t getkeyword(const order * ord) * keywords are expanded to their full length. */ char* get_command(const order *ord, const struct locale *lang, char *sbuffer, size_t size) { - char *bufp = sbuffer; order_data *od = NULL; const char * text; keyword_t kwd = ORD_KEYWORD(ord); - int bytes; + sbstring sbs; + sbs_init(&sbs, sbuffer, size); if (ord->command & CMD_QUIET) { - if (size > 0) { - *bufp++ = '!'; - --size; - } - else { - WARN_STATIC_BUFFER(); - } + sbs_strcpy(&sbs, "!"); } if (ord->command & CMD_PERSIST) { - if (size > 0) { - *bufp++ = '@'; - --size; - } - else { - WARN_STATIC_BUFFER(); - } + sbs_strcat(&sbs, "@"); } if (ord->id < 0) { @@ -102,39 +89,19 @@ char* get_command(const order *ord, const struct locale *lang, char *sbuffer, si text = OD_STRING(od); } if (kwd != NOKEYWORD) { - if (size > 0) { - const char *str = (const char *)LOC(lang, keyword(kwd)); - assert(str); - if (text) --size; - bytes = (int)str_strlcpy(bufp, str, size); - if (wrptr(&bufp, &size, bytes) != 0) { - WARN_STATIC_BUFFER(); - } - if (text) *bufp++ = ' '; - } - else { - WARN_STATIC_BUFFER(); + const char *str = (const char *)LOC(lang, keyword(kwd)); + assert(str); + sbs_strcat(&sbs, str); + if (text) { + sbs_strcat(&sbs, " "); } } if (text) { - bytes = (int)str_strlcpy(bufp, (const char *)text, size); - if (wrptr(&bufp, &size, bytes) != 0) { - WARN_STATIC_BUFFER(); - if (bufp - sbuffer >= 6) { - bufp -= 6; - while (bufp > sbuffer && (*bufp & 0x80) != 0) { - ++size; - --bufp; - } - memcpy(bufp, "[...]", 6); /* TODO: make sure this only happens in eval_command */ - bufp += 6; - } - } + sbs_strcat(&sbs, text); } if (od) { odata_release(od); } - if (size > 0) *bufp = 0; return sbuffer; } @@ -267,50 +234,46 @@ order *create_order(keyword_t kwd, const struct locale * lang, order *ord; char zBuffer[DISPLAYSIZE]; if (params) { - char *bufp = zBuffer; - int bytes; - size_t size = sizeof(zBuffer) - 1; + sbstring sbs; va_list marker; + char *tok; assert(lang); va_start(marker, params); + sbs_init(&sbs, zBuffer, sizeof(zBuffer)); while (*params) { - if (*params == '%') { - int i; - const char *s; - ++params; - switch (*params) { + int i; + const char *s; + tok = strchr(params, '%'); + if (tok) { + if (tok != params) { + sbs_strncat(&sbs, params, tok - params); + } + switch (tok[1]) { case 's': s = va_arg(marker, const char *); assert(s); - bytes = (int)str_strlcpy(bufp, s, size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); + sbs_strcat(&sbs, s); break; case 'd': i = va_arg(marker, int); - bytes = (int)str_strlcpy(bufp, itoa10(i), size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); + sbs_strcat(&sbs, itoa10(i)); break; case 'i': i = va_arg(marker, int); - bytes = (int)str_strlcpy(bufp, itoa36(i), size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); + sbs_strcat(&sbs, itoa36(i)); break; default: assert(!"unknown format-character in create_order"); } + params = tok + 2; } - else if (size > 0) { - *bufp++ = *params; - --size; + else { + sbs_strcat(&sbs, params); + break; } - ++params; } va_end(marker); - *bufp = 0; } else { zBuffer[0] = 0; diff --git a/src/report.c b/src/report.c index c431f1b1b..e154ab045 100644 --- a/src/report.c +++ b/src/report.c @@ -2230,7 +2230,7 @@ report_plaintext(const char *filename, report_context * ctx, (int)str_strlcpy(bufp, LOC(f->locale, resourcename(rm->rtype, 0)), size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); - ++m; + ++rm; if (rm->number) bytes = (int)str_strlcpy(bufp, ", ", size); if (wrptr(&bufp, &size, bytes) != 0) diff --git a/src/reports.c b/src/reports.c index ff289c8d0..da4b2af45 100644 --- a/src/reports.c +++ b/src/reports.c @@ -20,6 +20,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include "reports.h" +#include "battle.h" #include "calendar.h" #include "guard.h" #include "laws.h" @@ -2030,6 +2031,54 @@ static void eval_order(struct opstack **stack, const void *userdata) opush(stack, var); } +void report_battle_start(battle * b) +{ + bfaction *bf; + char zText[32 * MAXSIDES]; + sbstring sbs; + + for (bf = b->factions; bf; bf = bf->next) { + message *m; + faction *f = bf->faction; + const char *lastf = NULL; + bool first = false; + side *s; + + sbs_init(&sbs, zText, sizeof(zText)); + for (s = b->sides; s != b->sides + b->nsides; ++s) { + fighter *df; + for (df = s->fighters; df; df = df->next) { + if (is_attacker(df)) { + if (first) { + sbs_strcpy(&sbs, ", "); + } + if (lastf) { + sbs_strcpy(&sbs, lastf); + first = true; + } + if (seematrix(f, s)) + lastf = sidename(s); + else + lastf = LOC(f->locale, "unknown_faction_dative"); + break; + } + } + } + if (first) { + sbs_strcpy(&sbs, " "); + sbs_strcpy(&sbs, LOC(f->locale, "and")); + sbs_strcpy(&sbs, " "); + } + if (lastf) { + sbs_strcpy(&sbs, lastf); + } + + m = msg_message("start_battle", "factions", zText); + battle_message_faction(b, f, m); + msg_release(m); + } +} + static void eval_resources(struct opstack **stack, const void *userdata) { /* order -> string */ const faction *f = (const faction *)userdata; diff --git a/src/reports.h b/src/reports.h index f30dfc051..3eaa6137c 100644 --- a/src/reports.h +++ b/src/reports.h @@ -29,6 +29,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif + struct battle; struct gamedate; struct selist; struct stream; @@ -97,6 +98,7 @@ extern "C" { const struct locale *lang); size_t report_status(const struct unit *u, const struct locale *lang, char *buf, size_t siz); + void report_battle_start(struct battle * b); void register_reports(void); diff --git a/src/util/strings.c b/src/util/strings.c index 9350f4d5e..d3a1b2eec 100644 --- a/src/util/strings.c +++ b/src/util/strings.c @@ -238,3 +238,44 @@ char *str_strdup(const char *s) { return strdup(s); #endif } + +void sbs_init(struct sbstring *sbs, char *buffer, size_t size) +{ + assert(sbs); + assert(size>0); + sbs->begin = buffer; + sbs->size = size; + sbs->end = buffer; + buffer[0] = '\0'; +} + +void sbs_strncat(struct sbstring *sbs, const char *str, size_t size) +{ + size_t len; + assert(sbs); + len = sbs->size - (sbs->end - sbs->begin) - 1; + if (len < size) { + size = len; + } + memcpy(sbs->end, str, size); + sbs->end[size] = '\0'; + sbs->end += size; +} + +void sbs_strcat(struct sbstring *sbs, const char *str) +{ + size_t len; + assert(sbs); + len = sbs->size - (sbs->end - sbs->begin); + len = str_strlcpy(sbs->end, str, len); + sbs->end += len; +} + +void sbs_strcpy(struct sbstring *sbs, const char *str) +{ + size_t len = str_strlcpy(sbs->begin, str, sbs->size); + if (len >= sbs->size) { + len = sbs->size - 1; + } + sbs->end = sbs->begin + len; +} diff --git a/src/util/strings.h b/src/util/strings.h index bc1b48d7e..76bc5a12a 100644 --- a/src/util/strings.h +++ b/src/util/strings.h @@ -37,6 +37,18 @@ extern "C" { unsigned int jenkins_hash(unsigned int a); unsigned int wang_hash(unsigned int a); + /* static buffered string */ + typedef struct sbstring { + size_t size; + char *begin; + char *end; + } sbstring; + + void sbs_init(struct sbstring *sbs, char *buffer, size_t size); + void sbs_strcat(struct sbstring *sbs, const char *str); + void sbs_strncat(struct sbstring *sbs, const char *str, size_t size); + void sbs_strcpy(struct sbstring *sbs, const char *str); + /* benchmark for units: * JENKINS_HASH: 5.25 misses/hit (with good cache behavior) * WANG_HASH: 5.33 misses/hit (with good cache behavior) diff --git a/src/util/strings.test.c b/src/util/strings.test.c index 68a7fefe0..89c880a70 100644 --- a/src/util/strings.test.c +++ b/src/util/strings.test.c @@ -91,6 +91,32 @@ static void test_str_strlcpy(CuTest * tc) errno = 0; } +static void test_sbstring(CuTest * tc) +{ + char buffer[16]; + sbstring sbs; + sbs_init(&sbs, buffer, sizeof(buffer)); + CuAssertStrEquals(tc, "", sbs.begin); + sbs_strcpy(&sbs, "Hodor"); + CuAssertStrEquals(tc, "Hodor", sbs.begin); + sbs_strcat(&sbs, "Hodor"); + CuAssertStrEquals(tc, "HodorHodor", sbs.begin); + sbs_strcpy(&sbs, "Hodor"); + CuAssertStrEquals(tc, "Hodor", sbs.begin); + sbs_strcpy(&sbs, "12345678901234567890"); + CuAssertStrEquals(tc, "123456789012345", sbs.begin); + CuAssertPtrEquals(tc, sbs.begin + sbs.size - 1, sbs.end); + sbs_strcat(&sbs, "12345678901234567890"); + CuAssertStrEquals(tc, "123456789012345", sbs.begin); + CuAssertPtrEquals(tc, buffer, sbs.begin); + sbs_strcpy(&sbs, "1234567890"); + CuAssertStrEquals(tc, "1234567890", sbs.begin); + sbs_strncat(&sbs, "1234567890", 4); + CuAssertStrEquals(tc, "12345678901234", sbs.begin); + sbs_strncat(&sbs, "567890", 6); + CuAssertStrEquals(tc, "123456789012345", sbs.begin); +} + CuSuite *get_strings_suite(void) { CuSuite *suite = CuSuiteNew(); @@ -100,5 +126,6 @@ CuSuite *get_strings_suite(void) SUITE_ADD_TEST(suite, test_str_slprintf); SUITE_ADD_TEST(suite, test_str_strlcat); SUITE_ADD_TEST(suite, test_str_strlcpy); + SUITE_ADD_TEST(suite, test_sbstring); return suite; }