diff --git a/process/checkpasswd.py b/process/checkpasswd.py index dd4924b32..1e6198600 100755 --- a/process/checkpasswd.py +++ b/process/checkpasswd.py @@ -9,6 +9,11 @@ if len(sys.argv)<4: filename=sys.argv[1] myfaction=sys.argv[2] mypasswd=sys.argv[3] +quiet=len(sys.argv)<=4 + +def log(str): + if not quiet: + print(str) if mypasswd[0] == '"': mypasswd = mypasswd.strip('"') @@ -16,10 +21,17 @@ if mypasswd[0] == '"': pw_data = EPasswd() try: pw_data.load_database(filename) + log("loaded from db " + filename) except: pw_data.load_file(filename) + log("loaded from file " + filename) if pw_data.fac_exists(myfaction): if pw_data.check(myfaction, mypasswd): + log("password match: " + myfaction) sys.exit(0) + log("password mismatch: " + myfaction) +else: + log("faction missing: " + myfaction) + sys.exit(-1) diff --git a/process/create-orders b/process/create-orders index 58235e2c9..ef7a8bf15 100755 --- a/process/create-orders +++ b/process/create-orders @@ -19,7 +19,7 @@ fi rm -f "orders.$TURN" find "orders.dir.$TURN" -maxdepth 1 -type f -printf "%T+\t%p\n" | sort | cut -f2 | while read -r do - cat "$REPLY" >> "orders.$TURN" + tr -d '\r' < "$REPLY" >> "orders.$TURN" done lockfile -r3 -l120 orders.queue.lock diff --git a/process/epasswd.py b/process/epasswd.py index 4cac6e1ce..20109b9ba 100755 --- a/process/epasswd.py +++ b/process/epasswd.py @@ -69,7 +69,7 @@ class EPasswd: def check(self, id, passwd): pw = self.get_passwd(id) if pw[0:4]=='$2a$' or pw[0:4]=='$2y$': - return bcrypt.checkpw(passwd, pw) + return bcrypt.checkpw(passwd.encode('utf8'), pw.encode('utf8')) return pw == passwd def get_passwd(self, id): diff --git a/process/process-orders.py b/process/process-orders.py index 3c741bfeb..30d9ea735 100755 --- a/process/process-orders.py +++ b/process/process-orders.py @@ -52,6 +52,9 @@ messages = { "validate-en": "Validating", "validate-de": "Verarbeite", +"noorders-en": "The email contained no recognizable orders.", +"noorders-de": "Es konnten keine Befehle gefunden werden.", + "faction-en": "Faction", "faction-de": "Partei", @@ -183,6 +186,8 @@ for line in lines: logfile = open(os.path.join(game_dir, "zug.log"), "a") dirname, filename = split_filename(infile) msg = messages["validate-"+locale] + " " + infile + "\n\n" + if len(results)==0: + msg = msg + messages["noorders-"+locale] for faction, game_email, success, pwd in results: msg = msg + messages["faction-"+locale] + " " + faction + "\n" if success: failed = False diff --git a/res/translations/messages.de.po b/res/translations/messages.de.po index 76ff0afc9..a9a87662e 100644 --- a/res/translations/messages.de.po +++ b/res/translations/messages.de.po @@ -2331,7 +2331,7 @@ msgid "curseinfo::magicboost" msgstr "Der Magier besitzt die Gabe des Chaos. ($int36($id))" msgid "illegal_password" -msgstr "\"Dein Passwort enthält Zeichen, die bei der Nachsendung von Reports Probleme bereiten können. Bitte beachte, dass Passwortenur aus Buchstaben von A bis Z und Zahlen bestehen dürfen. Dein neues Passwort ist '${newpass}'.\"" +msgstr "\"Das Passwort enthielt Zeichen, die bei der Nachsendung von Reports Probleme bereiten können. Bitte beachte, dass Passworte nur aus Ziffern und Buchstaben von A bis Z bestehen dürfen. Dein neues Passwort ist '${newpass}'.\"" msgid "curseinfo::sparkle_12" msgstr "\"Leuchtende Blumen erblühen rund um das Lager von $unit($unit). ($int36($id))\"" @@ -2429,6 +2429,9 @@ msgstr "\"$unit($unit) konnte nur $int($ships) von $int($maxships) Schiffen verz msgid "error283" msgstr "\"$unit($unit) in $region($region): '$order($command)' - Das Passwort darf nur Buchstaben und Ziffern enthalten.\"" +msgid "error321" +msgstr "\"$unit($unit) in $region($region): '$order($command)' - Das gewählte Passwort war zu lang.\"" + msgid "rust_effect" msgstr "\"$unit($mage) legt einen Rosthauch auf $unit($target). $int($amount) Waffen wurden vom Rost zerfressen.\"" diff --git a/res/translations/messages.en.po b/res/translations/messages.en.po index 50108fc03..25caf2446 100644 --- a/res/translations/messages.en.po +++ b/res/translations/messages.en.po @@ -2426,6 +2426,9 @@ msgstr "\"$unit($unit) in $region($region): '$order($command)' - No luxury items msgid "stormwinds_reduced" msgstr "\"$unit($unit) could only enchant $int($ships) of $int($maxships) ships.\"" +msgid "error321" +msgstr "\"$unit($unit) in $region($region): '$order($command)' - The chosen password was too long.\"" + msgid "error283" msgstr "\"$unit($unit) in $region($region): '$order($command)' - Your password may only contain alphanumeric symbols.\"" diff --git a/s/cppcheck b/s/cppcheck index e38e86de1..25191de66 100755 --- a/s/cppcheck +++ b/s/cppcheck @@ -1,8 +1,8 @@ #!/bin/sh IGNORE=$(find src -name "*.test.c" | awk '{ print "-i"$1 }') -cppcheck $IGNORE -isrc/tests.c \ - --quiet --enable=all -U_MSC_VER -UCLEANUP_CODE -UTODO \ - -UERESSEA_BUILDNO -UERESSEA_VERSION \ +#cppcheck $IGNORE -isrc/tests.c \ +cppcheck --quiet --enable=warning,style,performance,portability -U_MSC_VER -UCLEANUP_CODE -UTODO \ + -UERESSEA_BUILDNO -UERESSEA_VERSION -UTEST_THREADS \ -IcJSON -Isrc -Iclibs -Istorage src diff --git a/scripts/tests/e2/undead.lua b/scripts/tests/e2/undead.lua index c712111ba..e1b153f25 100644 --- a/scripts/tests/e2/undead.lua +++ b/scripts/tests/e2/undead.lua @@ -28,9 +28,10 @@ function test_undead_reserve_other() u1.race = "undead" u1:clear_orders() u1:add_order("RESERVIERE 1 Holz") + u1.name = 'Xolgrim' process_orders() - -- Intermittent Failure (clang): expected 0 but was 2 + -- Intermittent Failure: expected 0 but was 2 assert_equal(0, u1:get_item("log")) assert_equal(2, u2:get_item("log")) diff --git a/src/attributes/key.c b/src/attributes/key.c index cd369de66..ac4dbb4d5 100644 --- a/src/attributes/key.c +++ b/src/attributes/key.c @@ -121,7 +121,7 @@ static int read_keyval_orig(gamedata *data, int *keys, int n) { #endif static int a_readkeys(variant *var, void *owner, gamedata *data) { - int i, n, ksn, *keys; + int n, ksn, *keys; READ_INT(data->store, &n); assert(n < 4096 && n >= 0); @@ -155,7 +155,7 @@ static int a_readkeys(variant *var, void *owner, gamedata *data) { } keys[0] = n; if (data->version < SORTKEYS_VERSION) { - int e = 1; + int i, e = 1; for (i = 1; i != n; ++i) { int k = keys[i * 2 + 1]; int v = keys[i * 2 + 2]; @@ -260,6 +260,7 @@ static int *keys_update(int *base, int key, int val) ptrdiff_t diff = kv - base; sz = keys_size(n + 1); base = realloc(base, (sz * 2 + 1) * sizeof(int)); + if (!base) abort(); kv = base + diff; } base[0] = n + 1; diff --git a/src/attributes/seenspell.c b/src/attributes/seenspell.c index ae46980c3..082eecc6b 100644 --- a/src/attributes/seenspell.c +++ b/src/attributes/seenspell.c @@ -48,13 +48,12 @@ static int read_seenspells(variant *var, void *owner, struct gamedata *data) { selist *ql = NULL; storage *store = data->store; - spell *sp = 0; char token[32]; UNUSED_ARG(owner); READ_TOK(store, token, sizeof(token)); while (token[0]) { - sp = find_spell(token); + spell *sp = find_spell(token); if (!sp) { log_info("read_seenspells: could not find spell '%s'\n", token); return AT_READ_FAIL; diff --git a/src/automate.c b/src/automate.c index 04230096d..7fd0c5d62 100644 --- a/src/automate.c +++ b/src/automate.c @@ -46,7 +46,7 @@ int autostudy_init(scholar scholars[], int max_scholars, unit **units) st->level = effskill_study(u, st->sk); st->learn = 0; st->u = u; - if (++nscholars == max_scholars) { + if (++nscholars > max_scholars) { log_fatal("you must increase MAXSCHOLARS"); } } @@ -59,7 +59,6 @@ int autostudy_init(scholar scholars[], int max_scholars, unit **units) u = u->next; } *units = unext; - scholars[nscholars].u = NULL; if (nscholars > 0) { qsort(scholars, nscholars, sizeof(scholar), cmp_scholars); } @@ -83,7 +82,7 @@ void autostudy_run(scholar scholars[], int nscholars) int ti = 0; while (ti != nscholars) { skill_t sk = scholars[ti].sk; - int t, s, se, ts = 0, tt = 0, si = ti; + int t, se, ts = 0, tt = 0, si = ti; for (se = ti; se != nscholars && scholars[se].sk == sk; ++se) { int mint; ts += scholars[se].u->number; /* count total scholars */ @@ -111,7 +110,7 @@ void autostudy_run(scholar scholars[], int nscholars) /* invariant: unit ti can still teach i students */ int i = scholars[ti].u->number * STUDENTS_PER_TEACHER; /* invariant: unit si has n students that can still be taught */ - int n = scholars[si].u->number; + int s, n = scholars[si].u->number; for (t = ti, s = si; t != si && s != se; ) { if (i >= n) { /* t has more than enough teaching capacity for s */ @@ -125,25 +124,20 @@ void autostudy_run(scholar scholars[], int nscholars) n = scholars[s].u->number; } else { - /* s gets partial credit and we need a new teacher */ + /* a part of s gets credited and we need a new teacher: */ teaching(scholars + s, i); - - /* we are done with this teacher. any remaining people are regular learners: */ - if (scholars[t].u->number > 1) { - /* remain = number - ceil(taught/10); */ - int remain = (STUDENTS_PER_TEACHER * scholars[t].u->number - i + STUDENTS_PER_TEACHER - 1) / STUDENTS_PER_TEACHER; - learning(scholars + t, remain); - } - + /* we still need to teach n students in this unit: */ + n -= i; + i = 0; /* we want a new teacher for s. if any exists, it's next in the sequence. */ if (++t == si) { continue; } if (scholars[t].level - TEACHDIFFERENCE < scholars[s].level) { - /* next teacher cannot teach, we must skip students. */ + /* no remaining teacher can teach this student, so we skip ahead */ do { - learning(scholars + s, (n - i)); - i = 0; + /* remaining students learn without a teacher: */ + learning(scholars + s, n); if (++s == se) { break; } diff --git a/src/automate.test.c b/src/automate.test.c index 0da88ac69..698cda6be 100644 --- a/src/automate.test.c +++ b/src/automate.test.c @@ -62,13 +62,52 @@ static void test_autostudy_init(CuTest *tc) { CuAssertIntEquals(tc, 0, scholars[0].level); CuAssertIntEquals(tc, 0, scholars[0].learn); CuAssertIntEquals(tc, SK_PERCEPTION, scholars[0].sk); - CuAssertPtrEquals(tc, NULL, scholars[1].u); CuAssertPtrEquals(tc, NULL, ulist); test_teardown(); } +/** + * Reproduce Bug 2520 + */ +static void test_autostudy_run_twoteachers(CuTest *tc) { + scholar scholars[4]; + int nscholars; + unit *u1, *u2, *u3, *u4, *ulist; + faction *f; + region *r; + + test_setup(); + r = test_create_plain(0, 0); + f = test_create_faction(NULL); + u1 = test_create_unit(f, r); + set_level(u1, SK_ENTERTAINMENT, 2); + u1->thisorder = create_order(K_AUTOSTUDY, f->locale, skillnames[SK_ENTERTAINMENT]); + u2 = test_create_unit(f, r); + set_level(u2, SK_ENTERTAINMENT, 2); + u2->thisorder = create_order(K_AUTOSTUDY, f->locale, skillnames[SK_ENTERTAINMENT]); + + u3 = test_create_unit(f, r); + u3->thisorder = create_order(K_AUTOSTUDY, f->locale, skillnames[SK_ENTERTAINMENT]); + set_number(u3, 8); + u4 = test_create_unit(f, r); + u4->thisorder = create_order(K_AUTOSTUDY, f->locale, skillnames[SK_ENTERTAINMENT]); + set_number(u4, 12); + + ulist = r->units; + CuAssertIntEquals(tc, 4, nscholars = autostudy_init(scholars, 4, &ulist)); + CuAssertPtrEquals(tc, NULL, ulist); + autostudy_run(scholars, nscholars); + CuAssertIntEquals(tc, 0, scholars[0].learn); + CuAssertIntEquals(tc, 0, scholars[1].learn); + CuAssertIntEquals(tc, scholars[2].u->number * 2, scholars[2].learn); + CuAssertIntEquals(tc, scholars[3].u->number * 2, scholars[3].learn); + + test_teardown(); +} + static void test_autostudy_run(CuTest *tc) { scholar scholars[4]; + int nscholars; unit *u1, *u2, *u3, *ulist; faction *f; region *r; @@ -88,9 +127,9 @@ static void test_autostudy_run(CuTest *tc) { set_number(u3, 15); scholars[3].u = NULL; ulist = r->units; - CuAssertIntEquals(tc, 3, autostudy_init(scholars, 4, &ulist)); + CuAssertIntEquals(tc, 3, nscholars = autostudy_init(scholars, 4, &ulist)); CuAssertPtrEquals(tc, NULL, ulist); - autostudy_run(scholars, 3); + autostudy_run(scholars, nscholars); CuAssertIntEquals(tc, 1, scholars[0].learn); CuAssertIntEquals(tc, 20, scholars[1].learn); CuAssertIntEquals(tc, 15, scholars[2].learn); @@ -99,6 +138,7 @@ static void test_autostudy_run(CuTest *tc) { static void test_autostudy_run_noteachers(CuTest *tc) { scholar scholars[4]; + int nscholars; unit *u1, *u2, *u3, *ulist; faction *f; region *r; @@ -118,20 +158,50 @@ static void test_autostudy_run_noteachers(CuTest *tc) { set_number(u3, 15); scholars[3].u = NULL; ulist = r->units; - CuAssertIntEquals(tc, 3, autostudy_init(scholars, 4, &ulist)); + CuAssertIntEquals(tc, 3, nscholars = autostudy_init(scholars, 4, &ulist)); CuAssertPtrEquals(tc, NULL, ulist); - autostudy_run(scholars, 3); + autostudy_run(scholars, nscholars); CuAssertIntEquals(tc, 2, scholars[0].learn); CuAssertIntEquals(tc, 10, scholars[1].learn); CuAssertIntEquals(tc, 15, scholars[2].learn); test_teardown(); } +/** + * If a teacher unit doesn't have enough students, the remaining members study. + */ +static void test_autostudy_run_teachers_learn(CuTest *tc) { + scholar scholars[4]; + int nscholars; + unit *u1, *u2, *ulist; + faction *f; + region *r; + + test_setup(); + r = test_create_plain(0, 0); + f = test_create_faction(NULL); + u1 = test_create_unit(f, r); + u1->thisorder = create_order(K_AUTOSTUDY, f->locale, skillnames[SK_ENTERTAINMENT]); + set_number(u1, 2); + set_level(u1, SK_ENTERTAINMENT, 2); + u2 = test_create_unit(f, r); + u2->thisorder = create_order(K_AUTOSTUDY, f->locale, skillnames[SK_ENTERTAINMENT]); + set_number(u2, 10); + ulist = r->units; + CuAssertIntEquals(tc, 2, nscholars = autostudy_init(scholars, 4, &ulist)); + CuAssertPtrEquals(tc, NULL, ulist); + autostudy_run(scholars, nscholars); + CuAssertIntEquals(tc, 1, scholars[0].learn); + CuAssertIntEquals(tc, 20, scholars[1].learn); + test_teardown(); +} + /** * Reproduce Bug 2514 */ static void test_autostudy_run_skilldiff(CuTest *tc) { scholar scholars[4]; + int nscholars; unit *u1, *u2, *u3, *ulist; faction *f; region *r; @@ -152,9 +222,9 @@ static void test_autostudy_run_skilldiff(CuTest *tc) { set_number(u3, 10); scholars[3].u = NULL; ulist = r->units; - CuAssertIntEquals(tc, 3, autostudy_init(scholars, 4, &ulist)); + CuAssertIntEquals(tc, 3, nscholars = autostudy_init(scholars, 4, &ulist)); CuAssertPtrEquals(tc, NULL, ulist); - autostudy_run(scholars, 3); + autostudy_run(scholars, nscholars); CuAssertIntEquals(tc, 0, scholars[0].learn); CuAssertIntEquals(tc, 20, scholars[2].learn); CuAssertIntEquals(tc, 10, scholars[1].learn); @@ -167,6 +237,8 @@ CuSuite *get_automate_suite(void) SUITE_ADD_TEST(suite, test_autostudy_init); SUITE_ADD_TEST(suite, test_autostudy_run); SUITE_ADD_TEST(suite, test_autostudy_run_noteachers); + SUITE_ADD_TEST(suite, test_autostudy_run_teachers_learn); + SUITE_ADD_TEST(suite, test_autostudy_run_twoteachers); SUITE_ADD_TEST(suite, test_autostudy_run_skilldiff); return suite; } diff --git a/src/battle.c b/src/battle.c index 00cece5b0..b53209697 100644 --- a/src/battle.c +++ b/src/battle.c @@ -697,23 +697,20 @@ static int CavalryBonus(const unit * u, troop enemy, int type) return 0; } +/** + * Effektiver Waffenskill waehrend des Kampfes. + */ static int -weapon_effskill(troop t, troop enemy, const weapon * w, bool attacking, -bool missile) -/* effektiver Waffenskill w�hrend des Kampfes */ +weapon_effskill(troop t, troop enemy, const weapon * w, + bool attacking, bool missile) { - /* In dieser Runde alle die Modifier berechnen, die fig durch die - * Waffen bekommt. */ fighter *tf = t.fighter; unit *tu = t.fighter->unit; - int skill; - const weapon_type *wtype = w ? w->type : NULL; + /* Alle Modifier berechnen, die fig durch die Waffen bekommt. */ + if (w) { + int skill = 0; + const weapon_type *wtype = w->type; - if (wtype == NULL) { - /* Ohne Waffe: Waffenlose Angriffe */ - skill = weapon_skill(NULL, tu, attacking); - } - else { if (attacking) { skill = w->attackskill; } @@ -745,30 +742,31 @@ bool missile) } } } - } + /* Burgenbonus, Pferdebonus */ + if (is_riding(t) && (wtype == NULL || (fval(wtype, WTF_HORSEBONUS) + && !fval(wtype, WTF_MISSILE)))) { + skill += CavalryBonus(tu, enemy, BONUS_SKILL); + } - /* Burgenbonus, Pferdebonus */ - if (is_riding(t) && (wtype == NULL || (fval(wtype, WTF_HORSEBONUS) - && !fval(wtype, WTF_MISSILE)))) { - skill += CavalryBonus(tu, enemy, BONUS_SKILL); - } + if (t.index < tf->elvenhorses) { + /* Elfenpferde: Helfen dem Reiter, egal ob und welche Waffe. Das ist + * eleganter, und vor allem einfacher, sonst mu� man noch ein + * WMF_ELVENHORSE einbauen. */ + skill += 2; + } - if (t.index < tf->elvenhorses) { - /* Elfenpferde: Helfen dem Reiter, egal ob und welche Waffe. Das ist - * eleganter, und vor allem einfacher, sonst mu� man noch ein - * WMF_ELVENHORSE einbauen. */ - skill += 2; + if (skill > 0 && !attacking && missile) { + /* + * Wenn ich verteidige, und nicht direkt meinem Feind gegen�berstehe, + * halbiert sich mein Skill: (z.B. gegen Fernk�mpfer. Nahk�mpfer + * k�nnen mich eh nicht treffen) + */ + skill /= 2; + } + return skill; } - - if (skill > 0 && !attacking && missile) { - /* - * Wenn ich verteidige, und nicht direkt meinem Feind gegen�berstehe, - * halbiert sich mein Skill: (z.B. gegen Fernk�mpfer. Nahk�mpfer - * k�nnen mich eh nicht treffen) - */ - skill /= 2; - } - return skill; + /* no weapon: fight weaponless */ + return weapon_skill(NULL, tu, attacking); } const armor_type *select_armor(troop t, bool shield) @@ -1189,7 +1187,7 @@ static void destroy_items(troop dt) { } -static void calculate_defense_type(troop dt, troop at, int type, bool missile, +static void calculate_defense_type(troop at, troop dt, int type, bool missile, const weapon_type **dwtype, int *defskill) { const weapon *weapon; weapon = select_weapon(dt, false, true); /* missile=true to get the unmodified best weapon she has */ @@ -1198,7 +1196,7 @@ static void calculate_defense_type(troop dt, troop at, int type, bool missile, *dwtype = weapon->type; } -static void calculate_attack_type(troop dt, troop at, int type, bool missile, +static void calculate_attack_type(troop at, troop dt, int type, bool missile, const weapon_type **awtype, int *attskill, bool *magic) { const weapon *weapon; @@ -1318,7 +1316,7 @@ terminate(troop dt, troop at, int type, const char *damage_formula, bool missile ++at.fighter->hits; calculate_attack_type(at, dt, type, missile, &awtype, &attskill, &magic); - calculate_defense_type(at, dt, type, missile, &awtype, &attskill); + calculate_defense_type(at, dt, type, missile, &dwtype, &defskill); if (is_riding(at) && (awtype == NULL || (fval(awtype, WTF_HORSEBONUS) && !fval(awtype, WTF_MISSILE)))) { @@ -3383,23 +3381,6 @@ fighter *make_fighter(battle * b, unit * u, side * s1, bool attack) return fig; } -fighter * get_fighter(battle * b, const struct unit * u) -{ - side * s; - - for (s = b->sides; s != b->sides + b->nsides; ++s) { - fighter *fig; - if (s->faction == u->faction) { - for (fig = s->fighters; fig; fig = fig->next) { - if (fig->unit == u) { - return fig; - } - } - } - } - return 0; -} - int join_battle(battle * b, unit * u, bool attack, fighter ** cp) { side *s; diff --git a/src/battle.h b/src/battle.h index eb6335bce..1b0962eeb 100644 --- a/src/battle.h +++ b/src/battle.h @@ -213,7 +213,6 @@ extern "C" { /* BEGIN battle interface */ side * find_side(battle * b, const struct faction * f, const struct group * g, unsigned int flags, const struct faction * stealthfaction); side * get_side(battle * b, const struct unit * u); - fighter * get_fighter(battle * b, const struct unit * u); /* END battle interface */ void do_battles(void); diff --git a/src/battle.test.c b/src/battle.test.c index 92a26e692..be43a8ff6 100644 --- a/src/battle.test.c +++ b/src/battle.test.c @@ -123,6 +123,16 @@ static void test_select_weapon_restricted(CuTest *tc) { CuAssertIntEquals(tc, 0, af->weapons[0].count); free_battle(b); + itype->mask_deny = 0; + itype->mask_allow = rc_mask(au->_race); + b = make_battle(au->region); + af = make_fighter(b, au, make_side(b, au->faction, 0, 0, 0), false); + CuAssertPtrNotNull(tc, af->weapons); + CuAssertIntEquals(tc, 1, af->weapons[0].count); + CuAssertPtrEquals(tc, itype->rtype->wtype, (void *)af->weapons[0].type); + CuAssertIntEquals(tc, 0, af->weapons[1].count); + free_battle(b); + itype->mask_deny = 0; itype->mask_allow = rc_mask(rc); b = make_battle(au->region); diff --git a/src/bind_unit.c b/src/bind_unit.c index 4e3047367..d2bec0f3e 100644 --- a/src/bind_unit.c +++ b/src/bind_unit.c @@ -22,7 +22,6 @@ #include "kernel/skills.h" #include "kernel/types.h" #include -#include #include #include "kernel/equipment.h" #include @@ -432,38 +431,11 @@ static int tolua_unit_effskill(lua_State * L) return 1; } -typedef struct fctr_data { - unit *target; - int fhandle; -} fctr_data; - typedef struct event { struct event_arg *args; char *msg; } event; -int fctr_handle(struct trigger *tp, void *data) -{ - trigger *t = tp; - event evt = { 0 }; - fctr_data *fd = (fctr_data *)t->data.v; - lua_State *L = (lua_State *)global.vm_state; - unit *u = fd->target; - - evt.args = (event_arg *)data; - lua_rawgeti(L, LUA_REGISTRYINDEX, fd->fhandle); - tolua_pushusertype(L, u, TOLUA_CAST "unit"); - tolua_pushusertype(L, &evt, TOLUA_CAST "event"); - if (lua_pcall(L, 2, 0, 0) != 0) { - const char *error = lua_tostring(L, -1); - log_error("event (%s): %s\n", unitname(u), error); - lua_pop(L, 1); - tolua_error(L, TOLUA_CAST "event handler call failed", NULL); - } - - return 0; -} - static int tolua_unit_addnotice(lua_State * L) { unit *self = (unit *)tolua_tousertype(L, 1, 0); diff --git a/src/creport.c b/src/creport.c index 71c283e89..8f30fa50e 100644 --- a/src/creport.c +++ b/src/creport.c @@ -848,11 +848,13 @@ void cr_output_unit(stream *out, const faction * f, pzTmp = get_racename(u->attribs); if (pzTmp) { - stream_printf(out, "\"%s\";Typ\n", pzTmp); + const char *pzRace = LOC(lang, mkname("race", pzTmp)); + pzTmp = pzRace ? pzRace : pzTmp; + stream_printf(out, "\"%s\";Typ\n", translate(pzTmp, LOC(lang, pzTmp))); if (u->faction == f && fval(u_race(u), RCF_SHAPESHIFTANY)) { - const char *zRace = rc_name_s(u_race(u), NAME_PLURAL); + pzRace = rc_name_s(u_race(u), NAME_PLURAL); stream_printf(out, "\"%s\";wahrerTyp\n", - translate(zRace, LOC(lang, zRace))); + translate(pzRace, LOC(lang, pzRace))); } } else { @@ -1155,7 +1157,7 @@ static char *cr_output_resource(char *buf, const resource_type *rtype, assert(rtype); name = resourcename(rtype, NMF_PLURAL); assert(name); - buf += sprintf(buf, "RESOURCE %u\n", str_hash(rtype->_name)); + buf += sprintf(buf, "RESOURCE %d\n", str_hash(rtype->_name)); tname = LOC(loc, name); assert(tname); tname = translate(name, tname); diff --git a/src/economy.c b/src/economy.c index 1d3f6685f..067c3e513 100644 --- a/src/economy.c +++ b/src/economy.c @@ -2239,7 +2239,6 @@ static void breed_cmd(unit * u, struct order *ord) const char *s; param_t p; region *r = u->region; - const resource_type *rtype = NULL; if (r->land == NULL) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_onlandonly", "")); @@ -2275,7 +2274,7 @@ static void breed_cmd(unit * u, struct order *ord) break; default: if (p != P_ANY) { - rtype = findresourcetype(s, u->faction->locale); + const resource_type *rtype = findresourcetype(s, u->faction->locale); if (rtype == get_resourcetype(R_SEED) || rtype == get_resourcetype(R_MALLORN_SEED)) { breedtrees(u, m); break; diff --git a/src/eressea.c b/src/eressea.c index 8e7da7f7a..6efb1cb0b 100644 --- a/src/eressea.c +++ b/src/eressea.c @@ -28,6 +28,7 @@ #include "creport.h" #include "report.h" #include "names.h" +#include "prefix.h" #include "reports.h" #include "spells.h" #include "vortex.h" @@ -50,9 +51,10 @@ void game_done(void) calendar_cleanup(); free_functions(); free_config(); - free_special_directions(); free_locales(); #endif + free_prefixes(); + free_special_directions(); kernel_done(); swapdb_close(); } diff --git a/src/exparse.c b/src/exparse.c index 71efe0667..602bdf4e9 100644 --- a/src/exparse.c +++ b/src/exparse.c @@ -874,7 +874,6 @@ static void start_resources(parseinfo *pi, const XML_Char *el, const XML_Char ** } static void start_ships(parseinfo *pi, const XML_Char *el, const XML_Char **attr) { - const char *flag_names[] = { "opensea", "fly", "nocoast", "speedy", NULL }; if (xml_strequal(el, "ship")) { const XML_Char *name; @@ -917,10 +916,13 @@ static void start_ships(parseinfo *pi, const XML_Char *el, const XML_Char **attr else if (xml_strequal(attr[i], "storm")) { stype->storm = xml_float(attr[i + 1]); } - else if (!handle_flag(&flags, attr + i, flag_names)) { - /* we already handled the name earlier */ - if (!xml_strequal(attr[i], "name")) { - handle_bad_input(pi, el, attr[i]); + else { + const char *flag_names[] = { "opensea", "fly", "nocoast", "speedy", NULL }; + if (!handle_flag(&flags, attr + i, flag_names)) { + /* we already handled the name earlier */ + if (!xml_strequal(attr[i], "name")) { + handle_bad_input(pi, el, attr[i]); + } } } } @@ -1209,7 +1211,6 @@ static void start_races(parseinfo *pi, const XML_Char *el, const XML_Char **attr } static void start_buildings(parseinfo *pi, const XML_Char *el, const XML_Char **attr) { - const char *flag_names[] = { "nodestroy", "nobuild", "unique", "decay", "magic", "namechange", "fort", "oneperturn", NULL }; if (xml_strequal(el, "building")) { const XML_Char *name; @@ -1245,10 +1246,13 @@ static void start_buildings(parseinfo *pi, const XML_Char *el, const XML_Char ** /* magres is specified in percent! */ btype->magres = frac_make(xml_int(attr[i + 1]), 100); } - else if (!handle_flag(&flags, attr + i, flag_names)) { - /* we already handled the name earlier */ - if (!xml_strequal(attr[i], "name")) { - handle_bad_input(pi, el, attr[i]); + else { + const char *flag_names[] = { "nodestroy", "nobuild", "unique", "decay", "magic", "namechange", "fort", "oneperturn", NULL }; + if (!handle_flag(&flags, attr + i, flag_names)) { + /* we already handled the name earlier */ + if (!xml_strequal(attr[i], "name")) { + handle_bad_input(pi, el, attr[i]); + } } } } diff --git a/src/give.c b/src/give.c index 60b728479..90ed64f50 100644 --- a/src/give.c +++ b/src/give.c @@ -169,7 +169,6 @@ int give_quota(const unit * src, const unit * dst, const item_type * type, if (config_changed(&config)) { divisor = config_get_int("rules.items.give_divisor", divisor); } - assert(divisor <= 0 || divisor >= 1); if (divisor >= 1) { /* predictable > correct: */ return n / divisor; diff --git a/src/gmtool.c b/src/gmtool.c index 3b7aed36a..0ab31854e 100644 --- a/src/gmtool.c +++ b/src/gmtool.c @@ -1065,10 +1065,9 @@ static void seed_player(state *st, const newfaction *player) { pnormalize(&nx, &ny, st->cursor.pl); r = findregion(nx, ny); if (r) { - faction *f; - const char *password = player->password ? player->password : itoa36(rng_int()); - addplayer(r, f = addfaction(player->email, password, - player->race, player->lang)); + faction *f = addfaction(player->email, player->password, + player->race, player->lang); + addplayer(r, f); } } } diff --git a/src/jsonconf.c b/src/jsonconf.c index ff442f990..48be28b16 100644 --- a/src/jsonconf.c +++ b/src/jsonconf.c @@ -1032,12 +1032,14 @@ static int add_po_string(const char *msgid, const char *msgstr, const char *msgc } static int include_po(const char *uri) { - char name[PATH_MAX], lname[8]; + char name[PATH_MAX]; const char *filename = uri_to_file(uri, name, sizeof(name)); const char *pos = strstr(filename, ".po"); if (pos) { size_t len; const char *str = --pos; + char lname[8]; + while (str > filename && *str != '.') --str; len = (size_t)(pos - str); if (len < sizeof(lname)) { diff --git a/src/jsreport.c b/src/jsreport.c deleted file mode 100644 index a5c730438..000000000 --- a/src/jsreport.c +++ /dev/null @@ -1,90 +0,0 @@ -#include "reports.h" -#include "jsreport.h" -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -static void coor_to_tiled(int *x, int *y) { - *y = -*y; - *x = *x - (*y + 1) / 2; -} - -static void coor_from_tiled(int *x, int *y) { - *x = *x + (*y + 1) / 2; - *y = -*y; -} - -static int report_json(const char *filename, report_context * ctx, const char *charset) -{ - if (config_get_int("jsreport.enabled", 0) != 0) { - FILE * F = fopen(filename, "w"); - if (F) { - int minx = INT_MAX, maxx = INT_MIN, miny = INT_MAX, maxy = INT_MIN; - seen_region *sr; - region *r; - /* traverse all regions */ - for (sr = NULL, r = ctx->first; sr == NULL && r != ctx->last; r = r->next) { - sr = find_seen(ctx->f->seen, r); - } - for (; sr != NULL; sr = sr->next) { - int tx = sr->r->x; - int ty = sr->r->y; - coor_to_tiled(&tx, &ty); - if (ty < miny) miny = ty; - else if (ty > maxy) maxy = ty; - if (tx < minx) minx = tx; - else if (tx > maxx) maxx = tx; - } - if (maxx >= minx && maxy >= miny) { - int y, w = maxx - minx + 1, h = maxy - miny + 1; - fputs("{ \"orientation\":\"hexagonal\",\"staggeraxis\":\"y\",", F); - fprintf(F, "\"staggerindex\":\"%s\", \"height\":%d, \"width\":%d, \"layers\":[", (miny & 1) ? "odd" : "even", h, w); - fprintf(F, "{ \"height\":%d, \"width\":%d, ", h, w); - fputs("\"visible\":true, \"opacity\":1, \"type\":\"tilelayer\", \"name\":\"terrain\", \"x\":0, \"y\":0, \"data\":[", F); - for (y = miny; y <= maxy; ++y) { - int x; - for (x = minx; x <= maxx; ++x) { - int data = 0; - int tx = x, ty = y; - coor_from_tiled(&tx, &ty); - r = findregion(tx, ty); - if (r) { - sr = find_seen(ctx->f->seen, r); - if (sr) { - terrain_t ter = oldterrain(r->terrain); - if (ter == NOTERRAIN) { - data = 1 + r->terrain->_name[0]; - } - else { - data = 1 + (int)ter; - } - } - } - fprintf(F, "%d", data); - if (x != maxx || y != maxy) fputs(", ", F); - } - } - fputs("]}], \"tilesets\": [{\"firstgid\": 1, \"image\": \"magellan.png\", \"imageheight\": 192, \"imagewidth\": 256," - "\"margin\": 0, \"name\": \"hextiles\", \"properties\": { }, \"spacing\": 0, " - "\"tileheight\" : 64, \"tilewidth\" : 64 }], \"tilewidth\": 64, \"tileheight\": 96}", F); - } - fclose(F); - return 0; - } - return -1; - } - return 0; -} - -void register_jsreport(void) -{ - register_reporttype("json", &report_json, 1 << O_JSON); -} diff --git a/src/jsreport.h b/src/jsreport.h deleted file mode 100644 index fa3f7b115..000000000 --- a/src/jsreport.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once -/* -+-------------------+ Christian Schlittchen -| | Enno Rehling -| Eressea PBEM host | Katja Zedel -| (c) 1998 - 2003 | Henning Peters -| | Ingo Wilken -+-------------------+ Stefan Reich - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ -#ifndef H_GC_JSREPORT -#define H_GC_JSREPORT -#ifdef __cplusplus -extern "C" { -#endif - - void register_jsreport(void); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/src/kernel/attrib.c b/src/kernel/attrib.c index d84a8c8e9..997a04151 100644 --- a/src/kernel/attrib.c +++ b/src/kernel/attrib.c @@ -185,15 +185,15 @@ void at_register(attrib_type * at) static attrib_type *at_find_key(unsigned int hk) { - const char *translate[3][2] = { - { "zielregion", "targetregion" }, /* remapping: from 'zielregion, heute targetregion */ - { "verzaubert", "curse" }, /* remapping: früher verzaubert, jetzt curse */ - { NULL, NULL } - }; attrib_type *find = at_hash[hk % MAXATHASH]; while (find && hk != find->hashkey) find = find->nexthash; if (!find) { + const char *translate[3][2] = { + { "zielregion", "targetregion" }, /* remapping: from 'zielregion, heute targetregion */ + { "verzaubert", "curse" }, /* remapping: früher verzaubert, jetzt curse */ + { NULL, NULL } + }; int i = 0; while (translate[i][0]) { if (__at_hashkey(translate[i][0]) == hk) diff --git a/src/kernel/config.c b/src/kernel/config.c index 15387dca7..5c0bfc777 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -106,27 +106,31 @@ int findoption(const char *s, const struct locale *lang) /* -- Erschaffung neuer Einheiten ------------------------------ */ -static const char *forbidden[] = { "t", "te", "tem", "temp", NULL }; static int *forbidden_ids; +static const char *forbidden[] = { "t", "te", "tem", "temp", NULL }; -int forbiddenid(int id) +bool forbiddenid(int id) { static size_t len; size_t i; - if (id <= 0) - return 1; + if (id <= 0) { + return true; + } if (!forbidden_ids) { while (forbidden[len]) ++len; - forbidden_ids = calloc(len, sizeof(int)); + forbidden_ids = malloc(len * sizeof(int)); + if (!forbidden_ids) abort(); for (i = 0; i != len; ++i) { forbidden_ids[i] = atoi36(forbidden[i]); } } - for (i = 0; i != len; ++i) - if (id == forbidden_ids[i]) - return 1; - return 0; + for (i = 0; i != len; ++i) { + if (id == forbidden_ids[i]) { + return true; + } + } + return false; } int newcontainerid(void) @@ -274,6 +278,7 @@ void set_param(struct param **p, const char *key, const char *value) par = *p; if (!par && value) { *p = par = calloc(1, sizeof(param)); + if (!par) abort(); } if (par) { void *match; @@ -509,7 +514,6 @@ order *default_order(const struct locale *lang) int i = locale_index(lang); keyword_t kwd; const char * str; - order *result = 0; assert(i < MAXLOCALES); kwd = keyword_disabled(K_WORK) ? NOKEYWORD : K_WORK; @@ -518,7 +522,8 @@ order *default_order(const struct locale *lang) kwd = findkeyword(str); } if (kwd != NOKEYWORD) { - result = create_order(kwd, lang, NULL); + /* TODO: why is there a copy_order made here? */ + order *result = create_order(kwd, lang, NULL); return copy_order(result); } return NULL; diff --git a/src/kernel/config.h b/src/kernel/config.h index 7789cd36d..83241ac4c 100644 --- a/src/kernel/config.h +++ b/src/kernel/config.h @@ -52,7 +52,7 @@ extern "C" { void init_locale(struct locale *lang); void init_races(struct locale *lang); - int forbiddenid(int id); + bool forbiddenid(int id); int newcontainerid(void); bool rule_region_owners(void); diff --git a/src/kernel/curse.c b/src/kernel/curse.c index bf3c8fef0..d6d77a7ea 100644 --- a/src/kernel/curse.c +++ b/src/kernel/curse.c @@ -672,16 +672,6 @@ bool curse_active(const curse * c) return true; } -bool is_cursed_internal(attrib * ap, const curse_type * ct) -{ - curse *c = get_curse(ap, ct); - - if (!c) - return false; - - return true; -} - bool is_cursed_with(const attrib * ap, const curse * c) { const attrib *a = ap; diff --git a/src/kernel/faction.c b/src/kernel/faction.c index c0c908186..4c2eb0b3f 100755 --- a/src/kernel/faction.c +++ b/src/kernel/faction.c @@ -168,28 +168,6 @@ void set_show_item(faction * f, const struct item_type *itype) a->data.v = (void *)itype; } -const unit *random_unit_in_faction(const faction * f) -{ - unit *u; - int c = 0, u_nr; - - if (!f->units) { - return NULL; - } - for (u = f->units; u; u = u->next) - c++; - - u_nr = rng_int() % c; - c = 0; - - for (u = f->units; u; u = u->next) - if (u_nr == c) - return u; - - /* Hier sollte er nie ankommen */ - return NULL; -} - const char *factionname(const faction * f) { typedef char name[OBJECTIDSIZE + 1]; @@ -227,6 +205,12 @@ static int unused_faction_id(void) return id; } +void faction_genpassword(faction *f) { + const char * password = itoa36(rng_int()); + faction_setpassword(f, password_hash(password, PASSWORD_DEFAULT)); + ADDMSG(&f->msgs, msg_message("changepasswd", "value", password)); +} + faction *addfaction(const char *email, const char *password, const struct race * frace, const struct locale * loc) { @@ -241,7 +225,7 @@ faction *addfaction(const char *email, const char *password, } f->alliance_joindate = turn; - f->lastorders = turn; + f->lastorders = 0; f->_alive = true; f->password_id = 0; f->age = 0; diff --git a/src/kernel/faction.h b/src/kernel/faction.h index 0c579603a..438402286 100644 --- a/src/kernel/faction.h +++ b/src/kernel/faction.h @@ -117,7 +117,6 @@ extern "C" { int max_magicians(const faction * f); void set_show_item(faction * f, const struct item_type *itype); - const struct unit *random_unit_in_faction(const struct faction *f); const char *factionname(const struct faction *f); struct unit *addplayer(struct region *r, faction * f); struct faction *addfaction(const char *email, const char *password, @@ -151,6 +150,7 @@ extern "C" { const char *faction_getemail(const struct faction *self); void faction_setemail(struct faction *self, const char *email); + void faction_genpassword(struct faction *f); void faction_setpassword(struct faction *self, const char *pwhash); const char *faction_getpassword(const struct faction *f); bool valid_race(const struct faction *f, const struct race *rc); diff --git a/src/kernel/faction.test.c b/src/kernel/faction.test.c index 66e3c3945..65310ee3a 100644 --- a/src/kernel/faction.test.c +++ b/src/kernel/faction.test.c @@ -110,7 +110,7 @@ static void test_addfaction(CuTest *tc) { test_setup(); rc = rc_get_or_create("human"); lang = test_create_locale(); - f = addfaction("test@eressea.de", NULL, rc, lang); + f = addfaction("test@example.com", NULL, rc, lang); CuAssertPtrNotNull(tc, f); CuAssertPtrNotNull(tc, f->name); CuAssertPtrEquals(tc, NULL, (void *)f->units); @@ -119,14 +119,14 @@ static void test_addfaction(CuTest *tc) { CuAssertPtrEquals(tc, NULL, (void *)f->spellbook); CuAssertPtrEquals(tc, NULL, (void *)f->origin); CuAssertPtrEquals(tc, (void *)factions, (void *)f); - CuAssertStrEquals(tc, "test@eressea.de", f->email); + CuAssertStrEquals(tc, "test@example.com", f->email); CuAssertTrue(tc, checkpasswd(f, "hurrdurr")); CuAssertPtrEquals(tc, (void *)lang, (void *)f->locale); CuAssertIntEquals(tc, FFL_ISNEW|FFL_PWMSG, f->flags); CuAssertIntEquals(tc, 0, f->age); CuAssertTrue(tc, faction_alive(f)); CuAssertIntEquals(tc, M_GRAY, f->magiegebiet); - CuAssertIntEquals(tc, turn, f->lastorders); + CuAssertIntEquals(tc, 0, f->lastorders); CuAssertPtrEquals(tc, f, findfaction(f->no)); test_teardown(); } diff --git a/src/kernel/gamedata.h b/src/kernel/gamedata.h index 1d65f5085..77469f9da 100644 --- a/src/kernel/gamedata.h +++ b/src/kernel/gamedata.h @@ -40,8 +40,9 @@ #define FACTION_UID_VERSION 362 /* f->uid contains a database id */ #define CRYPT_VERSION 363 /* passwords are encrypted */ #define FAMILIAR_FIXMAGE_VERSION 364 /* familiar links are fixed */ +#define FAMILIAR_FIXSPELLBOOK_VERSION 365 /* familiar spells are fixed */ -#define RELEASE_VERSION FAMILIAR_FIXMAGE_VERSION /* current datafile */ +#define RELEASE_VERSION FAMILIAR_FIXSPELLBOOK_VERSION /* current datafile */ #define MIN_VERSION UIDHASH_VERSION /* minimal datafile we support */ #define MAX_VERSION RELEASE_VERSION /* change this if we can need to read the future datafile, and we can do so */ diff --git a/src/kernel/item.c b/src/kernel/item.c index 58702be07..a58df472c 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -194,12 +194,10 @@ resource_type *rt_get_or_create(const char *name) { if (!rtype) { rtype = calloc(1, sizeof(resource_type)); if (!rtype) { - perror("resource_type allocation failed"); - } - else { - rtype->_name = str_strdup(name); - rt_register(rtype); + abort(); } + rtype->_name = str_strdup(name); + rt_register(rtype); } return rtype; } @@ -247,6 +245,7 @@ item_type *it_get_or_create(resource_type *rtype) { if (!rtype->itype) { item_type * itype; itype = (item_type *)calloc(sizeof(item_type), 1); + if (!itype) abort(); itype->rtype = rtype; rtype->uchange = res_changeitem; rtype->itype = itype; @@ -269,6 +268,7 @@ luxury_type *new_luxurytype(item_type * itype, int price) assert(resource2luxury(itype->rtype) == NULL); ltype = calloc(sizeof(luxury_type), 1); + if (!ltype) abort(); ltype->itype = itype; ltype->price = price; lt_register(ltype); @@ -285,6 +285,7 @@ weapon_type *new_weapontype(item_type * itype, assert(itype && (!itype->rtype || !resource2weapon(itype->rtype))); wtype = calloc(sizeof(weapon_type), 1); + if (!wtype) abort(); if (damage) { wtype->damage[0] = str_strdup(damage[0]); wtype->damage[1] = str_strdup(damage[1]); @@ -309,6 +310,7 @@ armor_type *new_armortype(item_type * itype, double penalty, variant magres, assert(itype->rtype->atype == NULL); atype = calloc(sizeof(armor_type), 1); + if (!atype) abort(); atype->itype = itype; atype->penalty = penalty; @@ -530,6 +532,7 @@ item *i_new(const item_type * itype, int size) } else { i = malloc(sizeof(item)); + if (!i) abort(); } assert(itype); i->next = NULL; diff --git a/src/kernel/messages.test.c b/src/kernel/messages.test.c index c186973fa..707eb8e7e 100644 --- a/src/kernel/messages.test.c +++ b/src/kernel/messages.test.c @@ -2,6 +2,7 @@ #include "messages.h" #include "unit.h" +#include "faction.h" #include "order.h" #include @@ -25,10 +26,13 @@ void test_missing_message(CuTest *tc) { void test_missing_feedback(CuTest *tc) { message *msg; + unit *u; test_setup(); + u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL)); + u->thisorder = create_order(K_ENTERTAIN, u->faction->locale, NULL); message_handle_missing(MESSAGE_MISSING_REPLACE); - msg = msg_error(NULL, NULL, 77); + msg = msg_error(u, NULL, 77); CuAssertPtrNotNull(tc, msg); CuAssertPtrNotNull(tc, msg->type); CuAssertStrEquals(tc, msg->type->name, "missing_feedback"); @@ -113,6 +117,7 @@ static void test_noerror(CuTest *tc) { CuSuite *get_messages_suite(void) { CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_missing_message); + SUITE_ADD_TEST(suite, test_missing_feedback); SUITE_ADD_TEST(suite, test_merge_split); SUITE_ADD_TEST(suite, test_message); SUITE_ADD_TEST(suite, test_noerror); diff --git a/src/kernel/order.c b/src/kernel/order.c index 493922faa..b4467fa5b 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -120,7 +120,7 @@ char* get_command(const order *ord, const struct locale *lang, char *sbuffer, si sbs_init(&sbs, sbuffer, size); if (ord->command & CMD_QUIET) { - sbs_strcpy(&sbs, "!"); + sbs_strcat(&sbs, "!"); } if (ord->command & CMD_PERSIST) { sbs_strcat(&sbs, "@"); @@ -170,7 +170,6 @@ const char *crescape(const char *str, char *buffer, size_t size) { int stream_order(struct stream *out, const struct order *ord, const struct locale *lang, bool escape) { const char *text; - order_data *od = NULL; keyword_t kwd = ORD_KEYWORD(ord); if (ord->command & CMD_QUIET) { @@ -203,7 +202,7 @@ int stream_order(struct stream *out, const struct order *ord, const struct local } } else { - od = odata_load(ord->id); + order_data *od = odata_load(ord->id); text = OD_STRING(od); if (text) { char obuf[1024]; diff --git a/src/kernel/pool.test.c b/src/kernel/pool.test.c index 10c127f81..d5d190c26 100644 --- a/src/kernel/pool.test.c +++ b/src/kernel/pool.test.c @@ -6,6 +6,7 @@ #include "unit.h" #include "item.h" #include "faction.h" +#include "race.h" #include "region.h" #include "skill.h" @@ -42,6 +43,30 @@ void test_reservation(CuTest *tc) { test_teardown(); } +void test_pool_get_item(CuTest *tc) { + unit *u1, *u2; + faction *f; + region *r; + race *rc; + struct resource_type *rtype; + + test_setup(); + rtype = rt_get_or_create("money"); + rtype->flags |= RTF_POOLED; + it_get_or_create(rtype); + f = test_create_faction(NULL); + r = test_create_plain(0, 0); + u1 = test_create_unit(f, r); + u_setrace(u1, rc = test_create_race("undead")); + rc->ec_flags &= ~ECF_GETITEM; + u2 = test_create_unit(f, r); + i_change(&u2->items, rtype->itype, 2); + CuAssertIntEquals(tc, 0, get_pooled(u1, rtype, GET_DEFAULT, 1)); + CuAssertIntEquals(tc, 0, i_get(u1->items, rtype->itype)); + CuAssertIntEquals(tc, 2, i_get(u2->items, rtype->itype)); + test_teardown(); +} + void test_pool(CuTest *tc) { unit *u1, *u2, *u3; faction *f; @@ -49,11 +74,11 @@ void test_pool(CuTest *tc) { struct resource_type *rtype; test_setup(); - test_create_world(); rtype = rt_get_or_create("money"); + rtype->flags |= RTF_POOLED; it_get_or_create(rtype); f = test_create_faction(NULL); - r = findregion(0, 0); + r = test_create_plain(0, 0); assert(r && f && rtype && rtype->itype); u1 = test_create_unit(f, r); u2 = test_create_unit(f, r); @@ -188,6 +213,7 @@ CuSuite *get_pool_suite(void) CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_reservation); SUITE_ADD_TEST(suite, test_pool); + SUITE_ADD_TEST(suite, test_pool_get_item); SUITE_ADD_TEST(suite, test_pool_bug_2042); SUITE_ADD_TEST(suite, test_pool_use); SUITE_ADD_TEST(suite, test_change_resource); diff --git a/src/kernel/race.c b/src/kernel/race.c index 53abd339f..4a0d0689f 100644 --- a/src/kernel/race.c +++ b/src/kernel/race.c @@ -240,15 +240,6 @@ race_list *get_familiarraces(void) return familiarraces; } -void racelist_clear(struct race_list **rl) -{ - while (*rl) { - race_list *rl2 = (*rl)->next; - free(*rl); - *rl = rl2; - } -} - void racelist_insert(struct race_list **rl, const struct race *r) { race_list *rl2 = (race_list *)malloc(sizeof(race_list)); @@ -546,7 +537,7 @@ const char *racename(const struct locale *loc, const unit * u, const race * rc) char ch[2]; sbs_init(&sbs, lbuf, sizeof(lbuf)); - sbs_strcpy(&sbs, LOC(loc, mkname("prefix", prefix))); + sbs_strcat(&sbs, LOC(loc, mkname("prefix", prefix))); str = LOC(loc, rc_name_s(rc, u->number != 1)); assert(~str[0] & 0x80 || !"unicode/not implemented"); diff --git a/src/kernel/resources.c b/src/kernel/resources.c index 4bb27616d..b5741236b 100644 --- a/src/kernel/resources.c +++ b/src/kernel/resources.c @@ -181,10 +181,8 @@ struct rawmaterial_type *rmt_get(const struct resource_type *rtype) struct rawmaterial_type *rmt_create(struct resource_type *rtype) { - rawmaterial_type *rmtype; - if (!rtype->raw) { - rmtype = rtype->raw = malloc(sizeof(rawmaterial_type)); + rawmaterial_type *rmtype = rtype->raw = malloc(sizeof(rawmaterial_type)); rmtype->rtype = rtype; rmtype->terraform = terraform_default; rmtype->update = NULL; diff --git a/src/kernel/save.c b/src/kernel/save.c index 70f40e0cf..dc024c73b 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -272,12 +272,11 @@ static void read_owner(gamedata *data, region_owner ** powner) static void write_owner(gamedata *data, region_owner * owner) { if (owner) { - faction *f; WRITE_INT(data->store, owner->since_turn); if (owner->since_turn >= 0) { + faction *f = owner->last_owner; WRITE_INT(data->store, owner->morale_turn); WRITE_INT(data->store, owner->flags); - f = owner->last_owner; write_faction_reference((f && f->_alive) ? f : NULL, data->store); f = owner->owner; write_faction_reference((f && f->_alive) ? f : NULL, data->store); @@ -887,12 +886,12 @@ int get_spell_level_faction(const spell * sp, void * cbdata) } static char * getpasswd(int fno) { - const char *prefix = itoa36(fno); - size_t len = strlen(prefix); FILE * F = fopen("passwords.txt", "r"); - char line[80]; if (F) { + const char *prefix = itoa36(fno); + size_t len = strlen(prefix); while (!feof(F)) { + char line[80]; fgets(line, sizeof(line), F); if (line[len] == ':' && strncmp(prefix, line, len) == 0) { size_t slen = strlen(line) - 1; @@ -1147,7 +1146,7 @@ static int cb_sb_maxlevel(spellbook_entry *sbe, void *cbdata) { int readgame(const char *filename) { - int n, stream_version; + int n = -2, stream_version; char path[PATH_MAX]; gamedata gdata = { 0 }; storage store; @@ -1164,23 +1163,25 @@ int readgame(const char *filename) return -1; } sz = fread(&gdata.version, sizeof(int), 1, F); - sz = fread(&stream_version, sizeof(int), 1, F); - assert((sz == 1 && stream_version == STREAM_VERSION) || !"unsupported data format"); - assert(gdata.version >= MIN_VERSION || !"unsupported data format"); - assert(gdata.version <= MAX_VERSION || !"unsupported data format"); + if (sz == 1) { + sz = fread(&stream_version, sizeof(int), 1, F); + assert((sz == 1 && stream_version == STREAM_VERSION) || !"unsupported data format"); + assert(gdata.version >= MIN_VERSION || !"unsupported data format"); + assert(gdata.version <= MAX_VERSION || !"unsupported data format"); - fstream_init(&strm, F); - binstore_init(&store, &strm); - gdata.store = &store; + fstream_init(&strm, F); + binstore_init(&store, &strm); + gdata.store = &store; - if (gdata.version >= BUILDNO_VERSION) { - int build; - READ_INT(&store, &build); - log_debug("data in %s created with build %d.", filename, build); + if (gdata.version >= BUILDNO_VERSION) { + int build; + READ_INT(&store, &build); + log_debug("data in %s created with build %d.", filename, build); + } + n = read_game(&gdata); + binstore_done(&store); + fstream_done(&strm); } - n = read_game(&gdata); - binstore_done(&store); - fstream_done(&strm); return n; } @@ -1350,8 +1351,6 @@ int read_game(gamedata *data) int p, nread; faction *f, **fp; region *r; - building **bp; - ship **shp; unit *u; storage * store = data->store; const struct building_type *bt_lighthouse = bt_find("lighthouse"); @@ -1407,6 +1406,8 @@ int read_game(gamedata *data) while (--nread >= 0) { unit **up; + building **bp; + ship **shp; r = read_region(data); @@ -1527,7 +1528,7 @@ int read_game(gamedata *data) if (data->version < FAMILIAR_FIX_VERSION) { fix_familiars(fix_fam_triggers); } - if (data->version < FAMILIAR_FIXMAGE_VERSION) { + if (data->version < FAMILIAR_FIXSPELLBOOK_VERSION) { fix_familiars(fix_fam_mage); } diff --git a/src/kernel/terrain.c b/src/kernel/terrain.c index bec8fa8e8..f5041dc03 100644 --- a/src/kernel/terrain.c +++ b/src/kernel/terrain.c @@ -67,7 +67,6 @@ bool terrain_changed(int *cache) { return false; } - void free_terrains(void) { while (registered_terrains) { diff --git a/src/kernel/unit.c b/src/kernel/unit.c index 748c76003..0778fc48e 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -776,7 +776,6 @@ void clone_men(const unit * u, unit * dst, int n) /* "hat attackiert"-status wird uebergeben */ if (dst) { - skill *sv, *sn; skill_t sk; ship *sh; @@ -784,9 +783,8 @@ void clone_men(const unit * u, unit * dst, int n) for (sk = 0; sk != MAXSKILLS; ++sk) { int weeks, level = 0; - - sv = unit_skill(u, sk); - sn = unit_skill(dst, sk); + skill *sv = unit_skill(u, sk); + skill *sn = unit_skill(dst, sk); if (sv == NULL && sn == NULL) continue; @@ -984,9 +982,8 @@ void set_number(unit * u, int count) void remove_skill(unit * u, skill_t sk) { int i; - skill *sv; for (i = 0; i != u->skill_size; ++i) { - sv = u->skills + i; + skill *sv = u->skills + i; if (sv->id == sk) { if (u->skill_size - i - 1 > 0) { memmove(sv, sv + 1, (u->skill_size - i - 1) * sizeof(skill)); diff --git a/src/laws.c b/src/laws.c index feacca8a1..9de897cb0 100644 --- a/src/laws.c +++ b/src/laws.c @@ -154,8 +154,11 @@ bool IsImmune(const faction * f) int NMRTimeout(void) { - int nmr_timeout = config_get_int("nmr.timeout", 0); - int ini_timeout = config_get_int("game.maxnmr", 0); + static int config, nmr_timeout, ini_timeout; + if (config_changed(&config)) { + nmr_timeout = config_get_int("nmr.timeout", 0); + ini_timeout = config_get_int("game.maxnmr", 0); + } if (nmr_timeout > 0) { if (ini_timeout > nmr_timeout) { return nmr_timeout; @@ -1192,17 +1195,26 @@ void do_enter(struct region *r, bool is_final_attempt) int dropouts[2]; int *age = NULL; -static void nmr_death(faction * f) +bool nmr_death(const faction * f, int turn, int timeout) { - int rule = config_get_int("rules.nmr.destroy", 0) != 0; - if (rule) { - unit *u; - for (u = f->units; u; u = u->nextF) { - if (u->building && building_owner(u->building) == u) { - remove_building(&u->region->buildings, u->building); + if (f->age >= timeout && turn - f->lastorders >= timeout) { + static bool rule_destroy; + static int config; + + if (config_changed(&config)) { + rule_destroy = config_get_int("rules.nmr.destroy", 0) != 0; + } + if (rule_destroy) { + unit *u; + for (u = f->units; u; u = u->nextF) { + if (u->building && building_owner(u->building) == u) { + remove_building(&u->region->buildings, u->building); + } } } + return true; } + return false; } static void remove_idle_players(void) @@ -1215,8 +1227,7 @@ static void remove_idle_players(void) for (fp = &factions; *fp;) { faction *f = *fp; - if (timeout > 0 && turn - f->lastorders >= timeout) { - nmr_death(f); + if (timeout > 0 && nmr_death(f, turn, timeout)) { destroyfaction(fp); } else { if (fval(f, FFL_NOIDLEOUT)) { @@ -2088,34 +2099,33 @@ int email_cmd(unit * u, struct order *ord) int password_cmd(unit * u, struct order *ord) { - char pwbuf[32]; + char pwbuf[PASSWORD_MAXSIZE + 1]; const char *s; - bool pwok = true; init_order_depr(ord); + pwbuf[PASSWORD_MAXSIZE] = '\n'; s = gettoken(pwbuf, sizeof(pwbuf)); - - if (!s || !*s) { - int i; - for (i = 0; i < 6; i++) - pwbuf[i] = (char)(97 + rng_int() % 26); - pwbuf[6] = 0; + if (pwbuf[PASSWORD_MAXSIZE] == '\0') { + cmistake(u, ord, 321, MSG_EVENT); + pwbuf[PASSWORD_MAXSIZE - 1] = '\0'; } - else { - char *c; - for (c = pwbuf; *c && pwok; ++c) { - if (!isalnum(*(unsigned char *)c)) { - pwok = false; + + if (s && *s) { + unsigned char *c = (unsigned char *)pwbuf; + int i, r = 0; + + for (i = 0; c[i] && i != PASSWORD_MAXSIZE; ++i) { + if (!isalnum(c[i])) { + c[i] = 'X'; + ++r; } } - } - if (!pwok) { - cmistake(u, ord, 283, MSG_EVENT); - str_strlcpy(pwbuf, itoa36(rng_int()), sizeof(pwbuf)); + if (r != 0) { + cmistake(u, ord, 283, MSG_EVENT); + } } faction_setpassword(u->faction, password_hash(pwbuf, PASSWORD_DEFAULT)); - ADDMSG(&u->faction->msgs, msg_message("changepasswd", - "value", pwbuf)); + ADDMSG(&u->faction->msgs, msg_message("changepasswd", "value", pwbuf)); u->faction->flags |= FFL_PWMSG; return 0; } @@ -3339,7 +3349,6 @@ int pay_cmd(unit * u, struct order *ord) cmistake(u, ord, 6, MSG_EVENT); } else { - building *b = NULL; param_t p; int id; @@ -3355,13 +3364,12 @@ int pay_cmd(unit * u, struct order *ord) } else { /* If no building id is given or it is the id of our building, just set the do-not-pay flag */ - if (id == 0 || id == u->building->no) - { + if (id == 0 || id == u->building->no) { u->building->flags |= BLD_DONTPAY; } else { /* Find the building that matches to the given id*/ - b = findbuilding(id); + building *b = findbuilding(id); /* If there is a building and it is in the same region as the unit continue, else: error */ if (b && b->region == u->region) { @@ -3391,8 +3399,8 @@ int pay_cmd(unit * u, struct order *ord) static int reserve_i(unit * u, struct order *ord, int flags) { - char token[128]; if (u->number > 0) { + char token[128]; int use, count, para; const item_type *itype; const char *s; @@ -3426,10 +3434,7 @@ static int reserve_i(unit * u, struct order *ord, int flags) } int reserve_cmd(unit * u, struct order *ord) { - if ((u_race(u)->ec_flags & ECF_GETITEM)) { - return reserve_i(u, ord, GET_DEFAULT); - } - return 0; + return reserve_i(u, ord, GET_DEFAULT); } int reserve_self(unit * u, struct order *ord) { diff --git a/src/laws.h b/src/laws.h index c30479b38..1f9632c60 100755 --- a/src/laws.h +++ b/src/laws.h @@ -95,6 +95,7 @@ extern "C" { int claim_cmd(struct unit *u, struct order *ord); void nmr_warnings(void); + bool nmr_death(const struct faction * f, int turn, int timeout); bool cansee(const struct faction * f, const struct region * r, const struct unit *u, int modifier); diff --git a/src/laws.test.c b/src/laws.test.c index a2eca7ab5..0896b54f3 100644 --- a/src/laws.test.c +++ b/src/laws.test.c @@ -48,6 +48,37 @@ static void test_new_building_can_be_renamed(CuTest * tc) test_teardown(); } +static void test_password_cmd(CuTest * tc) +{ + unit *u; + faction * f; + test_setup(); + u = test_create_unit(f = test_create_faction(NULL), test_create_plain(0, 0)); + + u->thisorder = create_order(K_PASSWORD, f->locale, "abcdefgh"); + password_cmd(u, u->thisorder); + CuAssertPtrNotNull(tc, faction_getpassword(f)); + CuAssertTrue(tc, checkpasswd(f, "abcdefgh")); + CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "changepasswd")); + free_order(u->thisorder); + + u->thisorder = create_order(K_PASSWORD, f->locale, "abc*de*"); + password_cmd(u, u->thisorder); + CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error283")); + CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "changepasswd")); + CuAssertTrue(tc, !checkpasswd(f, "abc*de*")); + CuAssertTrue(tc, checkpasswd(f, "abcXdeX")); + free_order(u->thisorder); + + u->thisorder = create_order(K_PASSWORD, f->locale, "1234567890123456789012345678901234567890"); + password_cmd(u, u->thisorder); + CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error321")); + CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "changepasswd")); + CuAssertTrue(tc, checkpasswd(f, "1234567890123456789012345678901")); + + test_teardown(); +} + static void test_rename_building(CuTest * tc) { region *r; @@ -1831,6 +1862,7 @@ CuSuite *get_laws_suite(void) SUITE_ADD_TEST(suite, test_long_order_buy_cast); SUITE_ADD_TEST(suite, test_long_order_hungry); SUITE_ADD_TEST(suite, test_new_building_can_be_renamed); + SUITE_ADD_TEST(suite, test_password_cmd); SUITE_ADD_TEST(suite, test_rename_building); SUITE_ADD_TEST(suite, test_rename_building_twice); SUITE_ADD_TEST(suite, test_fishing_feeds_2_people); diff --git a/src/magic.c b/src/magic.c index ebaac3583..7ea51581e 100644 --- a/src/magic.c +++ b/src/magic.c @@ -1334,7 +1334,6 @@ static void do_fumble(castorder * co) int level = co->level; int duration; double effect; - static const race *rc_toad; static int rc_cache; fumble_f fun; @@ -1359,6 +1358,7 @@ static void do_fumble(castorder * co) * The list of things to happen are attached to a timeout * trigger and that's added to the triggerlit of the mage gone toad. */ + static const race *rc_toad; trigger *trestore = trigger_changerace(mage, u_race(mage), mage->irace); if (chance(0.7)) { const resource_type *rtype = rt_find("toadslime"); @@ -2090,7 +2090,7 @@ castorder *create_castorder(castorder * co, unit *caster, unit * familiar, const co->sp = sp; co->level = lev; co->force = MagicPower(force); - co->_rtarget = r ? r : (familiar ? familiar->region : (caster ? caster->region : 0)); + co->_rtarget = r ? r : (familiar ? familiar->region : (caster ? caster->region : NULL)); co->distance = range; co->order = copy_order(ord); co->par = p; @@ -2119,10 +2119,9 @@ void add_castorder(spellrank * cll, castorder * co) void free_castorders(castorder * co) { - castorder *co2; while (co) { - co2 = co; + castorder *co2 = co; co = co->next; free_castorder(co2); free(co2); @@ -2202,15 +2201,14 @@ void remove_familiar(unit * mage) { attrib *a = a_find(mage->attribs, &at_familiar); attrib *an; - skillmod_data *smd; if (a != NULL) { a_remove(&mage->attribs, a); } a = a_find(mage->attribs, &at_skillmod); while (a && a->type == &at_skillmod) { + skillmod_data *smd = (skillmod_data *)a->data.v; an = a->next; - smd = (skillmod_data *)a->data.v; if (smd->special == sm_familiar) { a_remove(&mage->attribs, a); } diff --git a/src/main.c b/src/main.c index 0dec070ce..bd5a92b46 100644 --- a/src/main.c +++ b/src/main.c @@ -108,11 +108,11 @@ static const char * valid_keys[] = { static dictionary *parse_config(const char *filename) { - char path[PATH_MAX]; dictionary *d; const char *str, *cfgpath = config_get("config.path"); if (cfgpath) { + char path[PATH_MAX]; path_join(cfgpath, filename, path, sizeof(path)); log_debug("reading from configuration file %s\n", path); d = iniparser_load(path); diff --git a/src/modules/autoseed.c b/src/modules/autoseed.c index bb31d3f4e..c16bb7d79 100644 --- a/src/modules/autoseed.c +++ b/src/modules/autoseed.c @@ -549,15 +549,13 @@ int autoseed(newfaction ** players, int nsize, int max_agediff) newfaction **nfp, *nextf = *players; faction *f; unit *u; - const char * password; isize += REGIONS_PER_FACTION; terraform_region(r, preferred_terrain(nextf->race)); prepare_starting_region(r); ++tsize; assert(r->land && r->units == 0); - password = nextf->password ? nextf->password : itoa36(rng_int()); - u = addplayer(r, addfaction(nextf->email, password, nextf->race, + u = addplayer(r, addfaction(nextf->email, nextf->password, nextf->race, nextf->lang)); f = u->faction; fset(f, FFL_ISNEW); @@ -857,8 +855,7 @@ static void starting_region(newfaction ** players, region * r, region * rn[]) newfaction *nf = *players; const struct race *rc = nf->race ? nf->race : races; const struct locale *lang = nf->lang ? nf->lang : default_locale; - const char * passwd = nf->password ? nf->password : itoa36(rng_int()); - addplayer(r, addfaction(nf->email, passwd, rc, lang)); + addplayer(r, addfaction(nf->email, nf->password, rc, lang)); *players = nf->next; free_newfaction(nf); } diff --git a/src/move.c b/src/move.c index c919bc041..683908065 100644 --- a/src/move.c +++ b/src/move.c @@ -637,6 +637,7 @@ void move_ship(ship * sh, region * from, region * to, region_list * route) unit **iunit = &from->units; unit **ulist = &to->units; + assert(sh); if (from != to) { translist(&from->ships, &to->ships, sh); sh->region = to; @@ -1676,10 +1677,9 @@ static bool ship_ready(const region * r, unit * u, order * ord) unit *owner_buildingtyp(const region * r, const building_type * bt) { building *b; - unit *owner; for (b = rbuildings(r); b; b = b->next) { - owner = building_owner(b); + unit *owner = building_owner(b); if (b->type == bt && owner != NULL) { if (building_finished(b)) { return owner; @@ -1971,7 +1971,7 @@ static void sail(unit * u, order * ord, region_list ** routep, bool drifting) /* Hafengebühren ? */ harbourmaster = owner_buildingtyp(current_point, bt_find("harbour")); - if (sh && harbourmaster != NULL) { + if (harbourmaster != NULL) { item *itm; unit *u2; item *trans = NULL; @@ -2286,7 +2286,7 @@ int follow_ship(unit * u, order * ord) } sbs_init(&sbcmd, command, sizeof(command)); - sbs_strcpy(&sbcmd, LOC(u->faction->locale, keyword(K_MOVE))); + sbs_strcat(&sbcmd, LOC(u->faction->locale, keyword(K_MOVE))); sbs_strcat(&sbcmd, " "); sbs_strcat(&sbcmd, LOC(u->faction->locale, directions[dir])); diff --git a/src/orderfile.c b/src/orderfile.c index 90b44477b..01169fa62 100644 --- a/src/orderfile.c +++ b/src/orderfile.c @@ -14,6 +14,7 @@ #include "util/filereader.h" #include "util/param.h" #include "util/parser.h" +#include "util/password.h" #include "util/order_parser.h" #include @@ -22,7 +23,7 @@ #include static void begin_orders(unit *u) { - if (u->flags & UFL_ORDERS) { + if ((u->flags & UFL_ORDERS) == 0) { order **ordp; /* alle wiederholbaren, langen befehle werden gesichert: */ u->flags |= UFL_ORDERS; @@ -47,13 +48,12 @@ static void begin_orders(unit *u) { u->orders = NULL; } -static unit *unitorders(input *in, faction *f) +static void unitorders(input *in, faction *f) { int i; unit *u; - if (!f) - return NULL; + assert(f); i = getid(); u = findunit(i); @@ -120,10 +120,6 @@ static unit *unitorders(input *in, faction *f) } } - else { - return NULL; - } - return u; } static faction *factionorders(void) @@ -132,7 +128,7 @@ static faction *factionorders(void) faction *f = findfaction(fid); if (f != NULL && (f->flags & FFL_NPC) == 0) { - char token[128]; + char token[PASSWORD_MAXSIZE]; const char *pass = gettoken(token, sizeof(token)); if (!checkpasswd(f, (const char *)pass)) { @@ -189,7 +185,8 @@ int read_orders(input *in) * vermerkt. */ case P_UNIT: - if (!f || !unitorders(in, f)) { + if (f) { + unitorders(in, f); do { b = in->getbuf(in->data); if (!b) { @@ -278,7 +275,7 @@ static void handle_unit(void *userData, int no) { static void handle_order(void *userData, const char *str) { parser_state *state = (parser_state *)userData; const char * tok, *input = str; - char buffer[16]; + char buffer[64]; const struct locale *lang; param_t p; faction * f = state->f; diff --git a/src/orderfile.test.c b/src/orderfile.test.c index ca98fdeb0..204e20d5d 100644 --- a/src/orderfile.test.c +++ b/src/orderfile.test.c @@ -3,9 +3,20 @@ #include "orderfile.h" +#include "direction.h" + #include #include +#include +#include + +#include +#include +#include +#include #include +#include +#include #include #include @@ -24,6 +35,52 @@ static void test_read_orders(CuTest *tc) { test_teardown(); } +static const char *getbuf_strings(void *data) +{ + strlist **listp = (strlist **)data; + if (listp && *listp) { + strlist *list = *listp; + *listp = list->next; + return list->s; + } + return NULL; +} + +static void test_unit_orders(CuTest *tc) { + input in; + unit *u; + faction *f; + strlist *orders = NULL, *backup; + char buf[64]; + + test_setup(); + u = test_create_unit(f = test_create_faction(NULL), test_create_plain(0, 0)); + f->locale = test_create_locale(); + u->orders = create_order(K_ENTERTAIN, f->locale, NULL); + faction_setpassword(f, password_hash("password", PASSWORD_DEFAULT)); + snprintf(buf, sizeof(buf), "%s %s %s", + LOC(f->locale, parameters[P_FACTION]), itoa36(f->no), "password"); + addstrlist(&orders, buf); + snprintf(buf, sizeof(buf), "%s %s", + LOC(f->locale, parameters[P_UNIT]), itoa36(u->no)); + addstrlist(&orders, buf); + snprintf(buf, sizeof(buf), "%s %s", keyword_name(K_MOVE, f->locale), + LOC(f->locale, shortdirections[D_WEST])); + backup = orders; + addstrlist(&orders, buf); + in.data = &orders; + in.getbuf = getbuf_strings; + CuAssertIntEquals(tc, 0, read_orders(&in)); + CuAssertPtrNotNull(tc, u->old_orders); + CuAssertPtrNotNull(tc, u->orders); + CuAssertPtrEquals(tc, NULL, orders); + CuAssertIntEquals(tc, K_MOVE, getkeyword(u->orders)); + CuAssertIntEquals(tc, K_ENTERTAIN, getkeyword(u->old_orders)); + CuAssertIntEquals(tc, UFL_ORDERS, u->flags & UFL_ORDERS); + freestrlist(backup); + test_teardown(); +} + typedef struct order_list { const char **orders; int next; @@ -85,6 +142,7 @@ CuSuite *get_orderfile_suite(void) { CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_read_orders); + SUITE_ADD_TEST(suite, test_unit_orders); SUITE_ADD_TEST(suite, test_faction_password_okay); SUITE_ADD_TEST(suite, test_faction_password_bad); diff --git a/src/report.c b/src/report.c index 2f4254901..fd73f6369 100644 --- a/src/report.c +++ b/src/report.c @@ -79,7 +79,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* util includes */ #include -#include "util/bsdstring.h" #include #include #include @@ -170,9 +169,8 @@ static void centre(struct stream *out, const char *s, bool breaking) } } -static void -paragraph(struct stream *out, const char *str, ptrdiff_t indent, int hanging_indent, - char marker) +void paragraph(struct stream *out, const char *str, ptrdiff_t indent, + int hanging_indent, char marker) { size_t length = REPORTWIDTH; const char *handle_end, *begin, *mark = 0; @@ -257,10 +255,10 @@ void nr_spell_syntax(char *buf, size_t size, spellbook_entry * sbe, const struct sbs_init(&sbs, buf, size); if (sp->sptyp & ISCOMBATSPELL) { - sbs_strcpy(&sbs, LOC(lang, keyword(K_COMBATSPELL))); + sbs_strcat(&sbs, LOC(lang, keyword(K_COMBATSPELL))); } else { - sbs_strcpy(&sbs, LOC(lang, keyword(K_CAST))); + sbs_strcat(&sbs, LOC(lang, keyword(K_CAST))); } /* Reihenfolge beachten: Erst REGION, dann STUFE! */ @@ -434,7 +432,7 @@ void nr_spell_syntax(char *buf, size_t size, spellbook_entry * sbe, const struct void nr_spell(struct stream *out, spellbook_entry * sbe, const struct locale *lang) { - int k, itemanz, costtyp; + int k; bool cont; char buf[4096]; const spell *sp = spellref_get(&sbe->spref); @@ -473,8 +471,8 @@ void nr_spell(struct stream *out, spellbook_entry * sbe, const struct locale *la paragraph(out, LOC(lang, "nr_spell_components"), 0, 0, 0); for (k = 0; sp->components[k].type; ++k) { const resource_type *rtype = sp->components[k].type; - itemanz = sp->components[k].amount; - costtyp = sp->components[k].cost; + int itemanz = sp->components[k].amount; + int costtyp = sp->components[k].cost; if (itemanz > 0) { sbs_init(&sbs, buf, sizeof(buf)); if (sp->sptyp & SPELLLEVEL) { @@ -521,7 +519,6 @@ static void nr_curses_i(struct stream *out, int indent, const faction *viewer, objtype_t typ, const void *obj, attrib *a, int self) { for (; a; a = a->next) { - char buf[4096]; message *msg = 0; if (a->type == &at_curse) { @@ -538,6 +535,7 @@ nr_curses_i(struct stream *out, int indent, const faction *viewer, objtype_t typ } } if (msg) { + char buf[4096]; newline(out); nr_render(msg, viewer->locale, buf, sizeof(buf), viewer); paragraph(out, buf, indent, 2, 0); @@ -849,7 +847,6 @@ static void report_region_resource(sbstring *sbp, const struct locale *lang, con static void report_region_description(struct stream *out, const region * r, faction * f, const bool see[]) { int n; - bool dh; int trees; int saplings; attrib *a; @@ -988,6 +985,7 @@ static void report_region_description(struct stream *out, const region * r, fact } else { int d, nrd = 0; + bool dh = false; /* Nachbarregionen, die gesehen werden, ermitteln */ for (d = 0; d != MAXDIRECTIONS; d++) { @@ -996,7 +994,6 @@ static void report_region_description(struct stream *out, const region * r, fact } /* list directions */ - dh = false; for (d = 0; d != MAXDIRECTIONS; d++) { if (see[d]) { region *r2 = rconnect(r, d); @@ -1039,7 +1036,6 @@ static void report_region_description(struct stream *out, const region * r, fact sbs_strcat(&sbs, " (\""); sbs_strcat(&sbs, LOC(f->locale, spd->keyword)); sbs_strcat(&sbs, "\")."); - dh = 1; } } pump_paragraph(&sbs, out, REPORTWIDTH, true); @@ -1431,6 +1427,7 @@ void pump_paragraph(sbstring *sbp, stream *out, size_t maxlen, bool isfinal) { while (sbs_length(sbp) > maxlen) { char *pos, *begin = sbp->begin; + assert(begin); while (*begin && IS_UTF8_SPACE(begin)) { /* eat whitespace */ ++begin; @@ -1440,7 +1437,12 @@ void pump_paragraph(sbstring *sbp, stream *out, size_t maxlen, bool isfinal) char *next = strchr(pos+1, ' '); if (next == NULL) { if (isfinal) { - swrite(begin, 1, sbp->end - begin, out); + swrite(begin, 1, pos - begin, out); + while (*pos && IS_UTF8_SPACE(pos)) { + ++pos; + } + newline(out); + swrite(pos, 1, sbp->end - pos, out); newline(out); } return; @@ -1619,41 +1621,32 @@ static void guards(struct stream *out, const region * r, const faction * see) } if (nextguard || tarned) { - char buf[8192]; - char *bufp = buf; - size_t size = sizeof(buf) - 1; - int bytes; + char buf[2048]; + sbstring sbs; - bytes = (int)str_strlcpy(bufp, LOC(see->locale, "nr_guarding_prefix"), size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); + sbs_init(&sbs, buf, sizeof(buf)); + sbs_strcat(&sbs, LOC(see->locale, "nr_guarding_prefix")); for (i = 0; i != nextguard + (tarned ? 1 : 0); ++i) { if (i != 0) { if (i == nextguard - (tarned ? 0 : 1)) { - bytes = (int)str_strlcpy(bufp, LOC(see->locale, "list_and"), size); + sbs_strcat(&sbs, LOC(see->locale, "list_and")); } else { - bytes = (int)str_strlcpy(bufp, ", ", size); + sbs_strcat(&sbs, ", "); } - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); } if (i < nextguard) { - bytes = (int)str_strlcpy(bufp, factionname(guardians[i]), size); + sbs_strcat(&sbs, factionname(guardians[i])); } else { - bytes = (int)str_strlcpy(bufp, LOC(see->locale, "nr_guarding_unknown"), size); + sbs_strcat(&sbs, LOC(see->locale, "nr_guarding_unknown")); } - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); + pump_paragraph(&sbs, out, REPORTWIDTH, false); } - bytes = (int)str_strlcpy(bufp, LOC(see->locale, "nr_guarding_postfix"), size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); + sbs_strcat(&sbs, LOC(see->locale, "nr_guarding_postfix")); newline(out); - *bufp = 0; - paragraph(out, buf, 0, 0, 0); + pump_paragraph(&sbs, out, REPORTWIDTH, true); } } @@ -1704,11 +1697,11 @@ static void nr_ship(struct stream *out, const region *r, const ship * sh, const faction * f, const unit * captain) { - char buffer[8192], *bufp = buffer; - size_t size = sizeof(buffer) - 1; - int bytes; + char buffer[1024]; char ch; + sbstring sbs; + sbs_init(&sbs, buffer, sizeof(buffer)); newline(out); if (captain && captain->faction == f) { @@ -1716,57 +1709,37 @@ nr_ship(struct stream *out, const region *r, const ship * sh, const faction * f, getshipweight(sh, &n, &p); n = (n + 99) / 100; /* 1 Silber = 1 GE */ - bytes = snprintf(bufp, size, "%s, %s, (%d/%d)", shipname(sh), + sbs_printf(&sbs, "%s, %s, (%d/%d)", shipname(sh), LOC(f->locale, sh->type->_name), n, shipcapacity(sh) / 100); } else { - bytes = - snprintf(bufp, size, "%s, %s", shipname(sh), LOC(f->locale, - sh->type->_name)); + sbs_printf(&sbs, "%s, %s", shipname(sh), LOC(f->locale, sh->type->_name)); } - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); if (sh->size != sh->type->construction->maxsize) { - bytes = snprintf(bufp, size, ", %s (%d/%d)", + sbs_printf(&sbs, ", %s (%d/%d)", LOC(f->locale, "nr_undercons"), sh->size, sh->type->construction->maxsize); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); } if (sh->damage) { int percent = ship_damage_percent(sh); - bytes = - snprintf(bufp, size, ", %d%% %s", percent, LOC(f->locale, "nr_damaged")); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); + sbs_printf(&sbs, ", %d%% %s", percent, LOC(f->locale, "nr_damaged")); } if (!fval(r->terrain, SEA_REGION)) { if (sh->coast != NODIRECTION) { - bytes = (int)str_strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); - bytes = (int)str_strlcpy(bufp, LOC(f->locale, coasts[sh->coast]), size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); + sbs_strcat(&sbs, ", "); + sbs_strcat(&sbs, LOC(f->locale, coasts[sh->coast])); } } ch = 0; if (sh->display && sh->display[0]) { - bytes = (int)str_strlcpy(bufp, "; ", size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); - bytes = (int)str_strlcpy(bufp, sh->display, size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); + sbs_strcat(&sbs, "; "); + sbs_strcat(&sbs, sh->display); ch = sh->display[strlen(sh->display) - 1]; } if (ch != '!' && ch != '?' && ch != '.') { - bytes = (int)str_strlcpy(bufp, ".", size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); + sbs_strcat(&sbs, "."); } - *bufp = 0; paragraph(out, buffer, 2, 0, 0); nr_curses(out, 4, f, TYP_SHIP, sh); @@ -1914,7 +1887,6 @@ static void cb_write_travelthru(region *r, unit *u, void *cbdata) { void report_travelthru(struct stream *out, region *r, const faction *f) { int maxtravel; - char buf[8192]; assert(r); assert(f); @@ -1926,6 +1898,7 @@ void report_travelthru(struct stream *out, region *r, const faction *f) maxtravel = count_travelthru(r, f); if (maxtravel > 0) { cb_data cbdata; + char buf[8192]; init_cb(&cbdata, out, buf, sizeof(buf), f); cbdata.maxtravel = maxtravel; @@ -1985,12 +1958,11 @@ report_plaintext(const char *filename, report_context * ctx, if (f->age <= 2) { const char *email; - const char *subject; email = config_get("game.email"); if (!email) log_error("game.email not set"); else { - subject = get_mailcmd(f->locale); + const char *subject = get_mailcmd(f->locale); m = msg_message("newbie_info_game", "email subject", email, subject); if (m) { @@ -2093,9 +2065,9 @@ report_plaintext(const char *filename, report_context * ctx, for (a = a_find(f->attribs, &at_showitem); a && a->type == &at_showitem; a = a->next) { const item_type *itype = (const item_type *)a->data.v; - const char *description = NULL; if (itype) { const char *pname = resourcename(itype->rtype, 0); + const char *description; if (ch == 0) { newline(out); @@ -2127,8 +2099,7 @@ report_plaintext(const char *filename, report_context * ctx, } centre(out, buf, true); newline(out); - description = mkname("describe", pname); - description = LOC(f->locale, description); + description = LOC(f->locale, mkname("describe", pname)); centre(out, description, true); } } diff --git a/src/report.h b/src/report.h index 307dba38b..ed31d179e 100644 --- a/src/report.h +++ b/src/report.h @@ -35,6 +35,7 @@ extern "C" { void report_region(struct stream *out, const struct region * r, struct faction * f); void report_allies(struct stream *out, size_t maxlen, const struct faction * f, struct allies * allies, const char *prefix); void pump_paragraph(struct sbstring *sbp, struct stream *out, size_t maxlen, bool isfinal); + void paragraph(struct stream *out, const char *str, ptrdiff_t indent, int hanging_indent, char marker); void nr_spell_syntax(char *buf, size_t size, struct spellbook_entry * sbe, const struct locale *lang); void nr_spell(struct stream *out, struct spellbook_entry * sbe, const struct locale *lang); diff --git a/src/report.test.c b/src/report.test.c index 601df8eb0..59148d3a2 100644 --- a/src/report.test.c +++ b/src/report.test.c @@ -379,11 +379,66 @@ static void test_write_spell_syntax(CuTest *tc) { test_teardown(); } +static void test_paragraph(CuTest *tc) { + const char *toolong = "im Westen das Hochland von Geraldin (93,-303)."; + const char *expect = "im Westen das Hochland von Geraldin (93,-303).\n"; + char buf[256]; + stream out = { 0 }; + size_t len; + + mstream_init(&out); + + paragraph(&out, toolong, 0, 0, 0); + out.api->rewind(out.handle); + len = out.api->read(out.handle, buf, sizeof(buf)); + buf[len] = '\0'; + CuAssertStrEquals(tc, expect, buf); +} + +static void test_paragraph_break(CuTest *tc) { + const char *toolong = "die Ebene von Godsettova (94,-304) und im Westen das Hochland von Geraldin (93,-303)."; + const char *expect = "die Ebene von Godsettova (94,-304) und im Westen das Hochland von Geraldin\n(93,-303).\n"; + char buf[256]; + stream out = { 0 }; + size_t len; + + mstream_init(&out); + + paragraph(&out, toolong, 0, 0, 0); + out.api->rewind(out.handle); + len = out.api->read(out.handle, buf, sizeof(buf)); + buf[len] = '\0'; + CuAssertStrEquals(tc, expect, buf); +} + +static void test_pump_paragraph_toolong(CuTest *tc) { + const char *toolong = "die Ebene von Godsettova (94,-304) und im Westen das Hochland von Geraldin (93,-303)."; + const char *expect = "die Ebene von Godsettova (94,-304) und im Westen das Hochland von Geraldin\n(93,-303).\n"; + sbstring sbs; + char buf[256]; + stream out = { 0 }; + size_t len; + + mstream_init(&out); + + sbs_init(&sbs, buf, sizeof(buf)); + sbs_strcat(&sbs, toolong); + + pump_paragraph(&sbs, &out, 78, true); + out.api->rewind(out.handle); + len = out.api->read(out.handle, buf, sizeof(buf)); + buf[len] = '\0'; + CuAssertStrEquals(tc, expect, buf); +} + CuSuite *get_report_suite(void) { CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_write_spaces); SUITE_ADD_TEST(suite, test_write_many_spaces); + SUITE_ADD_TEST(suite, test_paragraph); + SUITE_ADD_TEST(suite, test_paragraph_break); + SUITE_ADD_TEST(suite, test_pump_paragraph_toolong); SUITE_ADD_TEST(suite, test_report_travelthru); SUITE_ADD_TEST(suite, test_report_region); SUITE_ADD_TEST(suite, test_report_allies); diff --git a/src/reports.c b/src/reports.c index 561bcecf2..addc78dd7 100644 --- a/src/reports.c +++ b/src/reports.c @@ -319,11 +319,11 @@ report_items(const unit *u, item * result, int size, const unit * owner, } } for (itm = items; itm; itm = itm->next) { - item *ishow; const char *ic; report_item(owner, itm, viewer, NULL, &ic, NULL, false); if (ic && *ic) { + item *ishow; for (ishow = result; ishow != result + n; ++ishow) { const char *sc; @@ -714,7 +714,8 @@ void bufunit(const faction * f, const unit * u, const faction *fv, pzTmp = get_racename(u->attribs); if (pzTmp) { - sbs_strcat(sbp, pzTmp); + const char *name = LOC(lang, mkname("race", pzTmp)); + sbs_strcat(sbp, name ? name : pzTmp); if (u->faction == f && fval(u_race(u), RCF_SHAPESHIFTANY)) { sbs_strcat(sbp, " ("); sbs_strcat(sbp, racename(lang, u, u_race(u))); @@ -811,19 +812,14 @@ void bufunit(const faction * f, const unit * u, const faction *fv, if (book) { selist *ql = book->spells; int qi, header, maxlevel = effskill(u, SK_MAGIC, 0); - sbs_strcat(sbp, ". Aura "); - sbs_strcat(sbp, str_itoa(get_spellpoints(u))); - sbs_strcat(sbp, "/"); - sbs_strcat(sbp, str_itoa(max_spellpoints(u, NULL))); + sbs_printf(sbp, ". Aura %d/%d", get_spellpoints(u), max_spellpoints(u, NULL)); for (header = 0, qi = 0; ql; selist_advance(&ql, &qi, 1)) { spellbook_entry * sbe = (spellbook_entry *)selist_get(ql, qi); const spell *sp = spellref_get(&sbe->spref); if (sbe->level <= maxlevel) { if (!header) { - sbs_strcat(sbp, ", "); - sbs_strcat(sbp, LOC(lang, "nr_spells")); - sbs_strcat(sbp, ": "); + sbs_printf(sbp, ", %s: ", LOC(lang, "nr_spells")); header = 1; } else { @@ -839,9 +835,7 @@ void bufunit(const faction * f, const unit * u, const faction *fv, break; } if (i != MAXCOMBATSPELLS) { - sbs_strcat(sbp, ", "); - sbs_strcat(sbp, LOC(lang, "nr_combatspells")); - sbs_strcat(sbp, ": "); + sbs_printf(sbp, ", %s: ", LOC(lang, "nr_combatspells")); dh = 0; for (i = 0; i < MAXCOMBATSPELLS; i++) { const spell *sp; @@ -856,9 +850,7 @@ void bufunit(const faction * f, const unit * u, const faction *fv, int sl = get_combatspelllevel(u, i); sbs_strcat(sbp, spell_name(sp, lang)); if (sl > 0) { - sbs_strcat(sbp, "( "); - sbs_strcat(sbp, str_itoa(sl)); - sbs_strcat(sbp, ")"); + sbs_printf(sbp, "(%d)", sl); } } else { @@ -1606,6 +1598,9 @@ int write_reports(faction * f) if (noreports) { return false; } + if (f->lastorders == 0) { + faction_genpassword(f); + } prepare_report(&ctx, f); get_addresses(&ctx); log_debug("Reports for %s", factionname(f)); @@ -1788,9 +1783,9 @@ static void var_free_regions(variant x) /*-V524 */ const char *trailinto(const region * r, const struct locale *lang) { - static char ref[32]; - const char *s; if (r) { + static char ref[32]; + const char *s; const char *tname = terrain_name(r); size_t sz; @@ -2238,7 +2233,6 @@ static void eval_trail(struct opstack **stack, const void *userdata) handle_end = aregs->nregions; for (i = begin; i < handle_end; ++i) { region *r = aregs->regions[i]; - sbs_strcat(&sbs, ", "); print_trail(report, r, lang, &sbs); diff --git a/src/reports.test.c b/src/reports.test.c index 86f69b0fd..0f5f850e9 100644 --- a/src/reports.test.c +++ b/src/reports.test.c @@ -16,6 +16,7 @@ #include "kernel/building.h" #include "kernel/faction.h" #include "kernel/item.h" +#include "kernel/messages.h" #include "kernel/race.h" #include "kernel/region.h" #include "kernel/ship.h" @@ -29,6 +30,7 @@ #include "util/language.h" #include "util/lists.h" #include "util/message.h" +#include "util/nrmessage.h" #include "attributes/attributes.h" #include "attributes/key.h" @@ -599,14 +601,14 @@ static void test_prepare_lighthouse_owners(CuTest *tc) f = test_create_faction(NULL); r1 = test_create_region(0, 0, t_plain); r2 = test_create_region(1, 0, t_ocean); - r3 = test_create_region(2, 0, t_ocean); + test_create_region(2, 0, t_ocean); r3 = test_create_region(3, 0, t_ocean); btype = test_create_buildingtype("lighthouse"); b = test_create_building(r1, btype); b->flags |= BLD_MAINTAINED; b->size = 10; update_lighthouse(b); - u = test_create_unit(f, r1); + test_create_unit(f, r1); u = test_create_unit(test_create_faction(NULL), r1); u->building = b; region_set_owner(b->region, f, 0); @@ -906,6 +908,68 @@ static void test_visible_unit(CuTest *tc) { test_teardown(); } +static void test_eval_functions(CuTest *tc) +{ + message *msg; + message_type *mtype; + item *items = NULL; + char buf[1024]; + struct locale * lang; + + test_setup(); + init_resources(); + test_create_itemtype("stone"); + test_create_itemtype("iron"); + + lang = test_create_locale(); + locale_setstring(lang, "nr_claims", "$resources($items)"); + register_reports(); + mtype = mt_create_va(mt_new("nr_claims", NULL), "items:items", MT_NEW_END); + nrt_register(mtype); + + msg = msg_message("nr_claims", "items", items); + nr_render(msg, lang, buf, sizeof(buf), NULL); + CuAssertStrEquals(tc, "", buf); + msg_release(msg); + + i_change(&items, get_resourcetype(R_IRON)->itype, 1); + msg = msg_message("nr_claims", "items", items); + nr_render(msg, lang, buf, sizeof(buf), NULL); + CuAssertStrEquals(tc, "1 Eisen", buf); + msg_release(msg); + + i_change(&items, get_resourcetype(R_STONE)->itype, 2); + msg = msg_message("nr_claims", "items", items); + nr_render(msg, lang, buf, sizeof(buf), NULL); + CuAssertStrEquals(tc, "1 Eisen, 2 Steine", buf); + msg_release(msg); + i_freeall(&items); + + test_teardown(); +} + +static void test_reports_genpassword(CuTest *tc) { + faction *f; + int pwid; + + test_setup(); + mt_create_va(mt_new("changepasswd", NULL), "value:string", MT_NEW_END); + f = test_create_faction(NULL); + CuAssertIntEquals(tc, 0, f->lastorders); + CuAssertIntEquals(tc, 0, f->password_id); + f->options = 0; + write_reports(f); + CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "changepasswd")); + CuAssertTrue(tc, f->password_id != 0); + test_clear_messagelist(&f->msgs); + f->lastorders = 1; + pwid = f->password_id; + write_reports(f); + CuAssertIntEquals(tc, pwid, f->password_id); + CuAssertPtrEquals(tc, NULL, test_find_messagetype(f->msgs, "changepasswd")); + test_teardown(); +} + CuSuite *get_reports_suite(void) { CuSuite *suite = CuSuiteNew(); @@ -936,5 +1000,7 @@ CuSuite *get_reports_suite(void) SUITE_ADD_TEST(suite, test_insect_warnings); SUITE_ADD_TEST(suite, test_newbie_warning); SUITE_ADD_TEST(suite, test_visible_unit); + SUITE_ADD_TEST(suite, test_eval_functions); + SUITE_ADD_TEST(suite, test_reports_genpassword); return suite; } diff --git a/src/skill.c b/src/skill.c index abeecca04..41656f0ff 100644 --- a/src/skill.c +++ b/src/skill.c @@ -94,9 +94,9 @@ skill_t findskill(const char *name) skill_t get_skill(const char *s, const struct locale * lang) { skill_t result = NOSKILL; - char buffer[64]; if (s) { + char buffer[64]; char * str = transliterate(buffer, sizeof(buffer) - sizeof(int), s); if (str) { int i; diff --git a/src/spells.c b/src/spells.c index b29e86ea9..a5c8383a1 100644 --- a/src/spells.c +++ b/src/spells.c @@ -2346,7 +2346,6 @@ static int sp_earthquake(castorder * co) static void patzer_peasantmob(const castorder * co) { unit *u; - attrib *a; region *r; unit *mage = co_get_magician(co); r = mage->region->land ? mage->region : co_get_region(co); @@ -2355,6 +2354,7 @@ static void patzer_peasantmob(const castorder * co) faction *f = get_monsters(); const struct locale *lang = f->locale; message *msg; + attrib *a; int anteil, n; anteil = 6 + rng_int() % 4; @@ -2410,7 +2410,6 @@ static void patzer_peasantmob(const castorder * co) static int sp_forest_fire(castorder * co) { unit *u; - region *nr; direction_t i; region *r = co_get_region(co); unit *caster = co_get_caster(co); @@ -2442,7 +2441,7 @@ static int sp_forest_fire(castorder * co) msg_release(msg); for (i = 0; i < MAXDIRECTIONS; i++) { - nr = rconnect(r, i); + region *nr = rconnect(r, i); assert(nr); destroyed = 0; vernichtet_schoesslinge = 0; @@ -5629,7 +5628,6 @@ int sp_disruptastral(castorder * co) attrib *a; double effect; region *r2 = rl2->data; - spec_direction *sd; int inhab_regions = 0; region_list *trl = NULL; @@ -5649,7 +5647,7 @@ int sp_disruptastral(castorder * co) while (a != NULL && a->type == &at_direction) { attrib *a2 = a->next; - sd = (spec_direction *)(a->data.v); + spec_direction *sd = (spec_direction *)(a->data.v); if (sd->duration != -1) a_remove(&r->attribs, a); a = a2; @@ -6161,7 +6159,6 @@ int sp_speed2(castorder * co) */ int sp_break_curse(castorder * co) { - attrib **ap; int obj; curse *c; region *r = co_get_region(co); @@ -6169,7 +6166,6 @@ int sp_break_curse(castorder * co) int cast_level = co->level; double force = co->force; spellparameter *pa = co->par; - const char *ts = NULL; if (pa->length < 2) { /* Das Zielobjekt wurde vergessen */ @@ -6186,6 +6182,8 @@ int sp_break_curse(castorder * co) "unit region command", mage, mage->region, co->order)); } else { + const char *ts = NULL; + attrib **ap; switch (obj) { case SPP_REGION: ap = &r->attribs; diff --git a/src/spells/combatspells.c b/src/spells/combatspells.c index 21b33e7bf..296d88563 100644 --- a/src/spells/combatspells.c +++ b/src/spells/combatspells.c @@ -357,8 +357,6 @@ int sp_sleep(struct castorder * co) const spell * sp = co->sp; battle *b = fi->side->battle; unit *mage = fi->unit; - unit *du; - troop dt; int force, enemies; int k = 0; message *m; @@ -374,7 +372,8 @@ int sp_sleep(struct castorder * co) return 0; } while (force && enemies) { - dt = select_enemy(fi, FIGHT_ROW, BEHIND_ROW, SELECT_ADVANCE); + unit *du; + troop dt = select_enemy(fi, FIGHT_ROW, BEHIND_ROW, SELECT_ADVANCE); assert(dt.fighter); du = dt.fighter->unit; if (!is_magic_resistant(mage, du, 0)) { diff --git a/src/spy.c b/src/spy.c index c0d4d614c..b03896094 100644 --- a/src/spy.c +++ b/src/spy.c @@ -217,7 +217,6 @@ int setstealth_cmd(unit * u, struct order *ord) { char token[64]; const char *s; - int level; init_order_depr(ord); s = gettoken(token, sizeof(token)); @@ -231,7 +230,7 @@ int setstealth_cmd(unit * u, struct order *ord) if (isdigit(*(const unsigned char *)s)) { /* Tarnungslevel setzen */ - level = atoi((const char *)s); + int level = atoi((const char *)s); if (level > effskill(u, SK_STEALTH, 0)) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_lowstealth", "")); return 0; diff --git a/src/summary.c b/src/summary.c index 64bb055b5..e01679d56 100644 --- a/src/summary.c +++ b/src/summary.c @@ -77,11 +77,12 @@ int *nmrs = NULL; int update_nmrs(void) { - int i, newplayers = 0; + int newplayers = 0; faction *f; int timeout = NMRTimeout(); if (timeout>0) { + int i; if (nmrs == NULL) { nmrs = malloc(sizeof(int) * (timeout + 1)); } diff --git a/src/tests.c b/src/tests.c index 22c18ef9c..f6a87b396 100644 --- a/src/tests.c +++ b/src/tests.c @@ -1,6 +1,8 @@ #include #include "tests.h" #include "prefix.h" +#include "creport.h" +#include "report.h" #include "reports.h" #include "vortex.h" @@ -230,9 +232,12 @@ static void test_reset(void) { free_gamedata(); free_terrains(); free_resources(); + free_functions(); free_config(); default_locale = 0; calendar_cleanup(); + creport_cleanup(); + report_cleanup(); close_orders(); log_close(); stats_close(); @@ -245,29 +250,7 @@ static void test_reset(void) { free_spellbooks(); free_prefixes(); mt_clear(); -/* - for (i = 0; i != MAXTERRAINS; ++i) { - int flags = 0; - if (i == T_FIREWALL) { - flags |= FORBIDDEN_REGION; - } else { - flags = FLY_INTO | WALK_INTO; - if (i == T_OCEAN) { - flags |= SEA_REGION | SWIM_INTO; - } - else { - flags |= LAND_REGION; - if (i == T_PLAIN) { - flags |= CAVALRY_REGION | FOREST_REGION; - } - else if (i == T_GLACIER || i == T_ICEBERG || i == T_ICEBERG_SLEEP) { - flags |= ARCTIC_REGION; - } - } - } - test_create_terrain(terrainnames[i], flags); - } -*/ + for (i = 0; i != MAXSKILLS; ++i) { enable_skill(i, true); } diff --git a/src/tools/gethash.c b/src/tools/gethash.c index 75054b11e..f4385a495 100644 --- a/src/tools/gethash.c +++ b/src/tools/gethash.c @@ -4,21 +4,23 @@ int main(int argc, char **argv) { - char key[4]; - char code[4]; - char result[4]; - int a, i, rot; - for (a = 1; a < argc; ++a) { - const char *str = argv[a]; - size_t len = strlen(str); - str = str + len - 6; - memcpy(key, str, 3); - memcpy(code, str + 3, 3); - result[3] = key[3] = code[3] = 0; - rot = atoi(key); - for (i = 0; i != 3; ++i) - result[(i + rot) % 3] = ((code[i] + 10 - key[i]) % 10) + '0'; - printf("%s %s\n", argv[a], result); - } - return 0; + char key[4]; + char code[4]; + char result[4]; + int a; + for (a = 1; a < argc; ++a) { + int rot, i; + const char *str = argv[a]; + size_t len = strlen(str); + str = str + len - 6; + memcpy(key, str, 3); + memcpy(code, str + 3, 3); + result[3] = key[3] = code[3] = 0; + rot = atoi(key); + for (i = 0; i != 3; ++i) { + result[(i + rot) % 3] = ((code[i] + 10 - key[i]) % 10) + '0'; + } + printf("%s %s\n", argv[a], result); + } + return 0; } diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index 362ee4fb2..19bf70b12 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -4,7 +4,6 @@ add_subdirectory (crypto) SET(_TEST_FILES base36.test.c -# bsdstring.test.c # crmessage.test.c # dice.test.c # filereader.test.c @@ -34,7 +33,6 @@ variant.test.c SET(_FILES base36.c -bsdstring.c crmessage.c dice.c filereader.c diff --git a/src/util/base36.c b/src/util/base36.c index 3b5543e88..b1bef983d 100644 --- a/src/util/base36.c +++ b/src/util/base36.c @@ -125,13 +125,3 @@ const char *itoa10(int i) { return itoab(i, 10); } - -int i10toi36(int i) -{ - int r = 0; - while (i) { - r = r * 36 + i % 10; - i = i / 10; - } - return r; -} diff --git a/src/util/base36.h b/src/util/base36.h index 33f0d2f08..ef08094b2 100644 --- a/src/util/base36.h +++ b/src/util/base36.h @@ -25,14 +25,13 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif + const char *itoa36(int i); + int atoi36(const char *s); + const char *itoa36_r(int i, char *result, size_t len); const char *itoab_r(int i, int base, char *result, size_t len); const char *itoab(int i, int base); - const char *itoa36(int i); const char *itoa10(int i); - extern int atoi36(const char *s); - extern int atoi10(const char *s); - int i10toi36(int i); #ifdef __cplusplus } diff --git a/src/util/bsdstring.c b/src/util/bsdstring.c deleted file mode 100644 index 19d6dee0d..000000000 --- a/src/util/bsdstring.c +++ /dev/null @@ -1,52 +0,0 @@ -#ifdef _MSC_VER -#include -#endif -#include -#include -#include -#include - -#include "bsdstring.h" -#include "log.h" -#include "strings.h" - -int wrptr(char **ptr, size_t * size, int result) -{ - size_t bytes = (size_t)result; - if (result < 0) { - /* buffer was too small */ - if (*size > 0) { - **ptr = 0; - *size = 0; - } - errno = 0; - return ERANGE; - } - if (bytes == 0) { - return 0; - } - if (bytes <= *size) { - *ptr += bytes; - *size -= bytes; - return 0; - } - - *ptr += *size; - *size = 0; - return ERANGE; -} - -char * strlcpy_w(char *dst, const char *src, size_t *siz, const char *err, const char *file, int line) -{ - size_t bytes = str_strlcpy(dst, src, *siz); - char * buf = dst; - assert(bytes <= INT_MAX); - if (wrptr(&buf, siz, (int)bytes) != 0) { - if (err) { - log_warning("%s: static buffer too small in %s:%d\n", err, file, line); - } else { - log_warning("static buffer too small in %s:%d\n", file, line); - } - } - return buf; -} diff --git a/src/util/bsdstring.h b/src/util/bsdstring.h deleted file mode 100644 index 56772180a..000000000 --- a/src/util/bsdstring.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef UTIL_BSDSTRING_H -#define UTIL_BSDSTRING_H - -#include - -int wrptr(char **ptr, size_t * size, int bytes); -char * strlcpy_w(char *dst, const char *src, size_t *siz, const char *err, const char *file, int line); - -#define BUFFER_STRCAT(bufp, size, bytes) if (wrptr(&bufp, &size, bytes) != 0) log_warning("static buffer too small in %s:%d\n", __FILE__, __LINE__); - -#define WARN_STATIC_BUFFER() log_warning("static buffer too small in %s:%d\n", __FILE__, __LINE__) -#define INFO_STATIC_BUFFER() log_info("static buffer too small in %s:%d\n", __FILE__, __LINE__) -#define STRLCPY(dst, src, siz) strlcpy_w((dst), (src), &(siz), 0, __FILE__, __LINE__) -#define STRLCPY_EX(dst, src, siz, err) strlcpy_w((dst), (src), (siz), (err), __FILE__, __LINE__) - -#endif diff --git a/src/util/crypto/crypto.c b/src/util/crypto/crypto.c index 75129a826..1e9a84f91 100644 --- a/src/util/crypto/crypto.c +++ b/src/util/crypto/crypto.c @@ -131,14 +131,14 @@ int bcrypt_gensalt(int factor, char salt[BCRYPT_HASHSIZE]) return (aux == NULL)?5:0; } -int bcrypt_hashpw(const char *passwd, const char salt[BCRYPT_HASHSIZE], char hash[BCRYPT_HASHSIZE]) +int bcrypt_hashpw(const char *passwd, const char salt[], char hash[BCRYPT_HASHSIZE]) { char *aux; aux = crypt_rn(passwd, salt, hash, BCRYPT_HASHSIZE); return (aux == NULL)?1:0; } -int bcrypt_checkpw(const char *passwd, const char hash[BCRYPT_HASHSIZE]) +int bcrypt_checkpw(const char *passwd, const char hash[]) { int ret; char outhash[BCRYPT_HASHSIZE]; diff --git a/src/util/crypto/crypto.h b/src/util/crypto/crypto.h index e45b3ca13..b7adc6137 100644 --- a/src/util/crypto/crypto.h +++ b/src/util/crypto/crypto.h @@ -45,7 +45,7 @@ int bcrypt_gensalt(int workfactor, char salt[BCRYPT_HASHSIZE]); * The return value is zero if the password could be hashed and nonzero * otherwise. */ -int bcrypt_hashpw(const char *passwd, const char salt[BCRYPT_HASHSIZE], +int bcrypt_hashpw(const char *passwd, const char salt[], char hash[BCRYPT_HASHSIZE]); /* @@ -57,7 +57,7 @@ int bcrypt_hashpw(const char *passwd, const char salt[BCRYPT_HASHSIZE], * passwords don't match. * */ -int bcrypt_checkpw(const char *passwd, const char hash[BCRYPT_HASHSIZE]); +int bcrypt_checkpw(const char *passwd, const char hash[]); /* * Brief Example diff --git a/src/util/keyword.c b/src/util/keyword.c index e2b5b4775..9d5ba1e6a 100644 --- a/src/util/keyword.c +++ b/src/util/keyword.c @@ -52,13 +52,13 @@ keyword_t findkeyword(const char *s) { keyword_t get_keyword(const char *s, const struct locale *lang) { keyword_t result = NOKEYWORD; - char buffer[64]; assert(lang); assert(s); while (*s == '@') ++s; if (*s) { + char buffer[64]; char *str = transliterate(buffer, sizeof(buffer) - sizeof(int), s); if (str) { @@ -88,6 +88,11 @@ bool keyword_disabled(keyword_t kwd) { return disabled_kwd[kwd]; } +const char *keyword_name(keyword_t kwd, const struct locale *lang) +{ + return LOC(lang, mkname("keyword", keywords[kwd])); +} + const char *keywords[MAXKEYWORDS] = { "//", "banner", diff --git a/src/util/keyword.h b/src/util/keyword.h index 7bb11c485..cc78fd6f7 100644 --- a/src/util/keyword.h +++ b/src/util/keyword.h @@ -83,6 +83,7 @@ extern "C" void init_keywords(const struct locale *lang); void init_keyword(const struct locale *lang, keyword_t kwd, const char *str); bool keyword_disabled(keyword_t kwd); + const char *keyword_name(keyword_t kwd, const struct locale *lang); void enable_keyword(keyword_t kwd, bool enabled); const char *keyword(keyword_t kwd); diff --git a/src/util/lists.c b/src/util/lists.c index 97e782795..710a3c4f1 100644 --- a/src/util/lists.c +++ b/src/util/lists.c @@ -80,15 +80,6 @@ void translist(void *l1, void *l2, void *p) addlist(l2, p); } -void removelist(void *l, void *p) -{ - - /* remove entry p from list l; free p */ - - choplist(l, p); - free(p); -} - void freelist(void *p1) { diff --git a/src/util/lists.h b/src/util/lists.h index 7fd0ca034..ac6c4a7eb 100644 --- a/src/util/lists.h +++ b/src/util/lists.h @@ -32,7 +32,6 @@ extern "C" { void addlist(void *l1, void *p1); void translist(void *l1, void *l2, void *p); void freelist(void *p1); - void removelist(void *l, void *p); unsigned int listlen(void *l); #ifdef __cplusplus diff --git a/src/util/log.c b/src/util/log.c index 26f745a3b..8c198988f 100644 --- a/src/util/log.c +++ b/src/util/log.c @@ -205,15 +205,17 @@ log_t *log_to_file(int flags, FILE *out) { return log_create(flags, out, log_stdio); } -#ifdef _MSC_VER -/* https://social.msdn.microsoft.com/Forums/vstudio/en-US/53a4fd75-9f97-48b2-aa63-2e2e5a15efa3/stdcversion-problem?forum=vclanguage */ -#define VA_COPY(c, a) va_copy(c, a) -#elif !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L -/* GNU only: https://www.gnu.org/software/libc/manual/html_node/Argument-Macros.html */ -#define VA_COPY(c, a) __va_copy(c, a) -#else -#define VA_COPY(c, a) va_copy(c, a) -#endif +/* + * Notes for va_copy compatibility: + * MSVC: https://social.msdn.microsoft.com/Forums/vstudio/en-US/53a4fd75-9f97-48b2-aa63-2e2e5a15efa3/stdcversion-problem?forum=vclanguage + * GNU: https://www.gnu.org/software/libc/manual/html_node/Argument-Macros.html + */ +static void vlog(log_t *lg, int level, const char *format, va_list args) { + va_list copy; + va_copy(copy, args); + lg->log(lg->data, level, NULL, format, copy); + va_end(copy); +} static void log_write(int flags, const char *module, const char *format, va_list args) { log_t *lg; @@ -225,10 +227,7 @@ static void log_write(int flags, const char *module, const char *format, va_list dupe = check_dupe(format, level); } if (dupe == 0) { - va_list copy; - VA_COPY(copy, args); - lg->log(lg->data, level, NULL, format, copy); - va_end(copy); + vlog(lg, level, format, args); } } } @@ -325,10 +324,10 @@ int log_level(log_t * log, int flags) static critbit_tree stats = CRITBIT_TREE(); int stats_count(const char *stat, int delta) { - size_t len; - char data[128]; void * match; if (cb_find_prefix_str(&stats, stat, &match, 1, 0) == 0) { + size_t len; + char data[128]; len = cb_new_kv(stat, strlen(stat), &delta, sizeof(delta), data); cb_insert(&stats, data, len); return delta; diff --git a/src/util/message.c b/src/util/message.c index fc645f3a2..6eb1b9a16 100644 --- a/src/util/message.c +++ b/src/util/message.c @@ -148,6 +148,9 @@ const char *section_add(const char *name) { } } assert(i < MAXSECTIONS); + if (i == MAXSECTIONS) { + return NULL; + } assert(sections[i] == NULL); if (i + 1 < MAXSECTIONS) { sections[i + 1] = NULL; diff --git a/src/util/mt19937ar.c b/src/util/mt19937ar.c index 0dda925ca..ad58d2ca8 100644 --- a/src/util/mt19937ar.c +++ b/src/util/mt19937ar.c @@ -100,10 +100,10 @@ void init_by_array(unsigned long init_key[], int key_length) unsigned long genrand_int32(void) { unsigned long y; - static unsigned long mag01[2]={0x0UL, MATRIX_A}; - /* mag01[x] = x * MATRIX_A for x=0,1 */ if (mti >= N) { /* generate N words at one time */ + static unsigned long mag01[2] = { 0x0UL, MATRIX_A }; + /* mag01[x] = x * MATRIX_A for x=0,1 */ int kk; if (mti == N+1) /* if init_genrand() has not been called, */ diff --git a/src/util/password.h b/src/util/password.h index 7309e0c0e..faa2a0a85 100644 --- a/src/util/password.h +++ b/src/util/password.h @@ -6,6 +6,7 @@ typedef enum cryptalgo_t { PASSWORD_BCRYPT } cryptalgo_t; #define PASSWORD_DEFAULT PASSWORD_BCRYPT +#define PASSWORD_MAXSIZE 32 extern int bcrypt_workfactor; diff --git a/src/util/path.h b/src/util/path.h index 649777171..d7c82940e 100644 --- a/src/util/path.h +++ b/src/util/path.h @@ -2,7 +2,7 @@ #include -#ifdef _MSC_VER +#ifndef PATH_MAX /* @see https://insanecoding.blogspot.no/2007/11/pathmax-simply-isnt.html */ #define PATH_MAX 260 #endif diff --git a/src/util/rng.test.c b/src/util/rng.test.c index 34e530c5e..6ab8719a1 100644 --- a/src/util/rng.test.c +++ b/src/util/rng.test.c @@ -8,17 +8,13 @@ static void test_rng_round(CuTest * tc) { - double f; - int i, r; - for (i = 0; i < 1000; ++i) { - f = rng_double(); - r = RAND_ROUND(f); - CuAssertTrue(tc, f >= 0); - CuAssertTrue(tc, r <= (int)f + 1); - CuAssertTrue(tc, r >= (int)f); - CuAssertTrue(tc, r == (int)r); - CuAssertTrue(tc, r == RAND_ROUND(r)); - } + double f = rng_double(); + int r = RAND_ROUND(f); + CuAssertTrue(tc, f >= 0); + CuAssertTrue(tc, r <= (int)f + 1); + CuAssertTrue(tc, r >= (int)f); + CuAssertTrue(tc, r == (int)r); + CuAssertTrue(tc, r == RAND_ROUND(r)); } CuSuite *get_rng_suite(void) diff --git a/src/util/strings.c b/src/util/strings.c index 0ee0bd79c..7f6cad26c 100644 --- a/src/util/strings.c +++ b/src/util/strings.c @@ -18,7 +18,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #ifdef _MSC_VER #include -#define HAVE__ITOA +#undef HAVE__ITOA #endif #include "strings.h" @@ -35,27 +35,23 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #endif -const char* str_itoab(int val, int base) +const char* str_itoa_r(int val, char *buf) { - static char buf[32] = { 0 }; -#ifdef HAVE__ITOAB - return _itoa(val, buf, base); +#ifdef HAVE__ITOA + return _itoa(val, buf, 10); #else - int i = 30; - for (; val && i; --i, val /= base) { - buf[i] = "0123456789abcdefghijklmnopqrstuvwxyz"[val % base]; - } - return &buf[i + 1]; + snprintf(buf, 12, "%d", val); + return buf; #endif } const char *str_itoa(int n) { + static char buf[12]; #ifdef HAVE__ITOA - static char buf[32] = { 0 }; return _itoa(n, buf, 10); #else - return str_itoab(n, 10); + return str_itoa_r(n, buf); #endif } @@ -181,49 +177,6 @@ int str_hash(const char *s) return key & 0x7FFFFFFF; } -const char *str_escape_wrong(const char *str, char *buffer, size_t len) -{ - const char *handle_start = strchr(str, '\"'); - if (!handle_start) handle_start = strchr(str, '\\'); - assert(buffer); - if (handle_start) { - const char *p = str; - char *o = buffer; - size_t skip = handle_start - str; - - if (skip > len) { - skip = len; - } - if (skip > 0) { - memcpy(buffer, str, skip); - o += skip; - p += skip; - len -= skip; - } - do { - if (*p == '\"' || *p == '\\') { - if (len < 2) { - break; - } - (*o++) = '\\'; - len -= 2; - } - else { - if (len < 1) { - break; - } - --len; - } - if (len > 0) { - (*o++) = (*p); - } - } while (len > 0 && *p++); - *o = '\0'; - return buffer; - } - return str; -} - unsigned int jenkins_hash(unsigned int a) { a = (a + 0x7ed55d16) + (a << 12); @@ -260,6 +213,26 @@ char *str_strdup(const char *s) { #endif } +void sbs_printf(struct sbstring *sbs, const char *format, ...) +{ + size_t size = sbs->size - (sbs->end - sbs->begin); + + if (size > 0) { + va_list argp; + va_start(argp, format); + int bytes = vsnprintf(sbs->end, size, format, argp); + if (bytes > 0) { + if ((size_t)bytes >= size) { + bytes = size - 1; + /* terminate truncated output */ + sbs->end[bytes] = '\0'; + } + sbs->end += bytes; + } + va_end(argp); + } +} + void sbs_init(struct sbstring *sbs, char *buffer, size_t size) { assert(sbs); @@ -303,16 +276,6 @@ void sbs_strcat(struct sbstring *sbs, const char *str) assert(sbs->begin + sbs->size >= sbs->end); } -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; - assert(sbs->begin + sbs->size >= sbs->end); -} - void sbs_substr(sbstring *sbs, ptrdiff_t pos, size_t len) { if (pos > sbs->end - sbs->begin) { diff --git a/src/util/strings.h b/src/util/strings.h index 1e98a0968..a381b56b9 100644 --- a/src/util/strings.h +++ b/src/util/strings.h @@ -29,7 +29,6 @@ extern "C" { void str_replace(char *buffer, size_t size, const char *tmpl, const char *var, const char *value); int str_hash(const char *s); const char *str_itoa(int i); - const char *str_itoab(int i, int base); size_t str_slprintf(char * dst, size_t size, const char * format, ...); size_t str_strlcpy(char *dst, const char *src, size_t len); size_t str_strlcat(char *dst, const char *src, size_t len); @@ -49,11 +48,11 @@ extern "C" { char *end; } sbstring; + void sbs_printf(struct sbstring *sbs, const char *format, ...); void sbs_init(struct sbstring *sbs, char *buffer, size_t size); void sbs_adopt(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); void sbs_substr(struct sbstring *sbp, ptrdiff_t pos, size_t len); size_t sbs_length(const struct sbstring *sbs); diff --git a/src/util/strings.test.c b/src/util/strings.test.c index 5b8db0473..ac05b91e9 100644 --- a/src/util/strings.test.c +++ b/src/util/strings.test.c @@ -133,25 +133,41 @@ static void test_str_strlcpy(CuTest * tc) errno = 0; } +static void test_str_itoa(CuTest * tc) +{ + CuAssertStrEquals(tc, "1234", str_itoa(1234)); + CuAssertStrEquals(tc, "0", str_itoa(0)); + CuAssertStrEquals(tc, "1234567890", str_itoa(1234567890)); + CuAssertStrEquals(tc, "-1234567890", str_itoa(-1234567890)); +} + 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"); + sbs_strcat(&sbs, "Hodor"); CuAssertStrEquals(tc, "Hodor", sbs.begin); sbs_strcat(&sbs, "Hodor"); CuAssertStrEquals(tc, "HodorHodor", sbs.begin); - sbs_strcpy(&sbs, "Hodor"); + + sbs_init(&sbs, buffer, sizeof(buffer)); + sbs_strcat(&sbs, "Hodor"); CuAssertStrEquals(tc, "Hodor", sbs.begin); - sbs_strcpy(&sbs, "12345678901234567890"); + + sbs_init(&sbs, buffer, sizeof(buffer)); + sbs_strcat(&sbs, "12345678901234567890"); CuAssertStrEquals(tc, "123456789012345", sbs.begin); CuAssertPtrEquals(tc, sbs.begin + sbs.size - 1, sbs.end); + + sbs_init(&sbs, buffer, sizeof(buffer)); sbs_strcat(&sbs, "12345678901234567890"); CuAssertStrEquals(tc, "123456789012345", sbs.begin); CuAssertPtrEquals(tc, buffer, sbs.begin); - sbs_strcpy(&sbs, "1234567890"); + + sbs_init(&sbs, buffer, sizeof(buffer)); + sbs_strcat(&sbs, "1234567890"); CuAssertStrEquals(tc, "1234567890", sbs.begin); sbs_strncat(&sbs, "1234567890", 4); CuAssertStrEquals(tc, "12345678901234", sbs.begin); @@ -194,31 +210,35 @@ static void test_sbs_substr(CuTest * tc) buffer[9] = 'A'; sbs_init(&sbs, buffer, sizeof(buffer)); - sbs_strcpy(&sbs, "12345678"); + sbs_strcat(&sbs, "12345678"); CuAssertStrEquals(tc, "12345678", buffer); sbs_substr(&sbs, 0, 4); CuAssertStrEquals(tc, "1234", buffer); CuAssertIntEquals(tc, 4, (int)sbs_length(&sbs)); - sbs_strcpy(&sbs, "12345678"); + sbs_init(&sbs, buffer, sizeof(buffer)); + sbs_strcat(&sbs, "12345678"); CuAssertStrEquals(tc, "12345678", buffer); sbs_substr(&sbs, 4, 4); CuAssertStrEquals(tc, "5678", buffer); CuAssertIntEquals(tc, 4, (int)sbs_length(&sbs)); - sbs_strcpy(&sbs, "12345678"); + sbs_init(&sbs, buffer, sizeof(buffer)); + sbs_strcat(&sbs, "12345678"); CuAssertStrEquals(tc, "12345678", buffer); sbs_substr(&sbs, 2, 4); CuAssertStrEquals(tc, "3456", buffer); CuAssertIntEquals(tc, 4, (int)sbs_length(&sbs)); - sbs_strcpy(&sbs, "12345678"); + sbs_init(&sbs, buffer, sizeof(buffer)); + sbs_strcat(&sbs, "12345678"); CuAssertStrEquals(tc, "12345678", buffer); sbs_substr(&sbs, 4, 4); CuAssertStrEquals(tc, "5678", buffer); CuAssertIntEquals(tc, 4, (int)sbs_length(&sbs)); - sbs_strcpy(&sbs, "12345678"); + sbs_init(&sbs, buffer, sizeof(buffer)); + sbs_strcat(&sbs, "12345678"); CuAssertStrEquals(tc, "12345678", buffer); sbs_substr(&sbs, 4, 8); CuAssertStrEquals(tc, "5678", buffer); @@ -226,6 +246,31 @@ static void test_sbs_substr(CuTest * tc) CuAssertIntEquals(tc, 'A', buffer[9]); } +static void test_sbs_printf(CuTest * tc) +{ + char buffer[10]; + sbstring sbs; + + sbs_init(&sbs, buffer, sizeof(buffer)); + sbs_printf(&sbs, "%s %d", "1234", 5678); + CuAssertStrEquals(tc, "1234 5678", buffer); + + sbs_init(&sbs, buffer, sizeof(buffer)); + sbs_printf(&sbs, "%s", "12345"); + sbs_printf(&sbs, "%d", 6789); + CuAssertStrEquals(tc, "123456789", buffer); + + sbs_init(&sbs, buffer, sizeof(buffer)); + sbs_printf(&sbs, "%s", "1234567890"); + CuAssertStrEquals(tc, "123456789", buffer); + + sbs_init(&sbs, buffer, sizeof(buffer)); + sbs_printf(&sbs, "%d", 123456789); + CuAssertStrEquals(tc, "123456789", buffer); + sbs_printf(&sbs, "%s", "Hodor"); + CuAssertStrEquals(tc, "123456789", buffer); +} + CuSuite *get_strings_suite(void) { CuSuite *suite = CuSuiteNew(); @@ -237,8 +282,10 @@ 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_str_itoa); SUITE_ADD_TEST(suite, test_sbstring); SUITE_ADD_TEST(suite, test_sbs_strcat); SUITE_ADD_TEST(suite, test_sbs_substr); + SUITE_ADD_TEST(suite, test_sbs_printf); return suite; } diff --git a/src/vortex.c b/src/vortex.c index c743ad857..36945ca3f 100644 --- a/src/vortex.c +++ b/src/vortex.c @@ -129,13 +129,12 @@ attrib_type at_direction = { region *find_special_direction(const region * r, const char *token) { attrib *a; - spec_direction *d; if (strlen(token) == 0) return NULL; for (a = a_find(r->attribs, &at_direction); a && a->type == &at_direction; a = a->next) { - d = (spec_direction *)(a->data.v); + spec_direction *d = (spec_direction *)(a->data.v); if (d->active && strcmp(token, d->keyword) == 0) { return findregion(d->x, d->y);