From a4a3ebd633012d5977ee621fad00c953d661231e Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno@kn-bremen.de>
Date: Sat, 21 Jul 2018 21:41:13 +0200
Subject: [PATCH 01/81] backup the reports, because sometimes I am an idiot

---
 process/backup-eressea | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/process/backup-eressea b/process/backup-eressea
index 4914f5af0..4e5f69002 100755
--- a/process/backup-eressea
+++ b/process/backup-eressea
@@ -28,6 +28,9 @@ if [ -e orders.$TURN ]; then
 files="$files orders.$TURN"
 fi
 echo "backup turn $TURN, game $GAME, files: $files"
+if [ -d reports ] ; then
+  tar cjf backup/$TURN-reports.tar.bz2 reports
+fi
 tar cjf backup/$TURN.tar.bz2 $files
 echo "uploading game-$GAME/$TURN.tar.bz2"
 curl -s -n -T backup/$TURN.tar.bz2 https://dav.box.com/dav/Eressea/game-$GAME/$TURN.tar.bz2

From e7184add00e0d1e1de1629489bddd5537e88f023 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno@kn-bremen.de>
Date: Tue, 24 Jul 2018 13:57:46 +0200
Subject: [PATCH 02/81] use system-wide muttrc

---
 process/send-bz2-report | 2 +-
 process/send-zip-report | 2 +-
 s/preview               | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/process/send-bz2-report b/process/send-bz2-report
index c9fb87840..51a8113bf 100755
--- a/process/send-bz2-report
+++ b/process/send-bz2-report
@@ -25,6 +25,6 @@ addr=$1
 subj=$2
 shift 2
 
-mutt -F "$ERESSEA/etc/muttrc" -s "$subj" -a "$@" -- "$addr" \
+mutt -s "$subj" -a "$@" -- "$addr" \
 	< "$ERESSEA/server/etc/$TEMPLATE"
 
diff --git a/process/send-zip-report b/process/send-zip-report
index 89f742b82..a6bd85246 100755
--- a/process/send-zip-report
+++ b/process/send-zip-report
@@ -44,6 +44,6 @@ addr=$1
 subject=$2
 shift 2
 
-mutt -F "$ERESSEA/etc/muttrc" -s "$subject" -a "$@" -- "$addr" \
+mutt -s "$subject" -a "$@" -- "$addr" \
 	< "$TEMPLATE" || echo "Sending failed for email/report: $2/$3"
 
diff --git a/s/preview b/s/preview
index 68fe6e39f..39d5466d0 100755
--- a/s/preview
+++ b/s/preview
@@ -93,7 +93,7 @@ email=$(grep "faction=$1:" reports.txt | cut -d: -f2 | sed 's/email=//')
 echo "sending reports to $1 / $email"
 info=/dev/null
 [ -e ../email.txt ] && info=../email.txt
-cat $info | mutt -F $ERESSEA/etc/muttrc -s "Testauswertung Spiel $game Partei $1" -a $zip -- $email
+cat $info | mutt -s "Testauswertung Spiel $game Partei $1" -a $zip -- $email
 }
 
 game=0

From ec571924037cc06b23eff622b828f865cd65a57b Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Mon, 30 Jul 2018 22:19:40 +0200
Subject: [PATCH 03/81] equip_newunits got called twice.

---
 scripts/eressea/equipment.lua |  1 -
 scripts/tests/config.lua      | 21 +++++++++++++++++++++
 2 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/scripts/eressea/equipment.lua b/scripts/eressea/equipment.lua
index 8852dfb27..c7bfe7dad 100644
--- a/scripts/eressea/equipment.lua
+++ b/scripts/eressea/equipment.lua
@@ -2,7 +2,6 @@
 local self = {}
 
 local function equip_first(u)
-    equip_newunits(u)
     name = 'seed_' .. u.race
     equip_unit(u, name, 255)
 end
diff --git a/scripts/tests/config.lua b/scripts/tests/config.lua
index 316a8ccca..733a8ee07 100644
--- a/scripts/tests/config.lua
+++ b/scripts/tests/config.lua
@@ -30,6 +30,26 @@ function test_first_troll()
     assert_equal(2, u:eff_skill('perception'))
 end
 
+function test_first_human()
+    local f = faction.create('human')
+    local r = region.create(0, 0, "plain")
+    local u = unit.create(f, r, 1)
+    u:equip('first_unit')
+    assert_not_nil(u.building)
+    assert_equal('castle', u.building.type)
+    assert_equal(10, u.building.size)
+end
+
+function test_first_aquarian()
+    local f = faction.create('aquarian')
+    local r = region.create(0, 0, "plain")
+    local u = unit.create(f, r, 1)
+    u:equip('first_unit')
+    assert_not_nil(u.ship)
+    assert_equal('boat', u.ship.type)
+    assert_equal(1, u:get_skill('sailing'))
+end
+
 function test_seed_unit()
     local r = region.create(0, 0, "plain")
     local f = faction.create('human')
@@ -53,3 +73,4 @@ function test_seed_elf()
     assert_equal('castle', u.building.type)
     assert_equal(10, u.building.size)
 end
+

From 6f5f1651c7a1f86358929c1ebe404f310f5e6e17 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sun, 9 Sep 2018 07:41:30 +0200
Subject: [PATCH 04/81] fix crashes when trying to trade on ocean. fix missing
 message sections.

---
 res/core/messages.xml | 6 +++---
 src/economy.c         | 5 +++--
 src/kernel/region.c   | 5 ++++-
 3 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/res/core/messages.xml b/res/core/messages.xml
index d566c82e6..7e55e05f9 100644
--- a/res/core/messages.xml
+++ b/res/core/messages.xml
@@ -30,7 +30,7 @@
     </type>
   </message>
 
-  <message name="target_region_invalid">
+  <message name="target_region_invalid" section="errors">
     <type>
       <arg name="unit" type="unit"/>
       <arg name="region" type="region"/>
@@ -38,7 +38,7 @@
     </type>
   </message>
   
-  <message name="missing_direction">
+  <message name="missing_direction" section="errors">
     <type>
       <arg name="unit" type="unit"/>
       <arg name="region" type="region"/>
@@ -46,7 +46,7 @@
     </type>
   </message>
   
-  <message name="target_region_not_empty">
+  <message name="target_region_not_empty" section="errors">
     <type>
       <arg name="unit" type="unit"/>
       <arg name="region" type="region"/>
diff --git a/src/economy.c b/src/economy.c
index 3bb7b1066..4a6aa5672 100644
--- a/src/economy.c
+++ b/src/economy.c
@@ -1660,7 +1660,7 @@ static void buy(unit * u, econ_request ** buyorders, struct order *ord)
             return;
         }
     }
-    if (r_demand(r, ltype)) {
+    if (!r->land || r_demand(r, ltype)) {
         ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "luxury_notsold", ""));
         return;
     }
@@ -1702,6 +1702,7 @@ static void expandselling(region * r, econ_request * sellorders, int limit)
     static int bt_cache;
     static const struct building_type *castle_bt, *harbour_bt, *caravan_bt;
 
+    assert(r->land);
     if (bt_changed(&bt_cache)) {
         castle_bt = bt_find("castle");
         harbour_bt = bt_find("harbour");
@@ -1971,7 +1972,7 @@ static bool sell(unit * u, econ_request ** sellorders, struct order *ord)
         econ_request *o;
         int k, available;
 
-        if (!r_demand(r, ltype)) {
+        if (!r->land || !r_demand(r, ltype)) {
             cmistake(u, ord, 263, MSG_COMMERCE);
             return false;
         }
diff --git a/src/kernel/region.c b/src/kernel/region.c
index 7cb52c201..29f7222e1 100644
--- a/src/kernel/region.c
+++ b/src/kernel/region.c
@@ -716,7 +716,10 @@ const item_type *r_luxury(const region * r)
 
 int r_demand(const region * r, const luxury_type * ltype)
 {
-    struct demand *d = r->land->demands;
+    struct demand *d;
+
+    assert(r && r->land);
+    d = r->land->demands;
     while (d && d->type != ltype)
         d = d->next;
     if (!d)

From 67089aeb8c528412303c416631e94f9541d50a4b Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sun, 9 Sep 2018 15:13:20 +0200
Subject: [PATCH 05/81] Bug 2487: Fix LERNE AUTO translations Also disallow
 autolearning expensive skills.

---
 clibs                           |  2 +-
 res/translations/strings.de.po  |  7 +++++
 res/translations/strings.en.po  |  9 ++++++-
 scripts/tests/e2/e2features.lua | 24 +++++++++++++++++
 scripts/tests/study.lua         | 14 +++++-----
 src/automate.c                  |  8 +++---
 src/kernel/order.c              | 19 +++++++++-----
 src/kernel/order.test.c         | 13 ++++++++++
 src/skill.c                     | 35 +++++++++++++++++++++++++
 src/skill.h                     |  2 ++
 src/skill.test.c                | 26 ++++++++++++++++++-
 src/study.c                     | 46 ++++++++-------------------------
 src/study.h                     | 37 +++++++++++++-------------
 13 files changed, 169 insertions(+), 73 deletions(-)

diff --git a/clibs b/clibs
index 66a891b38..d86c85254 160000
--- a/clibs
+++ b/clibs
@@ -1 +1 @@
-Subproject commit 66a891b383f1a51bb0d4e5cf002530f7f70bf7f4
+Subproject commit d86c8525489d7f11b7ba13e101bb59ecf160b871
diff --git a/res/translations/strings.de.po b/res/translations/strings.de.po
index 1731fa10e..f4b166221 100644
--- a/res/translations/strings.de.po
+++ b/res/translations/strings.de.po
@@ -2864,6 +2864,9 @@ msgstr "der Schatten"
 msgid "ALLES"
 msgstr "ALLES"
 
+msgid "AUTO"
+msgstr "AUTO"
+
 msgid "undead_postfix_2"
 msgstr "der Finsternis"
 
@@ -5958,6 +5961,10 @@ msgctxt "keyword"
 msgid "maketemp"
 msgstr "MACHE TEMP"
 
+msgctxt "keyword"
+msgid "autostudy"
+msgstr "LERNE AUTO"
+
 msgctxt "spell"
 msgid "reanimate"
 msgstr "Wiederbelebung"
diff --git a/res/translations/strings.en.po b/res/translations/strings.en.po
index 0d64e9f99..32924310c 100644
--- a/res/translations/strings.en.po
+++ b/res/translations/strings.en.po
@@ -2510,6 +2510,9 @@ msgstr "halfling foot"
 msgid "ALLES"
 msgstr "ALL"
 
+msgid "AUTO"
+msgstr "AUTO"
+
 msgctxt "race"
 msgid "songdragon_d"
 msgstr "song dragons"
@@ -5268,7 +5271,11 @@ msgstr "berserkers blood potions"
 
 msgctxt "keyword"
 msgid "maketemp"
-msgstr "MAKETEMP"
+msgstr "MAKE TEMP"
+
+msgctxt "keyword"
+msgid "autostudy"
+msgstr "LEARN AUTO"
 
 msgctxt "spell"
 msgid "reanimate"
diff --git a/scripts/tests/e2/e2features.lua b/scripts/tests/e2/e2features.lua
index bf90ab6a0..54033d496 100644
--- a/scripts/tests/e2/e2features.lua
+++ b/scripts/tests/e2/e2features.lua
@@ -12,6 +12,30 @@ function setup()
     eressea.settings.set("rules.peasants.growth.factor", "0")
 end
 
+function test_study_auto()
+    local r = region.create(0, 0, "plain")
+    local f = faction.create("human")
+    local u = unit.create(f, r, 1)
+    u:add_order("LERN AUT Waffenbau")
+    assert_equal("LERNE AUTO Waffenbau", u:get_order(0))
+    process_orders()
+    assert_equal(1, u:get_skill("weaponsmithing"))
+end
+
+function test_study_auto_expensive()
+    local r = region.create(0, 0, "plain")
+    local f = faction.create("human")
+    local u = unit.create(f, r, 1)
+    u:add_order("LERNE AUTO Magie")
+    assert_equal("LERNE Magie", u:get_order(0))
+    u:clear_orders()
+    u:add_order("LERN AUT Taktik")
+    assert_equal("LERNE Taktik", u:get_order(0))
+    u:clear_orders()
+    u:add_order("LERN AUT Waffenbau")
+    assert_equal("LERNE AUTO Waffenbau", u:get_order(0))
+end
+
 function test_calendar()
     assert_equal("winter", get_season(1011))
     assert_equal("spring", get_season(1012))
diff --git a/scripts/tests/study.lua b/scripts/tests/study.lua
index 14d4ce1d6..32638ba90 100644
--- a/scripts/tests/study.lua
+++ b/scripts/tests/study.lua
@@ -24,7 +24,7 @@ end
 
 function test_study()
     local r = region.create(0, 0, "plain")
-    local f = faction.create("human", "test@example.com", "de")
+    local f = faction.create("human")
     local u = unit.create(f, r, 1)
     u:add_order("LERNEN Armbrust")
     process_orders()
@@ -33,7 +33,7 @@ end
 
 function test_study_expensive()
     local r = region.create(0, 0, "plain")
-    local f = faction.create("human", "test@example.com", "de")
+    local f = faction.create("human")
     local u = unit.create(f, r, 1)
     eressea.settings.set("skills.cost.alchemy", "50")
     u:add_order("LERNEN Alchemie")
@@ -45,7 +45,7 @@ end
 
 function test_unit_spells()
     local r = region.create(0, 0, "plain")
-    local f = faction.create("human", "test@example.com", "de")
+    local f = faction.create("human")
     local u = unit.create(f, r, 1)
     u.magic = "gray"
     u:set_skill("magic", 1)
@@ -75,7 +75,7 @@ end
 
 function test_study_no_teacher()
     local r = region.create(0, 0, "plain")
-    local f = faction.create("human", "test@example.com", "de")
+    local f = faction.create("human")
     local u1 = make_student(f, r, 1)
     u1:set_skill("crossbow", 1)
     process_orders()
@@ -84,7 +84,7 @@ end
 
 function test_study_with_teacher()
     local r = region.create(0, 0, "plain")
-    local f = faction.create("human", "test@example.com", "de")
+    local f = faction.create("human")
     local u1 = make_student(f, r, 1)
 
     make_teacher(u1)
@@ -95,7 +95,7 @@ end
 
 function test_study_too_many_students()
     local r = region.create(0, 0, "plain")
-    local f = faction.create("human", "test@example.com", "de")
+    local f = faction.create("human")
     local u1 = make_student(f, r, 20, "Taktik")
     u1.name = "Student"
     u1:add_item("money", 201*u1.number)
@@ -106,7 +106,7 @@ end
 
 function test_study_multiple_teachers()
     local r = region.create(0, 0, "plain")
-    local f = faction.create("human", "test@example.com", "de")
+    local f = faction.create("human")
     local u1 = make_student(f, r, 20, "Taktik")
     u1.name = "Student"
     u1:add_item("money", 201*u1.number)
diff --git a/src/automate.c b/src/automate.c
index a74cf770b..6af40d649 100644
--- a/src/automate.c
+++ b/src/automate.c
@@ -38,14 +38,14 @@ int autostudy_init(scholar scholars[], int max_scholars, region *r)
         if (kwd == K_AUTOSTUDY) {
             if (long_order_allowed(u) && unit_can_study(u)) {
                 scholar * st = scholars + nscholars;
-                if (++nscholars == max_scholars) {
-                    log_fatal("you must increase MAXSCHOLARS");
-                }
-                st->u = u;
                 init_order(u->thisorder, u->faction->locale);
                 st->sk = getskill(u->faction->locale);
                 st->level = effskill_study(u, st->sk);
                 st->learn = 0;
+                st->u = u;
+                if (++nscholars == max_scholars) {
+                    log_fatal("you must increase MAXSCHOLARS");
+                }
             }
             else {
                 ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "error_race_nolearn", "race",
diff --git a/src/kernel/order.c b/src/kernel/order.c
index 342f45577..c14a2b30b 100644
--- a/src/kernel/order.c
+++ b/src/kernel/order.c
@@ -141,7 +141,8 @@ int stream_order(struct stream *out, const struct order *ord, const struct local
     if (ord->id < 0) {
         skill_t sk = (skill_t)(100 + ord->id);
 
-        assert(kwd == K_STUDY && sk != SK_MAGIC && sk < MAXSKILLS);
+        assert(kwd == K_AUTOSTUDY || kwd == K_STUDY);
+        assert(sk != SK_MAGIC && sk < MAXSKILLS);
         text = skillname(sk, lang);
         if (strchr(text, ' ') != NULL) {
             swrite(" '", 1, 2, out);
@@ -310,12 +311,13 @@ order *parse_order(const char *s, const struct locale * lang)
     assert(lang);
     assert(s);
     if (*s != 0) {
+        char token[32];
         keyword_t kwd = NOKEYWORD;
         const char *sptr = s;
         bool persistent = false, noerror = false;
-        const char * p;
+        char * p;
 
-        p = *sptr ? parse_token_depr(&sptr) : 0;
+        p = parse_token(&sptr, token, sizeof(token));
         if (p) {
             while (*p == '!' || *p == '@') {
                 if (*p == '!') noerror = true;
@@ -326,7 +328,7 @@ order *parse_order(const char *s, const struct locale * lang)
         }
         if (kwd == K_MAKE) {
             const char *sp = sptr;
-            p = parse_token_depr(&sp);
+            p = parse_token(&sp, token, sizeof(token));
             if (p && isparam(p, lang, P_TEMP)) {
                 kwd = K_MAKETEMP;
                 sptr = sp;
@@ -334,10 +336,15 @@ order *parse_order(const char *s, const struct locale * lang)
         }
         else if (kwd == K_STUDY) {
             const char *sp = sptr;
-            p = parse_token_depr(&sp);
+            p = parse_token(&sp, token, sizeof(token));
             if (p && isparam(p, lang, P_AUTO)) {
-                kwd = K_AUTOSTUDY;
+                skill_t sk;
                 sptr = sp;
+                p = parse_token(&sp, token, sizeof(token));
+                sk = get_skill(p, lang);
+                if (!expensive_skill(sk)) {
+                    kwd = K_AUTOSTUDY;
+                }
             }
         }
         if (kwd != NOKEYWORD) {
diff --git a/src/kernel/order.test.c b/src/kernel/order.test.c
index d1f8b4176..c4a55177b 100644
--- a/src/kernel/order.test.c
+++ b/src/kernel/order.test.c
@@ -121,6 +121,8 @@ static void test_parse_autostudy(CuTest *tc) {
     test_setup();
     lang = get_or_create_locale("en");
     locale_setstring(lang, mkname("skill", skillnames[SK_ENTERTAINMENT]), "Entertainment");
+    locale_setstring(lang, mkname("skill", skillnames[SK_MAGIC]), "Magic");
+    locale_setstring(lang, mkname("skill", skillnames[SK_TACTICS]), "Tactics");
     locale_setstring(lang, keyword(K_STUDY), "STUDY");
     locale_setstring(lang, keyword(K_AUTOSTUDY), "AUTOSTUDY");
     locale_setstring(lang, parameters[P_AUTO], "AUTO");
@@ -134,6 +136,17 @@ static void test_parse_autostudy(CuTest *tc) {
     CuAssertIntEquals(tc, K_AUTOSTUDY, init_order(ord, lang));
     CuAssertStrEquals(tc, "Entertainment", getstrtoken());
     free_order(ord);
+
+    ord = parse_order("STUDY AUTO Magic", lang);
+    CuAssertIntEquals(tc, K_STUDY, getkeyword(ord));
+    CuAssertStrEquals(tc, "STUDY Magic", get_command(ord, lang, cmd, sizeof(cmd)));
+    free_order(ord);
+
+    ord = parse_order("STUDY AUTO Tactics", lang);
+    CuAssertIntEquals(tc, K_STUDY, getkeyword(ord));
+    CuAssertStrEquals(tc, "STUDY Tactics", get_command(ord, lang, cmd, sizeof(cmd)));
+    free_order(ord);
+
     test_teardown();
 }
 
diff --git a/src/skill.c b/src/skill.c
index 3d5b77a96..b279ab488 100644
--- a/src/skill.c
+++ b/src/skill.c
@@ -113,3 +113,38 @@ skill_t get_skill(const char *s, const struct locale * lang)
     return result;
 }
 
+int skill_cost(skill_t sk) {
+    static int config;
+    static int costs[MAXSKILLS];
+    int cost;
+    switch (sk) {
+    case SK_SPY:
+        cost = 100;
+        break;
+    case SK_TACTICS:
+    case SK_HERBALISM:
+    case SK_ALCHEMY:
+        cost = 200;
+        break;
+    default:
+        cost = -1;
+    }
+
+    if (config_changed(&config)) {
+        memset(costs, 0, sizeof(costs));
+    }
+
+    if (costs[sk] == 0) {
+        char buffer[256];
+        sprintf(buffer, "skills.cost.%s", skillnames[sk]);
+        costs[sk] = config_get_int(buffer, cost);
+    }
+    if (costs[sk] >= 0) {
+        return costs[sk];
+    }
+    return (cost > 0) ? cost : 0;
+}
+
+bool expensive_skill(skill_t sk) {
+    return (sk == SK_MAGIC) || skill_cost(sk) > 0;
+}
diff --git a/src/skill.h b/src/skill.h
index 3c88be725..ad6c7c2cb 100644
--- a/src/skill.h
+++ b/src/skill.h
@@ -49,5 +49,7 @@ void init_skills(const struct locale *lang);
 void init_skill(const struct locale *lang, skill_t kwd, const char *str);
 void enable_skill(skill_t sk, bool enabled);
 bool skill_enabled(skill_t sk);
+int skill_cost(skill_t sk);
+bool expensive_skill(skill_t sk);
 
 #endif
diff --git a/src/skill.test.c b/src/skill.test.c
index abfe529f9..09e9c8fe9 100644
--- a/src/skill.test.c
+++ b/src/skill.test.c
@@ -1,6 +1,8 @@
 #include <platform.h>
-#include "skill.h"
+
+#include "kernel/config.h"
 #include "util/language.h"
+#include "skill.h"
 #include "tests.h"
 
 #include <CuTest.h>
@@ -38,12 +40,34 @@ static void test_get_skill(CuTest *tc) {
     test_teardown();
 }
 
+static void test_skill_cost(CuTest *tc) {
+    test_setup();
+    CuAssertTrue(tc, expensive_skill(SK_MAGIC));
+    CuAssertTrue(tc, expensive_skill(SK_TACTICS));
+    CuAssertTrue(tc, expensive_skill(SK_SPY));
+    CuAssertTrue(tc, expensive_skill(SK_ALCHEMY));
+    CuAssertTrue(tc, expensive_skill(SK_HERBALISM));
+    CuAssertTrue(tc, !expensive_skill(SK_CROSSBOW));
+
+    CuAssertIntEquals(tc, 100, skill_cost(SK_SPY));
+    CuAssertIntEquals(tc, 200, skill_cost(SK_TACTICS));
+    CuAssertIntEquals(tc, 200, skill_cost(SK_ALCHEMY));
+    CuAssertIntEquals(tc, 200, skill_cost(SK_HERBALISM));
+    CuAssertIntEquals(tc, 0, skill_cost(SK_CROSSBOW));
+
+    config_set_int("skills.cost.crossbow", 300);
+    CuAssertIntEquals(tc, 300, skill_cost(SK_CROSSBOW));
+    CuAssertTrue(tc, expensive_skill(SK_CROSSBOW));
+    test_teardown();
+}
+
 CuSuite *get_skill_suite(void)
 {
     CuSuite *suite = CuSuiteNew();
     SUITE_ADD_TEST(suite, test_init_skill);
     SUITE_ADD_TEST(suite, test_init_skills);
     SUITE_ADD_TEST(suite, test_get_skill);
+    SUITE_ADD_TEST(suite, test_skill_cost);
     return suite;
 }
 
diff --git a/src/study.c b/src/study.c
index bd29fc2a8..c978e69ad 100644
--- a/src/study.c
+++ b/src/study.c
@@ -130,47 +130,23 @@ bool magic_lowskill(unit * u)
     return u_race(u) == toad_rc;
 }
 
-/* ------------------------------------------------------------- */
-
 int study_cost(struct unit *u, skill_t sk)
 {
-    static int config;
-    static int costs[MAXSKILLS];
-    int cost = -1;
-
     if (sk == SK_MAGIC) {
-        int next_level = 1 + (u ? get_level(u, sk) : 0);
+        static int config;
+        static int cost;
         /* Die Magiekosten betragen 50+Summe(50*Stufe) */
         /* 'Stufe' ist dabei die naechste zu erreichende Stufe */
-        cost = config_get_int("skills.cost.magic", 50);
-        return cost * (1 + ((next_level + next_level * next_level) / 2));
+        if (config_changed(&config)) {
+            cost = config_get_int("skills.cost.magic", 50);
+        }
+        if (cost > 0) {
+            int next_level = 1 + (u ? get_level(u, sk) : 0);
+            return cost * (1 + ((next_level + next_level * next_level) / 2));
+        }
+        return cost;
     }
-    else switch (sk) {
-    case SK_SPY:
-        cost = 100;
-        break;
-    case SK_TACTICS:
-    case SK_HERBALISM:
-    case SK_ALCHEMY:
-        cost = 200;
-        break;
-    default:
-        cost = -1;
-    }
-
-    if (config_changed(&config)) {
-        memset(costs, 0, sizeof(costs));
-    }
-
-    if (costs[sk] == 0) {
-        char buffer[256];
-        sprintf(buffer, "skills.cost.%s", skillnames[sk]);
-        costs[sk] = config_get_int(buffer, cost);
-    }
-    if (costs[sk] >= 0) {
-        return costs[sk];
-    }
-    return (cost > 0) ? cost : 0;
+    return skill_cost(sk);
 }
 
 /* ------------------------------------------------------------- */
diff --git a/src/study.h b/src/study.h
index e99fb4808..cca0428b7 100644
--- a/src/study.h
+++ b/src/study.h
@@ -29,26 +29,9 @@ extern "C" {
     struct unit;
     struct selist;
 
-    int teach_cmd(struct unit *u, struct order *ord);
-    int study_cmd(struct unit *u, struct order *ord);
-
-    magic_t getmagicskill(const struct locale *lang);
-    skill_t getskill(const struct locale *lang);
-    bool is_migrant(struct unit *u);
-    int study_cost(struct unit *u, skill_t talent);
-
-    typedef void(*learn_fun)(struct unit *u, skill_t sk, int days);
-
 #define STUDYDAYS 30
-    void learn_skill(struct unit *u, skill_t sk, int days);
-    void reduce_skill_days(struct unit *u, skill_t sk, int days);
-
-    void produceexp(struct unit *u, skill_t sk, int n);
-    void produceexp_ex(struct unit *u, skill_t sk, int n, learn_fun learn);
-
-    void demon_skillchange(struct unit *u);
-
 #define TEACHNUMBER 10
+
     typedef struct teaching_info {
         struct selist *teachers;
         int students;
@@ -57,6 +40,24 @@ extern "C" {
 
     extern const struct attrib_type at_learning;
 
+    int teach_cmd(struct unit *u, struct order *ord);
+    int study_cmd(struct unit *u, struct order *ord);
+
+    magic_t getmagicskill(const struct locale *lang);
+    skill_t getskill(const struct locale *lang);
+    bool is_migrant(struct unit *u);
+    int study_cost(struct unit *u, skill_t sk);
+
+    typedef void(*learn_fun)(struct unit *u, skill_t sk, int days);
+
+    void learn_skill(struct unit *u, skill_t sk, int days);
+    void reduce_skill_days(struct unit *u, skill_t sk, int days);
+
+    void produceexp(struct unit *u, skill_t sk, int n);
+    void produceexp_ex(struct unit *u, skill_t sk, int n, learn_fun learn);
+
+    void demon_skillchange(struct unit *u);
+
     void inject_learn(learn_fun fun);
 
 #ifdef __cplusplus

From 9456c4bdc7306f8be246764de07ef04aa04ce35f Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sun, 9 Sep 2018 15:16:11 +0200
Subject: [PATCH 06/81] fix debug logging.

---
 scripts/tests/e3/buildings.lua | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/scripts/tests/e3/buildings.lua b/scripts/tests/e3/buildings.lua
index e642c1aa7..9899d138e 100644
--- a/scripts/tests/e3/buildings.lua
+++ b/scripts/tests/e3/buildings.lua
@@ -42,7 +42,8 @@ function test_build_watch()
     process_orders()
     assert_not_nil(u.building)
     if 5 ~= u.building.size then
-        for k,v in f.messages do
+    -- debug logging to find intermittent errors
+        for k,v in ipairs(f.messages) do
             print(v)
         end
     end

From 062abe81026a6afd03950980764dda45184eb023 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sun, 9 Sep 2018 17:10:18 +0200
Subject: [PATCH 07/81] refactor siege property w. getter/setter

---
 src/battle.c          |  6 ++----
 src/creport.c         |  8 ++++++--
 src/economy.c         |  2 ++
 src/kernel/building.c | 11 +++++++++++
 src/kernel/building.h |  5 ++++-
 src/kernel/unit.c     |  8 +++++---
 src/laws.c            |  9 +++++++--
 src/laws.test.c       |  3 ++-
 src/report.c          | 16 +++++++++-------
 src/settings.h        | 12 ------------
 src/study.h           |  1 +
 src/wormhole.c        |  1 -
 12 files changed, 49 insertions(+), 33 deletions(-)

diff --git a/src/battle.c b/src/battle.c
index 9e2f841c0..3f61269a0 100644
--- a/src/battle.c
+++ b/src/battle.c
@@ -100,9 +100,7 @@ typedef enum combatmagic {
 #define MINSPELLRANGE 1
 #define MAXSPELLRANGE 7
 
-#ifndef ROW_FACTOR
-# define ROW_FACTOR 10
-#endif
+#define ROW_FACTOR 3            /* factor for combat row advancement rule */
 #define EFFECT_PANIC_SPELL 0.25
 #define TROLL_REGENERATION 0.10
 
@@ -161,7 +159,7 @@ static void init_rules(void)
     skill_formula = config_get_int("rules.combat.skill_formula",
         FORMULA_ORIG);
     /* maximum number of combat turns */
-    max_turns = config_get_int("rules.combat.turns", COMBAT_TURNS);
+    max_turns = config_get_int("rules.combat.turns", 5);
     /* damage calculation */
     if (config_get_int("rules.combat.critical", 1)) {
         rule_damage |= DAMAGE_CRITICAL;
diff --git a/src/creport.c b/src/creport.c
index 91d56ca3b..137259083 100644
--- a/src/creport.c
+++ b/src/creport.c
@@ -645,6 +645,7 @@ static void cr_output_building(struct stream *out, building *b,
     const unit *owner, int fno, faction *f)
 {
     const char *bname, *billusion;
+    int i;
 
     stream_printf(out, "BURG %d\n", b->no);
 
@@ -673,9 +674,12 @@ static void cr_output_building(struct stream *out, building *b,
     if (fno >= 0) {
         stream_printf(out, "%d;Partei\n", fno);
     }
-    if (b->besieged) {
-        stream_printf(out, "%d;Belagerer\n", b->besieged);
+
+    i = building_get_siege(b);
+    if (i) {
+        stream_printf(out, "%d;Belagerer\n", i);
     }
+
     cr_output_curses(out, f, b, TYP_BUILDING);
 }
 
diff --git a/src/economy.c b/src/economy.c
index baba6c1ac..cc611d49d 100644
--- a/src/economy.c
+++ b/src/economy.c
@@ -103,6 +103,8 @@ static void recruit_init(void)
     }
 }
 
+#define ENTERTAINFRACTION 20
+
 int entertainmoney(const region * r)
 {
     double n;
diff --git a/src/kernel/building.c b/src/kernel/building.c
index 75cad30f7..9dfc7db35 100644
--- a/src/kernel/building.c
+++ b/src/kernel/building.c
@@ -870,3 +870,14 @@ int cmp_current_owner(const building * b, const building * a)
     }
     return 0;
 }
+
+int building_get_siege(const struct building *b)
+{
+    return b->_besieged;
+}
+
+int building_add_siege(struct building *b, int delta)
+{
+    b->_besieged += delta;
+    return b->_besieged;
+}
diff --git a/src/kernel/building.h b/src/kernel/building.h
index eacf42942..319304d79 100644
--- a/src/kernel/building.h
+++ b/src/kernel/building.h
@@ -118,7 +118,7 @@ extern "C" {
         int no;
         int size;
         int sizeleft;               /* is only used during battle. should be a temporary attribute */
-        int besieged;               /* should be an attribute */
+        int _besieged;               /* should be an attribute */
         int flags;
     } building;
 
@@ -134,6 +134,9 @@ extern "C" {
         int id, int size, struct order *ord);
     bool building_finished(const struct building *b);
 
+    int building_get_siege(const struct building *b);
+    int building_add_siege(struct building *b, int delta);
+
     int wage(const struct region *r, const struct faction *f,
         const struct race *rc, int in_turn);
 
diff --git a/src/kernel/unit.c b/src/kernel/unit.c
index 770723bea..146761f05 100644
--- a/src/kernel/unit.c
+++ b/src/kernel/unit.c
@@ -1917,9 +1917,11 @@ int getunit(const region * r, const faction * f, unit **uresult)
 int besieged(const unit * u)
 {
     /* belagert kann man in schiffen und burgen werden */
-    return (u && !keyword_disabled(K_BESIEGE)
-        && u->building && u->building->besieged
-        && u->building->besieged >= u->building->size * SIEGEFACTOR);
+    if (u && !keyword_disabled(K_BESIEGE) && u->building) {
+        building * b = u->building;
+        return building_get_siege(b) >= b->size * SIEGEFACTOR;
+    }
+    return false;
 }
 
 bool has_horses(const unit * u)
diff --git a/src/laws.c b/src/laws.c
index 68f2894b3..67a44c673 100644
--- a/src/laws.c
+++ b/src/laws.c
@@ -306,6 +306,11 @@ static void calculate_emigration(region * r)
     }
 }
 
+/* Vermehrungsrate Bauern in 1/10000.
+* TODO: Evt. Berechnungsfehler, reale Vermehrungsraten scheinen hoeher. */
+#define PEASANTGROWTH 10
+#define PEASANTLUCK 10
+#define PEASANTFORCE 0.75       /* Chance einer Vermehrung trotz 90% Auslastung */
 
 static double peasant_growth_factor(void)
 {
@@ -908,7 +913,7 @@ static int slipthru(const region * r, const unit * u, const building * b)
     int n, o;
 
     /* b ist die burg, in die man hinein oder aus der man heraus will. */
-    if (b == NULL || b->besieged < b->size * SIEGEFACTOR) {
+    if (b == NULL || building_get_siege(b) < b->size * SIEGEFACTOR) {
         return 1;
     }
 
@@ -3857,7 +3862,7 @@ int siege_cmd(unit * u, order * ord)
 
     usetsiege(u, b);
     if (katapultiere < bewaffnete) katapultiere = bewaffnete;
-    b->besieged += katapultiere;
+    building_add_siege(b, katapultiere);
 
     /* definitiver schaden eingeschraenkt */
     if (d > b->size - 1) d = b->size - 1;
diff --git a/src/laws.test.c b/src/laws.test.c
index c7c7a6682..fb644dc90 100644
--- a/src/laws.test.c
+++ b/src/laws.test.c
@@ -113,7 +113,8 @@ static void test_contact(CuTest * tc)
     u3 = test_create_unit(test_create_faction(NULL), r);
     set_level(u3, SK_PERCEPTION, 2);
     usetsiege(u3, b);
-    b->besieged = 1;
+    building_add_siege(b, 1);
+    CuAssertIntEquals(tc, 1, building_get_siege(b));
     CuAssertIntEquals(tc, 1, can_contact(r, u1, u2));
 
     u_set_building(u1, b);
diff --git a/src/report.c b/src/report.c
index 9f1bfa4bd..7de2550a4 100644
--- a/src/report.c
+++ b/src/report.c
@@ -1853,14 +1853,16 @@ nr_building(struct stream *out, const region *r, const building *b, const factio
         sbs_strcat(&sbs, LOC(lang, "nr_building_inprogress"));
     }
 
-    if (b->besieged > 0 && r->seen.mode >= seen_lighthouse) {
-        msg = msg_message("nr_building_besieged", "soldiers diff", b->besieged,
-            b->besieged - b->size * SIEGEFACTOR);
+    if (!keyword_disabled(K_BESIEGE) && r->seen.mode >= seen_lighthouse) {
+        int s = building_get_siege(b);
+        if (s > 0) {
+            msg = msg_message("nr_building_besieged", "soldiers diff", s,
+                s - b->size * SIEGEFACTOR);
+            size = nr_render(msg, lang, sbs.end, sbs.size - (sbs.end - sbs.begin), f);
+            sbs.end += size;
 
-        size = nr_render(msg, lang, sbs.end, sbs.size - (sbs.end - sbs.begin), f);
-        sbs.end += size;
-
-        msg_release(msg);
+            msg_release(msg);
+        }
     }
     i = 0;
     if (b->display && b->display[0]) {
diff --git a/src/settings.h b/src/settings.h
index 57edb1566..498786be9 100644
--- a/src/settings.h
+++ b/src/settings.h
@@ -10,23 +10,11 @@
  without prior permission by the authors of Eressea.
  */
 
-#define ENTERTAINFRACTION 20
-#define TEACHDIFFERENCE 2
 #define RESOURCE_QUANTITY 0.5
 #define RECRUITFRACTION 40      /* 100/RECRUITFRACTION% */
-#define COMBAT_TURNS 5
-#undef NEWATSROI
-
-/* Vermehrungsrate Bauern in 1/10000.
-* TODO: Evt. Berechnungsfehler, reale Vermehrungsraten scheinen hoeher. */
-#define PEASANTGROWTH 10
-#define PEASANTLUCK 10
-
-#define ROW_FACTOR 3            /* factor for combat row advancement rule */
 
  /* TODO: move these settings to settings.h or into configuration files */
 #define TREESIZE (8)            /* space used by trees (in #peasants) */
-#define PEASANTFORCE 0.75       /* Chance einer Vermehrung trotz 90% Auslastung */
 
 /* Gebaeudegroesse = Minimalbelagerer */
 #define SIEGEFACTOR     2
diff --git a/src/study.h b/src/study.h
index cca0428b7..686677064 100644
--- a/src/study.h
+++ b/src/study.h
@@ -31,6 +31,7 @@ extern "C" {
 
 #define STUDYDAYS 30
 #define TEACHNUMBER 10
+#define TEACHDIFFERENCE 2
 
     typedef struct teaching_info {
         struct selist *teachers;
diff --git a/src/wormhole.c b/src/wormhole.c
index 197fc346d..2000018ab 100644
--- a/src/wormhole.c
+++ b/src/wormhole.c
@@ -12,7 +12,6 @@
 
 #include <platform.h>
 #include <kernel/config.h>
-#include "settings.h"
 
 #include "wormhole.h"
 

From 2e5e8347aca8b3643139dc3d6a1ad2e16d2fcdd1 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sun, 9 Sep 2018 21:01:10 +0200
Subject: [PATCH 08/81] Bug 2489: Kill the SIEGE command, forever.

---
 conf/e3/config.json             |   1 -
 conf/keywords.json              |   1 -
 res/core/messages.xml           |  55 ----------
 res/translations/messages.de.po |  24 -----
 res/translations/messages.en.po |  24 -----
 res/translations/strings.de.po  |   4 -
 res/translations/strings.en.po  |   4 -
 scripts/tests/bindings.lua      |   1 -
 src/attributes/attributes.c     |   9 +-
 src/battle.c                    |  11 --
 src/bind_process.c              |   4 -
 src/creport.c                   |  10 --
 src/economy.c                   |  33 ------
 src/guard.c                     |   2 -
 src/jsonconf.test.c             |   6 +-
 src/kernel/build.c              |  13 ---
 src/kernel/building.c           |  11 --
 src/kernel/building.h           |   4 -
 src/kernel/order.c              |   3 -
 src/kernel/unit.c               |  64 ------------
 src/kernel/unit.h               |   5 -
 src/keyword.c                   |   2 +-
 src/keyword.h                   |   2 +-
 src/laws.c                      | 177 +-------------------------------
 src/laws.h                      |   2 -
 src/laws.test.c                 |  33 ------
 src/process.pkg                 |   1 -
 src/process.pkg.c               |  25 -----
 src/report.c                    |  12 ---
 src/reports.c                   |   6 --
 src/spy.c                       |   4 -
 src/spy.test.c                  |   6 +-
 src/steal.c                     |   4 -
 33 files changed, 16 insertions(+), 547 deletions(-)

diff --git a/conf/e3/config.json b/conf/e3/config.json
index b4b6d0e48..dcc3e9f53 100644
--- a/conf/e3/config.json
+++ b/conf/e3/config.json
@@ -28,7 +28,6 @@
         "stealth",
         "taxation",
         "trade",
-        "besiege",
         "steal",
         "buy",
         "teach",
diff --git a/conf/keywords.json b/conf/keywords.json
index 4f8f27f5b..11376ea95 100644
--- a/conf/keywords.json
+++ b/conf/keywords.json
@@ -12,7 +12,6 @@
             "work": [ "ARBEITE", "ARBEITEN" ],
             "attack": ["ATTACKIERE", "ATTACKIEREN"],
             "steal": [ "BEKLAUE", "BEKLAUEN" ],
-            "besiege": ["BELAGERE", "BELAGERN" ],
             "name": [ "BENENNE", "BENENNEN" ],
             "use": [ "BENUTZE", "BENUTZEN" ],
             "describe": [ "BESCHREIBE", "BESCHREIBEN" ],
diff --git a/res/core/messages.xml b/res/core/messages.xml
index 1e4e977e0..d2c40f9b3 100644
--- a/res/core/messages.xml
+++ b/res/core/messages.xml
@@ -710,12 +710,6 @@
       <arg name="dir" type="direction"/>
     </type>
   </message>
-  <message name="nr_building_besieged" section="nr">
-    <type>
-      <arg name="soldiers" type="int"/>
-      <arg name="diff" type="int"/>
-    </type>
-  </message>
 
   <message name="newbie_password" section="events">
     <type>
@@ -2684,19 +2678,6 @@
       <arg name="want" type="int"/>
     </type>
   </message>
-  <message name="siege_catapults" section="events">
-    <type>
-      <arg name="unit" type="unit"/>
-      <arg name="building" type="building"/>
-      <arg name="destruction" type="int"/>
-    </type>
-  </message>
-  <message name="siege" section="events">
-    <type>
-      <arg name="unit" type="unit"/>
-      <arg name="building" type="building"/>
-    </type>
-  </message>
   <message name="drown_on_ship" section="events">
     <type>
       <arg name="unit" type="unit"/>
@@ -3351,14 +3332,6 @@
       <arg name="command" type="order"/>
     </type>
   </message>
-  <message name="entrance_besieged" section="events">
-    <type>
-      <arg name="unit" type="unit"/>
-      <arg name="region" type="region"/>
-      <arg name="command" type="order"/>
-      <arg name="building" type="building"/>
-    </type>
-  </message>
   <message name="entrance_denied" section="events">
     <type>
       <arg name="unit" type="unit"/>
@@ -3890,13 +3863,6 @@
       <arg name="command" type="order"/>
     </type>
   </message>
-  <message name="error166" section="errors">
-    <type>
-      <arg name="unit" type="unit"/>
-      <arg name="region" type="region"/>
-      <arg name="command" type="order"/>
-    </type>
-  </message>
   <message name="error165" section="errors">
     <type>
       <arg name="unit" type="unit"/>
@@ -4002,13 +3968,6 @@
       <arg name="command" type="order"/>
     </type>
   </message>
-  <message name="error60" section="errors">
-    <type>
-      <arg name="unit" type="unit"/>
-      <arg name="region" type="region"/>
-      <arg name="command" type="order"/>
-    </type>
-  </message>
   <message name="error151" section="errors">
     <type>
       <arg name="unit" type="unit"/>
@@ -4993,20 +4952,6 @@
       <arg name="command" type="order"/>
     </type>
   </message>
-  <message name="error24" section="errors">
-    <type>
-      <arg name="unit" type="unit"/>
-      <arg name="region" type="region"/>
-      <arg name="command" type="order"/>
-    </type>
-  </message>
-  <message name="error23" section="errors">
-    <type>
-      <arg name="unit" type="unit"/>
-      <arg name="region" type="region"/>
-      <arg name="command" type="order"/>
-    </type>
-  </message>
   <message name="error22" section="errors">
     <type>
       <arg name="unit" type="unit"/>
diff --git a/res/translations/messages.de.po b/res/translations/messages.de.po
index 507f0e39d..76ff0afc9 100644
--- a/res/translations/messages.de.po
+++ b/res/translations/messages.de.po
@@ -257,9 +257,6 @@ msgstr "\"$unit($unit) in $region($region): '$order($command)' - Hier kann man k
 msgid "error165"
 msgstr "\"$unit($unit) in $region($region): '$order($command)' - Der Trank bekommt der Einheit nicht.\""
 
-msgid "siege_catapults"
-msgstr "\"$unit($unit) belagert $building($building). Dabei richten die Katapulte Zerstörungen von $int($destruction) Größenpunkten an.\""
-
 msgid "curseinfo::magicstreet"
 msgstr "\"Die Straßen sind erstaunlich trocken und gut begehbar. ($int36($id))\""
 
@@ -638,9 +635,6 @@ msgstr "\"$unit($unit) erscheint plötzlich.\""
 msgid "magicresistance_effect"
 msgstr "\"$unit($unit) wird kurz von einem magischen Licht umhüllt.\""
 
-msgid "siege"
-msgstr "\"$unit($unit) belagert $building($building).\""
-
 msgid "missing_force"
 msgstr "\"$unit($unit) schafft es nicht, genug Kraft aufzubringen, um $spell($spell) auf Stufe $int($level) zu zaubern.\""
 
@@ -977,9 +971,6 @@ msgstr "\"$unit($mage) kümmert sich um die Verletzten und benutzt ein $resource
 msgid "error276"
 msgstr "\"$unit($unit) in $region($region): '$order($command)' - Hier kann man keine Schiffe bauen.\""
 
-msgid "error166"
-msgstr "\"$unit($unit) in $region($region): '$order($command)' - Diese Rasse kann eine Burg nicht belagern.\""
-
 msgid "chaosgate_effect_2"
 msgstr "\"Ein Wirbel aus blendendem Licht erscheint.\""
 
@@ -998,9 +989,6 @@ msgstr "\"$unit($unit) in $region($region): '$order($command)' - Die Einheit ist
 msgid "error82"
 msgstr "\"$unit($unit) in $region($region): '$order($command)' - Es gibt keine Abstimmung mit dieser Nummer.\""
 
-msgid "error60"
-msgstr "\"$unit($unit) in $region($region): '$order($command)' - Die Einheit wird belagert.\""
-
 msgid "error162"
 msgstr "\"$unit($unit) in $region($region): '$order($command)' - Der Heiltrank wird automatisch bei Bedarf benutzt.\""
 
@@ -1457,9 +1445,6 @@ msgstr "\"$unit($unit) öffnet eines der Schlösser in $region($region) mit $if(
 msgid "error255"
 msgstr "\"$unit($unit) in $region($region): '$order($command)' - So etwas kann man nicht opfern.\""
 
-msgid "entrance_besieged"
-msgstr "\"$unit($unit) in $region($region): '$order($command)' - $building($building) wird belagert.\""
-
 msgid "error260"
 msgstr "\"$unit($unit) in $region($region): '$order($command)' - Der Besitzer eines Schiffes oder Gebäudes kann nicht neu sortiert werden.\""
 
@@ -1550,9 +1535,6 @@ msgstr "\"In $region($region) findet ein Kampf statt.\""
 msgid "wormhole_dissolve"
 msgstr "\"Das Wurmloch in $region($region) schließt sich.\""
 
-msgid "error23"
-msgstr "\"$unit($unit) in $region($region): '$order($command)' - Der Belagerungszustand macht die Kontaktaufnahme unmöglich.\""
-
 msgid "error12"
 msgstr "\"$unit($unit) in $region($region): '$order($command)' - Das Schiff gehört uns nicht.\""
 
@@ -2135,9 +2117,6 @@ msgstr "\"Seit $int($age) Wochen Mitglied der Allianz '$name ($int36($id))', ang
 msgid "deathcloud_effect"
 msgstr "\"$unit($mage) beschwört einen Giftelementar in $region($region).\""
 
-msgid "nr_building_besieged"
-msgstr "\", belagert von $int($soldiers) Personen$if($lt($diff,0),\"\",\" (abgeschnitten)\")\""
-
 msgid "nr_population"
 msgstr "\"Deine Partei hat $int($population) Personen in $int($units) von maximal $int($limit) Einheiten.\""
 
@@ -2414,9 +2393,6 @@ msgstr "\"$unit($unit) in $region($region): '$order($command)' - Das Schiff hat
 msgid "aborted_battle"
 msgstr "\"Der Kampf wurde abgebrochen, da alle Verteidiger flohen.\""
 
-msgid "error24"
-msgstr "\"$unit($unit) in $region($region): '$order($command)' - Der Belagerungszustand macht Spionage unmöglich.\""
-
 msgid "usecatapult"
 msgstr "\"$int($amount) Krieger von $unit($unit) feuern ihre Katapulte ab.\""
 
diff --git a/res/translations/messages.en.po b/res/translations/messages.en.po
index bf9d8e3c9..50108fc03 100644
--- a/res/translations/messages.en.po
+++ b/res/translations/messages.en.po
@@ -257,9 +257,6 @@ msgstr "\"$unit($unit) in $region($region): '$order($command)' - Buildings canno
 msgid "error165"
 msgstr "\"$unit($unit) in $region($region): '$order($command)' - The potion does not agree with the unit.\""
 
-msgid "siege_catapults"
-msgstr "\"$building($building) is under siege by $unit($unit). During siege, catapults caused $int($destruction) points destruction.\""
-
 msgid "curseinfo::magicstreet"
 msgstr "\"The roads are extremely dry and well-kept. ($int36($id))\""
 
@@ -638,9 +635,6 @@ msgstr "\"$unit($unit) appears.\""
 msgid "magicresistance_effect"
 msgstr "\"$unit($unit) is briefly surrounded by a magical light.\""
 
-msgid "siege"
-msgstr "\"$building($building) is under siege by $unit($unit).\""
-
 msgid "missing_force"
 msgstr "\"$unit($unit) cannot muster enough energy to cast $spell($spell) on level $int($level).\""
 
@@ -977,9 +971,6 @@ msgstr "\"$unit($mage) sees after the wounded and heals $int($amount). A $resour
 msgid "error276"
 msgstr "\"$unit($unit) in $region($region): '$order($command)' - Ships cannot be built here.\""
 
-msgid "error166"
-msgstr "\"$unit($unit) in $region($region): '$order($command)' - This race cannot besiege a castle.\""
-
 msgid "chaosgate_effect_2"
 msgstr "\"A vortex of blinding light appears.\""
 
@@ -998,9 +989,6 @@ msgstr "\"'$order($command)' - $unit($unit) marched into $region($region) during
 msgid "error82"
 msgstr "\"$unit($unit) in $region($region): '$order($command)' - There is no agreement with this number.\""
 
-msgid "error60"
-msgstr "\"$unit($unit) in $region($region): '$order($command)' - The unit is under siege.\""
-
 msgid "error162"
 msgstr "\"$unit($unit) in $region($region): '$order($command)' - This healing potion will be automatically used when needed.\""
 
@@ -1457,9 +1445,6 @@ msgstr "\"$unit($unit) unlocks one of the locks in $region($region) with $if($eq
 msgid "error255"
 msgstr "\"$unit($unit) in $region($region): '$order($command)' - You cannot sacrifice this.\""
 
-msgid "entrance_besieged"
-msgstr "\"$unit($unit) in $region($region): '$order($command)' - $building($building) is under siege.\""
-
 msgid "error260"
 msgstr "\"$unit($unit) in $region($region): '$order($command)' - The owner of a ship or a building cannot be sorted.\""
 
@@ -1550,9 +1535,6 @@ msgstr "\"There is a battle in $region($region).\""
 msgid "wormhole_dissolve"
 msgstr "\"The wormhole in $region($region) disappears.\""
 
-msgid "error23"
-msgstr "\"$unit($unit) in $region($region): '$order($command)' - Contact was not possible due to siege.\""
-
 msgid "error12"
 msgstr "\"$unit($unit) in $region($region): '$order($command)' - The ship is not ours.\""
 
@@ -2135,9 +2117,6 @@ msgstr "\"Member of '$name ($int36($id))' for $int($age) weeks, led by $faction(
 msgid "deathcloud_effect"
 msgstr "\"$unit($mage) summons a poison elemental in $region($region).\""
 
-msgid "nr_building_besieged"
-msgstr "\", besieged by $int($soldiers) soldiers$if($lt($diff,0),\"\",\" (cut off)\")\""
-
 msgid "nr_population"
 msgstr "\"Your faction has $int($population) people in $int($units) of $int($limit) possible units.\""
 
@@ -2414,9 +2393,6 @@ msgstr "\"$unit($unit) in $region($region): '$order($command)' - The ship has mo
 msgid "aborted_battle"
 msgstr "\"The battle was aborted because all enemies escaped.\""
 
-msgid "error24"
-msgstr "\"$unit($unit) in $region($region): '$order($command)' - Espionage was not possible due to siege.\""
-
 msgid "usecatapult"
 msgstr "\"$int($amount) fighters of $unit($unit) launch their catapults.\""
 
diff --git a/res/translations/strings.de.po b/res/translations/strings.de.po
index f4b166221..47d70ecc0 100644
--- a/res/translations/strings.de.po
+++ b/res/translations/strings.de.po
@@ -2772,10 +2772,6 @@ msgstr "Dieser wunderschoen geschmueckte Baum entfaltet in den Wintermonaten ein
 msgid "h10"
 msgstr "Kakteenschwitz"
 
-msgctxt "keyword"
-msgid "besiege"
-msgstr "BELAGERE"
-
 msgid "h11"
 msgstr "Sandfäule"
 
diff --git a/res/translations/strings.en.po b/res/translations/strings.en.po
index 32924310c..8a5dcb30f 100644
--- a/res/translations/strings.en.po
+++ b/res/translations/strings.en.po
@@ -2421,10 +2421,6 @@ msgctxt "iteminfo"
 msgid "xmastree"
 msgstr "In the winter months, this beautifully decorated tree has a magical effect on the entire forest."
 
-msgctxt "keyword"
-msgid "besiege"
-msgstr "BESIEGE"
-
 msgid "h10"
 msgstr "peyote"
 
diff --git a/scripts/tests/bindings.lua b/scripts/tests/bindings.lua
index 9aab6fd57..5820e0a47 100644
--- a/scripts/tests/bindings.lua
+++ b/scripts/tests/bindings.lua
@@ -31,7 +31,6 @@ function test_process()
 	assert_equal("function", _G.type(eressea.process.movement))
 	assert_equal("function", _G.type(eressea.process.use))
 	assert_equal("function", _G.type(eressea.process.battle))
-	assert_equal("function", _G.type(eressea.process.siege))
 	assert_equal("function", _G.type(eressea.process.leave))
 	assert_equal("function", _G.type(eressea.process.promote))
 	assert_equal("function", _G.type(eressea.process.restack))
diff --git a/src/attributes/attributes.c b/src/attributes/attributes.c
index fa6f15d73..6bf78da63 100644
--- a/src/attributes/attributes.c
+++ b/src/attributes/attributes.c
@@ -182,13 +182,13 @@ void register_attributes(void)
     at_register(&at_seenspell);
     at_register(&at_seenspells);
 
-    /* neue REGION-Attribute */
+    /* REGION Attribute */
     at_register(&at_moveblock);
     at_register(&at_deathcount);
     at_register(&at_woodcount);
+    at_register(&at_germs);
 
-    /* neue UNIT-Attribute */
-    at_register(&at_siege);
+    /* UNIT Attribute */
     at_register(&at_effect);
     at_register(&at_private);
 
@@ -205,8 +205,7 @@ void register_attributes(void)
     register_bordertype(&bt_illusionwall);
     register_bordertype(&bt_road);
 
-    at_register(&at_germs);
-
+    at_deprecate("siege", a_readint);
     at_deprecate("maxmagicians", a_readint); /* factions with differnt magician limits, probably unused */
     at_deprecate("hurting", a_readint); /* an old arena attribute */
     at_deprecate("chaoscount", a_readint); /* used to increase the chance of monster spawns */
diff --git a/src/battle.c b/src/battle.c
index 3f61269a0..1e256f9ca 100644
--- a/src/battle.c
+++ b/src/battle.c
@@ -3577,17 +3577,6 @@ static void join_allies(battle * b)
                 }
                 if (se == s_end)
                     continue;
-                /* Wenn die Einheit belagert ist, mu� auch einer der Alliierten belagert sein: */
-                if (besieged(u)) {
-                    fighter *ally;
-                    for (ally = s->fighters; ally; ally = ally->next) {
-                        if (besieged(ally->unit)) {
-                            break;
-                        }
-                    }
-                    if (ally == NULL)
-                        continue;
-                }
                 /* keine Einw�nde, also soll er mitmachen: */
                 if (c == NULL) {
                     if (!join_battle(b, u, false, &c)) {
diff --git a/src/bind_process.c b/src/bind_process.c
index 947458ce5..58f90076f 100755
--- a/src/bind_process.c
+++ b/src/bind_process.c
@@ -76,10 +76,6 @@ void process_battle(void) {
     do_battles();
 }
 
-void process_siege(void) {
-    process_cmd(K_BESIEGE, siege_cmd, PROC_LAND_REGION);
-}
-
 void process_update_long_order(void) {
     region * r;
     for (r = regions; r; r = r->next) {
diff --git a/src/creport.c b/src/creport.c
index 137259083..ce67493da 100644
--- a/src/creport.c
+++ b/src/creport.c
@@ -645,7 +645,6 @@ static void cr_output_building(struct stream *out, building *b,
     const unit *owner, int fno, faction *f)
 {
     const char *bname, *billusion;
-    int i;
 
     stream_printf(out, "BURG %d\n", b->no);
 
@@ -675,11 +674,6 @@ static void cr_output_building(struct stream *out, building *b,
         stream_printf(out, "%d;Partei\n", fno);
     }
 
-    i = building_get_siege(b);
-    if (i) {
-        stream_printf(out, "%d;Belagerer\n", i);
-    }
-
     cr_output_curses(out, f, b, TYP_BUILDING);
 }
 
@@ -784,7 +778,6 @@ void cr_output_unit(stream *out, const faction * f,
     const item_type *lasttype;
     int pr;
     item *itm, *show = NULL;
-    building *b;
     const char *pzTmp;
     skill *sv;
     item result[MAX_INVENTORY];
@@ -883,9 +876,6 @@ void cr_output_unit(stream *out, const faction * f,
     if (is_guard(u)) {
         stream_printf(out, "%d;bewacht\n", 1);
     }
-    if ((b = usiege(u)) != NULL) {
-        stream_printf(out, "%d;belagert\n", b->no);
-    }
     /* additional information for own units */
     if (u->faction == f || omniscient(f)) {
         order *ord;
diff --git a/src/economy.c b/src/economy.c
index cc611d49d..f0c930a3f 100644
--- a/src/economy.c
+++ b/src/economy.c
@@ -980,11 +980,6 @@ static void allocate_resource(unit * u, const resource_type * rtype, int want)
         }
     }
 
-    if (besieged(u)) {
-        cmistake(u, u->thisorder, 60, MSG_PRODUCE);
-        return;
-    }
-
     if (rtype->modifiers) {
         message *msg = get_modifiers(u, sk, rtype, &save_mod, &skill_mod);
         if (msg) {
@@ -1606,11 +1601,6 @@ static void buy(unit * u, econ_request ** buyorders, struct order *ord)
         cmistake(u, ord, 26, MSG_COMMERCE);
         return;
     }
-    if (besieged(u)) {
-        /* Belagerte Einheiten k�nnen nichts kaufen. */
-        cmistake(u, ord, 60, MSG_COMMERCE);
-        return;
-    }
 
     /* Entweder man ist Insekt in Sumpf/Wueste, oder es muss
      * einen Handelsposten in der Region geben: */
@@ -1930,12 +1920,6 @@ static bool sell(unit * u, econ_request ** sellorders, struct order *ord)
             return false;
         }
     }
-    /* Belagerte Einheiten k�nnen nichts verkaufen. */
-
-    if (besieged(u)) {
-        ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error60", ""));
-        return false;
-    }
     /* In der Region mu� es eine Burg geben. */
 
     if (u_race(u) == get_race(RC_INSECT)) {
@@ -2409,10 +2393,6 @@ void entertain_cmd(unit * u, struct order *ord)
         cmistake(u, ord, 58, MSG_INCOME);
         return;
     }
-    if (besieged(u)) {
-        cmistake(u, ord, 60, MSG_INCOME);
-        return;
-    }
     if (u->ship && is_guarded(r, u)) {
         cmistake(u, ord, 69, MSG_INCOME);
         return;
@@ -2501,11 +2481,6 @@ static int do_work(unit * u, order * ord, econ_request * o)
                 cmistake(u, ord, 313, MSG_INCOME);
             return -1;
         }
-        if (besieged(u)) {
-            if (ord)
-                cmistake(u, ord, 60, MSG_INCOME);
-            return -1;
-        }
         if (u->ship && is_guarded(r, u)) {
             if (ord)
                 cmistake(u, ord, 69, MSG_INCOME);
@@ -2614,10 +2589,6 @@ void tax_cmd(unit * u, struct order *ord, econ_request ** taxorders)
         return;
     }
 
-    if (besieged(u)) {
-        cmistake(u, ord, 60, MSG_INCOME);
-        return;
-    }
     n = armedmen(u, false);
 
     if (!n) {
@@ -2688,10 +2659,6 @@ void loot_cmd(unit * u, struct order *ord, econ_request ** lootorders)
         return;
     }
 
-    if (besieged(u)) {
-        cmistake(u, ord, 60, MSG_INCOME);
-        return;
-    }
     n = armedmen(u, false);
 
     if (!n) {
diff --git a/src/guard.c b/src/guard.c
index 118ede5fc..468dd99bc 100644
--- a/src/guard.c
+++ b/src/guard.c
@@ -105,8 +105,6 @@ static bool is_guardian_r(const unit * guard)
 {
     if (guard->number == 0)
         return false;
-    if (besieged(guard))
-        return false;
 
     /* if region_owners exist then they may be guardians: */
     if (guard->building && rule_region_owners() && guard == building_owner(guard->building)) {
diff --git a/src/jsonconf.test.c b/src/jsonconf.test.c
index 7c15b63f1..9e0e8f6b6 100644
--- a/src/jsonconf.test.c
+++ b/src/jsonconf.test.c
@@ -120,7 +120,7 @@ static void test_disable(CuTest * tc)
     const char * data = "{\"disabled\": [ "
         "\"alchemy\","
         "\"pay\","
-        "\"besiege\","
+        "\"attack\","
         "\"module\""
         "]}";
     cJSON *json = cJSON_Parse(data);
@@ -129,13 +129,13 @@ static void test_disable(CuTest * tc)
     CuAssertTrue(tc, skill_enabled(SK_ALCHEMY));
     CuAssertTrue(tc, !keyword_disabled(K_BANNER));
     CuAssertTrue(tc, !keyword_disabled(K_PAY));
-    CuAssertTrue(tc, !keyword_disabled(K_BESIEGE));
+    CuAssertTrue(tc, !keyword_disabled(K_ATTACK));
     CuAssertIntEquals(tc, 1, config_get_int("module.enabled", 1));
     json_config(json);
     CuAssertTrue(tc, !skill_enabled(SK_ALCHEMY));
     CuAssertTrue(tc, !keyword_disabled(K_BANNER));
     CuAssertTrue(tc, keyword_disabled(K_PAY));
-    CuAssertTrue(tc, keyword_disabled(K_BESIEGE));
+    CuAssertTrue(tc, keyword_disabled(K_ATTACK));
     CuAssertIntEquals(tc, 0, config_get_int("module.enabled", 1));
     cJSON_Delete(json);
     test_teardown();
diff --git a/src/kernel/build.c b/src/kernel/build.c
index 11324f752..4e3dc4721 100644
--- a/src/kernel/build.c
+++ b/src/kernel/build.c
@@ -279,10 +279,6 @@ void build_road(unit * u, int size, direction_t d)
         cmistake(u, u->thisorder, 103, MSG_PRODUCE);
         return;
     }
-    if (besieged(u)) {
-        cmistake(u, u->thisorder, 60, MSG_PRODUCE);
-        return;
-    }
 
     if (rn == NULL || rn->terrain->max_road < 0) {
         cmistake(u, u->thisorder, 94, MSG_PRODUCE);
@@ -780,11 +776,6 @@ build_building(unit * u, const building_type * btype, int id, int want, order *
         cmistake(u, ord, 93, MSG_PRODUCE);
         return 0;
     }
-    if (besieged(u)) {
-        /* units under siege can not build */
-        cmistake(u, ord, 60, MSG_PRODUCE);
-        return 0;
-    }
     if (btype->flags & BTF_NOBUILD) {
         /* special building, cannot be built */
         cmistake(u, ord, 221, MSG_PRODUCE);
@@ -949,10 +940,6 @@ create_ship(unit * u, const struct ship_type *newtype, int want,
         cmistake(u, ord, 100, MSG_PRODUCE);
         return;
     }
-    if (besieged(u)) {
-        cmistake(u, ord, 60, MSG_PRODUCE);
-        return;
-    }
 
     /* check if skill and material for 1 size is available */
     if (effskill(u, cons->skill, 0) < cons->minskill) {
diff --git a/src/kernel/building.c b/src/kernel/building.c
index 9dfc7db35..75cad30f7 100644
--- a/src/kernel/building.c
+++ b/src/kernel/building.c
@@ -870,14 +870,3 @@ int cmp_current_owner(const building * b, const building * a)
     }
     return 0;
 }
-
-int building_get_siege(const struct building *b)
-{
-    return b->_besieged;
-}
-
-int building_add_siege(struct building *b, int delta)
-{
-    b->_besieged += delta;
-    return b->_besieged;
-}
diff --git a/src/kernel/building.h b/src/kernel/building.h
index 319304d79..af605b448 100644
--- a/src/kernel/building.h
+++ b/src/kernel/building.h
@@ -118,7 +118,6 @@ extern "C" {
         int no;
         int size;
         int sizeleft;               /* is only used during battle. should be a temporary attribute */
-        int _besieged;               /* should be an attribute */
         int flags;
     } building;
 
@@ -134,9 +133,6 @@ extern "C" {
         int id, int size, struct order *ord);
     bool building_finished(const struct building *b);
 
-    int building_get_siege(const struct building *b);
-    int building_add_siege(struct building *b, int delta);
-
     int wage(const struct region *r, const struct faction *f,
         const struct race *rc, int in_turn);
 
diff --git a/src/kernel/order.c b/src/kernel/order.c
index c14a2b30b..2fd7c6eb8 100644
--- a/src/kernel/order.c
+++ b/src/kernel/order.c
@@ -373,7 +373,6 @@ bool is_repeated(keyword_t kwd)
     case K_ROUTE:
     case K_DRIVE:
     case K_WORK:
-    case K_BESIEGE:
     case K_ENTERTAIN:
     case K_TAX:
     case K_RESEARCH:
@@ -414,7 +413,6 @@ bool is_exclusive(const order * ord)
     case K_ROUTE:
     case K_DRIVE:
     case K_WORK:
-    case K_BESIEGE:
     case K_ENTERTAIN:
     case K_TAX:
     case K_RESEARCH:
@@ -456,7 +454,6 @@ bool is_long(keyword_t kwd)
     case K_ROUTE:
     case K_DRIVE:
     case K_WORK:
-    case K_BESIEGE:
     case K_ENTERTAIN:
     case K_TAX:
     case K_RESEARCH:
diff --git a/src/kernel/unit.c b/src/kernel/unit.c
index 146761f05..30971310d 100644
--- a/src/kernel/unit.c
+++ b/src/kernel/unit.c
@@ -530,60 +530,6 @@ attrib_type at_target = {
     NO_READ
 };
 
-/*********************/
-/*   at_siege   */
-/*********************/
-
-void a_writesiege(const variant *var, const void *owner, struct storage *store)
-{
-    struct building *b = (struct building *)var->v;
-    write_building_reference(b, store);
-}
-
-int a_readsiege(variant *var, void *owner, gamedata *data)
-{
-    if (read_building_reference(data, (building **)&var->v, NULL) <= 0) {
-        return AT_READ_FAIL;
-    }
-    return AT_READ_OK;
-}
-
-attrib_type at_siege = {
-    "siege",
-    DEFAULT_INIT,
-    DEFAULT_FINALIZE,
-    DEFAULT_AGE,
-    a_writesiege,
-    a_readsiege
-};
-
-struct building *usiege(const unit * u)
-{
-    attrib *a;
-    if (!fval(u, UFL_SIEGE))
-        return NULL;
-    a = a_find(u->attribs, &at_siege);
-    assert(a || !"flag set, but no siege found");
-    return (struct building *)a->data.v;
-}
-
-void usetsiege(unit * u, const struct building *t)
-{
-    attrib *a = a_find(u->attribs, &at_siege);
-    if (!a && t)
-        a = a_add(&u->attribs, a_new(&at_siege));
-    if (a) {
-        if (!t) {
-            a_remove(&u->attribs, a);
-            freset(u, UFL_SIEGE);
-        }
-        else {
-            a->data.v = (void *)t;
-            fset(u, UFL_SIEGE);
-        }
-    }
-}
-
 /*********************/
 /*   at_contact   */
 /*********************/
@@ -1914,16 +1860,6 @@ int getunit(const region * r, const faction * f, unit **uresult)
     return result;
 }
 
-int besieged(const unit * u)
-{
-    /* belagert kann man in schiffen und burgen werden */
-    if (u && !keyword_disabled(K_BESIEGE) && u->building) {
-        building * b = u->building;
-        return building_get_siege(b) >= b->size * SIEGEFACTOR;
-    }
-    return false;
-}
-
 bool has_horses(const unit * u)
 {
     item *itm = u->items;
diff --git a/src/kernel/unit.h b/src/kernel/unit.h
index a6135715c..3f82ef80a 100644
--- a/src/kernel/unit.h
+++ b/src/kernel/unit.h
@@ -47,7 +47,6 @@ extern "C" {
 #define UFL_NOTMOVING     (1<<9)        /* Die Einheit kann sich wg. langen Kampfes nicht bewegen */
 #define UFL_DEFENDER      (1<<10)
 #define UFL_HUNGER        (1<<11)       /* kann im Folgemonat keinen langen Befehl au�er ARBEITE ausf�hren */
-#define UFL_SIEGE         (1<<12)       /* speedup: belagert eine burg, siehe attribut */
 #define UFL_TARGET        (1<<13)       /* speedup: hat ein target, siehe attribut */
 #define UFL_WERE          (1<<14)
 #define UFL_ENTER         (1<<15)       /* unit has entered a ship/building and will not leave it */
@@ -121,7 +120,6 @@ extern "C" {
 
     extern struct attrib_type at_creator;
     extern struct attrib_type at_alias;
-    extern struct attrib_type at_siege;
     extern struct attrib_type at_target;
     extern struct attrib_type at_potionuser;
     extern struct attrib_type at_contact;
@@ -138,8 +136,6 @@ extern "C" {
     const struct race *u_irace(const struct unit *u);
     const struct race *u_race(const struct unit *u);
     void u_setrace(struct unit *u, const struct race *);
-    struct building *usiege(const struct unit *u);
-    void usetsiege(struct unit *u, const struct building *b);
 
     const char *uprivate(const struct unit *u);
     void usetprivate(struct unit *u, const char *c);
@@ -257,7 +253,6 @@ extern "C" {
     int read_unitid(const struct faction *f, const struct region *r);
 
     /* !< sets combatstatus of a unit */
-    int besieged(const struct unit *u);
     bool has_horses(const struct unit *u);
     int maintenance_cost(const struct unit *u);
     bool has_limited_skills(const struct unit *u);
diff --git a/src/keyword.c b/src/keyword.c
index 48726bcbc..47fcc3c8e 100644
--- a/src/keyword.c
+++ b/src/keyword.c
@@ -94,7 +94,7 @@ const char *keywords[MAXKEYWORDS] = {
     "work",
     "attack",
     "steal",
-    "besiege",
+    "deprecated_besiege",
     "name",
     "use",
     "describe",
diff --git a/src/keyword.h b/src/keyword.h
index 6e4832708..bd4ab02d0 100644
--- a/src/keyword.h
+++ b/src/keyword.h
@@ -17,7 +17,7 @@ extern "C"
         K_WORK,
         K_ATTACK,
         K_STEAL,
-        K_BESIEGE,
+        K_BESIEGE_UNUSED,
         K_NAME,
         K_USE,
         K_DISPLAY,
diff --git a/src/laws.c b/src/laws.c
index 67a44c673..0e9285281 100644
--- a/src/laws.c
+++ b/src/laws.c
@@ -901,61 +901,6 @@ void demographics(void)
     immigration();
 }
 
-/* ------------------------------------------------------------- */
-
-/* test if the unit can slip through a siege undetected.
- * returns 0 if siege is successful, or 1 if the building is either
- * not besieged or the unit can slip through the siege due to better stealth.
- */
-static int slipthru(const region * r, const unit * u, const building * b)
-{
-    unit *u2;
-    int n, o;
-
-    /* b ist die burg, in die man hinein oder aus der man heraus will. */
-    if (b == NULL || building_get_siege(b) < b->size * SIEGEFACTOR) {
-        return 1;
-    }
-
-    /* u wird am hinein- oder herausschluepfen gehindert, wenn STEALTH <=
-     * OBSERVATION +2 der belagerer u2 ist */
-    n = effskill(u, SK_STEALTH, r);
-
-    for (u2 = r->units; u2; u2 = u2->next) {
-        if (usiege(u2) == b) {
-
-            if (invisible(u, u2) >= u->number)
-                continue;
-
-            o = effskill(u2, SK_PERCEPTION, r);
-
-            if (o + 2 >= n) {
-                return 0;               /* entdeckt! */
-            }
-        }
-    }
-    return 1;
-}
-
-int can_contact(const region * r, const unit * u, const unit * u2) {
-
-    /* hier geht es nur um die belagerung von burgen */
-    UNUSED_ARG(r);
-    if (u->building == u2->building) {
-        return 1;
-    }
-
-    /* unit u is trying to contact u2 - unasked for contact. wenn u oder u2
-     * nicht in einer burg ist, oder die burg nicht belagert ist, ist
-     * slipthru () == 1. ansonsten ist es nur 1, wenn man die belagerer */
-
-    if (slipthru(u->region, u, u->building) && slipthru(u->region, u2, u2->building)) {
-        return 1;
-    }
-
-    return (alliedunit(u, u2->faction, HELP_GIVE));
-}
-
 int contact_cmd(unit * u, order * ord)
 {
     unit *u2;
@@ -966,10 +911,6 @@ int contact_cmd(unit * u, order * ord)
     u2 = findunit(n);
 
     if (u2 != NULL) {
-        if (!can_contact(u->region, u, u2)) {
-            cmistake(u, u->thisorder, 23, MSG_EVENT);
-            return -1;
-        }
         usetcontact(u, u2);
     }
     return 0;
@@ -994,13 +935,7 @@ int leave_cmd(unit * u, struct order *ord)
             return 0;
         }
     }
-    if (!slipthru(r, u, u->building)) {
-        ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "entrance_besieged",
-            "building", u->building));
-    }
-    else {
-        leave(u, true);
-    }
+    leave(u, true);
     return 0;
 }
 
@@ -1148,13 +1083,6 @@ int enter_building(unit * u, order * ord, int id, bool report)
         }
         return 0;
     }
-    if (!slipthru(r, u, b)) {
-        if (report) {
-            ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "entrance_besieged",
-                "building", b));
-        }
-        return 0;
-    }
 
     if (leave(u, 0)) {
         fset(u, UFL_ENTER);
@@ -3804,98 +3732,6 @@ int armedmen(const unit * u, bool siege_weapons)
     return n;
 }
 
-int siege_cmd(unit * u, order * ord)
-{
-    region *r = u->region;
-    building *b;
-    int d, pooled;
-    int bewaffnete, katapultiere = 0;
-    resource_type *rt_catapultammo = NULL;
-    resource_type *rt_catapult = NULL;
-
-    init_order_depr(ord);
-    b = getbuilding(r);
-
-    if (!b) {
-        cmistake(u, ord, 31, MSG_BATTLE);
-        return 31;
-    }
-
-    if (!playerrace(u_race(u))) {
-        /* keine Drachen, Illusionen, Untote etc */
-        cmistake(u, ord, 166, MSG_BATTLE);
-        return 166;
-    }
-    /* schaden durch katapulte */
-
-    rt_catapultammo = rt_find("catapultammo");
-    rt_catapult = rt_find("catapult");
-
-    d = i_get(u->items, rt_catapult->itype);
-    if (d > u->number) d = u->number;
-    pooled = get_pooled(u, rt_catapultammo, GET_DEFAULT, d);
-    if (d > pooled) d = pooled;
-    if (effskill(u, SK_CATAPULT, 0) >= 1) {
-        katapultiere = d;
-        d *= effskill(u, SK_CATAPULT, 0);
-    }
-    else {
-        d = 0;
-    }
-
-    bewaffnete = armedmen(u, true);
-    if (d == 0 && bewaffnete == 0) {
-        /* abbruch, falls unbewaffnet oder unfaehig, katapulte zu benutzen */
-        cmistake(u, ord, 80, MSG_EVENT);
-        return 80;
-    }
-
-    if (!is_guard(u)) {
-        /* abbruch, wenn die einheit nicht vorher die region bewacht - als
-         * warnung fuer alle anderen! */
-        cmistake(u, ord, 81, MSG_EVENT);
-        return 81;
-    }
-    /* einheit und burg markieren - spart zeit beim behandeln der einheiten
-     * in der burg, falls die burg auch markiert ist und nicht alle
-     * einheiten wieder abgesucht werden muessen! */
-
-    usetsiege(u, b);
-    if (katapultiere < bewaffnete) katapultiere = bewaffnete;
-    building_add_siege(b, katapultiere);
-
-    /* definitiver schaden eingeschraenkt */
-    if (d > b->size - 1) d = b->size - 1;
-
-    /* meldung, schaden anrichten */
-    if (d && !curse_active(get_curse(b->attribs, &ct_magicwalls))) {
-        b->size -= d;
-        use_pooled(u, rt_catapultammo,
-            GET_SLACK | GET_RESERVE | GET_POOLED_SLACK, d);
-        /* send message to the entire region */
-        ADDMSG(&r->msgs, msg_message("siege_catapults",
-            "unit building destruction", u, b, d));
-    }
-    else {
-        /* send message to the entire region */
-        ADDMSG(&r->msgs, msg_message("siege", "unit building", u, b));
-    }
-    return 0;
-}
-
-void do_siege(region * r)
-{
-    if (fval(r->terrain, LAND_REGION)) {
-        unit *u;
-
-        for (u = r->units; u; u = u->next) {
-            if (getkeyword(u->thisorder) == K_BESIEGE) {
-                siege_cmd(u, u->thisorder);
-            }
-        }
-    }
-}
-
 static void enter_1(region * r)
 {
     do_enter(r, 0);
@@ -3979,11 +3815,6 @@ void init_processor(void)
     p += 10;
     add_proc_global(p, do_battles, "Attackieren");
 
-    if (!keyword_disabled(K_BESIEGE)) {
-        p += 10;
-        add_proc_region(p, do_siege, "Belagern");
-    }
-
     p += 10;                      /* can't allow reserve before siege (weapons) */
     add_proc_region(p, enter_1, "Betreten (3. Versuch)");  /* to claim a castle after a victory and to be able to DESTROY it in the same turn */
     if (config_get_int("rules.reserve.twophase", 0)) {
@@ -4201,7 +4032,7 @@ cansee(const faction * f, const region * r, const unit * u, int modifier)
     }
 
     /* simple visibility, just gotta have a viewer in the region to see 'em */
-    if (leftship(u) || is_guard(u) || usiege(u) || u->building || u->ship) {
+    if (leftship(u) || is_guard(u) || u->building || u->ship) {
         return true;
     }
 
@@ -4239,7 +4070,7 @@ bool cansee_unit(const unit * u, const unit * target, int modifier)
     else {
         int n, rings;
 
-        if (is_guard(target) || usiege(target) || target->building
+        if (is_guard(target) || target->building
             || target->ship) {
             return true;
         }
@@ -4282,7 +4113,7 @@ cansee_durchgezogen(const faction * f, const region * r, const unit * u,
     else {
         int rings, n;
 
-        if (is_guard(u) || usiege(u) || u->building || u->ship) {
+        if (is_guard(u) || u->building || u->ship) {
             return true;
         }
 
diff --git a/src/laws.h b/src/laws.h
index 0b5db17c7..b7958891f 100755
--- a/src/laws.h
+++ b/src/laws.h
@@ -48,7 +48,6 @@ extern "C" {
     bool renamed_building(const struct building * b);
     int rename_building(struct unit * u, struct order * ord, struct building * b, const char *name);
     void get_food(struct region * r);
-    int can_contact(const struct region *r, const struct unit *u, const struct unit *u2);
 
     int enter_building(struct unit *u, struct order *ord, int id, bool report);
     int enter_ship(struct unit *u, struct order *ord, int id, bool report);
@@ -82,7 +81,6 @@ extern "C" {
     int quit_cmd(struct unit *u, struct order *ord);
     int name_cmd(struct unit *u, struct order *ord);
     int use_cmd(struct unit *u, struct order *ord);
-    int siege_cmd(struct unit *u, struct order *ord);
     int leave_cmd(struct unit *u, struct order *ord);
     int pay_cmd(struct unit *u, struct order *ord);
     int promotion_cmd(struct unit *u, struct order *ord);
diff --git a/src/laws.test.c b/src/laws.test.c
index fb644dc90..778ee3323 100644
--- a/src/laws.test.c
+++ b/src/laws.test.c
@@ -95,38 +95,6 @@ static void test_rename_building_twice(CuTest * tc)
     test_teardown();
 }
 
-static void test_contact(CuTest * tc)
-{
-    region *r;
-    unit *u1, *u2, *u3;
-    building *b;
-    building_type *btype;
-    ally *al;
-
-    test_setup();
-    test_create_locale();
-    btype = test_create_buildingtype("castle");
-    r = test_create_region(0, 0, NULL);
-    b = new_building(btype, r, default_locale);
-    u1 = test_create_unit(test_create_faction(NULL), r);
-    u2 = test_create_unit(test_create_faction(NULL), r);
-    u3 = test_create_unit(test_create_faction(NULL), r);
-    set_level(u3, SK_PERCEPTION, 2);
-    usetsiege(u3, b);
-    building_add_siege(b, 1);
-    CuAssertIntEquals(tc, 1, building_get_siege(b));
-    CuAssertIntEquals(tc, 1, can_contact(r, u1, u2));
-
-    u_set_building(u1, b);
-    CuAssertIntEquals(tc, 0, can_contact(r, u1, u2));
-    al = ally_add(&u1->faction->allies, u2->faction);
-    al->status = HELP_ALL;
-    CuAssertIntEquals(tc, HELP_GIVE, can_contact(r, u1, u2));
-    u_set_building(u2, b);
-    CuAssertIntEquals(tc, 1, can_contact(r, u1, u2));
-    test_teardown();
-}
-
 static void test_enter_building(CuTest * tc)
 {
     unit *u;
@@ -1833,7 +1801,6 @@ CuSuite *get_laws_suite(void)
     SUITE_ADD_TEST(suite, test_pay_cmd_must_be_owner);
     SUITE_ADD_TEST(suite, test_new_units);
     SUITE_ADD_TEST(suite, test_cannot_create_unit_above_limit);
-    SUITE_ADD_TEST(suite, test_contact);
     SUITE_ADD_TEST(suite, test_enter_building);
     SUITE_ADD_TEST(suite, test_enter_ship);
     SUITE_ADD_TEST(suite, test_display_cmd);
diff --git a/src/process.pkg b/src/process.pkg
index a81917293..89e8f2fa7 100755
--- a/src/process.pkg
+++ b/src/process.pkg
@@ -21,7 +21,6 @@ module eressea {
         void process_movement @ movement(void); /* MOVE/FOLLOW/ROUTE */
         void process_use @ use(void); /* USE */
         void process_battle @ battle(void); /* ATTACK */
-        void process_siege @ siege(void); /* SIEGE */
         void process_leave @ leave(void); /* LEAVE */
         void process_maintenance @ maintenance(void); /* PAY */
         void process_promote @ promote(void); /* PROMOTE */
diff --git a/src/process.pkg.c b/src/process.pkg.c
index 42dff20ff..3e818f7ce 100644
--- a/src/process.pkg.c
+++ b/src/process.pkg.c
@@ -435,30 +435,6 @@ static int tolua_process_eressea_process_battle00(lua_State* tolua_S)
 #endif
 }
 
-/* function: process_siege */
-static int tolua_process_eressea_process_siege00(lua_State* tolua_S)
-{
-#ifndef TOLUA_RELEASE
- tolua_Error tolua_err;
- if (
- !tolua_isnoobj(tolua_S,1,&tolua_err)
- )
- goto tolua_lerror;
- else
-#endif
- {
- {
-  process_siege();
- }
- }
- return 0;
-#ifndef TOLUA_RELEASE
- tolua_lerror:
- tolua_error(tolua_S,"#ferror in function 'siege'.",&tolua_err);
- return 0;
-#endif
-}
-
 /* function: process_leave */
 static int tolua_process_eressea_process_leave00(lua_State* tolua_S)
 {
@@ -993,7 +969,6 @@ LUALIB_API int luaopen_process (lua_State* tolua_S)
  tolua_function(tolua_S,"movement",tolua_process_eressea_process_movement00);
  tolua_function(tolua_S,"use",tolua_process_eressea_process_use00);
  tolua_function(tolua_S,"battle",tolua_process_eressea_process_battle00);
- tolua_function(tolua_S,"siege",tolua_process_eressea_process_siege00);
  tolua_function(tolua_S,"leave",tolua_process_eressea_process_leave00);
  tolua_function(tolua_S,"maintenance",tolua_process_eressea_process_maintenance00);
  tolua_function(tolua_S,"promote",tolua_process_eressea_process_promote00);
diff --git a/src/report.c b/src/report.c
index 7de2550a4..29f124cef 100644
--- a/src/report.c
+++ b/src/report.c
@@ -1821,7 +1821,6 @@ nr_building(struct stream *out, const region *r, const building *b, const factio
     const char *name, *bname, *billusion = NULL;
     const struct locale *lang;
     char buffer[8192];
-    message *msg;
     size_t size;
     sbstring sbs;
 
@@ -1853,17 +1852,6 @@ nr_building(struct stream *out, const region *r, const building *b, const factio
         sbs_strcat(&sbs, LOC(lang, "nr_building_inprogress"));
     }
 
-    if (!keyword_disabled(K_BESIEGE) && r->seen.mode >= seen_lighthouse) {
-        int s = building_get_siege(b);
-        if (s > 0) {
-            msg = msg_message("nr_building_besieged", "soldiers diff", s,
-                s - b->size * SIEGEFACTOR);
-            size = nr_render(msg, lang, sbs.end, sbs.size - (sbs.end - sbs.begin), f);
-            sbs.end += size;
-
-            msg_release(msg);
-        }
-    }
     i = 0;
     if (b->display && b->display[0]) {
         sbs_strcat(&sbs, "; ");
diff --git a/src/reports.c b/src/reports.c
index 9d9ab5f6f..25c331a9f 100644
--- a/src/reports.c
+++ b/src/reports.c
@@ -683,7 +683,6 @@ bufunit(const faction * f, const unit * u, seen_mode mode, char *buf,
     int i, dh;
     int getarnt = fval(u, UFL_ANON_FACTION);
     const char *pzTmp, *str;
-    building *b;
     bool isbattle = (bool)(mode == seen_battle);
     item *itm, *show = NULL;
     faction *fv;
@@ -807,11 +806,6 @@ bufunit(const faction * f, const unit * u, seen_mode mode, char *buf,
         bufp = STRLCPY(bufp, LOC(lang, "unit_guards"), size);
     }
 
-    if ((b = usiege(u)) != NULL) {
-        bufp = STRLCPY(bufp, ", belagert ", size);
-        bufp = STRLCPY(bufp, buildingname(b), size);
-    }
-
     dh = 0;
     if (u->faction == f) {
         skill *sv;
diff --git a/src/spy.c b/src/spy.c
index ae70f4db8..9dc9de35a 100644
--- a/src/spy.c
+++ b/src/spy.c
@@ -137,10 +137,6 @@ int spy_cmd(unit * u, struct order *ord)
             msg_feedback(u, u->thisorder, "feedback_unit_not_found", ""));
         return 0;
     }
-    if (!can_contact(r, u, target)) {
-        cmistake(u, u->thisorder, 24, MSG_EVENT);
-        return 0;
-    }
     if (effskill(u, SK_SPY, 0) < 1) {
         cmistake(u, u->thisorder, 39, MSG_EVENT);
         return 0;
diff --git a/src/spy.test.c b/src/spy.test.c
index 0224698a0..d8b879e3f 100644
--- a/src/spy.test.c
+++ b/src/spy.test.c
@@ -198,17 +198,17 @@ static void test_setstealth_cmd(CuTest *tc) {
     test_setup();
     u = test_create_unit(test_create_faction(NULL), test_create_plain(0, 0));
     lang = u->faction->locale;
-    u->flags = UFL_ANON_FACTION | UFL_SIEGE;
+    u->flags = UFL_ANON_FACTION | UFL_DEFENDER;
     u->thisorder = create_order(K_SETSTEALTH, lang, "%s %s",
         LOC(lang, parameters[P_FACTION]),
         LOC(lang, parameters[P_NOT]));
     setstealth_cmd(u, u->thisorder);
-    CuAssertIntEquals(tc, UFL_SIEGE, u->flags);
+    CuAssertIntEquals(tc, UFL_DEFENDER, u->flags);
     free_order(u->thisorder);
     u->thisorder = create_order(K_SETSTEALTH, lang, "%s",
         LOC(lang, parameters[P_FACTION]));
     setstealth_cmd(u, u->thisorder);
-    CuAssertIntEquals(tc, UFL_SIEGE | UFL_ANON_FACTION, u->flags);
+    CuAssertIntEquals(tc, UFL_DEFENDER | UFL_ANON_FACTION, u->flags);
     test_teardown();
 }
 
diff --git a/src/steal.c b/src/steal.c
index 68a4239ec..8a390c8fb 100644
--- a/src/steal.c
+++ b/src/steal.c
@@ -188,10 +188,6 @@ void steal_cmd(unit * u, struct order *ord, econ_request ** stealorders)
     }
 
     assert(u->region == u2->region);
-    if (!can_contact(r, u, u2)) {
-        ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error60", ""));
-        return;
-    }
 
     effsk = effskill(u, SK_STEALTH, 0);
     n = effsk - max_skill(r, f, SK_PERCEPTION);

From 418d6b1f6c5c2471553998b075f7edba360df3d1 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno@kn-bremen.de>
Date: Mon, 10 Sep 2018 17:52:23 +0200
Subject: [PATCH 09/81] =?UTF-8?q?Bug=202486:=20spawn=5Fchance=20f=C3=BCr?=
 =?UTF-8?q?=20Drachen=20und=20Seeschlangen=20war=20zu=20hoch.?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/monsters.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/monsters.c b/src/monsters.c
index a2d2b2121..d009f8bda 100644
--- a/src/monsters.c
+++ b/src/monsters.c
@@ -876,7 +876,7 @@ void spawn_dragons(void)
     region *r;
     faction *monsters = get_or_create_monsters();
     int minage = config_get_int("monsters.spawn.min_age", 100);
-    int spawn_chance = config_get_int("monsters.spawn.chance", 100);
+    int spawn_chance = config_get_int("monsters.spawn.chance", 100) * 100;
 
     if (spawn_chance <= 0) {
         /* monster spawning disabled */

From bca987ee64b2e4da55dc14afb008d9abd6fb479a Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno@kn-bremen.de>
Date: Mon, 10 Sep 2018 17:54:39 +0200
Subject: [PATCH 10/81] force tag update after release

---
 s/release | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/s/release b/s/release
index 89b2bd9e9..1d10ac125 100755
--- a/s/release
+++ b/s/release
@@ -5,6 +5,6 @@ import sys
 
 def new_version(ver):
     os.system("git tag -f v%s" % ver)
-    os.system("git push --tags")
+    os.system("git push --tags -f")
 
 new_version(sys.argv[1])

From d32689bac898bb9614632b55f769bae865f09d5f Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Mon, 10 Sep 2018 17:58:10 +0200
Subject: [PATCH 11/81] experiments with clang-tidy

---
 src/academy.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/academy.c b/src/academy.c
index 1298e9b57..538d36e06 100644
--- a/src/academy.c
+++ b/src/academy.c
@@ -16,8 +16,8 @@ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 **/
 
-#include <platform.h>
-#include <kernel/config.h>
+#include "platform.h"
+#include "kernel/config.h"
 #include <kernel/unit.h>
 #include <kernel/building.h>
 #include <kernel/item.h>

From 12fd6435c5346b8d8edd12125a32affe64895140 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Mon, 10 Sep 2018 18:17:34 +0200
Subject: [PATCH 12/81] eliminate apparently dead code, and coverity warning.

---
 src/util/message.c | 8 +-------
 1 file changed, 1 insertion(+), 7 deletions(-)

diff --git a/src/util/message.c b/src/util/message.c
index 8915dca8f..d8c66f5e0 100644
--- a/src/util/message.c
+++ b/src/util/message.c
@@ -86,13 +86,7 @@ static void mt_register(message_type * mtype) {
 
 message_type *mt_create(message_type * mtype, const char *args[], int nparameters)
 {
-    if (args != NULL && args[nparameters]) {
-        /* count the number of parameters */
-        do {
-            ++nparameters;
-        } while (args[nparameters]);
-    }
-    if (nparameters > 0) {
+    if (args && nparameters > 0) {
         int i;
         mtype->nparameters = nparameters;
         mtype->pnames = (char **)malloc(sizeof(char *) * nparameters);

From ecaf72324cdd91597c0f2bccdc7ae77b2f52019a Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Mon, 10 Sep 2018 19:50:22 +0200
Subject: [PATCH 13/81] Bug 2481: FOLGE wurde durch ZAUBERE verhindert.

---
 src/move.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/move.c b/src/move.c
index b815f5ea5..7f56932d8 100644
--- a/src/move.c
+++ b/src/move.c
@@ -2633,9 +2633,9 @@ void follow_unit(unit * u)
             }
         }
         if (follow) {
-            fset(u, UFL_FOLLOWING);
             fset(u2, UFL_FOLLOWED);
             /* FOLLOW unit on a (potentially) moving unit prevents long orders */
+            fset(u, UFL_FOLLOWING | UFL_LONGACTION);
             set_order(&u->thisorder, NULL);
         }
     }

From d6e8b38724f4b5164f012c1aacd9e207f6bb4837 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Wed, 12 Sep 2018 20:35:27 +0200
Subject: [PATCH 14/81] FOLGE SCHIFF reparieren (hat UFL_LONGORDER getestet).

---
 scripts/tests/e2/astral.lua   | 6 ------
 scripts/tests/e2/init.lua     | 8 +++++++-
 scripts/tests/e2/movement.lua | 3 ++-
 src/move.c                    | 2 +-
 4 files changed, 10 insertions(+), 9 deletions(-)

diff --git a/scripts/tests/e2/astral.lua b/scripts/tests/e2/astral.lua
index efed6345f..1573c9af2 100644
--- a/scripts/tests/e2/astral.lua
+++ b/scripts/tests/e2/astral.lua
@@ -13,12 +13,6 @@ function setup()
     eressea.settings.set("magic.regeneration.enable", "0")
 end
 
-local function dump_messages(f)
-    for k, v in ipairs(f.messages) do
-        print(v)
-    end
-end
-
 function test_fetch_astral()
     local r = region.create(0, 0, "plain")
     local f = faction.create("human")
diff --git a/scripts/tests/e2/init.lua b/scripts/tests/e2/init.lua
index 5c942fc74..55feab5bf 100644
--- a/scripts/tests/e2/init.lua
+++ b/scripts/tests/e2/init.lua
@@ -1,3 +1,10 @@
+function dump_messages(f)
+    for k, v in ipairs(f.messages) do
+        print(v)
+    end
+end
+
+require 'tests.e2.movement'
 require 'tests.e2.astral'
 require 'tests.e2.spells'
 require 'tests.e2.e2features'
@@ -7,7 +14,6 @@ require 'tests.e2.production'
 require 'tests.e2.adamantium'
 require 'tests.e2.undead'
 require 'tests.e2.shiplanding'
-require 'tests.e2.movement'
 require 'tests.e2.destroy'
 require 'tests.e2.guard'
 require 'tests.e2.stealth'
diff --git a/scripts/tests/e2/movement.lua b/scripts/tests/e2/movement.lua
index fb82567af..57d2413c4 100644
--- a/scripts/tests/e2/movement.lua
+++ b/scripts/tests/e2/movement.lua
@@ -9,7 +9,7 @@ function setup()
     eressea.settings.set("NewbieImmunity", "0")
 end
 
- function test_piracy()
+function test_piracy()
     local r = region.create(0, 0, "plain")
     local r2 = region.create(1, 0, "plain")
     local r3 = region.create(-1, 0, "ocean")
@@ -96,6 +96,7 @@ function test_follow_ship()
     local f = faction.create("human", "test@example.com", "de")
     local u1 = unit.create(f, r1, 1)
     local u2 = unit.create(f, r1, 1)
+    u2.name = 'Xolgrim'
     u1:add_item("money", 100)
     u2:add_item("money", 100)
     u1.ship = ship.create(r1, "boat")
diff --git a/src/move.c b/src/move.c
index 7f56932d8..5e8c56235 100644
--- a/src/move.c
+++ b/src/move.c
@@ -2368,7 +2368,7 @@ static void move_hunters(void)
                             break;
                         }
 
-                        if (!fval(u, UFL_LONGACTION) && !LongHunger(u) && follow_ship(u, ord)) {
+                        if (!LongHunger(u) && follow_ship(u, ord)) {
                             up = &r->units;
                             break;
                         }

From a876a60b6855c7e034ac3c229657934b741a6158 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Thu, 13 Sep 2018 16:16:32 +0200
Subject: [PATCH 15/81] Stop using player email to set faction name.

---
 src/economy.test.c  |  1 +
 src/gmtool.c        | 10 ----------
 src/races/races.c   |  2 --
 src/races/zombies.c | 23 -----------------------
 src/tests.c         | 24 ++++++++++++++++++++++++
 5 files changed, 25 insertions(+), 35 deletions(-)

diff --git a/src/economy.test.c b/src/economy.test.c
index 90a4bd260..1a40c03db 100644
--- a/src/economy.test.c
+++ b/src/economy.test.c
@@ -487,6 +487,7 @@ static void test_recruit_insect(CuTest *tc) {
 
     test_setup();
     test_create_calendar();
+    test_create_terrain("desert", -1);
     f = test_create_faction(test_create_race("insect"));
     u = test_create_unit(f, test_create_region(0, 0, NULL));
     u->thisorder = create_order(K_RECRUIT, f->locale, "%d", 1);
diff --git a/src/gmtool.c b/src/gmtool.c
index fdbfd3faa..c2193bd32 100644
--- a/src/gmtool.c
+++ b/src/gmtool.c
@@ -932,20 +932,10 @@ static void seed_player(state *st, const newfaction *player) {
         pnormalize(&nx, &ny, st->cursor.pl);
         r = findregion(nx, ny);
         if (r) {
-            const char *at = strchr(player->email, '@');
             faction *f;
             addplayer(r, f = addfaction(player->email, player->password,
                                         player->race, player->lang,
                                         player->subscription));
-            if (at) {
-                char fname[64];
-                size_t len = at - player->email;
-                if (len>4 && len<sizeof(fname)) {
-                    memcpy(fname, player->email, len);
-                    fname[len]=0;
-                    faction_setname(f, fname);
-                }
-            }
         }
     }
 }
diff --git a/src/races/races.c b/src/races/races.c
index 120a15dd9..44ca5d95e 100644
--- a/src/races/races.c
+++ b/src/races/races.c
@@ -30,7 +30,6 @@
 
 void age_firedragon(struct unit *u);
 void age_dragon(struct unit *u);
-void age_undead(struct unit *u);
 void age_skeleton(struct unit *u);
 void age_zombie(struct unit *u);
 void age_ghoul(struct unit *u);
@@ -81,7 +80,6 @@ void equip_newunits(struct unit *u)
 void register_races(void)
 {
     /* function age for race->age() */
-    register_function((pf_generic)age_undead, "age_undead");
     register_function((pf_generic)age_skeleton, "age_skeleton");
     register_function((pf_generic)age_zombie, "age_zombie");
     register_function((pf_generic)age_ghoul, "age_ghoul");
diff --git a/src/races/zombies.c b/src/races/zombies.c
index de3d81972..3c880d819 100644
--- a/src/races/zombies.c
+++ b/src/races/zombies.c
@@ -40,29 +40,6 @@ void make_undead_unit(unit * u)
     u->flags |= UFL_ISNEW;
 }
 
-void age_undead(unit * u)
-{
-    region *r = u->region;
-
-    /* untote, die einer partei angehoeren, koennen sich
-     * absplitten, anstatt sich zu vermehren. monster
-     * untote vermehren sich nur noch */
-
-    if (u->number > UNDEAD_MIN && !is_monsters(u->faction)
-        && rng_int() % 100 < UNDEAD_BREAKUP) {
-        int m, n = 0;
-        unit *u2;
-
-        for (m = u->number; m; m--) {
-            if (rng_int() % 100 < UNDEAD_BREAKUP_FRACTION)
-                ++n;
-        }
-        u2 = create_unit(r, get_monsters(), 0, get_race(RC_UNDEAD), 0, NULL, u);
-        make_undead_unit(u2);
-        transfermen(u, u2, u->number - n);
-    }
-}
-
 void age_skeleton(unit * u)
 {
     if (is_monsters(u->faction) && rng_int() % 100 < age_chance(u->age, 27, 1)) {
diff --git a/src/tests.c b/src/tests.c
index 4ee38d195..6395b4fcb 100644
--- a/src/tests.c
+++ b/src/tests.c
@@ -13,6 +13,7 @@
 #include <kernel/plane.h>
 #include <kernel/region.h>
 #include <kernel/terrain.h>
+#include <kernel/terrainid.h>
 #include <kernel/item.h>
 #include <kernel/unit.h>
 #include <kernel/order.h>
@@ -238,6 +239,29 @@ 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);
     }

From 681cf32e1f82a650f37ee2eba927b4e9ca57fab0 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sat, 15 Sep 2018 18:35:27 +0200
Subject: [PATCH 16/81] remove besiege from keywords[] array fix broken at_keys
 attributes remove unused global.attribs

---
 scripts/tests/e3/rules.lua |  7 ++--
 src/attributes/key.c       | 79 +++++++++++++++++++++++++++++++++-----
 src/bindings.c             | 25 ------------
 src/jsonconf.c             |  2 +-
 src/kernel/config.c        |  4 --
 src/kernel/config.h        |  1 -
 src/kernel/save.c          | 11 ++++--
 src/keyword.c              |  6 +--
 src/tests.c                |  4 +-
 src/util/gamedata.h        |  3 +-
 10 files changed, 88 insertions(+), 54 deletions(-)

diff --git a/scripts/tests/e3/rules.lua b/scripts/tests/e3/rules.lua
index 6d3e56d1a..b262f99a6 100644
--- a/scripts/tests/e3/rules.lua
+++ b/scripts/tests/e3/rules.lua
@@ -953,12 +953,11 @@ function test_bug2083()
     -- this is a bit weird, but the bug was caused by market code
     -- being called in two places. We want to make sure this doesn't happen
     for k, v in pairs(rules) do
-        set_key("xm09", true)
-    	if 'table' == type(v) then
+        if 'table' == type(v) then
            cb = v['update']
-	   if 'function' == type(cb) then
+            if 'function' == type(cb) then
               cb()
-	   end
+            end
         end
      end
 
diff --git a/src/attributes/key.c b/src/attributes/key.c
index 75958a6fb..1808c561f 100644
--- a/src/attributes/key.c
+++ b/src/attributes/key.c
@@ -25,6 +25,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <util/log.h>
 #include <storage.h>
 
+#include <errno.h>
 #include <stdlib.h>
 #include <string.h>
 #include <assert.h>
@@ -76,25 +77,83 @@ static int keys_size(int n) {
     return 4096;
 }
 
+static int read_flags(gamedata *data, int *keys, int n) {
+    int i;
+    for (i = 0; i != n; ++i) {
+        int key;
+        READ_INT(data->store, &key);
+        keys[i * 2] = key;
+        keys[i * 2 + 1] = 1;
+    }
+    return n;
+}
+
+#ifdef KEYVAL_VERSION
+static int read_keyval(gamedata *data, int *keys, int n) {
+    int i;
+    for (i = 0; i != n; ++i) {
+        int key, val;
+        READ_INT(data->store, &key);
+        READ_INT(data->store, &val);
+        keys[i * 2] = key;
+        keys[i * 2 + 1] = val;
+    }
+    return n;
+}
+#endif
+
+#ifdef FIXATKEYS_VERSION
+static int read_keyval_orig(gamedata *data, int *keys, int n) {
+    int i, j = 0, dk = -1;
+    for (i = 0; i != n; ++i) {
+        int key, val;
+        READ_INT(data->store, &key);
+        READ_INT(data->store, &val);
+        if (key > dk) {
+            keys[j * 2] = key;
+            keys[j * 2 + 1] = val;
+            dk = key;
+            ++j;
+        }
+    }
+    return j;
+}
+#endif
+
 static int a_readkeys(variant *var, void *owner, gamedata *data) {
-    int i, n, *keys;
+    int i, n, ksn, *keys;
 
     READ_INT(data->store, &n);
     assert(n < 4096 && n >= 0);
     if (n == 0) {
         return AT_READ_FAIL;
     }
-    keys = malloc(sizeof(int)*(keys_size(n) * 2 + 1));
-    *keys = n;
-    for (i = 0; i != n; ++i) {
-        READ_INT(data->store, keys + i * 2 + 1);
-        if (data->version >= KEYVAL_VERSION) {
-            READ_INT(data->store, keys + i * 2 + 2);
-        }
-        else {
-            keys[i * 2 + 2] = 1;
+    ksn = keys_size(n);
+    keys = malloc((ksn * 2 + 1) * sizeof(int));
+    if (data->version >= FIXATKEYS_VERSION) {
+        n = read_keyval(data, keys + 1, n);
+    }
+    else if (data->version >= KEYVAL_VERSION) {
+        int m = read_keyval_orig(data, keys + 1, n);
+        if (n != m) {
+            int ksm = keys_size(m);
+            if (ksm != ksn) {
+                int *nkeys = (int *)realloc(keys, (ksm * 2 + 1) * sizeof(int));
+                if (nkeys != NULL) {
+                    keys = nkeys;
+                }
+                else {
+                    log_error("a_readkeys allocation failed: %s", strerror(errno));
+                    return AT_READ_FAIL;
+                }
+            }
+            n = m;
         }
     }
+    else {
+        n = read_flags(data, keys + 1, n);
+    }
+    keys[0] = n;
     if (data->version < SORTKEYS_VERSION) {
         int e = 1;
         for (i = 1; i != n; ++i) {
diff --git a/src/bindings.c b/src/bindings.c
index d72bddac2..bdf03afdf 100755
--- a/src/bindings.c
+++ b/src/bindings.c
@@ -153,15 +153,6 @@ int tolua_itemlist_next(lua_State * L)
     return 0;
 }
 
-static int tolua_getkey(lua_State * L)
-{
-    const char *name = tolua_tostring(L, 1, 0);
-    int flag = atoi36(name);
-
-    lua_pushboolean(L, key_get(global.attribs, flag));
-    return 1;
-}
-
 static int tolua_translate(lua_State * L)
 {
     const char *str = tolua_tostring(L, 1, 0);
@@ -175,20 +166,6 @@ static int tolua_translate(lua_State * L)
     return 0;
 }
 
-static int tolua_setkey(lua_State * L)
-{
-    const char *name = tolua_tostring(L, 1, 0);
-    int value = (int)tolua_tonumber(L, 3, 0);
-    int flag = atoi36(name);
-    if (value) {
-        key_set(&global.attribs, flag, value);
-    }
-    else {
-        key_unset(&global.attribs, flag);
-    }
-    return 0;
-}
-
 static int tolua_random(lua_State * L)
 {
     lua_pushinteger(L, rng_int());
@@ -1003,8 +980,6 @@ int tolua_bindings_open(lua_State * L, const dictionary *inifile)
         tolua_function(L, TOLUA_CAST "update_owners", tolua_update_owners);
         tolua_function(L, TOLUA_CAST "learn_skill", tolua_learn_skill);
         tolua_function(L, TOLUA_CAST "create_curse", tolua_create_curse);
-        tolua_function(L, TOLUA_CAST "get_key", tolua_getkey);
-        tolua_function(L, TOLUA_CAST "set_key", tolua_setkey);
         tolua_function(L, TOLUA_CAST "translate", &tolua_translate);
         tolua_function(L, TOLUA_CAST "spells", tolua_get_spells);
         tolua_function(L, TOLUA_CAST "equip_newunits", tolua_equip_newunits);
diff --git a/src/jsonconf.c b/src/jsonconf.c
index fcd6f5c78..51116691f 100644
--- a/src/jsonconf.c
+++ b/src/jsonconf.c
@@ -846,7 +846,7 @@ static void json_keyword(cJSON *json, struct locale *lang) {
     }
     for (child = json->child; child; child = child->next) {
         keyword_t kwd = findkeyword(child->string);
-        if (kwd != NOKEYWORD) {
+        if (kwd != NOKEYWORD && keywords[kwd]) {
             if (child->type == cJSON_String) {
                 init_keyword(lang, kwd, child->valuestring);
                 locale_setstring(lang, mkname("keyword", keywords[kwd]), child->valuestring);
diff --git a/src/kernel/config.c b/src/kernel/config.c
index 750d406f6..eee2ec0f5 100644
--- a/src/kernel/config.c
+++ b/src/kernel/config.c
@@ -767,10 +767,6 @@ void free_gamedata(void)
     free_borders();
     free_alliances();
 
-    while (global.attribs) {
-        a_remove(&global.attribs, global.attribs);
-    }
-
     while (planes) {
         plane *pl = planes;
         planes = planes->next;
diff --git a/src/kernel/config.h b/src/kernel/config.h
index 94abcb7f4..e104d4a1a 100644
--- a/src/kernel/config.h
+++ b/src/kernel/config.h
@@ -109,7 +109,6 @@ extern "C" {
 
     /* globale settings des Spieles */
     typedef struct settings {
-        struct attrib *attribs;
         void *vm_state;
     } settings;
 
diff --git a/src/kernel/save.c b/src/kernel/save.c
index b51e82734..51585f26c 100644
--- a/src/kernel/save.c
+++ b/src/kernel/save.c
@@ -1392,7 +1392,13 @@ int read_game(gamedata *data)
     else {
         READ_STR(store, NULL, 0);
     }
-    read_attribs(data, &global.attribs, NULL);
+
+    if (data->version < FIXATKEYS_VERSION) {
+        attrib *a = NULL;
+        read_attribs(data, &a, NULL);
+        a_removeall(&a, NULL);
+    }
+
     READ_INT(store, &turn);
     log_debug(" - reading turn %d", turn);
     rng_init(turn + config_get_int("game.seed", 0));
@@ -1614,9 +1620,6 @@ int write_game(gamedata *data) {
     WRITE_INT(store, game_id());
     WRITE_SECTION(store);
 
-    write_attribs(store, global.attribs, NULL);
-    WRITE_SECTION(store);
-
     WRITE_INT(store, turn);
     WRITE_INT(store, 0 /* max_unique_id */);
     WRITE_INT(store, nextborder);
diff --git a/src/keyword.c b/src/keyword.c
index 47fcc3c8e..e2b5b4775 100644
--- a/src/keyword.c
+++ b/src/keyword.c
@@ -15,7 +15,7 @@
 const char * keyword(keyword_t kwd)
 {
     static char result[32]; /* FIXME: static return value */
-    if (kwd==NOKEYWORD) {
+    if (kwd==NOKEYWORD || keywords[kwd] == NULL) {
         return NULL;
     }
     if (!result[0]) {
@@ -43,7 +43,7 @@ void init_keywords(const struct locale *lang) {
 keyword_t findkeyword(const char *s) {
     int i;
     for (i = 0; i != MAXKEYWORDS; ++i) {
-        if (strcmp(s, keywords[i]) == 0) {
+        if (keywords[i] && (strcmp(s, keywords[i]) == 0)) {
             return (keyword_t)i;
         }
     }
@@ -94,7 +94,7 @@ const char *keywords[MAXKEYWORDS] = {
     "work",
     "attack",
     "steal",
-    "deprecated_besiege",
+    NULL,
     "name",
     "use",
     "describe",
diff --git a/src/tests.c b/src/tests.c
index 6395b4fcb..ddd6f7cf5 100644
--- a/src/tests.c
+++ b/src/tests.c
@@ -147,7 +147,9 @@ struct locale * test_create_locale(void) {
             locale_setstring(loc, combatstatus[i], combatstatus[i] + 7);
         }
         for (i = 0; i != MAXKEYWORDS; ++i) {
-            locale_setstring(loc, mkname("keyword", keywords[i]), keywords[i]);
+            if (keywords[i]) {
+                locale_setstring(loc, mkname("keyword", keywords[i]), keywords[i]);
+            }
         }
         for (i = 0; i != MAXPARAMS; ++i) {
             locale_setstring(loc, parameters[i], parameters[i]);
diff --git a/src/util/gamedata.h b/src/util/gamedata.h
index 22c1d9052..2dd4e1342 100644
--- a/src/util/gamedata.h
+++ b/src/util/gamedata.h
@@ -36,10 +36,11 @@
 #define FAMILIAR_FIX_VERSION 359 /* familiar links are fixed */
 #define SKILLSORT_VERSION 360 /* u->skills is sorted */
 #define LANDDISPLAY_VERSION 360 /* r.display is now in r.land.display */
+#define FIXATKEYS_VERSION 361 /* remove global.attribs, fix at_keys */
 /* unfinished: */
 #define CRYPT_VERSION 400 /* passwords are encrypted */
 
-#define RELEASE_VERSION LANDDISPLAY_VERSION /* current datafile */
+#define RELEASE_VERSION FIXATKEYS_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 */
 

From 658b47aeb4a8302515e26016094bc72463ad3c61 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sat, 15 Sep 2018 19:12:32 +0200
Subject: [PATCH 17/81] remove seaserpent test that is not a test.

---
 scripts/tests/e2/e2features.lua | 13 -------------
 1 file changed, 13 deletions(-)

diff --git a/scripts/tests/e2/e2features.lua b/scripts/tests/e2/e2features.lua
index 54033d496..acd2f1e03 100644
--- a/scripts/tests/e2/e2features.lua
+++ b/scripts/tests/e2/e2features.lua
@@ -541,16 +541,3 @@ function test_buy_sell()
     assert_equal(4, u:get_item(item))
     assert_not_equal(0, u:get_item('money'))
 end
-
-function test_seaserpent_attack()
-    local r = region.create(0, 0, 'ocean')
-    local sh = ship.create(r, 'boat')
-    local us = unit.create(get_monsters(), r, 1, 'seaserpent')
-    local u = unit.create(faction.create('human', 'enno@example.com'), r, 20, 'human')
-    u.ship = sh
-    us:clear_orders()
-    us:add_order('ATTACKIERE ' .. itoa36(u.id))
-    us:set_skill('unarmed', 10)
-    process_orders()
-    write_reports()
-end

From 65675d19478e19e13d0db58be7bf47aa7f809bf5 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sun, 16 Sep 2018 10:02:09 +0200
Subject: [PATCH 18/81] Fix crash when removing drifted ships.

---
 src/move.c | 53 +++++++++++++++++++++++------------------------------
 src/move.h |  2 +-
 2 files changed, 24 insertions(+), 31 deletions(-)

diff --git a/src/move.c b/src/move.c
index b815f5ea5..70425b72e 100644
--- a/src/move.c
+++ b/src/move.c
@@ -630,7 +630,7 @@ mark_travelthru(unit * u, region * r, const region_list * route,
     }
 }
 
-ship *move_ship(ship * sh, region * from, region * to, region_list * route)
+void move_ship(ship * sh, region * from, region * to, region_list * route)
 {
     unit **iunit = &from->units;
     unit **ulist = &to->units;
@@ -663,8 +663,6 @@ ship *move_ship(ship * sh, region * from, region * to, region_list * route)
         if (*iunit == u)
             iunit = &u->next;
     }
-
-    return sh;
 }
 
 static bool is_freezing(const unit * u)
@@ -857,39 +855,34 @@ static void drifting_ships(region * r)
                 }
             }
 
-            if (rnext != NULL) {
+            if (firstu != NULL) {
+                message *msg = msg_message("ship_drift", "ship dir", sh, dir);
+                msg_to_ship_inmates(sh, &firstu, &lastu, msg);
+            }
 
+            fset(sh, SF_DRIFTED);
+            if (ovl >= overload_start()) {
+                damage_ship(sh, damage_overload(ovl));
+                msg_to_ship_inmates(sh, &firstu, &lastu, msg_message("massive_overload", "ship", sh));
+            }
+            else {
+                damage_ship(sh, damage_drift);
+            }
+            if (sh->damage >= sh->size * DAMAGE_SCALE) {
+                msg_to_ship_inmates(sh, &firstu, &lastu, msg_message("shipsink", "ship", sh));
+                sink_ship(sh);
+                remove_ship(shp, sh);
+            }
+            else if (rnext != NULL) {
                 /* Das Schiff und alle Einheiten darin werden nun von r
-                 * nach rnext verschoben. Danach eine Meldung. */
+                    * nach rnext verschoben. Danach eine Meldung. */
                 add_regionlist(&route, rnext);
 
                 set_coast(sh, r, rnext);
-                sh = move_ship(sh, r, rnext, route);
+                move_ship(sh, r, rnext, route);
                 free_regionlist(route);
-
-                if (firstu != NULL) {
-                    message *msg = msg_message("ship_drift", "ship dir", sh, dir);
-                    msg_to_ship_inmates(sh, &firstu, &lastu, msg);
-                }
             }
-
-            if (sh != NULL) {
-                fset(sh, SF_DRIFTED);
-                if (ovl >= overload_start()) {
-                    damage_ship(sh, damage_overload(ovl));
-                    msg_to_ship_inmates(sh, &firstu, &lastu, msg_message("massive_overload", "ship", sh));
-                }
-                else {
-                    damage_ship(sh, damage_drift);
-                }
-                if (sh->damage >= sh->size * DAMAGE_SCALE) {
-                    msg_to_ship_inmates(sh, &firstu, &lastu, msg_message("shipsink", "ship", sh));
-                    sink_ship(sh);
-                    remove_ship(shp, sh);
-                }
-            }
-
-            if (*shp == sh) {
+            else {
                 shp = &sh->next;
             }
         }
@@ -1970,7 +1963,7 @@ static void sail(unit * u, order * ord, region_list ** routep, bool drifting)
         if (fval(u, UFL_FOLLOWING))
             caught_target(current_point, u);
 
-        sh = move_ship(sh, starting_point, current_point, *routep);
+        move_ship(sh, starting_point, current_point, *routep);
 
         /* Hafengebühren ? */
 
diff --git a/src/move.h b/src/move.h
index ceab50aa3..754b708aa 100644
--- a/src/move.h
+++ b/src/move.h
@@ -77,7 +77,7 @@ extern "C" {
     bool canfly(struct unit *u);
     void leave_trail(struct ship *sh, struct region *from,
                             struct region_list *route);
-    struct ship *move_ship(struct ship *sh, struct region *from,
+    void move_ship(struct ship *sh, struct region *from,
     struct region *to, struct region_list *route);
     int walkingcapacity(const struct unit *u);
     int movement_speed(const struct unit * u);

From 552dbe5e72f6cc6ef8604daf76ad7381816dd343 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sun, 16 Sep 2018 10:10:17 +0200
Subject: [PATCH 19/81] In Rosthauch min und max verwechselt.

---
 src/spells/combatspells.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/spells/combatspells.c b/src/spells/combatspells.c
index 976c29aed..06a78c4f4 100644
--- a/src/spells/combatspells.c
+++ b/src/spells/combatspells.c
@@ -299,7 +299,7 @@ int sp_combatrosthauch(struct castorder * co)
         for (w = 0; df->weapons[w].type != NULL; ++w) {
             weapon *wp = df->weapons;
             int n = force;
-            if (n < wp->used) n = wp->used;
+            if (n > wp->used) n = wp->used;
             if (n) {
                 requirement *mat = wp->type->itype->construction->materials;
                 bool iron = false;

From 0c3126eb70a4d52f65692e9649e6f60a1a1b3a2b Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno@kn-bremen.de>
Date: Sun, 16 Sep 2018 11:25:34 +0200
Subject: [PATCH 20/81] fix non-drifting ships crash

---
 src/move.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/move.c b/src/move.c
index 70425b72e..227277ab6 100644
--- a/src/move.c
+++ b/src/move.c
@@ -855,7 +855,7 @@ static void drifting_ships(region * r)
                 }
             }
 
-            if (firstu != NULL) {
+            if (rnext && firstu) {
                 message *msg = msg_message("ship_drift", "ship dir", sh, dir);
                 msg_to_ship_inmates(sh, &firstu, &lastu, msg);
             }
@@ -873,7 +873,7 @@ static void drifting_ships(region * r)
                 sink_ship(sh);
                 remove_ship(shp, sh);
             }
-            else if (rnext != NULL) {
+            else if (rnext) {
                 /* Das Schiff und alle Einheiten darin werden nun von r
                     * nach rnext verschoben. Danach eine Meldung. */
                 add_regionlist(&route, rnext);

From 174a91968b248bc3ba8f9af6fc85d60cb73f9a78 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sat, 22 Sep 2018 08:54:17 +0200
Subject: [PATCH 21/81] make herb growth code a little more readable.

---
 src/laws.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/src/laws.c b/src/laws.c
index 0e9285281..922f4c366 100644
--- a/src/laws.c
+++ b/src/laws.c
@@ -741,11 +741,13 @@ growing_herbs(region * r, const int current_season, const int last_weeks_season)
      * Kräuter))% sich zu vermehren. */
     UNUSED_ARG(last_weeks_season);
     if (current_season != SEASON_WINTER) {
-        int i;
-        for (i = rherbs(r); i > 0; i--) {
-            if (rng_int() % 100 < (100 - rherbs(r)))
-                rsetherbs(r, (short)(rherbs(r) + 1));
+        int i, herbs = rherbs(r);
+        for (i = herbs; i > 0; --i) {
+            if (rng_int() % 100 < (100 - herbs)) {
+                ++herbs;
+            }
         }
+        rsetherbs(r, herbs);
     }
 }
 

From f609bb01f2638208401f68419c25ca9b4c221859 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sun, 23 Sep 2018 14:01:47 +0200
Subject: [PATCH 22/81] unused variable is never read.

---
 src/battle.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/src/battle.c b/src/battle.c
index 1e256f9ca..8e8c3610b 100644
--- a/src/battle.c
+++ b/src/battle.c
@@ -3865,7 +3865,6 @@ static void battle_flee(battle * b)
             for (fig = s->fighters; fig; fig = fig->next) {
                 unit *u = fig->unit;
                 troop dt;
-                int runners = 0;
                 /* Flucht nicht bei mehr als 600 HP. Damit Wyrme t�tbar bleiben. */
                 int runhp = (int)(0.9 + unit_max_hp(u) * hpflee(u->status));
                 if (runhp > 600) runhp = 600;
@@ -3912,7 +3911,6 @@ static void battle_flee(battle * b)
                         ispaniced = EFFECT_PANIC_SPELL;
                     }
                     if (chance(fmin(fleechance(u) + ispaniced, 0.90))) {
-                        ++runners;
                         flee(dt);
                     }
                 }

From 91a7b94cec8315f335de5161cdcffd1dd3605eaa Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sun, 23 Sep 2018 19:03:28 +0200
Subject: [PATCH 23/81] run iwyu if we have it

---
 src/CMakeLists.txt |  9 +++++++++
 src/gmtool.c       | 22 +++++-----------------
 src/listbox.c      |  2 --
 3 files changed, 14 insertions(+), 19 deletions(-)

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index cf96cfbc2..96351cdc9 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -169,9 +169,18 @@ set (SERVER_SRC ${SERVER_SRC}
 )
 endif(CURSES_FOUND)
 
+find_program(IWYU_PATH NAMES include-what-you-use iwyu)
+if(NOT IWYU_PATH)
+	message(STATUS "Could not find the program include-what-you-use")
+endif()
+
+
 add_library(version STATIC ${VERSION_SRC})
 add_library(game ${ERESSEA_SRC})
 add_executable(eressea ${SERVER_SRC})
+if (IWYU_PATH)
+set_property(TARGET eressea PROPERTY C_INCLUDE_WHAT_YOU_USE ${IWYU_PATH})
+endif(IWYU_PATH)
 target_link_libraries(game version)
 target_link_libraries(eressea
   game
diff --git a/src/gmtool.c b/src/gmtool.c
index c2193bd32..48a51d354 100644
--- a/src/gmtool.c
+++ b/src/gmtool.c
@@ -18,49 +18,37 @@
 
 #include "gmtool.h"
 
-#include <modules/xmas.h>
-#include <modules/gmcmd.h>
-#include <modules/museum.h>
 #include <modules/autoseed.h>
 
 #include "kernel/building.h"
-#include "kernel/calendar.h"
 #include "kernel/faction.h"
 #include "kernel/item.h"
 #include "kernel/plane.h"
-#include "kernel/race.h"
 #include "kernel/region.h"
 #include "kernel/terrainid.h"
 #include "kernel/unit.h"
-#include "kernel/resources.h"
 #include "kernel/save.h"
 #include "kernel/ship.h"
 #include "kernel/terrain.h"
 
-#include <attributes/attributes.h>
-#include <triggers/triggers.h>
-
 #include <util/attrib.h>
 #include <util/base36.h>
 #include <util/lists.h>
-#include <util/log.h>
 #include <util/macros.h>
-#include <util/path.h>
-#include <util/rng.h>
-#include <util/unicode.h>
+#include "util/path.h"
+#include "util/rng.h"
+#include "util/unicode.h"
 
 #include "gmtool_structs.h"
 #include "console.h"
 #include "listbox.h"
-#include "wormhole.h"
 #include "teleport.h"
 
-#include <storage.h>
-#include <lua.h>
-
 #include <assert.h>
 #include <locale.h>
+#include <limits.h>
 #include <stdlib.h>
+#include <stdarg.h>
 #include <stdio.h>
 #include <string.h>
 
diff --git a/src/listbox.c b/src/listbox.c
index afc04b232..cd7118da7 100644
--- a/src/listbox.c
+++ b/src/listbox.c
@@ -13,12 +13,10 @@
 #endif
 
 #include <curses.h>
-#include <kernel/config.h>
 
 #include "listbox.h"
 #include "gmtool_structs.h"
 
-#include <util/log.h>
 #include <util/strings.h>
 
 #include <stdlib.h>

From dfa9c644650617e269089ebee85a2422b245e41d Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sun, 23 Sep 2018 19:44:05 +0200
Subject: [PATCH 24/81] clean includes for bindings

---
 src/bind_eressea.c  |  3 +--
 src/bind_faction.c  |  8 +++++++-
 src/bind_gmtool.c   |  2 ++
 src/bind_message.c  |  4 ++++
 src/bind_monsters.c |  7 +++----
 src/bind_order.c    |  1 +
 src/bind_region.c   | 17 ++++++++--------
 src/bind_storage.c  |  5 +----
 src/bind_unit.c     | 28 ++++++++++++++++----------
 src/bindings.c      | 49 +++++++++++++++++++++------------------------
 src/gmtool.c        |  2 --
 src/listbox.c       |  1 +
 12 files changed, 68 insertions(+), 59 deletions(-)

diff --git a/src/bind_eressea.c b/src/bind_eressea.c
index 11c03898d..9f73c4a29 100755
--- a/src/bind_eressea.c
+++ b/src/bind_eressea.c
@@ -3,8 +3,6 @@
 #endif
 #include "bind_eressea.h"
 
-#include <platform.h>
-
 #include "json.h"
 #include "orderfile.h"
 
@@ -16,6 +14,7 @@
 #include <util/language.h>
 
 #include <stream.h>
+#include <stdio.h>
 #include <filestream.h>
 
 
diff --git a/src/bind_faction.c b/src/bind_faction.c
index ac797093d..eae029f4b 100644
--- a/src/bind_faction.c
+++ b/src/bind_faction.c
@@ -18,6 +18,7 @@ without prior permission by the authors of Eressea.
 #include "bind_unit.h"
 #include "bindings.h"
 #include "helpers.h"
+#include "magic.h"
 
 #include <kernel/alliance.h>
 #include <kernel/faction.h>
@@ -29,14 +30,19 @@ without prior permission by the authors of Eressea.
 #include <kernel/race.h>
 #include <kernel/region.h>
 #include <kernel/spellbook.h>
-#include <attributes/key.h>
+#include "kernel/types.h"
 
 #include <util/base36.h>
 #include <util/language.h>
 #include <util/log.h>
 #include <util/macros.h>
+#include <util/message.h>
 #include <util/password.h>
 
+#include "attributes/key.h"
+
+#include <lua.h>
+#include <lauxlib.h>
 #include <tolua.h>
 #include <string.h>
 #include <stdlib.h>
diff --git a/src/bind_gmtool.c b/src/bind_gmtool.c
index 5c08f6e2c..d0a023a5b 100644
--- a/src/bind_gmtool.c
+++ b/src/bind_gmtool.c
@@ -14,6 +14,8 @@
 #include <util/log.h>
 #include <util/macros.h>
 
+#include <lua.h>
+#include <lauxlib.h>
 #include <tolua.h>
 
 #include <string.h>
diff --git a/src/bind_message.c b/src/bind_message.c
index 8eee85bc1..bf82ddd02 100644
--- a/src/bind_message.c
+++ b/src/bind_message.c
@@ -16,14 +16,18 @@
 #include <util/macros.h>
 #include <util/message.h>
 #include <util/nrmessage.h>
+#include <util/variant.h>
 
 /* lua includes */
+#include <lua.h>
 #include <tolua.h>
 
 #include <assert.h>
 #include <string.h>
 #include <stdlib.h>
 
+struct order;
+
 #define E_OK 0
 #define E_INVALID_MESSAGE 1
 #define E_INVALID_PARAMETER_NAME 2
diff --git a/src/bind_monsters.c b/src/bind_monsters.c
index af630bb41..f9aef4a2a 100644
--- a/src/bind_monsters.c
+++ b/src/bind_monsters.c
@@ -2,20 +2,19 @@
 #include <platform.h>
 #endif
 
-#include "spells/shipcurse.h"
 #include "monsters.h"
 
 #include <spells/flyingship.h>
 
 #include <kernel/faction.h>
-#include <kernel/race.h>
 #include <kernel/ship.h>
-#include <kernel/spellbook.h>
 #include <kernel/unit.h>
 
 #include <util/macros.h>
 
+#include <lua.h>
 #include <tolua.h>
+
 #include <stdlib.h>
 
 static int tolua_levitate_ship(lua_State * L)
@@ -62,7 +61,7 @@ static int tolua_spawn_undead(lua_State * L)
     return 0;
 }
 
-void bind_monsters(struct lua_State *L)
+void bind_monsters(lua_State *L)
 {
     tolua_module(L, NULL, 0);
     tolua_beginmodule(L, NULL);
diff --git a/src/bind_order.c b/src/bind_order.c
index 407e29037..dd38f4adb 100644
--- a/src/bind_order.c
+++ b/src/bind_order.c
@@ -8,6 +8,7 @@
 #include <util/macros.h>
 
 /* lua includes */
+#include <lua.h>
 #include <tolua.h>
 
 #include <stdlib.h>
diff --git a/src/bind_region.c b/src/bind_region.c
index b49ceb078..3b0e7f3a3 100644
--- a/src/bind_region.c
+++ b/src/bind_region.c
@@ -8,38 +8,37 @@
 #include "bind_building.h"
 
 #include "teleport.h"
+#include "direction.h"
 
+#include <kernel/building.h>
 #include <kernel/calendar.h>
-#include <kernel/config.h>
 #include <kernel/curse.h>
 #include <kernel/region.h>
 #include <kernel/resources.h>
 #include <kernel/unit.h>
-#include <kernel/region.h>
 #include <kernel/item.h>
-#include <kernel/build.h>
-#include <kernel/building.h>
 #include <kernel/ship.h>
 #include <kernel/plane.h>
 #include <kernel/terrain.h>
 #include <kernel/messages.h>
-#include <modules/autoseed.h>
-#include <attributes/key.h>
-#include <attributes/racename.h>
 
 #include <util/attrib.h>
 #include <util/base36.h>
-#include <util/language.h>
 #include <util/log.h>
 #include <util/macros.h>
+#include <util/message.h>
 #include <util/strings.h>
 
-#include <critbit.h>
+#include <attributes/key.h>
+#include <attributes/racename.h>
 
+#include <lua.h>
+#include <lauxlib.h>
 #include <tolua.h>
 
 #include <assert.h>
 #include <string.h>
+#include <stdbool.h>
 #include <stdlib.h>
 
 static int tolua_region_count_msg_type(lua_State *L) {
diff --git a/src/bind_storage.c b/src/bind_storage.c
index e1339312c..aa7935312 100644
--- a/src/bind_storage.c
+++ b/src/bind_storage.c
@@ -11,16 +11,13 @@
 #include <util/macros.h>
 
 #include <storage.h>
-#include <stream.h>
-#include <filestream.h>
-#include <binarystore.h>
 
 #include <math.h>
 #include <stdio.h>
 #include <string.h>
-#include <stdlib.h>
 #include <errno.h>
 
+#include <lua.h>
 #include <tolua.h>
 
 static int tolua_storage_create(lua_State * L)
diff --git a/src/bind_unit.c b/src/bind_unit.c
index fddcd5608..9f6c39163 100644
--- a/src/bind_unit.c
+++ b/src/bind_unit.c
@@ -5,15 +5,22 @@
 #include "bind_unit.h"
 #include "alchemy.h"
 #include "bindings.h"
-#include "move.h"
 #include "reports.h"
 #include "guard.h"
+#include "magic.h"
+#include "skill.h"
 
-/*  attributes includes */
-#include <attributes/racename.h>
-#include <attributes/key.h>
+/*  util includes */
+#include <util/attrib.h>
+#include <util/base36.h>
+#include <util/event.h>
+#include <util/log.h>
+#include <util/macros.h>
+#include "util/variant.h"
 
 /*  kernel includes */
+#include "kernel/skills.h"
+#include "kernel/types.h"
 #include <kernel/building.h>
 #include <kernel/config.h>
 #include <kernel/curse.h>
@@ -31,21 +38,20 @@
 #include <kernel/spell.h>
 #include <kernel/unit.h>
 
-/*  util includes */
-#include <util/attrib.h>
-#include <util/base36.h>
-#include <util/event.h>
-#include <util/lists.h>
-#include <util/log.h>
-#include <util/macros.h>
+/*  attributes includes */
+#include <attributes/racename.h>
+#include <attributes/key.h>
 
 #include <selist.h>
 
+#include <lauxlib.h>
+#include <lua.h>
 #include <tolua.h>
 
 #include <assert.h>
 #include <errno.h>
 #include <string.h>
+#include <stdbool.h>
 #include <stdlib.h>
 #include <limits.h>
 
diff --git a/src/bindings.c b/src/bindings.c
index bdf03afdf..60519260a 100755
--- a/src/bindings.c
+++ b/src/bindings.c
@@ -4,30 +4,38 @@
 
 #include "bindings.h"
 
+#include "magic.h"
+#include "skill.h"
+#include "helpers.h"
+#include "console.h"
+#include "reports.h"
+#include "study.h"
+#include "summary.h"
+#include "teleport.h"
+#include "laws.h"
+
 #include "kernel/calendar.h"
 #include "kernel/config.h"
 #include "kernel/alliance.h"
 #include "kernel/building.h"
+#include "kernel/build.h"
 #include "kernel/curse.h"
 #include "kernel/unit.h"
 #include "kernel/terrain.h"
 #include "kernel/messages.h"
-#include "kernel/region.h"
-#include "kernel/building.h"
 #include "kernel/plane.h"
-#include "kernel/race.h"
-#include "kernel/item.h"
-#include "kernel/order.h"
-#include "kernel/ship.h"
-#include "kernel/faction.h"
+#include "kernel/region.h"
 #include "kernel/save.h"
+#include "kernel/ship.h"
 #include "kernel/spell.h"
+#include "kernel/types.h"
+#include "kernel/item.h"
+#include "kernel/faction.h"
 #include "kernel/spellbook.h"
 #include "races/races.h"
 
 #include "bind_unit.h"
 #include "bind_storage.h"
-#include "bind_building.h"
 #include "bind_message.h"
 #include "bind_building.h"
 #include "bind_faction.h"
@@ -36,42 +44,31 @@
 #include "bind_gmtool.h"
 #include "bind_region.h"
 
-#include "helpers.h"
-#include "console.h"
-#include "reports.h"
-#include "study.h"
-#include "economy.h"
-#include "summary.h"
-#include "teleport.h"
-#include "laws.h"
-#include "monsters.h"
-#include "market.h"
-
 #include <modules/score.h>
-#include <attributes/key.h>
 
 #include <util/attrib.h>
 #include <util/base36.h>
 #include <util/language.h>
-#include <util/lists.h>
 #include <util/log.h>
 #include <util/macros.h>
-#include <util/nrmessage.h>
+#include <util/message.h>
 #include <util/rand.h>
 #include <util/rng.h>
 
 #include <selist.h>
-#include <storage.h>
 
-#include <iniparser.h>
+#include <dictionary.h>
 #include <tolua.h>
 #include <lua.h>
 #include <lualib.h>
 #include <lauxlib.h>
 
-#include <time.h>
-#include <errno.h>
 #include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 
 #define TOLUA_PKG(NAME) void tolua_##NAME##_open(lua_State * L)
 
diff --git a/src/gmtool.c b/src/gmtool.c
index 48a51d354..e4eefd337 100644
--- a/src/gmtool.c
+++ b/src/gmtool.c
@@ -22,7 +22,6 @@
 
 #include "kernel/building.h"
 #include "kernel/faction.h"
-#include "kernel/item.h"
 #include "kernel/plane.h"
 #include "kernel/region.h"
 #include "kernel/terrainid.h"
@@ -45,7 +44,6 @@
 #include "teleport.h"
 
 #include <assert.h>
-#include <locale.h>
 #include <limits.h>
 #include <stdlib.h>
 #include <stdarg.h>
diff --git a/src/listbox.c b/src/listbox.c
index cd7118da7..4aa00adaf 100644
--- a/src/listbox.c
+++ b/src/listbox.c
@@ -19,6 +19,7 @@
 
 #include <util/strings.h>
 
+#include <stdbool.h>
 #include <stdlib.h>
 #include <string.h>
 #include <ctype.h>

From 0759482934e84e4366512b51bad6c285c6c8445f Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sun, 23 Sep 2018 19:53:01 +0200
Subject: [PATCH 25/81] clean includes for bindings and main

---
 src/bind_building.c |  6 ++++--
 src/bind_config.c   |  4 +---
 src/bind_faction.c  |  4 ----
 src/bind_tolua.c    |  2 ++
 src/main.c          | 18 +++++++++---------
 5 files changed, 16 insertions(+), 18 deletions(-)

diff --git a/src/bind_building.c b/src/bind_building.c
index 9e39a54a5..93576ed3b 100644
--- a/src/bind_building.c
+++ b/src/bind_building.c
@@ -5,7 +5,6 @@
 #include "bind_building.h"
 #include "bind_unit.h"
 
-#include <kernel/config.h>
 #include <kernel/unit.h>
 #include <kernel/building.h>
 #include <kernel/region.h>
@@ -15,9 +14,12 @@
 #include <util/macros.h>
 #include <util/strings.h>
 
+#include <lua.h>
+#include <lauxlib.h>
 #include <tolua.h>
+
+#include <stdbool.h>
 #include <stdlib.h>
-#include <string.h>
 
 int tolua_buildinglist_next(lua_State * L)
 {
diff --git a/src/bind_config.c b/src/bind_config.c
index 2d4086ccf..31ffcc287 100644
--- a/src/bind_config.c
+++ b/src/bind_config.c
@@ -5,17 +5,15 @@
 #include "bind_config.h"
 
 #include "jsonconf.h"
+#include "magic.h"
 
 #include <kernel/config.h>
 #include <kernel/building.h>
 #include <kernel/race.h>
 #include <kernel/ship.h>
 #include <kernel/spell.h>
-#include <kernel/spellbook.h>
-#include <kernel/terrain.h>
 
 #include <util/log.h>
-#include <util/language.h>
 #include <util/nrmessage.h>
 #include <util/path.h>
 #include <util/strings.h>
diff --git a/src/bind_faction.c b/src/bind_faction.c
index eae029f4b..e113d924c 100644
--- a/src/bind_faction.c
+++ b/src/bind_faction.c
@@ -17,19 +17,16 @@ without prior permission by the authors of Eressea.
 #include "bind_faction.h"
 #include "bind_unit.h"
 #include "bindings.h"
-#include "helpers.h"
 #include "magic.h"
 
 #include <kernel/alliance.h>
 #include <kernel/faction.h>
 #include <kernel/unit.h>
 #include <kernel/item.h>
-#include <kernel/faction.h>
 #include <kernel/messages.h>
 #include <kernel/plane.h>
 #include <kernel/race.h>
 #include <kernel/region.h>
-#include <kernel/spellbook.h>
 #include "kernel/types.h"
 
 #include <util/base36.h>
@@ -46,7 +43,6 @@ without prior permission by the authors of Eressea.
 #include <tolua.h>
 #include <string.h>
 #include <stdlib.h>
-#include <stdbool.h>
 
 typedef struct helpmode {
     const char *name;
diff --git a/src/bind_tolua.c b/src/bind_tolua.c
index 669d5848b..d681b9088 100644
--- a/src/bind_tolua.c
+++ b/src/bind_tolua.c
@@ -12,6 +12,8 @@
 #include "settings.pkg.c"
 #pragma warning(pop)
 
+#include <lua.h>
+
 void tolua_bind_open(lua_State * L) {
     tolua_eressea_open(L);
     tolua_process_open(L);
diff --git a/src/main.c b/src/main.c
index bb353fc2f..599fbdd67 100644
--- a/src/main.c
+++ b/src/main.c
@@ -22,15 +22,11 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
 #include <kernel/calendar.h>
 #include <kernel/config.h>
-#include <kernel/database.h>
 #include <kernel/messages.h>
-#include <kernel/save.h>
 #include <kernel/version.h>
 
-#include <util/filereader.h>
 #include <util/language.h>
 #include <util/log.h>
-#include <util/macros.h>
 #include <util/path.h>
 
 #include "eressea.h"
@@ -39,14 +35,18 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #endif
 
 #include "bindings.h"
-#include "races/races.h"
-#include "spells.h"
+
+#include <iniparser.h>
+#include <dictionary.h>
 
 #include <lua.h>
-#include <assert.h>
+
+#include <limits.h>
 #include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 #include <wctype.h>
-#include <iniparser.h>
 
 static const char *logfile = "eressea.log";
 static const char *luafile = 0;
@@ -302,7 +302,7 @@ void locale_init(void)
     }
 }
 
-extern void bind_monsters(struct lua_State *L);
+extern void bind_monsters(lua_State *L);
 
 int main(int argc, char **argv)
 {

From d70f05f8dbe35877b2550d9d2c27e0c85653e158 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sun, 23 Sep 2018 20:01:12 +0200
Subject: [PATCH 26/81] BUG 2478: Fleeing units cannot move.

---
 src/battle.c      | 62 ++++++++++++++++++++++++++---------------------
 src/battle.test.c | 56 +++++++++++++++++++++++++++++++++++++++---
 2 files changed, 87 insertions(+), 31 deletions(-)

diff --git a/src/battle.c b/src/battle.c
index 8e8c3610b..bf9df9b2b 100644
--- a/src/battle.c
+++ b/src/battle.c
@@ -101,7 +101,7 @@ typedef enum combatmagic {
 #define MAXSPELLRANGE 7
 
 #define ROW_FACTOR 3            /* factor for combat row advancement rule */
-#define EFFECT_PANIC_SPELL 0.25
+#define EFFECT_PANIC_SPELL 25
 #define TROLL_REGENERATION 0.10
 
 /* Nach dem alten System: */
@@ -126,6 +126,9 @@ const troop no_troop = { 0, 0 };
 static int max_turns;
 static int rule_damage;
 static int rule_loot;
+static int flee_chance_max_percent;
+static int flee_chance_base;
+static int flee_chance_skill_bonus;
 static int skill_formula;
 static int rule_cavalry_skill;
 static int rule_population_damage;
@@ -144,6 +147,9 @@ static void init_rules(void)
 {
     it_mistletoe = it_find("mistletoe");
 
+    flee_chance_skill_bonus = config_get_int("rules.combat.flee_chance_bonus", 5);
+    flee_chance_base = config_get_int("rules.combat.flee_chance_base", 20);
+    flee_chance_max_percent = config_get_int("rules.combat.flee_chance_limit", 90);
     rule_nat_armor = config_get_int("rules.combat.nat_armor", 0);
     rule_tactics_formula = config_get_int("rules.tactics.formula", 0);
     rule_goblin_bonus = config_get_int("rules.combat.goblinbonus", 10);
@@ -2276,7 +2282,7 @@ static void add_tactics(tactics * ta, fighter * fig, int value)
     ta->value = value;
 }
 
-static double horse_fleeing_bonus(const unit * u)
+static int horse_fleeing_bonus(const unit * u)
 {
     const item_type *it_horse, *it_elvenhorse, *it_charger;
     int n1 = 0, n2 = 0, n3 = 0;
@@ -2299,26 +2305,26 @@ static double horse_fleeing_bonus(const unit * u)
         }
     }
     if (skl >= 5 && n3 >= u->number)
-        return 0.30;
+        return 30;
     if (skl >= 2 && n2 + n3 >= u->number)
-        return 0.20;
+        return 20;
     if (n1 + n2 + n3 >= u->number)
-        return 0.10;
-    return 0.0F;
+        return 10;
+    return 0;
 }
 
-double fleechance(unit * u)
+static int fleechance(unit * u)
 {
-    double p = 0.20;              /* Fluchtwahrscheinlichkeit in % */
+    int p = flee_chance_base;              /* Fluchtwahrscheinlichkeit in % */
     /* Einheit u versucht, dem Get�mmel zu entkommen */
 
-    p += (effskill(u, SK_STEALTH, 0) * 0.05);
+    p += (effskill(u, SK_STEALTH, 0) * flee_chance_skill_bonus);
     p += horse_fleeing_bonus(u);
 
     if (u_race(u) == get_race(RC_HALFLING)) {
-        p += 0.20;
-        if (p > 0.9) {
-            p = 0.9;
+        p += flee_chance_base;
+        if (p > flee_chance_max_percent) {
+            p = flee_chance_max_percent;
         }
     }
     return p;
@@ -2617,7 +2623,7 @@ static void aftermath(battle * b)
                 }
             }
             snumber += du->number;
-            if (df->alive == 0) {
+            if (dead == df->unit->number) {
                 flags = UFL_DEAD;
             }
             else if (relevant) {
@@ -3631,13 +3637,21 @@ static void flee(const troop dt)
 {
     fighter *fig = dt.fighter;
     unit *u = fig->unit;
+    int fchance = fleechance(u);
 
-    fig->run.hp += fig->person[dt.index].hp;
-    ++fig->run.number;
+    if (fig->person[dt.index].flags & FL_PANICED) {
+        fchance += EFFECT_PANIC_SPELL;
+    }
+    if (fchance > flee_chance_max_percent) {
+        fchance = flee_chance_max_percent;
+    }
+    if (rng_int() % 100 < fchance) {
+        fig->run.hp += fig->person[dt.index].hp;
+        ++fig->run.number;
 
-    setguard(u, false);
-
-    kill_troop(dt);
+        setguard(u, false);
+        kill_troop(dt);
+    }
 }
 
 static bool is_calmed(const unit *u, const faction *f) {
@@ -3881,7 +3895,6 @@ static void battle_flee(battle * b)
                 dt.fighter = fig;
                 dt.index = fig->alive - fig->removed;
                 while (s->size[SUM_ROW] && dt.index != 0) {
-                    double ispaniced = 0.0;
                     --dt.index;
                     assert(dt.index >= 0 && dt.index < fig->unit->number);
                     assert(fig->person[dt.index].hp > 0);
@@ -3906,13 +3919,7 @@ static void battle_flee(battle * b)
                         }
                         continue;
                     }
-
-                    if (fig->person[dt.index].flags & FL_PANICED) {
-                        ispaniced = EFFECT_PANIC_SPELL;
-                    }
-                    if (chance(fmin(fleechance(u) + ispaniced, 0.90))) {
-                        flee(dt);
-                    }
+                    flee(dt);
                 }
             }
         }
@@ -3966,8 +3973,7 @@ void force_leave(region *r, battle *b) {
 }
 
 
-void do_battle(region * r)
-{
+static void do_battle(region * r) {
     battle *b = NULL;
     bool fighting;
     ship *sh;
diff --git a/src/battle.test.c b/src/battle.test.c
index 7c7012e77..8cfbb0d2a 100644
--- a/src/battle.test.c
+++ b/src/battle.test.c
@@ -2,6 +2,8 @@
 
 #include "battle.h"
 
+#include "guard.h"
+#include "keyword.h"
 #include "reports.h"
 #include "skill.h"
 
@@ -10,6 +12,7 @@
 #include <kernel/faction.h>
 #include <kernel/curse.h>
 #include <kernel/item.h>
+#include <kernel/order.h>
 #include <kernel/race.h>
 #include <kernel/region.h>
 #include <kernel/ship.h>
@@ -17,6 +20,7 @@
 
 #include <spells/buildingcurse.h>
 
+#include <util/base36.h>
 #include <util/functions.h>
 #include <util/language.h>
 #include <util/message.h>
@@ -31,6 +35,21 @@
 
 #include "tests.h"
 
+static void setup_messages(void) {
+    mt_create_va(mt_new("start_battle", NULL), "factions:string", MT_NEW_END);
+    mt_create_va(mt_new("para_army_index", NULL), "index:int", "name:string", MT_NEW_END);
+    mt_create_va(mt_new("battle_msg", NULL), "string:string", MT_NEW_END);
+    mt_create_va(mt_new("battle_row", NULL), "row:int", MT_NEW_END);
+    mt_create_va(mt_new("para_lineup_battle", NULL), "turn:int", MT_NEW_END);
+    mt_create_va(mt_new("para_after_battle", NULL), MT_NEW_END);
+    mt_create_va(mt_new("army_report", NULL), 
+        "index:int",  "abbrev:string", "dead:int", "fled:int", "survived:int",
+        MT_NEW_END);
+    mt_create_va(mt_new("casualties", NULL), 
+        "unit:unit", "runto:region", "run:int", "alive:int", "fallen:int",
+        MT_NEW_END);
+}
+
 static void test_make_fighter(CuTest * tc)
 {
     unit *au;
@@ -566,7 +585,7 @@ static void test_battle_report_one(CuTest *tc)
     fighter *fig;
 
     test_setup();
-    mt_create_va(mt_new("start_battle", NULL), "factions:string", MT_NEW_END);
+    setup_messages();
     r = test_create_plain(0, 0);
     u1 = test_create_unit(test_create_faction(NULL), r);
     u2 = test_create_unit(test_create_faction(NULL), r);
@@ -597,7 +616,7 @@ static void test_battle_report_two(CuTest *tc)
     test_setup();
     lang = test_create_locale();
     locale_setstring(lang, "and", "and");
-    mt_create_va(mt_new("start_battle", NULL), "factions:string", MT_NEW_END);
+    setup_messages();
     r = test_create_plain(0, 0);
     u1 = test_create_unit(test_create_faction(NULL), r);
     u1->faction->locale = lang;
@@ -630,7 +649,7 @@ static void test_battle_report_three(CuTest *tc)
     test_setup();
     lang = test_create_locale();
     locale_setstring(lang, "and", "and");
-    mt_create_va(mt_new("start_battle", NULL), "factions:string", MT_NEW_END);
+    setup_messages();
     r = test_create_plain(0, 0);
     u1 = test_create_unit(test_create_faction(NULL), r);
     u1->faction->locale = lang;
@@ -783,12 +802,43 @@ static void test_tactics_chance(CuTest *tc) {
     test_teardown();
 }
 
+static void test_battle_fleeing(CuTest *tc) {
+    region *r;
+    unit *u1, *u2;
+    test_setup();
+    setup_messages();
+    r = test_create_plain(0, 0);
+    u1 = test_create_unit(test_create_faction(NULL), r);
+    u2 = test_create_unit(test_create_faction(NULL), r);
+    u1->status = ST_FLEE;
+    u2->status = ST_AGGRO;
+#if 0
+    setguard(u1, true);
+    CuAssertIntEquals(tc, UFL_GUARD, (u1->flags & UFL_GUARD));
+    CuAssertIntEquals(tc, RF_GUARDED, (r->flags & RF_GUARDED));
+#endif
+    config_set_int("rules.combat.flee_chance_base", 100);
+    config_set_int("rules.combat.flee_chance_limit", 100);
+    unit_addorder(u2, create_order(K_ATTACK, u2->faction->locale, itoa36(u1->no)));
+    do_battles();
+    CuAssertIntEquals(tc, 1, u1->number);
+    CuAssertIntEquals(tc, 1, u2->number);
+#if 0
+    CuAssertIntEquals(tc, 0, (u1->flags & UFL_GUARD));
+    CuAssertIntEquals(tc, 0, (r->flags & RF_GUARDED));
+#endif
+    CuAssertIntEquals(tc, UFL_LONGACTION, (u1->flags & UFL_LONGACTION));
+    CuAssertIntEquals(tc, UFL_LONGACTION | UFL_NOTMOVING, (u2->flags & (UFL_LONGACTION | UFL_NOTMOVING)));
+    test_teardown();
+}
+
 CuSuite *get_battle_suite(void)
 {
     CuSuite *suite = CuSuiteNew();
     SUITE_ADD_TEST(suite, test_make_fighter);
     SUITE_ADD_TEST(suite, test_select_weapon_restricted);
     SUITE_ADD_TEST(suite, test_select_armor);
+    SUITE_ADD_TEST(suite, test_battle_fleeing);
     SUITE_ADD_TEST(suite, test_battle_skilldiff);
     SUITE_ADD_TEST(suite, test_battle_skilldiff_building);
     SUITE_ADD_TEST(suite, test_battle_report_one);

From 409a3da7cf29aedaabc28d1aad15f10ad433b0de Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Mon, 24 Sep 2018 11:57:28 +0200
Subject: [PATCH 27/81] more iwyu warnings

---
 src/console.c |  3 +--
 src/helpers.c | 15 ++++++---------
 src/helpers.h |  2 --
 3 files changed, 7 insertions(+), 13 deletions(-)

diff --git a/src/console.c b/src/console.c
index 7a32b83f0..f134b2164 100644
--- a/src/console.c
+++ b/src/console.c
@@ -5,13 +5,12 @@
 
 /* lua includes */
 #include <lua.h>
+#include <luaconf.h>
 #include <lauxlib.h>
-#include <lualib.h>
 
 /* libc includes */
 #include <assert.h>
 #include <signal.h>
-#include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
 
diff --git a/src/helpers.c b/src/helpers.c
index 8acabd97c..01fa19abc 100644
--- a/src/helpers.c
+++ b/src/helpers.c
@@ -17,26 +17,21 @@ without prior permission by the authors of Eressea.
 #include "helpers.h"
 #include "vortex.h"
 #include "alchemy.h"
+#include "magic.h"
 
 #include <util/attrib.h>
-#include <util/base36.h>
 #include <util/event.h>
 #include <util/functions.h>
 #include <util/gamedata.h>
 #include <util/log.h>
 #include <util/macros.h>
 #include <util/parser.h>
-#include <util/resolve.h>
+#include <util/variant.h>
 
-#include <kernel/callbacks.h>
 #include <kernel/config.h>
 #include <kernel/callbacks.h>
-#include <kernel/faction.h>
 #include <kernel/spell.h>
-#include <kernel/race.h>
-#include <kernel/resources.h>
 #include <kernel/unit.h>
-#include <kernel/building.h>
 #include <kernel/item.h>
 #include <kernel/region.h>
 
@@ -46,8 +41,10 @@ without prior permission by the authors of Eressea.
 #include <lua.h>
 
 #include <assert.h>
-#include <string.h>
-#include <stdlib.h>
+#include <stdbool.h>
+#include <stdio.h>
+
+struct order;
 
 static int
 lua_giveitem(unit * s, unit * d, const item_type * itype, int n, struct order *ord)
diff --git a/src/helpers.h b/src/helpers.h
index d0bbcc58b..a5eccd0f5 100644
--- a/src/helpers.h
+++ b/src/helpers.h
@@ -14,8 +14,6 @@ without prior permission by the authors of Eressea.
 extern "C" {
 #endif
 
-    struct lua_State;
-
     void register_tolua_helpers(void);
 
 #ifdef __cplusplus

From ccc555668210151db807f338ee619b9f9870f58b Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Mon, 24 Sep 2018 20:18:21 +0200
Subject: [PATCH 28/81] adding code to export faction information. sqlite3
 implementation only, not tied to anything yet. add faction.uid remove
 faction.subscription

---
 src/battle.c               |   2 +-
 src/bind_faction.c         |   6 +-
 src/bindings.c             |   8 ---
 src/eressea.c              |  12 ++++
 src/eressea.h              |   1 +
 src/gmtool.c               |   3 +-
 src/kernel/CMakeLists.txt  |  16 ++---
 src/kernel/connection.c    |   2 +-
 src/kernel/database.c      |   5 ++
 src/kernel/database.h      |   2 +
 src/kernel/database.test.c |  16 +++++
 src/kernel/db/berkeley.c   |   5 ++
 src/kernel/db/critbit.c    |   5 ++
 src/kernel/db/driver.h     |   1 +
 src/kernel/db/sqlite.c     | 137 ++++++++++++++++++++++++++++---------
 src/kernel/faction.c       |   8 +--
 src/kernel/faction.h       |   4 +-
 src/kernel/faction.test.c  |   3 +-
 src/kernel/save.c          |   8 ++-
 src/laws.c                 |  27 --------
 src/laws.h                 |   1 -
 src/main.c                 |   1 +
 src/modules/autoseed.c     |  12 ++--
 src/modules/autoseed.h     |   2 +-
 src/spells.c               |   2 +-
 src/tests.c                |   2 +-
 src/util/gamedata.h        |   3 +-
 27 files changed, 190 insertions(+), 104 deletions(-)

diff --git a/src/battle.c b/src/battle.c
index bf9df9b2b..aa5de9f71 100644
--- a/src/battle.c
+++ b/src/battle.c
@@ -3659,7 +3659,7 @@ static bool is_calmed(const unit *u, const faction *f) {
 
     while (a && a->type == &at_curse) {
         curse *c = (curse *)a->data.v;
-        if (c->type == &ct_calmmonster && curse_geteffect_int(c) == f->subscription) {
+        if (c->type == &ct_calmmonster && curse_geteffect_int(c) == f->uid) {
             if (curse_active(c)) {
                 return true;
             }
diff --git a/src/bind_faction.c b/src/bind_faction.c
index e113d924c..850679933 100644
--- a/src/bind_faction.c
+++ b/src/bind_faction.c
@@ -432,7 +432,7 @@ static int tolua_faction_create(lua_State * L)
     faction *f = NULL;
     const struct race *frace = rc_find(racename ? racename : "human");
     if (frace != NULL) {
-        f = addfaction(email, NULL, frace, loc, 0);
+        f = addfaction(email, NULL, frace, loc);
     }
     if (!f) {
         log_error("cannot create %s faction for %s, unknown race.", racename, email);
@@ -528,14 +528,14 @@ static int tolua_faction_set_name(lua_State * L)
 static int tolua_faction_get_uid(lua_State * L)
 {
     faction *f = (faction *)tolua_tousertype(L, 1, 0);
-    lua_pushinteger(L, f->subscription);
+    lua_pushinteger(L, f->uid);
     return 1;
 }
 
 static int tolua_faction_set_uid(lua_State * L)
 {
     faction *f = (faction *)tolua_tousertype(L, 1, 0);
-    f->subscription = (int)tolua_tonumber(L, 2, 0);
+    f->uid = (int)tolua_tonumber(L, 2, 0);
     return 0;
 }
 
diff --git a/src/bindings.c b/src/bindings.c
index 60519260a..c549a4801 100755
--- a/src/bindings.c
+++ b/src/bindings.c
@@ -339,13 +339,6 @@ static int tolua_update_owners(lua_State * L)
     return 0;
 }
 
-static int tolua_update_subscriptions(lua_State * L)
-{
-    UNUSED_ARG(L);
-    update_subscriptions();
-    return 0;
-}
-
 static int tolua_remove_empty_units(lua_State * L)
 {
     UNUSED_ARG(L);
@@ -972,7 +965,6 @@ int tolua_bindings_open(lua_State * L, const dictionary *inifile)
         tolua_function(L, TOLUA_CAST "dice_roll", tolua_dice_rand);
         tolua_function(L, TOLUA_CAST "get_nmrs", tolua_get_nmrs);
         tolua_function(L, TOLUA_CAST "remove_empty_units", tolua_remove_empty_units);
-        tolua_function(L, TOLUA_CAST "update_subscriptions", tolua_update_subscriptions);
         tolua_function(L, TOLUA_CAST "update_scores", tolua_update_scores);
         tolua_function(L, TOLUA_CAST "update_owners", tolua_update_owners);
         tolua_function(L, TOLUA_CAST "learn_skill", tolua_learn_skill);
diff --git a/src/eressea.c b/src/eressea.c
index 0bf1454ee..67ab26af5 100644
--- a/src/eressea.c
+++ b/src/eressea.c
@@ -39,6 +39,18 @@
 /* manually free() everything at exit? */
 #undef CLEANUP_CODE
 
+void game_write_dbstate(void)
+{
+    faction *f;
+
+    for (f = factions; f; f = f->next) {
+        int uid = dblib_save_faction(f, turn);
+        if (uid > 0) {
+            f->uid = uid;
+        }
+    }
+}
+
 void game_done(void)
 {
     log_dead_factions();
diff --git a/src/eressea.h b/src/eressea.h
index f3ea4d4a5..cfc1b12ef 100755
--- a/src/eressea.h
+++ b/src/eressea.h
@@ -6,6 +6,7 @@ extern "C" {
 
     void game_init(void);
     void game_done(void);
+    void game_write_dbstate(void);
 
 #ifdef __cplusplus
 }
diff --git a/src/gmtool.c b/src/gmtool.c
index e4eefd337..f841fa305 100644
--- a/src/gmtool.c
+++ b/src/gmtool.c
@@ -920,8 +920,7 @@ static void seed_player(state *st, const newfaction *player) {
         if (r) {
             faction *f;
             addplayer(r, f = addfaction(player->email, player->password,
-                                        player->race, player->lang,
-                                        player->subscription));
+                                        player->race, player->lang));
         }
     }
 }
diff --git a/src/kernel/CMakeLists.txt b/src/kernel/CMakeLists.txt
index 86c2fb90c..db448bf11 100644
--- a/src/kernel/CMakeLists.txt
+++ b/src/kernel/CMakeLists.txt
@@ -1,6 +1,14 @@
 cmake_minimum_required(VERSION 2.6)
 project(kernel C)
 
+SET(_DBFILES db/critbit.c)
+
+IF(SQLITE3_FOUND)
+SET(_DBFILES db/sqlite.c)
+ELSEIF(DB_FOUND)
+SET(_DBFILES db/berkeley.c)
+ENDIF(SQLITE3_FOUND)
+
 SET(_TEST_FILES
 alliance.test.c
 ally.test.c
@@ -35,14 +43,6 @@ spell.test.c
 unit.test.c
 )
 
-SET(_DBFILES db/critbit.c)
-
-IF(SQLITE3_FOUND)
-SET(_DBFILES db/sqlite.c)
-ELSEIF(DB_FOUND)
-SET(_DBFILES db/berkeley.c)
-ENDIF(SQLITE3_FOUND)
-
 SET(_FILES
 ${_DBFILES}
 alliance.c
diff --git a/src/kernel/connection.c b/src/kernel/connection.c
index 213700fe1..ddaf163c1 100644
--- a/src/kernel/connection.c
+++ b/src/kernel/connection.c
@@ -440,7 +440,7 @@ static const char *b_nameillusionwall(const connection * b, const region * r,
         return (f && fno == f->no) ? "illusionwall" : "wall";
     if (gflags & GF_ARTICLE) {
         return LOC(f->locale, mkname("border", (f
-            && fno == f->subscription) ? "an_illusionwall" : "a_wall"));
+            && fno == f->uid) ? "an_illusionwall" : "a_wall"));
     }
     return LOC(f->locale, mkname("border", (f
         && fno == f->no) ? "illusionwall" : "wall"));
diff --git a/src/kernel/database.c b/src/kernel/database.c
index eaf695613..c27ca21fc 100644
--- a/src/kernel/database.c
+++ b/src/kernel/database.c
@@ -4,6 +4,7 @@
 #include <platform.h>
 
 #include <kernel/config.h>
+#include <kernel/faction.h>
 #include <kernel/database.h>
 #include <kernel/orderdb.h>
 
@@ -27,6 +28,10 @@ int dblib_save_order(order_data *od)
     return 0;
 }
 
+int dblib_save_faction(const faction *f, int turn) {
+    return db_driver_faction_save(f->uid, f->no, turn, f->email, f->_password);
+}
+
 void dblib_open(void)
 {
     db_driver_open();
diff --git a/src/kernel/database.h b/src/kernel/database.h
index 0dd5a70fb..e3bdf11d1 100644
--- a/src/kernel/database.h
+++ b/src/kernel/database.h
@@ -8,12 +8,14 @@ extern "C" {
 #endif
 
     struct order_data;
+    struct faction;
 
     void dblib_open(void);
     void dblib_close(void);
 
     struct order_data *dblib_load_order(int id);
     int dblib_save_order(struct order_data *od);
+    int dblib_save_faction(const struct faction *f, int turn);
 
 #ifdef __cplusplus
 }
diff --git a/src/kernel/database.test.c b/src/kernel/database.test.c
index 2e1104185..cde4edc11 100644
--- a/src/kernel/database.test.c
+++ b/src/kernel/database.test.c
@@ -1,5 +1,6 @@
 #include <platform.h>
 #include <kernel/config.h>
+#include <kernel/faction.h>
 
 #include "database.h"
 #include "orderdb.h"
@@ -7,6 +8,7 @@
 #include <CuTest.h>
 #include <tests.h>
 
+#include <stdio.h>
 #include <string.h>
 
 static void test_save_load_order(CuTest *tc) {
@@ -31,10 +33,24 @@ static void test_save_load_order(CuTest *tc) {
     test_teardown();
 }
 
+static void test_update_faction(CuTest *tc) {
+    faction *f;
+    int uid;
+
+    test_setup();
+    f = test_create_faction(NULL);
+    uid = dblib_save_faction(f, 0);
+    f->uid = uid;
+    uid = dblib_save_faction(f, 0);
+    CuAssertIntEquals(tc, f->uid, uid);
+    test_teardown();
+}
+
 CuSuite *get_db_suite(void)
 {
     CuSuite *suite = CuSuiteNew();
     SUITE_ADD_TEST(suite, test_save_load_order);
+    SUITE_ADD_TEST(suite, test_update_faction);
 
     return suite;
 }
diff --git a/src/kernel/db/berkeley.c b/src/kernel/db/berkeley.c
index 210c36f01..778e0bfe7 100644
--- a/src/kernel/db/berkeley.c
+++ b/src/kernel/db/berkeley.c
@@ -53,6 +53,11 @@ int db_driver_order_save(struct order_data *od)
     return (int)recno;
 }
 
+int db_driver_faction_save(int id, int no, int turn, const char *email, const char *password)
+{
+    return -1;
+}
+
 struct order_data *db_driver_order_load(int id)
 {
     int ret;
diff --git a/src/kernel/db/critbit.c b/src/kernel/db/critbit.c
index 9afb0926d..69bac159e 100644
--- a/src/kernel/db/critbit.c
+++ b/src/kernel/db/critbit.c
@@ -44,6 +44,11 @@ int db_driver_order_save(order_data *od)
     return ent.id;
 }
 
+int db_driver_faction_save(int id, int no, int turn, const char *email, const char *password)
+{
+    return -1;
+}
+
 static int free_data_cb(const void *match, const void *key, size_t keylen,
     void *udata)
 {
diff --git a/src/kernel/db/driver.h b/src/kernel/db/driver.h
index df839b93d..1e408e37e 100644
--- a/src/kernel/db/driver.h
+++ b/src/kernel/db/driver.h
@@ -6,3 +6,4 @@ void db_driver_open(void);
 void db_driver_close(void);
 int db_driver_order_save(struct order_data *od);
 struct order_data *db_driver_order_load(int id);
+int db_driver_faction_save(int id, int no, int turn, const char *email, const char *password);
diff --git a/src/kernel/db/sqlite.c b/src/kernel/db/sqlite.c
index b3090cca0..49dbd001e 100644
--- a/src/kernel/db/sqlite.c
+++ b/src/kernel/db/sqlite.c
@@ -15,9 +15,12 @@
 #include <stdlib.h>
 #include <string.h>
 
-static sqlite3 *g_db;
-static sqlite3_stmt * g_stmt_insert;
-static sqlite3_stmt * g_stmt_select;
+static sqlite3 *g_game_db;
+static sqlite3 *g_temp_db;
+static sqlite3_stmt * g_stmt_insert_order;
+static sqlite3_stmt * g_stmt_select_order;
+static sqlite3_stmt * g_stmt_update_faction;
+static sqlite3_stmt * g_stmt_insert_faction;
 
 static int g_order_batchsize;
 static int g_order_tx_size;
@@ -30,21 +33,21 @@ order_data *db_driver_order_load(int id)
     ERRNO_CHECK();
     if (g_order_tx_size > 0) {
         g_order_tx_size = 0;
-        err = sqlite3_exec(g_db, "COMMIT", NULL, NULL, NULL);
+        err = sqlite3_exec(g_temp_db, "COMMIT", NULL, NULL, NULL);
         assert(err == SQLITE_OK);
     }
-    err = sqlite3_reset(g_stmt_select);
+    err = sqlite3_reset(g_stmt_select_order);
     assert(err == SQLITE_OK);
-    err = sqlite3_bind_int(g_stmt_select, 1, id);
+    err = sqlite3_bind_int(g_stmt_select_order, 1, id);
     assert(err == SQLITE_OK);
     do {
-        err = sqlite3_step(g_stmt_select);
+        err = sqlite3_step(g_stmt_select_order);
         if (err == SQLITE_ROW) {
             const unsigned char *text;
             int bytes;
-            bytes = sqlite3_column_bytes(g_stmt_select, 0);
+            bytes = sqlite3_column_bytes(g_stmt_select_order, 0);
             assert(bytes > 0);
-            text = sqlite3_column_text(g_stmt_select, 0);
+            text = sqlite3_column_text(g_stmt_select_order, 0);
             odata_create(&od, 1+(size_t)bytes, (const char *)text);
             ERRNO_CHECK();
             return od;
@@ -66,23 +69,23 @@ int db_driver_order_save(order_data *od)
 
     if (g_order_batchsize > 0) {
         if (g_order_tx_size == 0) {
-            err = sqlite3_exec(g_db, "BEGIN TRANSACTION", NULL, NULL, NULL);
+            err = sqlite3_exec(g_temp_db, "BEGIN TRANSACTION", NULL, NULL, NULL);
             assert(err == SQLITE_OK);
         }
     }
     
-    err = sqlite3_reset(g_stmt_insert);
+    err = sqlite3_reset(g_stmt_insert_order);
     assert(err == SQLITE_OK);
-    err = sqlite3_bind_text(g_stmt_insert, 1, od->_str, -1, SQLITE_STATIC);
+    err = sqlite3_bind_text(g_stmt_insert_order, 1, od->_str, -1, SQLITE_STATIC);
     assert(err == SQLITE_OK);
-    err = sqlite3_step(g_stmt_insert);
+    err = sqlite3_step(g_stmt_insert_order);
     assert(err == SQLITE_DONE);
-    id = sqlite3_last_insert_rowid(g_db);
+    id = sqlite3_last_insert_rowid(g_temp_db);
     assert(id <= INT_MAX);
     
     if (g_order_batchsize > 0) {
         if (++g_order_tx_size >= g_order_batchsize) {
-            err = sqlite3_exec(g_db, "COMMIT", NULL, NULL, NULL);
+            err = sqlite3_exec(g_temp_db, "COMMIT", NULL, NULL, NULL);
             assert(err == SQLITE_OK);
             g_order_tx_size = 0;
         }
@@ -91,29 +94,89 @@ int db_driver_order_save(order_data *od)
     return (int)id;
 }
 
+
+int db_driver_faction_save(int id, int no, int turn, const char *email, const char *password)
+{
+    sqlite3_int64 row_id;
+    int err;
+
+    if (!g_game_db) {
+        return -1;
+    }
+    if (id != 0) {
+        int rows;
+
+        err = sqlite3_reset(g_stmt_update_faction);
+        assert(err == SQLITE_OK);
+        err = sqlite3_bind_int(g_stmt_update_faction, 1, no);
+        assert(err == SQLITE_OK);
+        err = sqlite3_bind_int(g_stmt_update_faction, 2, turn);
+        assert(err == SQLITE_OK);
+        err = sqlite3_bind_text(g_stmt_update_faction, 3, email, -1, SQLITE_STATIC);
+        assert(err == SQLITE_OK);
+        err = sqlite3_bind_text(g_stmt_update_faction, 4, password, -1, SQLITE_STATIC);
+        assert(err == SQLITE_OK);
+        err = sqlite3_bind_int(g_stmt_update_faction, 5, id);
+        assert(err == SQLITE_OK);
+        err = sqlite3_step(g_stmt_update_faction);
+        assert(err == SQLITE_DONE);
+        rows = sqlite3_changes(g_game_db);
+        if (rows != 0) {
+            return id;
+        }
+    }
+    err = sqlite3_reset(g_stmt_insert_faction);
+    assert(err == SQLITE_OK);
+    err = sqlite3_bind_int(g_stmt_insert_faction, 1, no);
+    assert(err == SQLITE_OK);
+    err = sqlite3_bind_int(g_stmt_insert_faction, 2, turn);
+    assert(err == SQLITE_OK);
+    err = sqlite3_bind_text(g_stmt_insert_faction, 3, email, -1, SQLITE_STATIC);
+    assert(err == SQLITE_OK);
+    err = sqlite3_bind_text(g_stmt_insert_faction, 4, password, -1, SQLITE_STATIC);
+    assert(err == SQLITE_OK);
+    err = sqlite3_step(g_stmt_insert_faction);
+    assert(err == SQLITE_DONE);
+    ERRNO_CHECK();
+
+    row_id = sqlite3_last_insert_rowid(g_game_db);
+    assert(row_id <= INT_MAX);
+    return (int)row_id;
+}
+
 void db_driver_open(void)
 {
     int err;
-    const char *dbname;
+    const char *dbname, *dbtemp;
 
     ERRNO_CHECK();
-    g_order_batchsize = config_get_int("game.dbbatch", 100);
+
     dbname = config_get("game.dbname");
-    if (!dbname) {
-        dbname = "";
-    }
-    err = sqlite3_open(dbname, &g_db);
+    if (!dbname) dbname = "";
+    err = sqlite3_open(dbname, &g_game_db);
     assert(err == SQLITE_OK);
-    err = sqlite3_exec(g_db, "PRAGMA journal_mode=OFF", NULL, NULL, NULL);
+    err = sqlite3_exec(g_game_db, "CREATE TABLE IF NOT EXISTS factions (id INTEGER PRIMARY KEY, no INTEGER NOT NULL, email VARCHAR(128), password VARCHAR(128), turn INTEGER NOT NULL)", NULL, NULL, NULL);
     assert(err == SQLITE_OK);
-    err = sqlite3_exec(g_db, "PRAGMA synchronous=OFF", NULL, NULL, NULL);
+    err = sqlite3_prepare_v2(g_game_db, "UPDATE factions SET no=?, turn=?, email=?, password=? WHERE id=?", -1, &g_stmt_update_faction, NULL);
     assert(err == SQLITE_OK);
-    err = sqlite3_exec(g_db, "CREATE TABLE IF NOT EXISTS orders (id INTEGER PRIMARY KEY, data TEXT NOT NULL)", NULL, NULL, NULL);
+    err = sqlite3_prepare_v2(g_game_db, "INSERT INTO factions (no, turn, email, password) VALUES (?,?,?,?)", -1, &g_stmt_insert_faction, NULL);
     assert(err == SQLITE_OK);
-    err = sqlite3_prepare_v2(g_db, "INSERT INTO orders (data) VALUES (?)", -1, &g_stmt_insert, NULL);
+
+    g_order_batchsize = config_get_int("game.dbbatch", 100);
+    dbtemp = config_get("game.db.temp");
+    err = sqlite3_open(dbtemp ? dbtemp : dbname, &g_temp_db);
     assert(err == SQLITE_OK);
-    err = sqlite3_prepare_v2(g_db, "SELECT data FROM orders WHERE id = ?", -1, &g_stmt_select, NULL);
+    err = sqlite3_exec(g_temp_db, "PRAGMA journal_mode=OFF", NULL, NULL, NULL);
     assert(err == SQLITE_OK);
+    err = sqlite3_exec(g_temp_db, "PRAGMA synchronous=OFF", NULL, NULL, NULL);
+    assert(err == SQLITE_OK);
+    err = sqlite3_exec(g_temp_db, "CREATE TABLE IF NOT EXISTS orders (id INTEGER PRIMARY KEY, data TEXT NOT NULL)", NULL, NULL, NULL);
+    assert(err == SQLITE_OK);
+    err = sqlite3_prepare_v2(g_temp_db, "INSERT INTO orders (data) VALUES (?)", -1, &g_stmt_insert_order, NULL);
+    assert(err == SQLITE_OK);
+    err = sqlite3_prepare_v2(g_temp_db, "SELECT data FROM orders WHERE id=?", -1, &g_stmt_select_order, NULL);
+    assert(err == SQLITE_OK);
+
     ERRNO_CHECK();
 }
 
@@ -122,12 +185,22 @@ void db_driver_close(void)
     int err;
 
     ERRNO_CHECK();
-    err = sqlite3_finalize(g_stmt_select);
-    assert(err == SQLITE_OK);
-    err = sqlite3_finalize(g_stmt_insert);
-    assert(err == SQLITE_OK);
-    err = sqlite3_close(g_db);
-    assert(err == SQLITE_OK);
+    if (g_temp_db) {
+        err = sqlite3_finalize(g_stmt_select_order);
+        assert(err == SQLITE_OK);
+        err = sqlite3_finalize(g_stmt_insert_order);
+        assert(err == SQLITE_OK);
+        err = sqlite3_close(g_temp_db);
+        assert(err == SQLITE_OK);
+    }
+    if (g_game_db) {
+        err = sqlite3_finalize(g_stmt_update_faction);
+        assert(err == SQLITE_OK);
+        err = sqlite3_finalize(g_stmt_insert_faction);
+        assert(err == SQLITE_OK);
+        err = sqlite3_close(g_game_db);
+        assert(err == SQLITE_OK);
+    }
     ERRNO_CHECK();
 }
 
diff --git a/src/kernel/faction.c b/src/kernel/faction.c
index b4dfe51ca..8c77984ba 100755
--- a/src/kernel/faction.c
+++ b/src/kernel/faction.c
@@ -230,7 +230,7 @@ static int unused_faction_id(void)
 }
 
 faction *addfaction(const char *email, const char *password,
-    const struct race * frace, const struct locale * loc, int subscription)
+    const struct race * frace, const struct locale * loc)
 {
     faction *f = calloc(sizeof(faction), 1);
     char buf[128];
@@ -249,7 +249,7 @@ faction *addfaction(const char *email, const char *password,
     f->race = frace;
     f->magiegebiet = 0;
     f->locale = loc;
-    f->subscription = subscription;
+    f->uid = 0;
     f->flags = FFL_ISNEW|FFL_PWMSG;
 
     if (!password) password = itoa36(rng_int());
@@ -393,7 +393,7 @@ faction *get_or_create_monsters(void)
     if (!f) {
         const race *rc = rc_get_or_create("dragon");
         const char *email = config_get("monster.email");
-        f = addfaction(email, NULL, rc, default_locale, 0);
+        f = addfaction(email, NULL, rc, default_locale);
         renumber_faction(f, MONSTER_ID);
         faction_setname(f, "Monster");
         fset(f, FFL_NPC | FFL_NOIDLEOUT);
@@ -839,7 +839,7 @@ int writepasswd(void)
 
         for (f = factions; f; f = f->next) {
             fprintf(F, "%s:%s:%s:%d\n",
-                itoa36(f->no), faction_getemail(f), f->_password, f->subscription);
+                itoa36(f->no), faction_getemail(f), f->_password, f->uid);
         }
         fclose(F);
         return 0;
diff --git a/src/kernel/faction.h b/src/kernel/faction.h
index 8d13f64d1..63c5a9993 100644
--- a/src/kernel/faction.h
+++ b/src/kernel/faction.h
@@ -61,7 +61,7 @@ extern "C" {
         struct region *first;
         struct region *last;
         int no;
-        int subscription;
+        int uid;
         int flags;
         char *name;
         char *banner;
@@ -112,7 +112,7 @@ extern "C" {
     const char *factionname(const struct faction *f);
     struct unit *addplayer(struct region *r, faction * f);
     struct faction *addfaction(const char *email, const char *password,
-        const struct race *frace, const struct locale *loc, int subscription);
+        const struct race *frace, const struct locale *loc);
     bool checkpasswd(const faction * f, const char *passwd);
     int writepasswd(void);
     void destroyfaction(faction ** f);
diff --git a/src/kernel/faction.test.c b/src/kernel/faction.test.c
index 37ec70e50..6f3c5cfaf 100644
--- a/src/kernel/faction.test.c
+++ b/src/kernel/faction.test.c
@@ -112,7 +112,7 @@ static void test_addfaction(CuTest *tc) {
     test_setup();
     rc = rc_get_or_create("human");
     lang = test_create_locale();
-    f = addfaction("test@eressea.de", "hurrdurr", rc, lang, 1234);
+    f = addfaction("test@eressea.de", "hurrdurr", rc, lang);
     CuAssertPtrNotNull(tc, f);
     CuAssertPtrNotNull(tc, f->name);
     CuAssertPtrEquals(tc, NULL, (void *)f->units);
@@ -124,7 +124,6 @@ static void test_addfaction(CuTest *tc) {
     CuAssertStrEquals(tc, "test@eressea.de", f->email);
     CuAssertTrue(tc, checkpasswd(f, "hurrdurr"));
     CuAssertPtrEquals(tc, (void *)lang, (void *)f->locale);
-    CuAssertIntEquals(tc, 1234, f->subscription);
     CuAssertIntEquals(tc, FFL_ISNEW|FFL_PWMSG, f->flags);
     CuAssertIntEquals(tc, 0, f->age);
     CuAssertTrue(tc, faction_alive(f));
diff --git a/src/kernel/save.c b/src/kernel/save.c
index 51585f26c..922fcc24f 100644
--- a/src/kernel/save.c
+++ b/src/kernel/save.c
@@ -969,7 +969,10 @@ faction *read_faction(gamedata * data)
             a_remove(&f->attribs, f->attribs);
         }
     }
-    READ_INT(data->store, &f->subscription);
+    READ_INT(data->store, &f->uid);
+    if (data->version < FACTION_UID_VERSION) {
+        f->uid = 0;
+    }
 
     if (data->version >= SPELL_LEVEL_VERSION) {
         READ_INT(data->store, &f->max_spelllevel);
@@ -1100,7 +1103,7 @@ void write_faction(gamedata *data, const faction * f)
     assert(f->_alive);
     assert(f->no > 0 && f->no <= MAX_UNIT_NR);
     WRITE_INT(data->store, f->no);
-    WRITE_INT(data->store, f->subscription);
+    WRITE_INT(data->store, f->uid);
 #if RELEASE_VERSION >= SPELL_LEVEL_VERSION
     WRITE_INT(data->store, f->max_spelllevel);
 #endif
@@ -1681,6 +1684,5 @@ int write_game(gamedata *data) {
     WRITE_SECTION(store);
     write_borders(store);
     WRITE_SECTION(store);
-
     return 0;
 }
diff --git a/src/laws.c b/src/laws.c
index 922f4c366..fe97931ad 100644
--- a/src/laws.c
+++ b/src/laws.c
@@ -3974,33 +3974,6 @@ void turn_end(void)
     update_spells();
 }
 
-void update_subscriptions(void)
-{
-    FILE *F;
-    char zText[4096];
-
-    path_join(basepath(), "subscriptions", zText, sizeof(zText));
-    F = fopen(zText, "r");
-    if (F == NULL) {
-        log_warning(0, "could not open %s.\n", zText);
-        return;
-    }
-    for (;;) {
-        char zFaction[5];
-        int subscription, fno;
-        faction *f;
-
-        if (fscanf(F, "%4d %4s", &subscription, zFaction) <= 0)
-            break;
-        fno = atoi36(zFaction);
-        f = findfaction(fno);
-        if (f != NULL) {
-            f->subscription = subscription;
-        }
-    }
-    fclose(F);
-}
-
 /** determine if unit can be seen by faction
  * @param f -- the observiong faction
  * @param u -- the unit that is observed
diff --git a/src/laws.h b/src/laws.h
index b7958891f..383b099ae 100755
--- a/src/laws.h
+++ b/src/laws.h
@@ -41,7 +41,6 @@ extern "C" {
     void demographics(void);
     void immigration(void);
     void update_guards(void);
-    void update_subscriptions(void);
     void deliverMail(struct faction *f, struct region *r, struct unit *u,
         const char *s, struct unit *receiver);
 
diff --git a/src/main.c b/src/main.c
index 599fbdd67..eae7f440c 100644
--- a/src/main.c
+++ b/src/main.c
@@ -96,6 +96,7 @@ static const char * valid_keys[] = {
     "game.era",
     "game.sender",
     "game.dbname",
+    "game.db.",
     "game.dbbatch",
     "editor.color",
     "editor.codepage",
diff --git a/src/modules/autoseed.c b/src/modules/autoseed.c
index 374b6379c..df4e543ce 100644
--- a/src/modules/autoseed.c
+++ b/src/modules/autoseed.c
@@ -95,7 +95,7 @@ newfaction *read_newfactions(const char *filename)
         faction *f;
         char race[20], email[64], lang[8], password[16];
         newfaction *nf, **nfi;
-        int alliance = 0, subscription = 0;
+        int alliance = 0, uid = 0;
 
         if (fgets(buf, sizeof(buf), F) == NULL)
             break;
@@ -104,7 +104,7 @@ newfaction *read_newfactions(const char *filename)
         password[0] = '\0';
 
         if (sscanf(buf, "%54s %19s %7s %15s %4d %4d", email, race, lang, 
-            password, &subscription, &alliance) < 3) {
+            password, &uid, &alliance) < 3) {
             break;
         }
         if (email[0] == '#') {
@@ -137,13 +137,13 @@ newfaction *read_newfactions(const char *filename)
         if (check_email(email) == 0) {
           nf->email = str_strdup(email);
         } else {
-            log_error("Invalid email address for subscription %s: %s\n", itoa36(subscription), email);
+            log_error("Invalid email address for subscription %s: %s\n", itoa36(uid), email);
             free(nf);
             continue;
         }
         nf->password = str_strdup(password);
         nf->race = rc_find(race);
-        nf->subscription = subscription;
+        nf->uid = uid;
         if (alliances != NULL) {
             struct alliance *al = findalliance(alliance);
             if (al == NULL) {
@@ -557,7 +557,7 @@ int autoseed(newfaction ** players, int nsize, int max_agediff)
             ++tsize;
             assert(r->land && r->units == 0);
             u = addplayer(r, addfaction(nextf->email, nextf->password, nextf->race,
-                nextf->lang, nextf->subscription));
+                nextf->lang));
             f = u->faction;
             fset(f, FFL_ISNEW);
             f->alliance = nextf->allies;
@@ -857,7 +857,7 @@ static void starting_region(newfaction ** players, region * r, region * rn[])
         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, 0));
+        addplayer(r, addfaction(nf->email, passwd, rc, lang));
         *players = nf->next;
         free_newfaction(nf);
     }
diff --git a/src/modules/autoseed.h b/src/modules/autoseed.h
index 937a1f8b5..74c7409ad 100644
--- a/src/modules/autoseed.h
+++ b/src/modules/autoseed.h
@@ -24,7 +24,7 @@ extern "C" {
         char *password;
         const struct locale *lang;
         const struct race *race;
-        int subscription;
+        int uid;
         bool oldregions;
         struct alliance *allies;
     } newfaction;
diff --git a/src/spells.c b/src/spells.c
index 8caf29039..02cbe43b5 100644
--- a/src/spells.c
+++ b/src/spells.c
@@ -4192,7 +4192,7 @@ static int sp_calm_monster(castorder * co)
         return 0;
     }
 
-    effect = mage->faction->subscription;
+    effect = mage->faction->uid;
     c = create_curse(mage, &target->attribs, &ct_calmmonster, force,
         (int)force, effect, 0);
     if (c == NULL) {
diff --git a/src/tests.c b/src/tests.c
index ddd6f7cf5..2dc5bccc6 100644
--- a/src/tests.c
+++ b/src/tests.c
@@ -166,7 +166,7 @@ struct locale * test_create_locale(void) {
 struct faction *test_create_faction(const struct race *rc)
 {
     struct locale * loc = test_create_locale();
-    faction *f = addfaction("nobody@eressea.de", NULL, rc ? rc : test_create_race("human"), loc, 0);
+    faction *f = addfaction("nobody@eressea.de", NULL, rc ? rc : test_create_race("human"), loc);
     test_clear_messages(f);
     return f;
 }
diff --git a/src/util/gamedata.h b/src/util/gamedata.h
index 2dd4e1342..191dab054 100644
--- a/src/util/gamedata.h
+++ b/src/util/gamedata.h
@@ -37,10 +37,11 @@
 #define SKILLSORT_VERSION 360 /* u->skills is sorted */
 #define LANDDISPLAY_VERSION 360 /* r.display is now in r.land.display */
 #define FIXATKEYS_VERSION 361 /* remove global.attribs, fix at_keys */
+#define FACTION_UID_VERSION 362 /* f->uid contains a database id */
 /* unfinished: */
 #define CRYPT_VERSION 400 /* passwords are encrypted */
 
-#define RELEASE_VERSION FIXATKEYS_VERSION /* current datafile */
+#define RELEASE_VERSION FACTION_UID_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 */
 

From 8cccef41ad4976e1e7d8457b3f1a7a744f9698ba Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Tue, 25 Sep 2018 18:02:00 +0200
Subject: [PATCH 29/81] sort cmakelists filenames

---
 .editorconfig      |  5 ++++
 src/CMakeLists.txt | 72 +++++++++++++++++++++++-----------------------
 2 files changed, 41 insertions(+), 36 deletions(-)

diff --git a/.editorconfig b/.editorconfig
index cd3315bd8..fafe79d54 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -24,3 +24,8 @@ indent_style = tab
 [.travis.yml]
 indent_style = space
 indent_size = 2
+
+# Matches exact files
+[CMakeLists.txt]
+indent_style = space
+indent_size = 2
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 96351cdc9..9502cc4bf 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -86,48 +86,48 @@ ENDIF()
 
 set (ERESSEA_SRC
   vortex.c
-  automate.c
-  move.c
-  piracy.c
-  spells.c
-  battle.c
-  alchemy.c
   academy.c
+  alchemy.c
+  automate.c
+  battle.c
   chaos.c
-  upkeep.c
-  names.c
-  lighthouse.c
-  reports.c
-  teleport.c
-  guard.c
-  jsonconf.c
-  prefix.c
-  donations.c
-  eressea.c
-  direction.c
-  keyword.c
-  skill.c
-  json.c
   creport.c
-  report.c
-  steal.c
+  direction.c
+  donations.c
   economy.c
+  eressea.c
   exparse.c
   give.c
+  guard.c
   items.c
+  json.c
+  jsonconf.c
+  keyword.c
   laws.c
+  lighthouse.c
   magic.c
   market.c
+  monsters.c
   morale.c
+  move.c
+  names.c
   orderfile.c
+  piracy.c
+  prefix.c
   randenc.c
   renumber.c
-  volcano.c
+  report.c
+  reports.c
+  skill.c
+  spells.c
   spy.c
+  steal.c
   study.c
   summary.c
   travelthru.c
-  monsters.c
+  teleport.c
+  upkeep.c
+  volcano.c
   wormhole.c
   ${SPELLS_SRC}
   ${RACES_SRC}
@@ -141,31 +141,31 @@ set (ERESSEA_SRC
 )
 
 set(SERVER_SRC
-  main.c
-  console.c
-  helpers.c
-  bind_tolua.c
   bind_building.c
   bind_config.c
-  bind_locale.c
   bind_eressea.c
   bind_faction.c
-  bind_order.c
-  bindings.c
+  bind_locale.c
   bind_message.c
   bind_monsters.c
+  bind_order.c
   bind_process.c
   bind_region.c
   bind_ship.c
   bind_storage.c
+  bind_tolua.c
   bind_unit.c
+  bindings.c
+  console.c
+  helpers.c
+  main.c
 )
 
 if (CURSES_FOUND)
 set (SERVER_SRC ${SERVER_SRC}
+  bind_gmtool.c
   gmtool.c
   listbox.c
-  bind_gmtool.c
 )
 endif(CURSES_FOUND)
 
@@ -193,8 +193,6 @@ target_link_libraries(eressea
 )
 
 set(TESTS_SRC
-  test_eressea.c
-  tests.c
   academy.test.c
   alchemy.test.c
   automate.test.c
@@ -219,13 +217,15 @@ set(TESTS_SRC
   piracy.test.c
   prefix.test.c
   renumber.test.c
-  reports.test.c
   report.test.c
-  summary.test.c
+  reports.test.c
   skill.test.c
   spells.test.c
   spy.test.c
   study.test.c
+  summary.test.c
+  test_eressea.c
+  tests.c
   tests.test.c
   travelthru.test.c
   upkeep.test.c

From 274d44ee183c3c43b6aa75b02dfd4e20bb6e7a07 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Tue, 25 Sep 2018 18:07:02 +0200
Subject: [PATCH 30/81] Move the gamedb to a separate file.

---
 src/CMakeLists.txt |  1 +
 src/eressea.c      | 12 ------------
 src/eressea.h      |  1 -
 src/gamedb.c       | 20 ++++++++++++++++++++
 src/gamedb.h       |  3 +++
 5 files changed, 24 insertions(+), 13 deletions(-)
 create mode 100644 src/gamedb.c
 create mode 100644 src/gamedb.h

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 9502cc4bf..7b50907f9 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -97,6 +97,7 @@ set (ERESSEA_SRC
   economy.c
   eressea.c
   exparse.c
+  gamedb.c
   give.c
   guard.c
   items.c
diff --git a/src/eressea.c b/src/eressea.c
index 67ab26af5..0bf1454ee 100644
--- a/src/eressea.c
+++ b/src/eressea.c
@@ -39,18 +39,6 @@
 /* manually free() everything at exit? */
 #undef CLEANUP_CODE
 
-void game_write_dbstate(void)
-{
-    faction *f;
-
-    for (f = factions; f; f = f->next) {
-        int uid = dblib_save_faction(f, turn);
-        if (uid > 0) {
-            f->uid = uid;
-        }
-    }
-}
-
 void game_done(void)
 {
     log_dead_factions();
diff --git a/src/eressea.h b/src/eressea.h
index cfc1b12ef..f3ea4d4a5 100755
--- a/src/eressea.h
+++ b/src/eressea.h
@@ -6,7 +6,6 @@ extern "C" {
 
     void game_init(void);
     void game_done(void);
-    void game_write_dbstate(void);
 
 #ifdef __cplusplus
 }
diff --git a/src/gamedb.c b/src/gamedb.c
new file mode 100644
index 000000000..cf9a922bc
--- /dev/null
+++ b/src/gamedb.c
@@ -0,0 +1,20 @@
+#ifdef _MSC_VER
+#include <platform.h>
+#endif
+
+#include "gamedb.h"
+
+#include "kernel/database.h"
+#include "kernel/faction.h"
+
+void gamedb_update(void)
+{
+    faction *f;
+
+    for (f = factions; f; f = f->next) {
+        int uid = dblib_save_faction(f, turn);
+        if (uid > 0) {
+            f->uid = uid;
+        }
+    }
+}
diff --git a/src/gamedb.h b/src/gamedb.h
new file mode 100644
index 000000000..ea4614298
--- /dev/null
+++ b/src/gamedb.h
@@ -0,0 +1,3 @@
+#pragma once
+
+void gamedb_update(void);

From 4e5240628ee6f3a3b3adb8d6c492833c0a912a48 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Tue, 25 Sep 2018 18:52:29 +0200
Subject: [PATCH 31/81] Extract gamedb open/close to separate functions.

---
 src/gamedb.c           | 20 +++++++++++++++-----
 src/kernel/database.c  |  7 +++++--
 src/kernel/db/driver.h |  9 +++++++--
 src/kernel/db/sqlite.c | 42 +++++++++++++++++++++++++++++-------------
 4 files changed, 56 insertions(+), 22 deletions(-)

diff --git a/src/gamedb.c b/src/gamedb.c
index cf9a922bc..e3c16b06e 100644
--- a/src/gamedb.c
+++ b/src/gamedb.c
@@ -4,17 +4,27 @@
 
 #include "gamedb.h"
 
+#include "kernel/db/driver.h"
 #include "kernel/database.h"
 #include "kernel/faction.h"
 
-void gamedb_update(void)
+int gamedb_update(void)
 {
     faction *f;
+    int err;
+    const char *dbname;
 
-    for (f = factions; f; f = f->next) {
-        int uid = dblib_save_faction(f, turn);
-        if (uid > 0) {
-            f->uid = uid;
+    dbname = config_get("game.dbname");
+
+    err = db_driver_open(DB_GAME, dbname);
+    if (err == 0) {
+        for (f = factions; f; f = f->next) {
+            int uid = dblib_save_faction(f, turn);
+            if (uid > 0) {
+                f->uid = uid;
+            }
         }
+        db_driver_close(DB_GAME);
     }
+    return err;
 }
diff --git a/src/kernel/database.c b/src/kernel/database.c
index c27ca21fc..137665e31 100644
--- a/src/kernel/database.c
+++ b/src/kernel/database.c
@@ -34,10 +34,13 @@ int dblib_save_faction(const faction *f, int turn) {
 
 void dblib_open(void)
 {
-    db_driver_open();
+    const char *dbname;
+
+    dbname = config_get("game.dbswap");
+    db_driver_open(DB_SWAP, dbname);
 }
 
 void dblib_close(void)
 {
-    db_driver_close();
+    db_driver_close(DB_SWAP);
 }
diff --git a/src/kernel/db/driver.h b/src/kernel/db/driver.h
index 1e408e37e..26b0461e3 100644
--- a/src/kernel/db/driver.h
+++ b/src/kernel/db/driver.h
@@ -2,8 +2,13 @@
 
 struct order_data;
 
-void db_driver_open(void);
-void db_driver_close(void);
+typedef enum database_t {
+    DB_SWAP,
+    DB_GAME,
+} database_t;
+
+int db_driver_open(database_t db, const char *dbname);
+void db_driver_close(database_t db);
 int db_driver_order_save(struct order_data *od);
 struct order_data *db_driver_order_load(int id);
 int db_driver_faction_save(int id, int no, int turn, const char *email, const char *password);
diff --git a/src/kernel/db/sqlite.c b/src/kernel/db/sqlite.c
index 49dbd001e..70cacaf48 100644
--- a/src/kernel/db/sqlite.c
+++ b/src/kernel/db/sqlite.c
@@ -144,15 +144,9 @@ int db_driver_faction_save(int id, int no, int turn, const char *email, const ch
     return (int)row_id;
 }
 
-void db_driver_open(void)
-{
+static int db_open_game(const char *dbname) {
     int err;
-    const char *dbname, *dbtemp;
 
-    ERRNO_CHECK();
-
-    dbname = config_get("game.dbname");
-    if (!dbname) dbname = "";
     err = sqlite3_open(dbname, &g_game_db);
     assert(err == SQLITE_OK);
     err = sqlite3_exec(g_game_db, "CREATE TABLE IF NOT EXISTS factions (id INTEGER PRIMARY KEY, no INTEGER NOT NULL, email VARCHAR(128), password VARCHAR(128), turn INTEGER NOT NULL)", NULL, NULL, NULL);
@@ -162,9 +156,16 @@ void db_driver_open(void)
     err = sqlite3_prepare_v2(g_game_db, "INSERT INTO factions (no, turn, email, password) VALUES (?,?,?,?)", -1, &g_stmt_insert_faction, NULL);
     assert(err == SQLITE_OK);
 
+    ERRNO_CHECK();
+    return 0;
+}
+
+static int db_open_swap(const char *dbname) {
+    int err;
+
     g_order_batchsize = config_get_int("game.dbbatch", 100);
-    dbtemp = config_get("game.db.temp");
-    err = sqlite3_open(dbtemp ? dbtemp : dbname, &g_temp_db);
+
+    err = sqlite3_open(dbname, &g_temp_db);
     assert(err == SQLITE_OK);
     err = sqlite3_exec(g_temp_db, "PRAGMA journal_mode=OFF", NULL, NULL, NULL);
     assert(err == SQLITE_OK);
@@ -176,16 +177,30 @@ void db_driver_open(void)
     assert(err == SQLITE_OK);
     err = sqlite3_prepare_v2(g_temp_db, "SELECT data FROM orders WHERE id=?", -1, &g_stmt_select_order, NULL);
     assert(err == SQLITE_OK);
-
     ERRNO_CHECK();
+    return 0;
 }
 
-void db_driver_close(void)
+int db_driver_open(database_t db, const char *dbname)
+{
+    ERRNO_CHECK();
+
+    if (db == DB_SWAP) {
+        return db_open_swap(dbname);
+    }
+    else if (db == DB_GAME) {
+        return db_open_game(dbname);
+    }
+    return -1;
+}
+
+void db_driver_close(database_t db)
 {
     int err;
 
     ERRNO_CHECK();
-    if (g_temp_db) {
+    if (db == DB_SWAP) {
+        assert(g_temp_db);
         err = sqlite3_finalize(g_stmt_select_order);
         assert(err == SQLITE_OK);
         err = sqlite3_finalize(g_stmt_insert_order);
@@ -193,7 +208,8 @@ void db_driver_close(void)
         err = sqlite3_close(g_temp_db);
         assert(err == SQLITE_OK);
     }
-    if (g_game_db) {
+    else if (db == DB_GAME) {
+        assert(g_game_db);
         err = sqlite3_finalize(g_stmt_update_faction);
         assert(err == SQLITE_OK);
         err = sqlite3_finalize(g_stmt_insert_faction);

From 74aa4bdaf37f1e6e551e86473acd753b536bb05b Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Tue, 25 Sep 2018 19:15:03 +0200
Subject: [PATCH 32/81] bindings for gamedb_update, run after turn.

---
 scripts/run-turn.lua |  3 ++-
 src/bindings.c       | 19 ++++++++++++++-----
 src/gamedb.c         |  4 +++-
 src/gamedb.h         |  2 +-
 src/main.c           |  2 +-
 5 files changed, 21 insertions(+), 9 deletions(-)

diff --git a/scripts/run-turn.lua b/scripts/run-turn.lua
index 62d48ec51..35303b038 100644
--- a/scripts/run-turn.lua
+++ b/scripts/run-turn.lua
@@ -95,8 +95,9 @@ local function write_htpasswd()
 end
 
 local function write_files(locales)
+    write_database()
     write_passwords()
-    write_htpasswd()
+    -- write_htpasswd()
     write_reports()
     write_summary()
 end
diff --git a/src/bindings.c b/src/bindings.c
index c549a4801..b2da38eba 100755
--- a/src/bindings.c
+++ b/src/bindings.c
@@ -4,15 +4,16 @@
 
 #include "bindings.h"
 
-#include "magic.h"
-#include "skill.h"
-#include "helpers.h"
 #include "console.h"
+#include "gamedb.h"
+#include "helpers.h"
+#include "laws.h"
+#include "magic.h"
 #include "reports.h"
+#include "skill.h"
 #include "study.h"
 #include "summary.h"
 #include "teleport.h"
-#include "laws.h"
 
 #include "kernel/calendar.h"
 #include "kernel/config.h"
@@ -437,7 +438,14 @@ static int tolua_write_passwords(lua_State * L)
 {
     int result = writepasswd();
     lua_pushinteger(L, result);
-    return 0;
+    return 1;
+}
+
+static int tolua_write_database(lua_State * L)
+{
+    int result = gamedb_update();
+    lua_pushinteger(L, result);
+    return 1;
 }
 
 static int tolua_write_summary(lua_State * L)
@@ -949,6 +957,7 @@ int tolua_bindings_open(lua_State * L, const dictionary *inifile)
         tolua_function(L, TOLUA_CAST "write_report", tolua_write_report);
         tolua_function(L, TOLUA_CAST "write_summary", tolua_write_summary);
         tolua_function(L, TOLUA_CAST "write_passwords", tolua_write_passwords);
+        tolua_function(L, TOLUA_CAST "write_database", tolua_write_database);
         tolua_function(L, TOLUA_CAST "message_unit", tolua_message_unit);
         tolua_function(L, TOLUA_CAST "message_faction", tolua_message_faction);
         tolua_function(L, TOLUA_CAST "message_region", tolua_message_region);
diff --git a/src/gamedb.c b/src/gamedb.c
index e3c16b06e..e570d61e8 100644
--- a/src/gamedb.c
+++ b/src/gamedb.c
@@ -4,9 +4,11 @@
 
 #include "gamedb.h"
 
-#include "kernel/db/driver.h"
+#include "kernel/config.h"
+#include "kernel/calendar.h"
 #include "kernel/database.h"
 #include "kernel/faction.h"
+#include "kernel/db/driver.h"
 
 int gamedb_update(void)
 {
diff --git a/src/gamedb.h b/src/gamedb.h
index ea4614298..01251f356 100644
--- a/src/gamedb.h
+++ b/src/gamedb.h
@@ -1,3 +1,3 @@
 #pragma once
 
-void gamedb_update(void);
+int gamedb_update(void);
diff --git a/src/main.c b/src/main.c
index eae7f440c..5bb4ad4ee 100644
--- a/src/main.c
+++ b/src/main.c
@@ -96,7 +96,7 @@ static const char * valid_keys[] = {
     "game.era",
     "game.sender",
     "game.dbname",
-    "game.db.",
+    "game.dbswap",
     "game.dbbatch",
     "editor.color",
     "editor.codepage",

From bbbed8079006828b2ca2c8c5db66cbd2b4647a89 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno@eressea.de>
Date: Wed, 26 Sep 2018 15:36:21 +0200
Subject: [PATCH 33/81] add openwall bcrypt sources

---
 crypt_blowfish/CMakeLists.txt   |  24 +
 crypt_blowfish/LINKS            |  29 +
 crypt_blowfish/PERFORMANCE      |  30 ++
 crypt_blowfish/README           |  68 +++
 crypt_blowfish/bcrypt.c         | 195 +++++++
 crypt_blowfish/bcrypt.h         |  97 ++++
 crypt_blowfish/crypt.h          |  24 +
 crypt_blowfish/crypt_blowfish.c | 907 ++++++++++++++++++++++++++++++++
 crypt_blowfish/crypt_blowfish.h |  27 +
 crypt_blowfish/crypt_gensalt.c  | 124 +++++
 crypt_blowfish/crypt_gensalt.h  |  30 ++
 crypt_blowfish/ow-crypt.h       |  43 ++
 crypt_blowfish/x86.S            | 203 +++++++
 13 files changed, 1801 insertions(+)
 create mode 100644 crypt_blowfish/CMakeLists.txt
 create mode 100644 crypt_blowfish/LINKS
 create mode 100644 crypt_blowfish/PERFORMANCE
 create mode 100644 crypt_blowfish/README
 create mode 100644 crypt_blowfish/bcrypt.c
 create mode 100644 crypt_blowfish/bcrypt.h
 create mode 100644 crypt_blowfish/crypt.h
 create mode 100644 crypt_blowfish/crypt_blowfish.c
 create mode 100644 crypt_blowfish/crypt_blowfish.h
 create mode 100644 crypt_blowfish/crypt_gensalt.c
 create mode 100644 crypt_blowfish/crypt_gensalt.h
 create mode 100644 crypt_blowfish/ow-crypt.h
 create mode 100644 crypt_blowfish/x86.S

diff --git a/crypt_blowfish/CMakeLists.txt b/crypt_blowfish/CMakeLists.txt
new file mode 100644
index 000000000..b6f810721
--- /dev/null
+++ b/crypt_blowfish/CMakeLists.txt
@@ -0,0 +1,24 @@
+cmake_minimum_required(VERSION 2.6)
+project (bcrypt C)
+
+IF (MSVC)
+    include (MSVC)
+    MSVC_SET_WARNING_LEVEL(3)
+ENDIF (MSVC)
+
+SET (LIB_SRC crypt_blowfish.c crypt_gensalt.c bcrypt.c)
+ADD_LIBRARY (bcrypt ${LIB_SRC})
+
+set (CJSON_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL "cJSON headers")
+set (CJSON_LIBRARIES bcrypt CACHE INTERNAL "bcrypt libraries")
+
+IF(UNIX AND NOT APPLE)
+    FIND_LIBRARY(UNIX_MATH_LIBRARY m)
+    SET(BCRYPT_LIBRARIES ${BCRYPT_LIBRARIES} ${UNIX_MATH_LIBRARY} CACHE
+	    INTERNAL "bcrypt libraries")
+ENDIF()
+            
+IF (MSVC)
+    MSVC_CRT_SECURE_NO_WARNINGS (bcrypt)
+ENDIF (MSVC)
+
diff --git a/crypt_blowfish/LINKS b/crypt_blowfish/LINKS
new file mode 100644
index 000000000..a6cb7e1c3
--- /dev/null
+++ b/crypt_blowfish/LINKS
@@ -0,0 +1,29 @@
+New versions of this package (crypt_blowfish):
+
+	http://www.openwall.com/crypt/
+
+A paper on the algorithm that explains its design decisions:
+
+	http://www.usenix.org/events/usenix99/provos.html
+
+Unix Seventh Edition Manual, Volume 2: the password scheme (1978):
+
+	http://plan9.bell-labs.com/7thEdMan/vol2/password
+
+The Openwall GNU/*/Linux (Owl) tcb suite implementing the alternative
+password shadowing scheme.  This includes a PAM module which
+supersedes pam_unix and uses the password hashing framework provided
+with crypt_blowfish when setting new passwords.
+
+	http://www.openwall.com/tcb/
+
+pam_passwdqc, a password strength checking and policy enforcement
+module for PAM-aware password changing programs:
+
+	http://www.openwall.com/passwdqc/
+
+John the Ripper password cracker:
+
+	http://www.openwall.com/john/
+
+$Owl: Owl/packages/glibc/crypt_blowfish/LINKS,v 1.4 2005/11/16 13:09:47 solar Exp $
diff --git a/crypt_blowfish/PERFORMANCE b/crypt_blowfish/PERFORMANCE
new file mode 100644
index 000000000..9d6fe4ef5
--- /dev/null
+++ b/crypt_blowfish/PERFORMANCE
@@ -0,0 +1,30 @@
+These numbers are for 32 iterations ("$2a$05"):
+
+			OpenBSD 3.0 bcrypt(*)	crypt_blowfish 0.4.4
+Pentium III, 840 MHz	99 c/s			121 c/s (+22%)
+Alpha 21164PC, 533 MHz	55.5 c/s		76.9 c/s (+38%)
+UltraSparc IIi, 400 MHz	49.9 c/s		52.5 c/s (+5%)
+Pentium, 120 MHz	8.8 c/s			20.1 c/s (+128%)
+PA-RISC 7100LC, 80 MHz	8.5 c/s			16.3 c/s (+92%)
+
+(*) built with -fomit-frame-pointer -funroll-loops, which I don't
+think happens for libcrypt.
+
+Starting with version 1.1 released in June 2011, default builds of
+crypt_blowfish invoke a quick self-test on every hash computation.
+This has roughly a 4.8% performance impact at "$2a$05", but only a 0.6%
+impact at a more typical setting of "$2a$08".
+
+The large speedup for the original Pentium is due to the assembly
+code and the weird optimizations this processor requires.
+
+The numbers for password cracking are 2 to 10% higher than those for
+crypt_blowfish as certain things may be done out of the loop and the
+code doesn't need to be reentrant.
+
+Recent versions of John the Ripper (1.6.25-dev and newer) achieve an
+additional 15% speedup on the Pentium Pro family of processors (which
+includes Pentium III) with a separate version of the assembly code and
+run-time CPU detection.
+
+$Owl: Owl/packages/glibc/crypt_blowfish/PERFORMANCE,v 1.6 2011/06/21 12:09:20 solar Exp $
diff --git a/crypt_blowfish/README b/crypt_blowfish/README
new file mode 100644
index 000000000..e95da230e
--- /dev/null
+++ b/crypt_blowfish/README
@@ -0,0 +1,68 @@
+This is an implementation of a password hashing method, provided via the
+crypt(3) and a reentrant interface.  It is fully compatible with
+OpenBSD's bcrypt.c for prefix "$2b$", originally by Niels Provos and
+David Mazieres.  (Please refer to the included crypt(3) man page for
+information on minor compatibility issues for other bcrypt prefixes.)
+
+I've placed this code in the public domain, with fallback to a
+permissive license.  Please see the comment in crypt_blowfish.c for
+more information.
+
+You can use the provided routines in your own packages, or link them
+into a C library.  I've provided hooks for linking into GNU libc, but
+it shouldn't be too hard to get this into another C library.  Note
+that simply adding this code into your libc is probably not enough to
+make your system use the new password hashing algorithm.  Changes to
+passwd(1), PAM modules, or whatever else your system uses will likely
+be needed as well.  These are not a part of this package, but see
+LINKS for a pointer to our tcb suite.
+
+Instructions on using the routines in one of the two common ways are
+given below.  It is recommended that you test the routines on your
+system before you start.  Type "make check" or "make check_threads"
+(if you have the POSIX threads library), then "make clean".
+
+
+1. Using the routines in your programs.
+
+The available interfaces are in ow-crypt.h, and this is the file you
+should include.  You won't need crypt.h.  When linking, add all of the
+C files and x86.S (you can compile and link it even on a non-x86, it
+will produce no code in this case).
+
+
+2. Building the routines into GNU C library.
+
+For versions 2.13 and 2.14 (and likely other nearby ones), extract the
+library sources as usual.  Apply the patch for glibc 2.14 provided in
+this package.  Enter crypt/ and rename crypt.h to gnu-crypt.h within
+that directory.  Copy the C sources, header, and assembly (x86.S) files
+from this package in there as well (but be sure you don't overwrite the
+Makefile).  Configure, build, and install the library as usual.
+
+For versions 2.2 to 2.3.6 (and likely also for some newer ones),
+extract the library sources and maybe its optional add-ons as usual.
+Apply the patch for glibc 2.3.6 provided in this package.  Enter
+crypt/ and rename crypt.h to gnu-crypt.h within that directory.  Copy
+the C sources, header, and assembly (x86.S) files from this package in
+there as well (but be sure you don't overwrite the Makefile).
+Configure, build, and install the library as usual.
+
+For versions 2.1 to 2.1.3, extract the library sources and the crypt
+and linuxthreads add-ons as usual.  Apply the patch for glibc 2.1.3
+provided in this package.  Enter crypt/sysdeps/unix/, and rename
+crypt.h to gnu-crypt.h within that directory.  Copy C sources, header,
+and assembly (x86.S) files from this package in there as well (but be
+sure you don't overwrite the Makefile).  Configure, build, and install
+the library as usual.
+
+Programs that want to use the provided interfaces will need to include
+crypt.h (but not ow-crypt.h directly).  By default, prototypes for the
+new routines aren't defined (but the extra functionality of crypt(3)
+is indeed available).  You need to define _OW_SOURCE to obtain the new
+routines as well.
+
+-- 
+Solar Designer <solar at openwall.com>
+
+$Owl: Owl/packages/glibc/crypt_blowfish/README,v 1.10 2014/07/07 15:19:04 solar Exp $
diff --git a/crypt_blowfish/bcrypt.c b/crypt_blowfish/bcrypt.c
new file mode 100644
index 000000000..a4c992258
--- /dev/null
+++ b/crypt_blowfish/bcrypt.c
@@ -0,0 +1,195 @@
+/*
+ * bcrypt wrapper library
+ *
+ * Written in 2011, 2013, 2014, 2015 by Ricardo Garcia <r@rg3.name>
+ *
+ * To the extent possible under law, the author(s) have dedicated all copyright
+ * and related and neighboring rights to this software to the public domain
+ * worldwide. This software is distributed without any warranty.
+ *
+ * You should have received a copy of the CC0 Public Domain Dedication along
+ * with this software. If not, see
+ * <http://creativecommons.org/publicdomain/zero/1.0/>.
+ */
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "bcrypt.h"
+#include "ow-crypt.h"
+
+#define RANDBYTES (16)
+
+static int try_close(int fd)
+{
+	int ret;
+	for (;;) {
+		errno = 0;
+		ret = close(fd);
+		if (ret == -1 && errno == EINTR)
+			continue;
+		break;
+	}
+	return ret;
+}
+
+static int try_read(int fd, char *out, size_t count)
+{
+	size_t total;
+	ssize_t partial;
+
+	total = 0;
+	while (total < count)
+	{
+		for (;;) {
+			errno = 0;
+			partial = read(fd, out + total, count - total);
+			if (partial == -1 && errno == EINTR)
+				continue;
+			break;
+		}
+
+		if (partial < 1)
+			return -1;
+
+		total += partial;
+	}
+
+	return 0;
+}
+
+/*
+ * This is a best effort implementation. Nothing prevents a compiler from
+ * optimizing this function and making it vulnerable to timing attacks, but
+ * this method is commonly used in crypto libraries like NaCl.
+ *
+ * Return value is zero if both strings are equal and nonzero otherwise.
+*/
+static int timing_safe_strcmp(const char *str1, const char *str2)
+{
+	const unsigned char *u1;
+	const unsigned char *u2;
+	int ret;
+	int i;
+
+	int len1 = strlen(str1);
+	int len2 = strlen(str2);
+
+	/* In our context both strings should always have the same length
+	 * because they will be hashed passwords. */
+	if (len1 != len2)
+		return 1;
+
+	/* Force unsigned for bitwise operations. */
+	u1 = (const unsigned char *)str1;
+	u2 = (const unsigned char *)str2;
+
+	ret = 0;
+	for (i = 0; i < len1; ++i)
+		ret |= (u1[i] ^ u2[i]);
+
+	return ret;
+}
+
+int bcrypt_gensalt(int factor, char salt[BCRYPT_HASHSIZE])
+{
+	int fd;
+	char input[RANDBYTES];
+	int workf;
+	char *aux;
+
+	fd = open("/dev/urandom", O_RDONLY);
+	if (fd == -1)
+		return 1;
+
+	if (try_read(fd, input, RANDBYTES) != 0) {
+		if (try_close(fd) != 0)
+			return 4;
+		return 2;
+	}
+
+	if (try_close(fd) != 0)
+		return 3;
+
+	/* Generate salt. */
+	workf = (factor < 4 || factor > 31)?12:factor;
+	aux = crypt_gensalt_rn("$2a$", workf, input, RANDBYTES,
+			       salt, BCRYPT_HASHSIZE);
+	return (aux == NULL)?5:0;
+}
+
+int bcrypt_hashpw(const char *passwd, const char salt[BCRYPT_HASHSIZE], 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 ret;
+	char outhash[BCRYPT_HASHSIZE];
+
+	ret = bcrypt_hashpw(passwd, hash, outhash);
+	if (ret != 0)
+		return -1;
+
+	return timing_safe_strcmp(hash, outhash);
+}
+
+#ifdef TEST_BCRYPT
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+int main(void)
+{
+	clock_t before;
+	clock_t after;
+	char salt[BCRYPT_HASHSIZE];
+	char hash[BCRYPT_HASHSIZE];
+	int ret;
+
+	const char pass[] = "hi,mom";
+	const char hash1[] = "$2a$10$VEVmGHy4F4XQMJ3eOZJAUeb.MedU0W10pTPCuf53eHdKJPiSE8sMK";
+	const char hash2[] = "$2a$10$3F0BVk5t8/aoS.3ddaB3l.fxg5qvafQ9NybxcpXLzMeAt.nVWn.NO";
+
+	ret = bcrypt_gensalt(12, salt);
+	assert(ret == 0);
+	printf("Generated salt: %s\n", salt);
+	before = clock();
+	ret = bcrypt_hashpw("testtesttest", salt, hash);
+	assert(ret == 0);
+	after = clock();
+	printf("Hashed password: %s\n", hash);
+	printf("Time taken: %f seconds\n",
+	       (double)(after - before) / CLOCKS_PER_SEC);
+
+	ret = bcrypt_hashpw(pass, hash1, hash);
+	assert(ret == 0);
+	printf("First hash check: %s\n", (strcmp(hash1, hash) == 0)?"OK":"FAIL");
+	ret = bcrypt_hashpw(pass, hash2, hash);
+	assert(ret == 0);
+	printf("Second hash check: %s\n", (strcmp(hash2, hash) == 0)?"OK":"FAIL");
+
+	before = clock();
+	ret = (bcrypt_checkpw(pass, hash1) == 0);
+	after = clock();
+	printf("First hash check with bcrypt_checkpw: %s\n", ret?"OK":"FAIL");
+	printf("Time taken: %f seconds\n",
+	       (double)(after - before) / CLOCKS_PER_SEC);
+
+	before = clock();
+	ret = (bcrypt_checkpw(pass, hash2) == 0);
+	after = clock();
+	printf("Second hash check with bcrypt_checkpw: %s\n", ret?"OK":"FAIL");
+	printf("Time taken: %f seconds\n",
+	       (double)(after - before) / CLOCKS_PER_SEC);
+
+	return 0;
+}
+#endif
diff --git a/crypt_blowfish/bcrypt.h b/crypt_blowfish/bcrypt.h
new file mode 100644
index 000000000..e45b3ca13
--- /dev/null
+++ b/crypt_blowfish/bcrypt.h
@@ -0,0 +1,97 @@
+#ifndef BCRYPT_H_
+#define BCRYPT_H_
+/*
+ * bcrypt wrapper library
+ *
+ * Written in 2011, 2013, 2014, 2015 by Ricardo Garcia <r@rg3.name>
+ *
+ * To the extent possible under law, the author(s) have dedicated all copyright
+ * and related and neighboring rights to this software to the public domain
+ * worldwide. This software is distributed without any warranty.
+ *
+ * You should have received a copy of the CC0 Public Domain Dedication along
+ * with this software. If not, see
+ * <http://creativecommons.org/publicdomain/zero/1.0/>.
+ */
+
+#define BCRYPT_HASHSIZE	(64)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This function expects a work factor between 4 and 31 and a char array to
+ * store the resulting generated salt. The char array should typically have
+ * BCRYPT_HASHSIZE bytes at least. If the provided work factor is not in the
+ * previous range, it will default to 12.
+ *
+ * The return value is zero if the salt could be correctly generated and
+ * nonzero otherwise.
+ *
+ */
+int bcrypt_gensalt(int workfactor, char salt[BCRYPT_HASHSIZE]);
+
+/*
+ * This function expects a password to be hashed, a salt to hash the password
+ * with and a char array to leave the result. Both the salt and the hash
+ * parameters should have room for BCRYPT_HASHSIZE characters at least.
+ *
+ * It can also be used to verify a hashed password. In that case, provide the
+ * expected hash in the salt parameter and verify the output hash is the same
+ * as the input hash. However, to avoid timing attacks, it's better to use
+ * bcrypt_checkpw when verifying a password.
+ *
+ * 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],
+		  char hash[BCRYPT_HASHSIZE]);
+
+/*
+ * This function expects a password and a hash to verify the password against.
+ * The internal implementation is tuned to avoid timing attacks.
+ *
+ * The return value will be -1 in case of errors, zero if the provided password
+ * matches the given hash and greater than zero if no errors are found and the
+ * passwords don't match.
+ *
+ */
+int bcrypt_checkpw(const char *passwd, const char hash[BCRYPT_HASHSIZE]);
+
+/*
+ * Brief Example
+ * -------------
+ *
+ * Hashing a password:
+ *
+ *	char salt[BCRYPT_HASHSIZE];
+ *	char hash[BCRYPT_HASHSIZE];
+ *	int ret;
+ *
+ *	ret = bcrypt_gensalt(12, salt);
+ *	assert(ret == 0);
+ *	ret = bcrypt_hashpw("thepassword", salt, hash);
+ *	assert(ret == 0);
+ *
+ *
+ * Verifying a password:
+ *
+ *	int ret;
+ *
+ *      ret = bcrypt_checkpw("thepassword", "expectedhash");
+ *      assert(ret != -1);
+ *
+ *	if (ret == 0) {
+ *		printf("The password matches\n");
+ *	} else {
+ *		printf("The password does NOT match\n");
+ *	}
+ *
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/crypt_blowfish/crypt.h b/crypt_blowfish/crypt.h
new file mode 100644
index 000000000..12e67055b
--- /dev/null
+++ b/crypt_blowfish/crypt.h
@@ -0,0 +1,24 @@
+/*
+ * Written by Solar Designer <solar at openwall.com> in 2000-2002.
+ * No copyright is claimed, and the software is hereby placed in the public
+ * domain.  In case this attempt to disclaim copyright and place the software
+ * in the public domain is deemed null and void, then the software is
+ * Copyright (c) 2000-2002 Solar Designer and it is hereby released to the
+ * general public under the following terms:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted.
+ *
+ * There's ABSOLUTELY NO WARRANTY, express or implied.
+ *
+ * See crypt_blowfish.c for more information.
+ */
+
+#include <gnu-crypt.h>
+
+#if defined(_OW_SOURCE) || defined(__USE_OW)
+#define __SKIP_GNU
+#undef __SKIP_OW
+#include <ow-crypt.h>
+#undef __SKIP_GNU
+#endif
diff --git a/crypt_blowfish/crypt_blowfish.c b/crypt_blowfish/crypt_blowfish.c
new file mode 100644
index 000000000..9d3f3be82
--- /dev/null
+++ b/crypt_blowfish/crypt_blowfish.c
@@ -0,0 +1,907 @@
+/*
+ * The crypt_blowfish homepage is:
+ *
+ *	http://www.openwall.com/crypt/
+ *
+ * This code comes from John the Ripper password cracker, with reentrant
+ * and crypt(3) interfaces added, but optimizations specific to password
+ * cracking removed.
+ *
+ * Written by Solar Designer <solar at openwall.com> in 1998-2014.
+ * No copyright is claimed, and the software is hereby placed in the public
+ * domain.  In case this attempt to disclaim copyright and place the software
+ * in the public domain is deemed null and void, then the software is
+ * Copyright (c) 1998-2014 Solar Designer and it is hereby released to the
+ * general public under the following terms:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted.
+ *
+ * There's ABSOLUTELY NO WARRANTY, express or implied.
+ *
+ * It is my intent that you should be able to use this on your system,
+ * as part of a software package, or anywhere else to improve security,
+ * ensure compatibility, or for any other purpose.  I would appreciate
+ * it if you give credit where it is due and keep your modifications in
+ * the public domain as well, but I don't require that in order to let
+ * you place this code and any modifications you make under a license
+ * of your choice.
+ *
+ * This implementation is fully compatible with OpenBSD's bcrypt.c for prefix
+ * "$2b$", originally by Niels Provos <provos at citi.umich.edu>, and it uses
+ * some of his ideas.  The password hashing algorithm was designed by David
+ * Mazieres <dm at lcs.mit.edu>.  For information on the level of
+ * compatibility for bcrypt hash prefixes other than "$2b$", please refer to
+ * the comments in BF_set_key() below and to the included crypt(3) man page.
+ *
+ * There's a paper on the algorithm that explains its design decisions:
+ *
+ *	http://www.usenix.org/events/usenix99/provos.html
+ *
+ * Some of the tricks in BF_ROUND might be inspired by Eric Young's
+ * Blowfish library (I can't be sure if I would think of something if I
+ * hadn't seen his code).
+ */
+
+#include <string.h>
+
+#include <errno.h>
+#ifndef __set_errno
+#define __set_errno(val) errno = (val)
+#endif
+
+/* Just to make sure the prototypes match the actual definitions */
+#include "crypt_blowfish.h"
+
+#ifdef __i386__
+#define BF_ASM				1
+#define BF_SCALE			1
+#elif defined(__x86_64__) || defined(__alpha__) || defined(__hppa__)
+#define BF_ASM				0
+#define BF_SCALE			1
+#else
+#define BF_ASM				0
+#define BF_SCALE			0
+#endif
+
+typedef unsigned int BF_word;
+typedef signed int BF_word_signed;
+
+/* Number of Blowfish rounds, this is also hardcoded into a few places */
+#define BF_N				16
+
+typedef BF_word BF_key[BF_N + 2];
+
+typedef struct {
+	BF_word S[4][0x100];
+	BF_key P;
+} BF_ctx;
+
+/*
+ * Magic IV for 64 Blowfish encryptions that we do at the end.
+ * The string is "OrpheanBeholderScryDoubt" on big-endian.
+ */
+static BF_word BF_magic_w[6] = {
+	0x4F727068, 0x65616E42, 0x65686F6C,
+	0x64657253, 0x63727944, 0x6F756274
+};
+
+/*
+ * P-box and S-box tables initialized with digits of Pi.
+ */
+static BF_ctx BF_init_state = {
+	{
+		{
+			0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7,
+			0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
+			0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
+			0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
+			0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee,
+			0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
+			0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef,
+			0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
+			0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
+			0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
+			0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce,
+			0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
+			0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e,
+			0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
+			0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
+			0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
+			0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88,
+			0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
+			0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e,
+			0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
+			0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
+			0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,
+			0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88,
+			0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
+			0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6,
+			0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
+			0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
+			0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
+			0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba,
+			0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
+			0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f,
+			0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
+			0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
+			0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,
+			0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279,
+			0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
+			0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab,
+			0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,
+			0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
+			0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,
+			0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0,
+			0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
+			0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790,
+			0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,
+			0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
+			0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
+			0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7,
+			0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
+			0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad,
+			0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
+			0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
+			0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
+			0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477,
+			0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
+			0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49,
+			0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
+			0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
+			0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
+			0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41,
+			0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
+			0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400,
+			0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
+			0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
+			0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a
+		}, {
+			0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623,
+			0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
+			0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
+			0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
+			0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6,
+			0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
+			0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e,
+			0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
+			0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
+			0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
+			0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff,
+			0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
+			0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701,
+			0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
+			0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
+			0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
+			0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf,
+			0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
+			0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e,
+			0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
+			0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
+			0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
+			0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16,
+			0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
+			0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b,
+			0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
+			0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
+			0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
+			0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f,
+			0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
+			0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4,
+			0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
+			0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
+			0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
+			0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802,
+			0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
+			0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510,
+			0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
+			0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
+			0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
+			0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50,
+			0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
+			0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8,
+			0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
+			0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
+			0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
+			0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128,
+			0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
+			0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0,
+			0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
+			0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
+			0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
+			0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3,
+			0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
+			0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00,
+			0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
+			0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
+			0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
+			0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735,
+			0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
+			0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9,
+			0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
+			0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
+			0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7
+		}, {
+			0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934,
+			0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
+			0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
+			0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
+			0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45,
+			0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
+			0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a,
+			0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
+			0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
+			0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
+			0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42,
+			0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
+			0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2,
+			0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
+			0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
+			0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
+			0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33,
+			0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
+			0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3,
+			0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
+			0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
+			0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
+			0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b,
+			0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
+			0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922,
+			0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
+			0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
+			0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
+			0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37,
+			0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
+			0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804,
+			0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
+			0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
+			0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
+			0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d,
+			0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
+			0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350,
+			0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
+			0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
+			0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
+			0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d,
+			0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
+			0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f,
+			0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
+			0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
+			0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
+			0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2,
+			0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
+			0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e,
+			0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
+			0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
+			0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
+			0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52,
+			0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
+			0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5,
+			0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
+			0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
+			0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
+			0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24,
+			0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
+			0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4,
+			0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
+			0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
+			0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0
+		}, {
+			0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b,
+			0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
+			0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
+			0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
+			0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8,
+			0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
+			0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304,
+			0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
+			0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
+			0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
+			0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9,
+			0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
+			0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593,
+			0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
+			0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
+			0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
+			0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b,
+			0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
+			0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c,
+			0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
+			0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
+			0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
+			0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb,
+			0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
+			0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991,
+			0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
+			0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
+			0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
+			0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae,
+			0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
+			0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5,
+			0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
+			0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
+			0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
+			0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84,
+			0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
+			0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8,
+			0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
+			0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
+			0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
+			0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38,
+			0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
+			0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c,
+			0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
+			0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
+			0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
+			0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964,
+			0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
+			0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8,
+			0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
+			0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
+			0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
+			0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02,
+			0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
+			0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614,
+			0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
+			0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
+			0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
+			0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0,
+			0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
+			0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e,
+			0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
+			0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
+			0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6
+		}
+	}, {
+		0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344,
+		0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89,
+		0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
+		0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917,
+		0x9216d5d9, 0x8979fb1b
+	}
+};
+
+static unsigned char BF_itoa64[64 + 1] =
+	"./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+
+static unsigned char BF_atoi64[0x60] = {
+	64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 1,
+	54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 64, 64, 64, 64, 64,
+	64, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+	17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 64, 64, 64, 64, 64,
+	64, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
+	43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 64, 64, 64, 64, 64
+};
+
+#define BF_safe_atoi64(dst, src) \
+{ \
+	tmp = (unsigned char)(src); \
+	if ((unsigned int)(tmp -= 0x20) >= 0x60) return -1; \
+	tmp = BF_atoi64[tmp]; \
+	if (tmp > 63) return -1; \
+	(dst) = tmp; \
+}
+
+static int BF_decode(BF_word *dst, const char *src, int size)
+{
+	unsigned char *dptr = (unsigned char *)dst;
+	unsigned char *end = dptr + size;
+	const unsigned char *sptr = (const unsigned char *)src;
+	unsigned int tmp, c1, c2, c3, c4;
+
+	do {
+		BF_safe_atoi64(c1, *sptr++);
+		BF_safe_atoi64(c2, *sptr++);
+		*dptr++ = (c1 << 2) | ((c2 & 0x30) >> 4);
+		if (dptr >= end) break;
+
+		BF_safe_atoi64(c3, *sptr++);
+		*dptr++ = ((c2 & 0x0F) << 4) | ((c3 & 0x3C) >> 2);
+		if (dptr >= end) break;
+
+		BF_safe_atoi64(c4, *sptr++);
+		*dptr++ = ((c3 & 0x03) << 6) | c4;
+	} while (dptr < end);
+
+	return 0;
+}
+
+static void BF_encode(char *dst, const BF_word *src, int size)
+{
+	const unsigned char *sptr = (const unsigned char *)src;
+	const unsigned char *end = sptr + size;
+	unsigned char *dptr = (unsigned char *)dst;
+	unsigned int c1, c2;
+
+	do {
+		c1 = *sptr++;
+		*dptr++ = BF_itoa64[c1 >> 2];
+		c1 = (c1 & 0x03) << 4;
+		if (sptr >= end) {
+			*dptr++ = BF_itoa64[c1];
+			break;
+		}
+
+		c2 = *sptr++;
+		c1 |= c2 >> 4;
+		*dptr++ = BF_itoa64[c1];
+		c1 = (c2 & 0x0f) << 2;
+		if (sptr >= end) {
+			*dptr++ = BF_itoa64[c1];
+			break;
+		}
+
+		c2 = *sptr++;
+		c1 |= c2 >> 6;
+		*dptr++ = BF_itoa64[c1];
+		*dptr++ = BF_itoa64[c2 & 0x3f];
+	} while (sptr < end);
+}
+
+static void BF_swap(BF_word *x, int count)
+{
+	static int endianness_check = 1;
+	char *is_little_endian = (char *)&endianness_check;
+	BF_word tmp;
+
+	if (*is_little_endian)
+	do {
+		tmp = *x;
+		tmp = (tmp << 16) | (tmp >> 16);
+		*x++ = ((tmp & 0x00FF00FF) << 8) | ((tmp >> 8) & 0x00FF00FF);
+	} while (--count);
+}
+
+#if BF_SCALE
+/* Architectures which can shift addresses left by 2 bits with no extra cost */
+#define BF_ROUND(L, R, N) \
+	tmp1 = L & 0xFF; \
+	tmp2 = L >> 8; \
+	tmp2 &= 0xFF; \
+	tmp3 = L >> 16; \
+	tmp3 &= 0xFF; \
+	tmp4 = L >> 24; \
+	tmp1 = data.ctx.S[3][tmp1]; \
+	tmp2 = data.ctx.S[2][tmp2]; \
+	tmp3 = data.ctx.S[1][tmp3]; \
+	tmp3 += data.ctx.S[0][tmp4]; \
+	tmp3 ^= tmp2; \
+	R ^= data.ctx.P[N + 1]; \
+	tmp3 += tmp1; \
+	R ^= tmp3;
+#else
+/* Architectures with no complicated addressing modes supported */
+#define BF_INDEX(S, i) \
+	(*((BF_word *)(((unsigned char *)S) + (i))))
+#define BF_ROUND(L, R, N) \
+	tmp1 = L & 0xFF; \
+	tmp1 <<= 2; \
+	tmp2 = L >> 6; \
+	tmp2 &= 0x3FC; \
+	tmp3 = L >> 14; \
+	tmp3 &= 0x3FC; \
+	tmp4 = L >> 22; \
+	tmp4 &= 0x3FC; \
+	tmp1 = BF_INDEX(data.ctx.S[3], tmp1); \
+	tmp2 = BF_INDEX(data.ctx.S[2], tmp2); \
+	tmp3 = BF_INDEX(data.ctx.S[1], tmp3); \
+	tmp3 += BF_INDEX(data.ctx.S[0], tmp4); \
+	tmp3 ^= tmp2; \
+	R ^= data.ctx.P[N + 1]; \
+	tmp3 += tmp1; \
+	R ^= tmp3;
+#endif
+
+/*
+ * Encrypt one block, BF_N is hardcoded here.
+ */
+#define BF_ENCRYPT \
+	L ^= data.ctx.P[0]; \
+	BF_ROUND(L, R, 0); \
+	BF_ROUND(R, L, 1); \
+	BF_ROUND(L, R, 2); \
+	BF_ROUND(R, L, 3); \
+	BF_ROUND(L, R, 4); \
+	BF_ROUND(R, L, 5); \
+	BF_ROUND(L, R, 6); \
+	BF_ROUND(R, L, 7); \
+	BF_ROUND(L, R, 8); \
+	BF_ROUND(R, L, 9); \
+	BF_ROUND(L, R, 10); \
+	BF_ROUND(R, L, 11); \
+	BF_ROUND(L, R, 12); \
+	BF_ROUND(R, L, 13); \
+	BF_ROUND(L, R, 14); \
+	BF_ROUND(R, L, 15); \
+	tmp4 = R; \
+	R = L; \
+	L = tmp4 ^ data.ctx.P[BF_N + 1];
+
+#if BF_ASM
+#define BF_body() \
+	_BF_body_r(&data.ctx);
+#else
+#define BF_body() \
+	L = R = 0; \
+	ptr = data.ctx.P; \
+	do { \
+		ptr += 2; \
+		BF_ENCRYPT; \
+		*(ptr - 2) = L; \
+		*(ptr - 1) = R; \
+	} while (ptr < &data.ctx.P[BF_N + 2]); \
+\
+	ptr = data.ctx.S[0]; \
+	do { \
+		ptr += 2; \
+		BF_ENCRYPT; \
+		*(ptr - 2) = L; \
+		*(ptr - 1) = R; \
+	} while (ptr < &data.ctx.S[3][0xFF]);
+#endif
+
+static void BF_set_key(const char *key, BF_key expanded, BF_key initial,
+    unsigned char flags)
+{
+	const char *ptr = key;
+	unsigned int bug, i, j;
+	BF_word safety, sign, diff, tmp[2];
+
+/*
+ * There was a sign extension bug in older revisions of this function.  While
+ * we would have liked to simply fix the bug and move on, we have to provide
+ * a backwards compatibility feature (essentially the bug) for some systems and
+ * a safety measure for some others.  The latter is needed because for certain
+ * multiple inputs to the buggy algorithm there exist easily found inputs to
+ * the correct algorithm that produce the same hash.  Thus, we optionally
+ * deviate from the correct algorithm just enough to avoid such collisions.
+ * While the bug itself affected the majority of passwords containing
+ * characters with the 8th bit set (although only a percentage of those in a
+ * collision-producing way), the anti-collision safety measure affects
+ * only a subset of passwords containing the '\xff' character (not even all of
+ * those passwords, just some of them).  This character is not found in valid
+ * UTF-8 sequences and is rarely used in popular 8-bit character encodings.
+ * Thus, the safety measure is unlikely to cause much annoyance, and is a
+ * reasonable tradeoff to use when authenticating against existing hashes that
+ * are not reliably known to have been computed with the correct algorithm.
+ *
+ * We use an approach that tries to minimize side-channel leaks of password
+ * information - that is, we mostly use fixed-cost bitwise operations instead
+ * of branches or table lookups.  (One conditional branch based on password
+ * length remains.  It is not part of the bug aftermath, though, and is
+ * difficult and possibly unreasonable to avoid given the use of C strings by
+ * the caller, which results in similar timing leaks anyway.)
+ *
+ * For actual implementation, we set an array index in the variable "bug"
+ * (0 means no bug, 1 means sign extension bug emulation) and a flag in the
+ * variable "safety" (bit 16 is set when the safety measure is requested).
+ * Valid combinations of settings are:
+ *
+ * Prefix "$2a$": bug = 0, safety = 0x10000
+ * Prefix "$2b$": bug = 0, safety = 0
+ * Prefix "$2x$": bug = 1, safety = 0
+ * Prefix "$2y$": bug = 0, safety = 0
+ */
+	bug = (unsigned int)flags & 1;
+	safety = ((BF_word)flags & 2) << 15;
+
+	sign = diff = 0;
+
+	for (i = 0; i < BF_N + 2; i++) {
+		tmp[0] = tmp[1] = 0;
+		for (j = 0; j < 4; j++) {
+			tmp[0] <<= 8;
+			tmp[0] |= (unsigned char)*ptr; /* correct */
+			tmp[1] <<= 8;
+			tmp[1] |= (BF_word_signed)(signed char)*ptr; /* bug */
+/*
+ * Sign extension in the first char has no effect - nothing to overwrite yet,
+ * and those extra 24 bits will be fully shifted out of the 32-bit word.  For
+ * chars 2, 3, 4 in each four-char block, we set bit 7 of "sign" if sign
+ * extension in tmp[1] occurs.  Once this flag is set, it remains set.
+ */
+			if (j)
+				sign |= tmp[1] & 0x80;
+			if (!*ptr)
+				ptr = key;
+			else
+				ptr++;
+		}
+		diff |= tmp[0] ^ tmp[1]; /* Non-zero on any differences */
+
+		expanded[i] = tmp[bug];
+		initial[i] = BF_init_state.P[i] ^ tmp[bug];
+	}
+
+/*
+ * At this point, "diff" is zero iff the correct and buggy algorithms produced
+ * exactly the same result.  If so and if "sign" is non-zero, which indicates
+ * that there was a non-benign sign extension, this means that we have a
+ * collision between the correctly computed hash for this password and a set of
+ * passwords that could be supplied to the buggy algorithm.  Our safety measure
+ * is meant to protect from such many-buggy to one-correct collisions, by
+ * deviating from the correct algorithm in such cases.  Let's check for this.
+ */
+	diff |= diff >> 16; /* still zero iff exact match */
+	diff &= 0xffff; /* ditto */
+	diff += 0xffff; /* bit 16 set iff "diff" was non-zero (on non-match) */
+	sign <<= 9; /* move the non-benign sign extension flag to bit 16 */
+	sign &= ~diff & safety; /* action needed? */
+
+/*
+ * If we have determined that we need to deviate from the correct algorithm,
+ * flip bit 16 in initial expanded key.  (The choice of 16 is arbitrary, but
+ * let's stick to it now.  It came out of the approach we used above, and it's
+ * not any worse than any other choice we could make.)
+ *
+ * It is crucial that we don't do the same to the expanded key used in the main
+ * Eksblowfish loop.  By doing it to only one of these two, we deviate from a
+ * state that could be directly specified by a password to the buggy algorithm
+ * (and to the fully correct one as well, but that's a side-effect).
+ */
+	initial[0] ^= sign;
+}
+
+static const unsigned char flags_by_subtype[26] =
+	{2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 0};
+
+static char *BF_crypt(const char *key, const char *setting,
+	char *output, int size,
+	BF_word min)
+{
+#if BF_ASM
+	extern void _BF_body_r(BF_ctx *ctx);
+#endif
+	struct {
+		BF_ctx ctx;
+		BF_key expanded_key;
+		union {
+			BF_word salt[4];
+			BF_word output[6];
+		} binary;
+	} data;
+	BF_word L, R;
+	BF_word tmp1, tmp2, tmp3, tmp4;
+	BF_word *ptr;
+	BF_word count;
+	int i;
+
+	if (size < 7 + 22 + 31 + 1) {
+		__set_errno(ERANGE);
+		return NULL;
+	}
+
+	if (setting[0] != '$' ||
+	    setting[1] != '2' ||
+	    setting[2] < 'a' || setting[2] > 'z' ||
+	    !flags_by_subtype[(unsigned int)(unsigned char)setting[2] - 'a'] ||
+	    setting[3] != '$' ||
+	    setting[4] < '0' || setting[4] > '3' ||
+	    setting[5] < '0' || setting[5] > '9' ||
+	    (setting[4] == '3' && setting[5] > '1') ||
+	    setting[6] != '$') {
+		__set_errno(EINVAL);
+		return NULL;
+	}
+
+	count = (BF_word)1 << ((setting[4] - '0') * 10 + (setting[5] - '0'));
+	if (count < min || BF_decode(data.binary.salt, &setting[7], 16)) {
+		__set_errno(EINVAL);
+		return NULL;
+	}
+	BF_swap(data.binary.salt, 4);
+
+	BF_set_key(key, data.expanded_key, data.ctx.P,
+	    flags_by_subtype[(unsigned int)(unsigned char)setting[2] - 'a']);
+
+	memcpy(data.ctx.S, BF_init_state.S, sizeof(data.ctx.S));
+
+	L = R = 0;
+	for (i = 0; i < BF_N + 2; i += 2) {
+		L ^= data.binary.salt[i & 2];
+		R ^= data.binary.salt[(i & 2) + 1];
+		BF_ENCRYPT;
+		data.ctx.P[i] = L;
+		data.ctx.P[i + 1] = R;
+	}
+
+	ptr = data.ctx.S[0];
+	do {
+		ptr += 4;
+		L ^= data.binary.salt[(BF_N + 2) & 3];
+		R ^= data.binary.salt[(BF_N + 3) & 3];
+		BF_ENCRYPT;
+		*(ptr - 4) = L;
+		*(ptr - 3) = R;
+
+		L ^= data.binary.salt[(BF_N + 4) & 3];
+		R ^= data.binary.salt[(BF_N + 5) & 3];
+		BF_ENCRYPT;
+		*(ptr - 2) = L;
+		*(ptr - 1) = R;
+	} while (ptr < &data.ctx.S[3][0xFF]);
+
+	do {
+		int done;
+
+		for (i = 0; i < BF_N + 2; i += 2) {
+			data.ctx.P[i] ^= data.expanded_key[i];
+			data.ctx.P[i + 1] ^= data.expanded_key[i + 1];
+		}
+
+		done = 0;
+		do {
+			BF_body();
+			if (done)
+				break;
+			done = 1;
+
+			tmp1 = data.binary.salt[0];
+			tmp2 = data.binary.salt[1];
+			tmp3 = data.binary.salt[2];
+			tmp4 = data.binary.salt[3];
+			for (i = 0; i < BF_N; i += 4) {
+				data.ctx.P[i] ^= tmp1;
+				data.ctx.P[i + 1] ^= tmp2;
+				data.ctx.P[i + 2] ^= tmp3;
+				data.ctx.P[i + 3] ^= tmp4;
+			}
+			data.ctx.P[16] ^= tmp1;
+			data.ctx.P[17] ^= tmp2;
+		} while (1);
+	} while (--count);
+
+	for (i = 0; i < 6; i += 2) {
+		L = BF_magic_w[i];
+		R = BF_magic_w[i + 1];
+
+		count = 64;
+		do {
+			BF_ENCRYPT;
+		} while (--count);
+
+		data.binary.output[i] = L;
+		data.binary.output[i + 1] = R;
+	}
+
+	memcpy(output, setting, 7 + 22 - 1);
+	output[7 + 22 - 1] = BF_itoa64[(int)
+		BF_atoi64[(int)setting[7 + 22 - 1] - 0x20] & 0x30];
+
+/* This has to be bug-compatible with the original implementation, so
+ * only encode 23 of the 24 bytes. :-) */
+	BF_swap(data.binary.output, 6);
+	BF_encode(&output[7 + 22], data.binary.output, 23);
+	output[7 + 22 + 31] = '\0';
+
+	return output;
+}
+
+int _crypt_output_magic(const char *setting, char *output, int size)
+{
+	if (size < 3)
+		return -1;
+
+	output[0] = '*';
+	output[1] = '0';
+	output[2] = '\0';
+
+	if (setting[0] == '*' && setting[1] == '0')
+		output[1] = '1';
+
+	return 0;
+}
+
+/*
+ * Please preserve the runtime self-test.  It serves two purposes at once:
+ *
+ * 1. We really can't afford the risk of producing incompatible hashes e.g.
+ * when there's something like gcc bug 26587 again, whereas an application or
+ * library integrating this code might not also integrate our external tests or
+ * it might not run them after every build.  Even if it does, the miscompile
+ * might only occur on the production build, but not on a testing build (such
+ * as because of different optimization settings).  It is painful to recover
+ * from incorrectly-computed hashes - merely fixing whatever broke is not
+ * enough.  Thus, a proactive measure like this self-test is needed.
+ *
+ * 2. We don't want to leave sensitive data from our actual password hash
+ * computation on the stack or in registers.  Previous revisions of the code
+ * would do explicit cleanups, but simply running the self-test after hash
+ * computation is more reliable.
+ *
+ * The performance cost of this quick self-test is around 0.6% at the "$2a$08"
+ * setting.
+ */
+char *_crypt_blowfish_rn(const char *key, const char *setting,
+	char *output, int size)
+{
+	const char *test_key = "8b \xd0\xc1\xd2\xcf\xcc\xd8";
+	const char *test_setting = "$2a$00$abcdefghijklmnopqrstuu";
+	static const char * const test_hashes[2] =
+		{"i1D709vfamulimlGcq0qq3UvuUasvEa\0\x55", /* 'a', 'b', 'y' */
+		"VUrPmXD6q/nVSSp7pNDhCR9071IfIRe\0\x55"}; /* 'x' */
+	const char *test_hash = test_hashes[0];
+	char *retval;
+	const char *p;
+	int save_errno, ok;
+	struct {
+		char s[7 + 22 + 1];
+		char o[7 + 22 + 31 + 1 + 1 + 1];
+	} buf;
+
+/* Hash the supplied password */
+	_crypt_output_magic(setting, output, size);
+	retval = BF_crypt(key, setting, output, size, 16);
+	save_errno = errno;
+
+/*
+ * Do a quick self-test.  It is important that we make both calls to BF_crypt()
+ * from the same scope such that they likely use the same stack locations,
+ * which makes the second call overwrite the first call's sensitive data on the
+ * stack and makes it more likely that any alignment related issues would be
+ * detected by the self-test.
+ */
+	memcpy(buf.s, test_setting, sizeof(buf.s));
+	if (retval) {
+		unsigned int flags = flags_by_subtype[
+		    (unsigned int)(unsigned char)setting[2] - 'a'];
+		test_hash = test_hashes[flags & 1];
+		buf.s[2] = setting[2];
+	}
+	memset(buf.o, 0x55, sizeof(buf.o));
+	buf.o[sizeof(buf.o) - 1] = 0;
+	p = BF_crypt(test_key, buf.s, buf.o, sizeof(buf.o) - (1 + 1), 1);
+
+	ok = (p == buf.o &&
+	    !memcmp(p, buf.s, 7 + 22) &&
+	    !memcmp(p + (7 + 22), test_hash, 31 + 1 + 1 + 1));
+
+	{
+		const char *k = "\xff\xa3" "34" "\xff\xff\xff\xa3" "345";
+		BF_key ae, ai, ye, yi;
+		BF_set_key(k, ae, ai, 2); /* $2a$ */
+		BF_set_key(k, ye, yi, 4); /* $2y$ */
+		ai[0] ^= 0x10000; /* undo the safety (for comparison) */
+		ok = ok && ai[0] == 0xdb9c59bc && ye[17] == 0x33343500 &&
+		    !memcmp(ae, ye, sizeof(ae)) &&
+		    !memcmp(ai, yi, sizeof(ai));
+	}
+
+	__set_errno(save_errno);
+	if (ok)
+		return retval;
+
+/* Should not happen */
+	_crypt_output_magic(setting, output, size);
+	__set_errno(EINVAL); /* pretend we don't support this hash type */
+	return NULL;
+}
+
+char *_crypt_gensalt_blowfish_rn(const char *prefix, unsigned long count,
+	const char *input, int size, char *output, int output_size)
+{
+	if (size < 16 || output_size < 7 + 22 + 1 ||
+	    (count && (count < 4 || count > 31)) ||
+	    prefix[0] != '$' || prefix[1] != '2' ||
+	    (prefix[2] != 'a' && prefix[2] != 'b' && prefix[2] != 'y')) {
+		if (output_size > 0) output[0] = '\0';
+		__set_errno((output_size < 7 + 22 + 1) ? ERANGE : EINVAL);
+		return NULL;
+	}
+
+	if (!count) count = 5;
+
+	output[0] = '$';
+	output[1] = '2';
+	output[2] = prefix[2];
+	output[3] = '$';
+	output[4] = '0' + count / 10;
+	output[5] = '0' + count % 10;
+	output[6] = '$';
+
+	BF_encode(&output[7], (const BF_word *)input, 16);
+	output[7 + 22] = '\0';
+
+	return output;
+}
diff --git a/crypt_blowfish/crypt_blowfish.h b/crypt_blowfish/crypt_blowfish.h
new file mode 100644
index 000000000..2ee0d8c1d
--- /dev/null
+++ b/crypt_blowfish/crypt_blowfish.h
@@ -0,0 +1,27 @@
+/*
+ * Written by Solar Designer <solar at openwall.com> in 2000-2011.
+ * No copyright is claimed, and the software is hereby placed in the public
+ * domain.  In case this attempt to disclaim copyright and place the software
+ * in the public domain is deemed null and void, then the software is
+ * Copyright (c) 2000-2011 Solar Designer and it is hereby released to the
+ * general public under the following terms:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted.
+ *
+ * There's ABSOLUTELY NO WARRANTY, express or implied.
+ *
+ * See crypt_blowfish.c for more information.
+ */
+
+#ifndef _CRYPT_BLOWFISH_H
+#define _CRYPT_BLOWFISH_H
+
+extern int _crypt_output_magic(const char *setting, char *output, int size);
+extern char *_crypt_blowfish_rn(const char *key, const char *setting,
+	char *output, int size);
+extern char *_crypt_gensalt_blowfish_rn(const char *prefix,
+	unsigned long count,
+	const char *input, int size, char *output, int output_size);
+
+#endif
diff --git a/crypt_blowfish/crypt_gensalt.c b/crypt_blowfish/crypt_gensalt.c
new file mode 100644
index 000000000..73c15a1ad
--- /dev/null
+++ b/crypt_blowfish/crypt_gensalt.c
@@ -0,0 +1,124 @@
+/*
+ * Written by Solar Designer <solar at openwall.com> in 2000-2011.
+ * No copyright is claimed, and the software is hereby placed in the public
+ * domain.  In case this attempt to disclaim copyright and place the software
+ * in the public domain is deemed null and void, then the software is
+ * Copyright (c) 2000-2011 Solar Designer and it is hereby released to the
+ * general public under the following terms:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted.
+ *
+ * There's ABSOLUTELY NO WARRANTY, express or implied.
+ *
+ * See crypt_blowfish.c for more information.
+ *
+ * This file contains salt generation functions for the traditional and
+ * other common crypt(3) algorithms, except for bcrypt which is defined
+ * entirely in crypt_blowfish.c.
+ */
+
+#include <string.h>
+
+#include <errno.h>
+#ifndef __set_errno
+#define __set_errno(val) errno = (val)
+#endif
+
+/* Just to make sure the prototypes match the actual definitions */
+#include "crypt_gensalt.h"
+
+unsigned char _crypt_itoa64[64 + 1] =
+	"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+char *_crypt_gensalt_traditional_rn(const char *prefix, unsigned long count,
+	const char *input, int size, char *output, int output_size)
+{
+	(void) prefix;
+
+	if (size < 2 || output_size < 2 + 1 || (count && count != 25)) {
+		if (output_size > 0) output[0] = '\0';
+		__set_errno((output_size < 2 + 1) ? ERANGE : EINVAL);
+		return NULL;
+	}
+
+	output[0] = _crypt_itoa64[(unsigned int)input[0] & 0x3f];
+	output[1] = _crypt_itoa64[(unsigned int)input[1] & 0x3f];
+	output[2] = '\0';
+
+	return output;
+}
+
+char *_crypt_gensalt_extended_rn(const char *prefix, unsigned long count,
+	const char *input, int size, char *output, int output_size)
+{
+	unsigned long value;
+
+	(void) prefix;
+
+/* Even iteration counts make it easier to detect weak DES keys from a look
+ * at the hash, so they should be avoided */
+	if (size < 3 || output_size < 1 + 4 + 4 + 1 ||
+	    (count && (count > 0xffffff || !(count & 1)))) {
+		if (output_size > 0) output[0] = '\0';
+		__set_errno((output_size < 1 + 4 + 4 + 1) ? ERANGE : EINVAL);
+		return NULL;
+	}
+
+	if (!count) count = 725;
+
+	output[0] = '_';
+	output[1] = _crypt_itoa64[count & 0x3f];
+	output[2] = _crypt_itoa64[(count >> 6) & 0x3f];
+	output[3] = _crypt_itoa64[(count >> 12) & 0x3f];
+	output[4] = _crypt_itoa64[(count >> 18) & 0x3f];
+	value = (unsigned long)(unsigned char)input[0] |
+		((unsigned long)(unsigned char)input[1] << 8) |
+		((unsigned long)(unsigned char)input[2] << 16);
+	output[5] = _crypt_itoa64[value & 0x3f];
+	output[6] = _crypt_itoa64[(value >> 6) & 0x3f];
+	output[7] = _crypt_itoa64[(value >> 12) & 0x3f];
+	output[8] = _crypt_itoa64[(value >> 18) & 0x3f];
+	output[9] = '\0';
+
+	return output;
+}
+
+char *_crypt_gensalt_md5_rn(const char *prefix, unsigned long count,
+	const char *input, int size, char *output, int output_size)
+{
+	unsigned long value;
+
+	(void) prefix;
+
+	if (size < 3 || output_size < 3 + 4 + 1 || (count && count != 1000)) {
+		if (output_size > 0) output[0] = '\0';
+		__set_errno((output_size < 3 + 4 + 1) ? ERANGE : EINVAL);
+		return NULL;
+	}
+
+	output[0] = '$';
+	output[1] = '1';
+	output[2] = '$';
+	value = (unsigned long)(unsigned char)input[0] |
+		((unsigned long)(unsigned char)input[1] << 8) |
+		((unsigned long)(unsigned char)input[2] << 16);
+	output[3] = _crypt_itoa64[value & 0x3f];
+	output[4] = _crypt_itoa64[(value >> 6) & 0x3f];
+	output[5] = _crypt_itoa64[(value >> 12) & 0x3f];
+	output[6] = _crypt_itoa64[(value >> 18) & 0x3f];
+	output[7] = '\0';
+
+	if (size >= 6 && output_size >= 3 + 4 + 4 + 1) {
+		value = (unsigned long)(unsigned char)input[3] |
+			((unsigned long)(unsigned char)input[4] << 8) |
+			((unsigned long)(unsigned char)input[5] << 16);
+		output[7] = _crypt_itoa64[value & 0x3f];
+		output[8] = _crypt_itoa64[(value >> 6) & 0x3f];
+		output[9] = _crypt_itoa64[(value >> 12) & 0x3f];
+		output[10] = _crypt_itoa64[(value >> 18) & 0x3f];
+		output[11] = '\0';
+	}
+
+	return output;
+}
diff --git a/crypt_blowfish/crypt_gensalt.h b/crypt_blowfish/crypt_gensalt.h
new file mode 100644
index 000000000..457bbfe29
--- /dev/null
+++ b/crypt_blowfish/crypt_gensalt.h
@@ -0,0 +1,30 @@
+/*
+ * Written by Solar Designer <solar at openwall.com> in 2000-2011.
+ * No copyright is claimed, and the software is hereby placed in the public
+ * domain.  In case this attempt to disclaim copyright and place the software
+ * in the public domain is deemed null and void, then the software is
+ * Copyright (c) 2000-2011 Solar Designer and it is hereby released to the
+ * general public under the following terms:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted.
+ *
+ * There's ABSOLUTELY NO WARRANTY, express or implied.
+ *
+ * See crypt_blowfish.c for more information.
+ */
+
+#ifndef _CRYPT_GENSALT_H
+#define _CRYPT_GENSALT_H
+
+extern unsigned char _crypt_itoa64[];
+extern char *_crypt_gensalt_traditional_rn(const char *prefix,
+	unsigned long count,
+	const char *input, int size, char *output, int output_size);
+extern char *_crypt_gensalt_extended_rn(const char *prefix,
+	unsigned long count,
+	const char *input, int size, char *output, int output_size);
+extern char *_crypt_gensalt_md5_rn(const char *prefix, unsigned long count,
+	const char *input, int size, char *output, int output_size);
+
+#endif
diff --git a/crypt_blowfish/ow-crypt.h b/crypt_blowfish/ow-crypt.h
new file mode 100644
index 000000000..2e4879426
--- /dev/null
+++ b/crypt_blowfish/ow-crypt.h
@@ -0,0 +1,43 @@
+/*
+ * Written by Solar Designer <solar at openwall.com> in 2000-2011.
+ * No copyright is claimed, and the software is hereby placed in the public
+ * domain.  In case this attempt to disclaim copyright and place the software
+ * in the public domain is deemed null and void, then the software is
+ * Copyright (c) 2000-2011 Solar Designer and it is hereby released to the
+ * general public under the following terms:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted.
+ *
+ * There's ABSOLUTELY NO WARRANTY, express or implied.
+ *
+ * See crypt_blowfish.c for more information.
+ */
+
+#ifndef _OW_CRYPT_H
+#define _OW_CRYPT_H
+
+#ifndef __GNUC__
+#undef __const
+#define __const const
+#endif
+
+#ifndef __SKIP_GNU
+extern char *crypt(__const char *key, __const char *setting);
+extern char *crypt_r(__const char *key, __const char *setting, void *data);
+#endif
+
+#ifndef __SKIP_OW
+extern char *crypt_rn(__const char *key, __const char *setting,
+	void *data, int size);
+extern char *crypt_ra(__const char *key, __const char *setting,
+	void **data, int *size);
+extern char *crypt_gensalt(__const char *prefix, unsigned long count,
+	__const char *input, int size);
+extern char *crypt_gensalt_rn(__const char *prefix, unsigned long count,
+	__const char *input, int size, char *output, int output_size);
+extern char *crypt_gensalt_ra(__const char *prefix, unsigned long count,
+	__const char *input, int size);
+#endif
+
+#endif
diff --git a/crypt_blowfish/x86.S b/crypt_blowfish/x86.S
new file mode 100644
index 000000000..b0f1cd2ef
--- /dev/null
+++ b/crypt_blowfish/x86.S
@@ -0,0 +1,203 @@
+/*
+ * Written by Solar Designer <solar at openwall.com> in 1998-2010.
+ * No copyright is claimed, and the software is hereby placed in the public
+ * domain.  In case this attempt to disclaim copyright and place the software
+ * in the public domain is deemed null and void, then the software is
+ * Copyright (c) 1998-2010 Solar Designer and it is hereby released to the
+ * general public under the following terms:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted.
+ *
+ * There's ABSOLUTELY NO WARRANTY, express or implied.
+ *
+ * See crypt_blowfish.c for more information.
+ */
+
+#ifdef __i386__
+
+#if defined(__OpenBSD__) && !defined(__ELF__)
+#define UNDERSCORES
+#define ALIGN_LOG
+#endif
+
+#if defined(__CYGWIN32__) || defined(__MINGW32__)
+#define UNDERSCORES
+#endif
+
+#ifdef __DJGPP__
+#define UNDERSCORES
+#define ALIGN_LOG
+#endif
+
+#ifdef UNDERSCORES
+#define _BF_body_r			__BF_body_r
+#endif
+
+#ifdef ALIGN_LOG
+#define DO_ALIGN(log)			.align (log)
+#elif defined(DUMBAS)
+#define DO_ALIGN(log)			.align 1 << log
+#else
+#define DO_ALIGN(log)			.align (1 << (log))
+#endif
+
+#define BF_FRAME			0x200
+#define ctx				%esp
+
+#define BF_ptr				(ctx)
+
+#define S(N, r)				N+BF_FRAME(ctx,r,4)
+#ifdef DUMBAS
+#define P(N)				0x1000+N+N+N+N+BF_FRAME(ctx)
+#else
+#define P(N)				0x1000+4*N+BF_FRAME(ctx)
+#endif
+
+/*
+ * This version of the assembly code is optimized primarily for the original
+ * Intel Pentium but is also careful to avoid partial register stalls on the
+ * Pentium Pro family of processors (tested up to Pentium III Coppermine).
+ *
+ * It is possible to do 15% faster on the Pentium Pro family and probably on
+ * many non-Intel x86 processors, but, unfortunately, that would make things
+ * twice slower for the original Pentium.
+ *
+ * An additional 2% speedup may be achieved with non-reentrant code.
+ */
+
+#define L				%esi
+#define R				%edi
+#define tmp1				%eax
+#define tmp1_lo				%al
+#define tmp2				%ecx
+#define tmp2_hi				%ch
+#define tmp3				%edx
+#define tmp3_lo				%dl
+#define tmp4				%ebx
+#define tmp4_hi				%bh
+#define tmp5				%ebp
+
+.text
+
+#define BF_ROUND(L, R, N) \
+	xorl L,tmp2; \
+	xorl tmp1,tmp1; \
+	movl tmp2,L; \
+	shrl $16,tmp2; \
+	movl L,tmp4; \
+	movb tmp2_hi,tmp1_lo; \
+	andl $0xFF,tmp2; \
+	movb tmp4_hi,tmp3_lo; \
+	andl $0xFF,tmp4; \
+	movl S(0,tmp1),tmp1; \
+	movl S(0x400,tmp2),tmp5; \
+	addl tmp5,tmp1; \
+	movl S(0x800,tmp3),tmp5; \
+	xorl tmp5,tmp1; \
+	movl S(0xC00,tmp4),tmp5; \
+	addl tmp1,tmp5; \
+	movl 4+P(N),tmp2; \
+	xorl tmp5,R
+
+#define BF_ENCRYPT_START \
+	BF_ROUND(L, R, 0); \
+	BF_ROUND(R, L, 1); \
+	BF_ROUND(L, R, 2); \
+	BF_ROUND(R, L, 3); \
+	BF_ROUND(L, R, 4); \
+	BF_ROUND(R, L, 5); \
+	BF_ROUND(L, R, 6); \
+	BF_ROUND(R, L, 7); \
+	BF_ROUND(L, R, 8); \
+	BF_ROUND(R, L, 9); \
+	BF_ROUND(L, R, 10); \
+	BF_ROUND(R, L, 11); \
+	BF_ROUND(L, R, 12); \
+	BF_ROUND(R, L, 13); \
+	BF_ROUND(L, R, 14); \
+	BF_ROUND(R, L, 15); \
+	movl BF_ptr,tmp5; \
+	xorl L,tmp2; \
+	movl P(17),L
+
+#define BF_ENCRYPT_END \
+	xorl R,L; \
+	movl tmp2,R
+
+DO_ALIGN(5)
+.globl _BF_body_r
+_BF_body_r:
+	movl 4(%esp),%eax
+	pushl %ebp
+	pushl %ebx
+	pushl %esi
+	pushl %edi
+	subl $BF_FRAME-8,%eax
+	xorl L,L
+	cmpl %esp,%eax
+	ja BF_die
+	xchgl %eax,%esp
+	xorl R,R
+	pushl %eax
+	leal 0x1000+BF_FRAME-4(ctx),%eax
+	movl 0x1000+BF_FRAME-4(ctx),tmp2
+	pushl %eax
+	xorl tmp3,tmp3
+BF_loop_P:
+	BF_ENCRYPT_START
+	addl $8,tmp5
+	BF_ENCRYPT_END
+	leal 0x1000+18*4+BF_FRAME(ctx),tmp1
+	movl tmp5,BF_ptr
+	cmpl tmp5,tmp1
+	movl L,-8(tmp5)
+	movl R,-4(tmp5)
+	movl P(0),tmp2
+	ja BF_loop_P
+	leal BF_FRAME(ctx),tmp5
+	xorl tmp3,tmp3
+	movl tmp5,BF_ptr
+BF_loop_S:
+	BF_ENCRYPT_START
+	BF_ENCRYPT_END
+	movl P(0),tmp2
+	movl L,(tmp5)
+	movl R,4(tmp5)
+	BF_ENCRYPT_START
+	BF_ENCRYPT_END
+	movl P(0),tmp2
+	movl L,8(tmp5)
+	movl R,12(tmp5)
+	BF_ENCRYPT_START
+	BF_ENCRYPT_END
+	movl P(0),tmp2
+	movl L,16(tmp5)
+	movl R,20(tmp5)
+	BF_ENCRYPT_START
+	addl $32,tmp5
+	BF_ENCRYPT_END
+	leal 0x1000+BF_FRAME(ctx),tmp1
+	movl tmp5,BF_ptr
+	cmpl tmp5,tmp1
+	movl P(0),tmp2
+	movl L,-8(tmp5)
+	movl R,-4(tmp5)
+	ja BF_loop_S
+	movl 4(%esp),%esp
+	popl %edi
+	popl %esi
+	popl %ebx
+	popl %ebp
+	ret
+
+BF_die:
+/* Oops, need to re-compile with a larger BF_FRAME. */
+	hlt
+	jmp BF_die
+
+#endif
+
+#if defined(__ELF__) && defined(__linux__)
+.section .note.GNU-stack,"",@progbits
+#endif

From 53afc86e009deef9cb4d5c43a65df6e7a2c8b9a1 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno@eressea.de>
Date: Wed, 26 Sep 2018 17:09:29 +0200
Subject: [PATCH 34/81] fix bcrypt library, add to password.c (works on mac)

---
 CMakeLists.txt                |   1 +
 crypt_blowfish/CMakeLists.txt |   6 +-
 crypt_blowfish/wrapper.c      | 551 ++++++++++++++++++++++++++++++++++
 src/CMakeLists.txt            |   3 +
 src/util/password.c           |  25 +-
 src/util/password.h           |   9 +-
 6 files changed, 587 insertions(+), 8 deletions(-)
 create mode 100644 crypt_blowfish/wrapper.c

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4b91565da..71d44ea9f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -62,6 +62,7 @@ endif(TOLUA_FOUND)
 
 enable_testing()
 
+add_subdirectory (crypt_blowfish)
 add_subdirectory (cJSON)
 add_subdirectory (storage)
 add_subdirectory (iniparser)
diff --git a/crypt_blowfish/CMakeLists.txt b/crypt_blowfish/CMakeLists.txt
index b6f810721..21cc29dea 100644
--- a/crypt_blowfish/CMakeLists.txt
+++ b/crypt_blowfish/CMakeLists.txt
@@ -6,11 +6,11 @@ IF (MSVC)
     MSVC_SET_WARNING_LEVEL(3)
 ENDIF (MSVC)
 
-SET (LIB_SRC crypt_blowfish.c crypt_gensalt.c bcrypt.c)
+SET (LIB_SRC bcrypt.c wrapper.c crypt_blowfish.c crypt_gensalt.c)
 ADD_LIBRARY (bcrypt ${LIB_SRC})
 
-set (CJSON_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL "cJSON headers")
-set (CJSON_LIBRARIES bcrypt CACHE INTERNAL "bcrypt libraries")
+set (BCRYPT_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL "cJSON headers")
+set (BCRYPT_LIBRARIES bcrypt CACHE INTERNAL "bcrypt libraries")
 
 IF(UNIX AND NOT APPLE)
     FIND_LIBRARY(UNIX_MATH_LIBRARY m)
diff --git a/crypt_blowfish/wrapper.c b/crypt_blowfish/wrapper.c
new file mode 100644
index 000000000..1e49c90d8
--- /dev/null
+++ b/crypt_blowfish/wrapper.c
@@ -0,0 +1,551 @@
+/*
+ * Written by Solar Designer <solar at openwall.com> in 2000-2014.
+ * No copyright is claimed, and the software is hereby placed in the public
+ * domain.  In case this attempt to disclaim copyright and place the software
+ * in the public domain is deemed null and void, then the software is
+ * Copyright (c) 2000-2014 Solar Designer and it is hereby released to the
+ * general public under the following terms:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted.
+ *
+ * There's ABSOLUTELY NO WARRANTY, express or implied.
+ *
+ * See crypt_blowfish.c for more information.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <errno.h>
+#ifndef __set_errno
+#define __set_errno(val) errno = (val)
+#endif
+
+#ifdef TEST
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/times.h>
+#ifdef TEST_THREADS
+#include <pthread.h>
+#endif
+#endif
+
+#define CRYPT_OUTPUT_SIZE		(7 + 22 + 31 + 1)
+#define CRYPT_GENSALT_OUTPUT_SIZE	(7 + 22 + 1)
+
+#if defined(__GLIBC__) && defined(_LIBC)
+#define __SKIP_GNU
+#endif
+#include "ow-crypt.h"
+
+#include "crypt_blowfish.h"
+#include "crypt_gensalt.h"
+
+#if defined(__GLIBC__) && defined(_LIBC)
+/* crypt.h from glibc-crypt-2.1 will define struct crypt_data for us */
+#include "crypt.h"
+extern char *__md5_crypt_r(const char *key, const char *salt,
+	char *buffer, int buflen);
+/* crypt-entry.c needs to be patched to define __des_crypt_r rather than
+ * __crypt_r, and not define crypt_r and crypt at all */
+extern char *__des_crypt_r(const char *key, const char *salt,
+	struct crypt_data *data);
+extern struct crypt_data _ufc_foobar;
+#endif
+
+static int _crypt_data_alloc(void **data, int *size, int need)
+{
+	void *updated;
+
+	if (*data && *size >= need) return 0;
+
+	updated = realloc(*data, need);
+
+	if (!updated) {
+#ifndef __GLIBC__
+		/* realloc(3) on glibc sets errno, so we don't need to bother */
+		__set_errno(ENOMEM);
+#endif
+		return -1;
+	}
+
+#if defined(__GLIBC__) && defined(_LIBC)
+	if (need >= sizeof(struct crypt_data))
+		((struct crypt_data *)updated)->initialized = 0;
+#endif
+
+	*data = updated;
+	*size = need;
+
+	return 0;
+}
+
+static char *_crypt_retval_magic(char *retval, const char *setting,
+	char *output, int size)
+{
+	if (retval)
+		return retval;
+
+	if (_crypt_output_magic(setting, output, size))
+		return NULL; /* shouldn't happen */
+
+	return output;
+}
+
+#if defined(__GLIBC__) && defined(_LIBC)
+/*
+ * Applications may re-use the same instance of struct crypt_data without
+ * resetting the initialized field in order to let crypt_r() skip some of
+ * its initialization code.  Thus, it is important that our multiple hashing
+ * algorithms either don't conflict with each other in their use of the
+ * data area or reset the initialized field themselves whenever required.
+ * Currently, the hashing algorithms simply have no conflicts: the first
+ * field of struct crypt_data is the 128-byte large DES key schedule which
+ * __des_crypt_r() calculates each time it is called while the two other
+ * hashing algorithms use less than 128 bytes of the data area.
+ */
+
+char *__crypt_rn(__const char *key, __const char *setting,
+	void *data, int size)
+{
+	if (setting[0] == '$' && setting[1] == '2')
+		return _crypt_blowfish_rn(key, setting, (char *)data, size);
+	if (setting[0] == '$' && setting[1] == '1')
+		return __md5_crypt_r(key, setting, (char *)data, size);
+	if (setting[0] == '$' || setting[0] == '_') {
+		__set_errno(EINVAL);
+		return NULL;
+	}
+	if (size >= sizeof(struct crypt_data))
+		return __des_crypt_r(key, setting, (struct crypt_data *)data);
+	__set_errno(ERANGE);
+	return NULL;
+}
+
+char *__crypt_ra(__const char *key, __const char *setting,
+	void **data, int *size)
+{
+	if (setting[0] == '$' && setting[1] == '2') {
+		if (_crypt_data_alloc(data, size, CRYPT_OUTPUT_SIZE))
+			return NULL;
+		return _crypt_blowfish_rn(key, setting, (char *)*data, *size);
+	}
+	if (setting[0] == '$' && setting[1] == '1') {
+		if (_crypt_data_alloc(data, size, CRYPT_OUTPUT_SIZE))
+			return NULL;
+		return __md5_crypt_r(key, setting, (char *)*data, *size);
+	}
+	if (setting[0] == '$' || setting[0] == '_') {
+		__set_errno(EINVAL);
+		return NULL;
+	}
+	if (_crypt_data_alloc(data, size, sizeof(struct crypt_data)))
+		return NULL;
+	return __des_crypt_r(key, setting, (struct crypt_data *)*data);
+}
+
+char *__crypt_r(__const char *key, __const char *setting,
+	struct crypt_data *data)
+{
+	return _crypt_retval_magic(
+		__crypt_rn(key, setting, data, sizeof(*data)),
+		setting, (char *)data, sizeof(*data));
+}
+
+char *__crypt(__const char *key, __const char *setting)
+{
+	return _crypt_retval_magic(
+		__crypt_rn(key, setting, &_ufc_foobar, sizeof(_ufc_foobar)),
+		setting, (char *)&_ufc_foobar, sizeof(_ufc_foobar));
+}
+#else
+char *crypt_rn(const char *key, const char *setting, void *data, int size)
+{
+	return _crypt_blowfish_rn(key, setting, (char *)data, size);
+}
+
+char *crypt_ra(const char *key, const char *setting,
+	void **data, int *size)
+{
+	if (_crypt_data_alloc(data, size, CRYPT_OUTPUT_SIZE))
+		return NULL;
+	return _crypt_blowfish_rn(key, setting, (char *)*data, *size);
+}
+
+char *crypt_r(const char *key, const char *setting, void *data)
+{
+	return _crypt_retval_magic(
+		crypt_rn(key, setting, data, CRYPT_OUTPUT_SIZE),
+		setting, (char *)data, CRYPT_OUTPUT_SIZE);
+}
+
+char *crypt(const char *key, const char *setting)
+{
+	static char output[CRYPT_OUTPUT_SIZE];
+
+	return _crypt_retval_magic(
+		crypt_rn(key, setting, output, sizeof(output)),
+		setting, output, sizeof(output));
+}
+
+#define __crypt_gensalt_rn crypt_gensalt_rn
+#define __crypt_gensalt_ra crypt_gensalt_ra
+#define __crypt_gensalt crypt_gensalt
+#endif
+
+char *__crypt_gensalt_rn(const char *prefix, unsigned long count,
+	const char *input, int size, char *output, int output_size)
+{
+	char *(*use)(const char *_prefix, unsigned long _count,
+		const char *_input, int _size,
+		char *_output, int _output_size);
+
+	/* This may be supported on some platforms in the future */
+	if (!input) {
+		__set_errno(EINVAL);
+		return NULL;
+	}
+
+	if (!strncmp(prefix, "$2a$", 4) || !strncmp(prefix, "$2b$", 4) ||
+	    !strncmp(prefix, "$2y$", 4))
+		use = _crypt_gensalt_blowfish_rn;
+	else
+	if (!strncmp(prefix, "$1$", 3))
+		use = _crypt_gensalt_md5_rn;
+	else
+	if (prefix[0] == '_')
+		use = _crypt_gensalt_extended_rn;
+	else
+	if (!prefix[0] ||
+	    (prefix[0] && prefix[1] &&
+	    memchr(_crypt_itoa64, prefix[0], 64) &&
+	    memchr(_crypt_itoa64, prefix[1], 64)))
+		use = _crypt_gensalt_traditional_rn;
+	else {
+		__set_errno(EINVAL);
+		return NULL;
+	}
+
+	return use(prefix, count, input, size, output, output_size);
+}
+
+char *__crypt_gensalt_ra(const char *prefix, unsigned long count,
+	const char *input, int size)
+{
+	char output[CRYPT_GENSALT_OUTPUT_SIZE];
+	char *retval;
+
+	retval = __crypt_gensalt_rn(prefix, count,
+		input, size, output, sizeof(output));
+
+	if (retval) {
+		retval = strdup(retval);
+#ifndef __GLIBC__
+		/* strdup(3) on glibc sets errno, so we don't need to bother */
+		if (!retval)
+			__set_errno(ENOMEM);
+#endif
+	}
+
+	return retval;
+}
+
+char *__crypt_gensalt(const char *prefix, unsigned long count,
+	const char *input, int size)
+{
+	static char output[CRYPT_GENSALT_OUTPUT_SIZE];
+
+	return __crypt_gensalt_rn(prefix, count,
+		input, size, output, sizeof(output));
+}
+
+#if defined(__GLIBC__) && defined(_LIBC)
+weak_alias(__crypt_rn, crypt_rn)
+weak_alias(__crypt_ra, crypt_ra)
+weak_alias(__crypt_r, crypt_r)
+weak_alias(__crypt, crypt)
+weak_alias(__crypt_gensalt_rn, crypt_gensalt_rn)
+weak_alias(__crypt_gensalt_ra, crypt_gensalt_ra)
+weak_alias(__crypt_gensalt, crypt_gensalt)
+weak_alias(crypt, fcrypt)
+#endif
+
+#ifdef TEST
+static const char *tests[][3] = {
+	{"$2a$05$CCCCCCCCCCCCCCCCCCCCC.E5YPO9kmyuRGyh0XouQYb4YMJKvyOeW",
+		"U*U"},
+	{"$2a$05$CCCCCCCCCCCCCCCCCCCCC.VGOzA784oUp/Z0DY336zx7pLYAy0lwK",
+		"U*U*"},
+	{"$2a$05$XXXXXXXXXXXXXXXXXXXXXOAcXxm9kjPGEMsLznoKqmqw7tc8WCx4a",
+		"U*U*U"},
+	{"$2a$05$abcdefghijklmnopqrstuu5s2v8.iXieOjg/.AySBTTZIIVFJeBui",
+		"0123456789abcdefghijklmnopqrstuvwxyz"
+		"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
+		"chars after 72 are ignored"},
+	{"$2x$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e",
+		"\xa3"},
+	{"$2x$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e",
+		"\xff\xff\xa3"},
+	{"$2y$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e",
+		"\xff\xff\xa3"},
+	{"$2a$05$/OK.fbVrR/bpIqNJ5ianF.nqd1wy.pTMdcvrRWxyiGL2eMz.2a85.",
+		"\xff\xff\xa3"},
+	{"$2b$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e",
+		"\xff\xff\xa3"},
+	{"$2y$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq",
+		"\xa3"},
+	{"$2a$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq",
+		"\xa3"},
+	{"$2b$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq",
+		"\xa3"},
+	{"$2x$05$/OK.fbVrR/bpIqNJ5ianF.o./n25XVfn6oAPaUvHe.Csk4zRfsYPi",
+		"1\xa3" "345"},
+	{"$2x$05$/OK.fbVrR/bpIqNJ5ianF.o./n25XVfn6oAPaUvHe.Csk4zRfsYPi",
+		"\xff\xa3" "345"},
+	{"$2x$05$/OK.fbVrR/bpIqNJ5ianF.o./n25XVfn6oAPaUvHe.Csk4zRfsYPi",
+		"\xff\xa3" "34" "\xff\xff\xff\xa3" "345"},
+	{"$2y$05$/OK.fbVrR/bpIqNJ5ianF.o./n25XVfn6oAPaUvHe.Csk4zRfsYPi",
+		"\xff\xa3" "34" "\xff\xff\xff\xa3" "345"},
+	{"$2a$05$/OK.fbVrR/bpIqNJ5ianF.ZC1JEJ8Z4gPfpe1JOr/oyPXTWl9EFd.",
+		"\xff\xa3" "34" "\xff\xff\xff\xa3" "345"},
+	{"$2y$05$/OK.fbVrR/bpIqNJ5ianF.nRht2l/HRhr6zmCp9vYUvvsqynflf9e",
+		"\xff\xa3" "345"},
+	{"$2a$05$/OK.fbVrR/bpIqNJ5ianF.nRht2l/HRhr6zmCp9vYUvvsqynflf9e",
+		"\xff\xa3" "345"},
+	{"$2a$05$/OK.fbVrR/bpIqNJ5ianF.6IflQkJytoRVc1yuaNtHfiuq.FRlSIS",
+		"\xa3" "ab"},
+	{"$2x$05$/OK.fbVrR/bpIqNJ5ianF.6IflQkJytoRVc1yuaNtHfiuq.FRlSIS",
+		"\xa3" "ab"},
+	{"$2y$05$/OK.fbVrR/bpIqNJ5ianF.6IflQkJytoRVc1yuaNtHfiuq.FRlSIS",
+		"\xa3" "ab"},
+	{"$2x$05$6bNw2HLQYeqHYyBfLMsv/OiwqTymGIGzFsA4hOTWebfehXHNprcAS",
+		"\xd1\x91"},
+	{"$2x$05$6bNw2HLQYeqHYyBfLMsv/O9LIGgn8OMzuDoHfof8AQimSGfcSWxnS",
+		"\xd0\xc1\xd2\xcf\xcc\xd8"},
+	{"$2a$05$/OK.fbVrR/bpIqNJ5ianF.swQOIzjOiJ9GHEPuhEkvqrUyvWhEMx6",
+		"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+		"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+		"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+		"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+		"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+		"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa"
+		"chars after 72 are ignored as usual"},
+	{"$2a$05$/OK.fbVrR/bpIqNJ5ianF.R9xrDjiycxMbQE2bp.vgqlYpW5wx2yy",
+		"\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55"
+		"\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55"
+		"\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55"
+		"\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55"
+		"\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55"
+		"\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55"},
+	{"$2a$05$/OK.fbVrR/bpIqNJ5ianF.9tQZzcJfm3uj2NvJ/n5xkhpqLrMpWCe",
+		"\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff"
+		"\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff"
+		"\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff"
+		"\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff"
+		"\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff"
+		"\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff"},
+	{"$2a$05$CCCCCCCCCCCCCCCCCCCCC.7uG0VCzI2bS7j6ymqJi9CdcdxiRTWNy",
+		""},
+	{"*0", "", "$2a$03$CCCCCCCCCCCCCCCCCCCCC."},
+	{"*0", "", "$2a$32$CCCCCCCCCCCCCCCCCCCCC."},
+	{"*0", "", "$2c$05$CCCCCCCCCCCCCCCCCCCCC."},
+	{"*0", "", "$2z$05$CCCCCCCCCCCCCCCCCCCCC."},
+	{"*0", "", "$2`$05$CCCCCCCCCCCCCCCCCCCCC."},
+	{"*0", "", "$2{$05$CCCCCCCCCCCCCCCCCCCCC."},
+	{"*1", "", "*0"},
+	{NULL}
+};
+
+#define which				tests[0]
+
+static volatile sig_atomic_t running;
+
+static void handle_timer(int signum)
+{
+	(void) signum;
+	running = 0;
+}
+
+static void *run(void *arg)
+{
+	unsigned long count = 0;
+	int i = 0;
+	void *data = NULL;
+	int size = 0x12345678;
+
+	do {
+		const char *hash = tests[i][0];
+		const char *key = tests[i][1];
+		const char *setting = tests[i][2];
+
+		if (!tests[++i][0])
+			i = 0;
+
+		if (setting && strlen(hash) < 30) /* not for benchmark */
+			continue;
+
+		if (strcmp(crypt_ra(key, hash, &data, &size), hash)) {
+			printf("%d: FAILED (crypt_ra/%d/%lu)\n",
+				(int)((char *)arg - (char *)0), i, count);
+			free(data);
+			return NULL;
+		}
+		count++;
+	} while (running);
+
+	free(data);
+	return count + (char *)0;
+}
+
+int main(void)
+{
+	struct itimerval it;
+	struct tms buf;
+	clock_t clk_tck, start_real, start_virtual, end_real, end_virtual;
+	unsigned long count;
+	void *data;
+	int size;
+	char *setting1, *setting2;
+	int i;
+#ifdef TEST_THREADS
+	pthread_t t[TEST_THREADS];
+	void *t_retval;
+#endif
+
+	data = NULL;
+	size = 0x12345678;
+
+	for (i = 0; tests[i][0]; i++) {
+		const char *hash = tests[i][0];
+		const char *key = tests[i][1];
+		const char *setting = tests[i][2];
+		const char *p;
+		int ok = !setting || strlen(hash) >= 30;
+		int o_size;
+		char s_buf[30], o_buf[61];
+		if (!setting) {
+			memcpy(s_buf, hash, sizeof(s_buf) - 1);
+			s_buf[sizeof(s_buf) - 1] = 0;
+			setting = s_buf;
+		}
+
+		__set_errno(0);
+		p = crypt(key, setting);
+		if ((!ok && !errno) || strcmp(p, hash)) {
+			printf("FAILED (crypt/%d)\n", i);
+			return 1;
+		}
+
+		if (ok && strcmp(crypt(key, hash), hash)) {
+			printf("FAILED (crypt/%d)\n", i);
+			return 1;
+		}
+
+		for (o_size = -1; o_size <= (int)sizeof(o_buf); o_size++) {
+			int ok_n = ok && o_size == (int)sizeof(o_buf);
+			const char *x = "abc";
+			strcpy(o_buf, x);
+			if (o_size >= 3) {
+				x = "*0";
+				if (setting[0] == '*' && setting[1] == '0')
+					x = "*1";
+			}
+			__set_errno(0);
+			p = crypt_rn(key, setting, o_buf, o_size);
+			if ((ok_n && (!p || strcmp(p, hash))) ||
+			    (!ok_n && (!errno || p || strcmp(o_buf, x)))) {
+				printf("FAILED (crypt_rn/%d)\n", i);
+				return 1;
+			}
+		}
+
+		__set_errno(0);
+		p = crypt_ra(key, setting, &data, &size);
+		if ((ok && (!p || strcmp(p, hash))) ||
+		    (!ok && (!errno || p || strcmp((char *)data, hash)))) {
+			printf("FAILED (crypt_ra/%d)\n", i);
+			return 1;
+		}
+	}
+
+	setting1 = crypt_gensalt(which[0], 12, data, size);
+	if (!setting1 || strncmp(setting1, "$2a$12$", 7)) {
+		puts("FAILED (crypt_gensalt)\n");
+		return 1;
+	}
+
+	setting2 = crypt_gensalt_ra(setting1, 12, data, size);
+	if (strcmp(setting1, setting2)) {
+		puts("FAILED (crypt_gensalt_ra/1)\n");
+		return 1;
+	}
+
+	(*(char *)data)++;
+	setting1 = crypt_gensalt_ra(setting2, 12, data, size);
+	if (!strcmp(setting1, setting2)) {
+		puts("FAILED (crypt_gensalt_ra/2)\n");
+		return 1;
+	}
+
+	free(setting1);
+	free(setting2);
+	free(data);
+
+#if defined(_SC_CLK_TCK) || !defined(CLK_TCK)
+	clk_tck = sysconf(_SC_CLK_TCK);
+#else
+	clk_tck = CLK_TCK;
+#endif
+
+	running = 1;
+	signal(SIGALRM, handle_timer);
+
+	memset(&it, 0, sizeof(it));
+	it.it_value.tv_sec = 5;
+	setitimer(ITIMER_REAL, &it, NULL);
+
+	start_real = times(&buf);
+	start_virtual = buf.tms_utime + buf.tms_stime;
+
+	count = (char *)run((char *)0) - (char *)0;
+
+	end_real = times(&buf);
+	end_virtual = buf.tms_utime + buf.tms_stime;
+	if (end_virtual == start_virtual) end_virtual++;
+
+	printf("%.1f c/s real, %.1f c/s virtual\n",
+		(float)count * clk_tck / (end_real - start_real),
+		(float)count * clk_tck / (end_virtual - start_virtual));
+
+#ifdef TEST_THREADS
+	running = 1;
+	it.it_value.tv_sec = 60;
+	setitimer(ITIMER_REAL, &it, NULL);
+	start_real = times(&buf);
+
+	for (i = 0; i < TEST_THREADS; i++)
+	if (pthread_create(&t[i], NULL, run, i + (char *)0)) {
+		perror("pthread_create");
+		return 1;
+	}
+
+	for (i = 0; i < TEST_THREADS; i++) {
+		if (pthread_join(t[i], &t_retval)) {
+			perror("pthread_join");
+			continue;
+		}
+		if (!t_retval) continue;
+		count = (char *)t_retval - (char *)0;
+		end_real = times(&buf);
+		printf("%d: %.1f c/s real\n", i,
+			(float)count * clk_tck / (end_real - start_real));
+	}
+#endif
+
+	return 0;
+}
+#endif
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index cf96cfbc2..c6ffe4a1e 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -3,6 +3,7 @@ project (server C)
 
 include_directories (${CMAKE_CURRENT_SOURCE_DIR})
 include_directories (${CJSON_INCLUDE_DIR})
+include_directories (${BCRYPT_INCLUDE_DIR})
 include_directories (${CLIBS_INCLUDE_DIR})
 include_directories (${STORAGE_INCLUDE_DIR})
 include_directories (${TOLUA_INCLUDE_DIR})
@@ -179,6 +180,7 @@ target_link_libraries(eressea
   ${LUA_LIBRARIES}
   ${STORAGE_LIBRARIES}
   ${CLIBS_LIBRARIES}
+  ${BCRYPT_LIBRARIES}
   ${CJSON_LIBRARIES}
   ${INIPARSER_LIBRARIES}
 )
@@ -239,6 +241,7 @@ target_link_libraries(test_eressea
   ${LUA_LIBRARIES}
   ${CLIBS_LIBRARIES}
   ${STORAGE_LIBRARIES}
+  ${BCRYPT_LIBRARIES}
   ${CJSON_LIBRARIES}
   ${INIPARSER_LIBRARIES}
   )
diff --git a/src/util/password.c b/src/util/password.c
index ac482d1f4..eb976ac8d 100644
--- a/src/util/password.c
+++ b/src/util/password.c
@@ -1,18 +1,39 @@
+#ifdef _MSC_VER
 #include <platform.h>
+#endif
 #include "password.h"
 
+#include <bcrypt.h>
+
 #include <assert.h>
 #include <string.h>
 #include <stdio.h>
 
-bool password_is_implemented(int algo) {
+bool password_is_implemented(cryptalgo_t algo) {
+    if (algo == PASSWORD_BCRYPT) return true;
     return algo == PASSWORD_PLAINTEXT;
 }
 
-const char * password_encode(const char * passwd, int algo) {
+const char * password_encode(const char * passwd, cryptalgo_t algo) {
+    if (algo == PASSWORD_BCRYPT) {
+        char salt[BCRYPT_HASHSIZE];
+        static char hash[BCRYPT_HASHSIZE];
+        int ret;
+        bcrypt_gensalt(12, salt);
+        ret = bcrypt_hashpw(passwd, salt, hash);
+        assert(ret == 0);
+        return hash;
+    }
     return passwd;
 }
 
 int password_verify(const char * pwhash, const char * passwd) {
+    if (pwhash[0] == '$') {
+        if (pwhash[1] == '2') {
+            int ret = bcrypt_checkpw(passwd, pwhash);
+            assert(ret != -1);
+            return (ret == 0) ? VERIFY_OK : VERIFY_FAIL;
+        }
+    }
     return (strcmp(passwd, pwhash) == 0) ? VERIFY_OK : VERIFY_FAIL;
 }
diff --git a/src/util/password.h b/src/util/password.h
index ba55f6cb9..acd695954 100644
--- a/src/util/password.h
+++ b/src/util/password.h
@@ -1,12 +1,15 @@
 #pragma once
 
 #include <stdbool.h>
-#define PASSWORD_PLAINTEXT 0
+typedef enum cryptalgo_t {
+    PASSWORD_PLAINTEXT,
+    PASSWORD_BCRYPT
+} cryptalgo_t;
 #define PASSWORD_DEFAULT PASSWORD_PLAINTEXT
 
 #define VERIFY_OK 0
 #define VERIFY_FAIL 1
 #define VERIFY_UNKNOWN 2
 int password_verify(const char *hash, const char *passwd);
-const char * password_encode(const char *passwd, int algo);
-bool password_is_implemented(int algo);
+const char * password_encode(const char *passwd, cryptalgo_t algo);
+bool password_is_implemented(cryptalgo_t algo);

From 21e54e09330da511d80db9691b7623eba93deccd Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Wed, 26 Sep 2018 18:33:38 +0200
Subject: [PATCH 35/81] move crypto implementations to util/crypto for easier
 inclusion

---
 CMakeLists.txt                                |  1 -
 crypt_blowfish/CMakeLists.txt                 | 24 ----------------
 src/CMakeLists.txt                            |  6 ++--
 src/util/CMakeLists.txt                       |  2 ++
 src/util/crypto/CMakeLists.txt                | 28 +++++++++++++++++++
 {crypt_blowfish => src/util/crypto}/bcrypt.c  |  2 +-
 {crypt_blowfish => src/util/crypto}/bcrypt.h  |  0
 .../util/crypto/crypt_blowfish}/LINKS         |  0
 .../util/crypto/crypt_blowfish}/PERFORMANCE   |  0
 .../util/crypto/crypt_blowfish}/README        |  0
 .../util/crypto/crypt_blowfish}/crypt.h       |  0
 .../crypto/crypt_blowfish}/crypt_blowfish.c   |  0
 .../crypto/crypt_blowfish}/crypt_blowfish.h   |  0
 .../crypto/crypt_blowfish}/crypt_gensalt.c    |  0
 .../crypto/crypt_blowfish}/crypt_gensalt.h    |  0
 .../util/crypto/crypt_blowfish}/ow-crypt.h    |  0
 .../util/crypto/crypt_blowfish}/wrapper.c     |  0
 .../util/crypto/crypt_blowfish}/x86.S         |  0
 src/util/password.c                           |  2 +-
 19 files changed, 35 insertions(+), 30 deletions(-)
 delete mode 100644 crypt_blowfish/CMakeLists.txt
 create mode 100644 src/util/crypto/CMakeLists.txt
 rename {crypt_blowfish => src/util/crypto}/bcrypt.c (99%)
 rename {crypt_blowfish => src/util/crypto}/bcrypt.h (100%)
 rename {crypt_blowfish => src/util/crypto/crypt_blowfish}/LINKS (100%)
 rename {crypt_blowfish => src/util/crypto/crypt_blowfish}/PERFORMANCE (100%)
 rename {crypt_blowfish => src/util/crypto/crypt_blowfish}/README (100%)
 rename {crypt_blowfish => src/util/crypto/crypt_blowfish}/crypt.h (100%)
 rename {crypt_blowfish => src/util/crypto/crypt_blowfish}/crypt_blowfish.c (100%)
 rename {crypt_blowfish => src/util/crypto/crypt_blowfish}/crypt_blowfish.h (100%)
 rename {crypt_blowfish => src/util/crypto/crypt_blowfish}/crypt_gensalt.c (100%)
 rename {crypt_blowfish => src/util/crypto/crypt_blowfish}/crypt_gensalt.h (100%)
 rename {crypt_blowfish => src/util/crypto/crypt_blowfish}/ow-crypt.h (100%)
 rename {crypt_blowfish => src/util/crypto/crypt_blowfish}/wrapper.c (100%)
 rename {crypt_blowfish => src/util/crypto/crypt_blowfish}/x86.S (100%)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 71d44ea9f..4b91565da 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -62,7 +62,6 @@ endif(TOLUA_FOUND)
 
 enable_testing()
 
-add_subdirectory (crypt_blowfish)
 add_subdirectory (cJSON)
 add_subdirectory (storage)
 add_subdirectory (iniparser)
diff --git a/crypt_blowfish/CMakeLists.txt b/crypt_blowfish/CMakeLists.txt
deleted file mode 100644
index 21cc29dea..000000000
--- a/crypt_blowfish/CMakeLists.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-cmake_minimum_required(VERSION 2.6)
-project (bcrypt C)
-
-IF (MSVC)
-    include (MSVC)
-    MSVC_SET_WARNING_LEVEL(3)
-ENDIF (MSVC)
-
-SET (LIB_SRC bcrypt.c wrapper.c crypt_blowfish.c crypt_gensalt.c)
-ADD_LIBRARY (bcrypt ${LIB_SRC})
-
-set (BCRYPT_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL "cJSON headers")
-set (BCRYPT_LIBRARIES bcrypt CACHE INTERNAL "bcrypt libraries")
-
-IF(UNIX AND NOT APPLE)
-    FIND_LIBRARY(UNIX_MATH_LIBRARY m)
-    SET(BCRYPT_LIBRARIES ${BCRYPT_LIBRARIES} ${UNIX_MATH_LIBRARY} CACHE
-	    INTERNAL "bcrypt libraries")
-ENDIF()
-            
-IF (MSVC)
-    MSVC_CRT_SECURE_NO_WARNINGS (bcrypt)
-ENDIF (MSVC)
-
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index c6ffe4a1e..506f35473 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -3,7 +3,7 @@ project (server C)
 
 include_directories (${CMAKE_CURRENT_SOURCE_DIR})
 include_directories (${CJSON_INCLUDE_DIR})
-include_directories (${BCRYPT_INCLUDE_DIR})
+include_directories (${CRYPTO_INCLUDE_DIR})
 include_directories (${CLIBS_INCLUDE_DIR})
 include_directories (${STORAGE_INCLUDE_DIR})
 include_directories (${TOLUA_INCLUDE_DIR})
@@ -180,7 +180,7 @@ target_link_libraries(eressea
   ${LUA_LIBRARIES}
   ${STORAGE_LIBRARIES}
   ${CLIBS_LIBRARIES}
-  ${BCRYPT_LIBRARIES}
+  ${CRYPTO_LIBRARIES}
   ${CJSON_LIBRARIES}
   ${INIPARSER_LIBRARIES}
 )
@@ -241,7 +241,7 @@ target_link_libraries(test_eressea
   ${LUA_LIBRARIES}
   ${CLIBS_LIBRARIES}
   ${STORAGE_LIBRARIES}
-  ${BCRYPT_LIBRARIES}
+  ${CRYPTO_LIBRARIES}
   ${CJSON_LIBRARIES}
   ${INIPARSER_LIBRARIES}
   )
diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt
index b462d2bd3..90059666a 100644
--- a/src/util/CMakeLists.txt
+++ b/src/util/CMakeLists.txt
@@ -1,5 +1,7 @@
 project(util C)
 
+add_subdirectory (crypto)
+
 SET(_TEST_FILES
 attrib.test.c
 base36.test.c
diff --git a/src/util/crypto/CMakeLists.txt b/src/util/crypto/CMakeLists.txt
new file mode 100644
index 000000000..925c73380
--- /dev/null
+++ b/src/util/crypto/CMakeLists.txt
@@ -0,0 +1,28 @@
+cmake_minimum_required(VERSION 2.6)
+project (crypto C)
+
+IF (MSVC)
+  include (MSVC)
+  MSVC_SET_WARNING_LEVEL(3)
+ENDIF (MSVC)
+
+SET (LIB_SRC
+  bcrypt.c
+  crypt_blowfish/wrapper.c
+  crypt_blowfish/crypt_blowfish.c
+  crypt_blowfish/crypt_gensalt.c
+)
+ADD_LIBRARY (crypto ${LIB_SRC})
+
+set (CRYPTO_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL "cJSON headers")
+set (CRYPTO_LIBRARIES crypto CACHE INTERNAL "crypto libraries")
+
+IF(WIN32)
+  FIND_LIBRARY(WIN32_CNG_LIBRARY bcrypt)
+  SET(CRYPTO_LIBRARIES ${CRYPTO_LIBRARIES} ${WIN32_CNG_LIBRARY} CACHE
+    INTERNAL "crypto libraries")
+ENDIF()
+            
+IF (MSVC)
+  MSVC_CRT_SECURE_NO_WARNINGS (crypto)
+ENDIF (MSVC)
diff --git a/crypt_blowfish/bcrypt.c b/src/util/crypto/bcrypt.c
similarity index 99%
rename from crypt_blowfish/bcrypt.c
rename to src/util/crypto/bcrypt.c
index a4c992258..bd8722beb 100644
--- a/crypt_blowfish/bcrypt.c
+++ b/src/util/crypto/bcrypt.c
@@ -19,7 +19,7 @@
 #include <errno.h>
 
 #include "bcrypt.h"
-#include "ow-crypt.h"
+#include "crypt_blowfish/ow-crypt.h"
 
 #define RANDBYTES (16)
 
diff --git a/crypt_blowfish/bcrypt.h b/src/util/crypto/bcrypt.h
similarity index 100%
rename from crypt_blowfish/bcrypt.h
rename to src/util/crypto/bcrypt.h
diff --git a/crypt_blowfish/LINKS b/src/util/crypto/crypt_blowfish/LINKS
similarity index 100%
rename from crypt_blowfish/LINKS
rename to src/util/crypto/crypt_blowfish/LINKS
diff --git a/crypt_blowfish/PERFORMANCE b/src/util/crypto/crypt_blowfish/PERFORMANCE
similarity index 100%
rename from crypt_blowfish/PERFORMANCE
rename to src/util/crypto/crypt_blowfish/PERFORMANCE
diff --git a/crypt_blowfish/README b/src/util/crypto/crypt_blowfish/README
similarity index 100%
rename from crypt_blowfish/README
rename to src/util/crypto/crypt_blowfish/README
diff --git a/crypt_blowfish/crypt.h b/src/util/crypto/crypt_blowfish/crypt.h
similarity index 100%
rename from crypt_blowfish/crypt.h
rename to src/util/crypto/crypt_blowfish/crypt.h
diff --git a/crypt_blowfish/crypt_blowfish.c b/src/util/crypto/crypt_blowfish/crypt_blowfish.c
similarity index 100%
rename from crypt_blowfish/crypt_blowfish.c
rename to src/util/crypto/crypt_blowfish/crypt_blowfish.c
diff --git a/crypt_blowfish/crypt_blowfish.h b/src/util/crypto/crypt_blowfish/crypt_blowfish.h
similarity index 100%
rename from crypt_blowfish/crypt_blowfish.h
rename to src/util/crypto/crypt_blowfish/crypt_blowfish.h
diff --git a/crypt_blowfish/crypt_gensalt.c b/src/util/crypto/crypt_blowfish/crypt_gensalt.c
similarity index 100%
rename from crypt_blowfish/crypt_gensalt.c
rename to src/util/crypto/crypt_blowfish/crypt_gensalt.c
diff --git a/crypt_blowfish/crypt_gensalt.h b/src/util/crypto/crypt_blowfish/crypt_gensalt.h
similarity index 100%
rename from crypt_blowfish/crypt_gensalt.h
rename to src/util/crypto/crypt_blowfish/crypt_gensalt.h
diff --git a/crypt_blowfish/ow-crypt.h b/src/util/crypto/crypt_blowfish/ow-crypt.h
similarity index 100%
rename from crypt_blowfish/ow-crypt.h
rename to src/util/crypto/crypt_blowfish/ow-crypt.h
diff --git a/crypt_blowfish/wrapper.c b/src/util/crypto/crypt_blowfish/wrapper.c
similarity index 100%
rename from crypt_blowfish/wrapper.c
rename to src/util/crypto/crypt_blowfish/wrapper.c
diff --git a/crypt_blowfish/x86.S b/src/util/crypto/crypt_blowfish/x86.S
similarity index 100%
rename from crypt_blowfish/x86.S
rename to src/util/crypto/crypt_blowfish/x86.S
diff --git a/src/util/password.c b/src/util/password.c
index eb976ac8d..73e02c551 100644
--- a/src/util/password.c
+++ b/src/util/password.c
@@ -3,7 +3,7 @@
 #endif
 #include "password.h"
 
-#include <bcrypt.h>
+#include "crypto/bcrypt.h"
 
 #include <assert.h>
 #include <string.h>

From 3c50a4260b5919d65ed50149cc7bc3327aa4cab0 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Wed, 26 Sep 2018 18:43:30 +0200
Subject: [PATCH 36/81] add some WIN32 workarounds, tests

---
 src/util/crypto/bcrypt.c                      | 20 ++++++++++++++-----
 .../crypto/crypt_blowfish/crypt_blowfish.c    |  2 +-
 src/util/password.test.c                      | 20 ++++++++++++-------
 3 files changed, 29 insertions(+), 13 deletions(-)

diff --git a/src/util/crypto/bcrypt.c b/src/util/crypto/bcrypt.c
index bd8722beb..c8cc14e23 100644
--- a/src/util/crypto/bcrypt.c
+++ b/src/util/crypto/bcrypt.c
@@ -15,14 +15,21 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
-#include <unistd.h>
 #include <errno.h>
 
+#ifdef WIN32
+#include <windows.h>
+#include <bcrypt.h>
+#else
+#include <unistd.h>
+#endif
+
 #include "bcrypt.h"
 #include "crypt_blowfish/ow-crypt.h"
 
 #define RANDBYTES (16)
 
+#ifndef WIN32
 static int try_close(int fd)
 {
 	int ret;
@@ -60,7 +67,7 @@ static int try_read(int fd, char *out, size_t count)
 
 	return 0;
 }
-
+#endif
 /*
  * This is a best effort implementation. Nothing prevents a compiler from
  * optimizing this function and making it vulnerable to timing attacks, but
@@ -96,12 +103,15 @@ static int timing_safe_strcmp(const char *str1, const char *str2)
 
 int bcrypt_gensalt(int factor, char salt[BCRYPT_HASHSIZE])
 {
-	int fd;
 	char input[RANDBYTES];
 	int workf;
 	char *aux;
 
-	fd = open("/dev/urandom", O_RDONLY);
+#ifdef WIN32
+    BCryptGenRandom(NULL, input, RANDBYTES, BCRYPT_USE_SYSTEM_PREFERRED_RNG);    
+#else
+    int fd;
+    fd = open("/dev/urandom", O_RDONLY);
 	if (fd == -1)
 		return 1;
 
@@ -113,7 +123,7 @@ int bcrypt_gensalt(int factor, char salt[BCRYPT_HASHSIZE])
 
 	if (try_close(fd) != 0)
 		return 3;
-
+#endif
 	/* Generate salt. */
 	workf = (factor < 4 || factor > 31)?12:factor;
 	aux = crypt_gensalt_rn("$2a$", workf, input, RANDBYTES,
diff --git a/src/util/crypto/crypt_blowfish/crypt_blowfish.c b/src/util/crypto/crypt_blowfish/crypt_blowfish.c
index 9d3f3be82..b0b11d3ad 100644
--- a/src/util/crypto/crypt_blowfish/crypt_blowfish.c
+++ b/src/util/crypto/crypt_blowfish/crypt_blowfish.c
@@ -896,7 +896,7 @@ char *_crypt_gensalt_blowfish_rn(const char *prefix, unsigned long count,
 	output[1] = '2';
 	output[2] = prefix[2];
 	output[3] = '$';
-	output[4] = '0' + count / 10;
+	output[4] = '0' + (char)count / 10;
 	output[5] = '0' + count % 10;
 	output[6] = '$';
 
diff --git a/src/util/password.test.c b/src/util/password.test.c
index 8efe5b107..34a252531 100644
--- a/src/util/password.test.c
+++ b/src/util/password.test.c
@@ -4,17 +4,23 @@
 #include <string.h>
 
 static void test_passwords(CuTest *tc) {
-    const char *hash, *expect;
+    const char *hash;
     
-    expect = "password";
+    if (password_is_implemented(PASSWORD_BCRYPT)) {
+        hash = password_encode("password", PASSWORD_BCRYPT);
+        CuAssertPtrNotNull(tc, hash);
+        CuAssertIntEquals(tc, '$', hash[0]);
+        CuAssertIntEquals(tc, '2', hash[1]);
+        CuAssertIntEquals(tc, '$', hash[3]);
+        CuAssertIntEquals(tc, VERIFY_OK, password_verify(hash, "password"));
+        CuAssertIntEquals(tc, VERIFY_FAIL, password_verify(hash, "arseword"));
+    }
     if (password_is_implemented(PASSWORD_PLAINTEXT)) {
         hash = password_encode("password", PASSWORD_PLAINTEXT);
         CuAssertPtrNotNull(tc, hash);
-        CuAssertStrEquals(tc, hash, expect);
-        CuAssertIntEquals(tc, VERIFY_OK, password_verify(expect, "password"));
-        CuAssertIntEquals(tc, VERIFY_FAIL, password_verify(expect, "arseword"));
-    } else {
-        CuAssertIntEquals(tc, VERIFY_UNKNOWN, password_verify(expect, "password"));
+        CuAssertStrEquals(tc, hash, "password");
+        CuAssertIntEquals(tc, VERIFY_OK, password_verify(hash, "password"));
+        CuAssertIntEquals(tc, VERIFY_FAIL, password_verify(hash, "arseword"));
     }
 }
 

From 2e9bde0261ca2e1374db27c5d63c0485fc21eec6 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Wed, 26 Sep 2018 19:05:49 +0200
Subject: [PATCH 37/81] More WIN32 adaptations, configurable work factor.

---
 src/CMakeLists.txt                       |  2 +-
 src/platform.h                           |  1 +
 src/util/crypto/CMakeLists.txt           |  5 ++---
 src/util/crypto/crypt_blowfish/wrapper.c | 10 ++++++----
 src/util/crypto/{bcrypt.c => crypto.c}   |  2 +-
 src/util/crypto/{bcrypt.h => crypto.h}   |  0
 src/util/password.c                      |  6 ++++--
 src/util/password.h                      |  2 ++
 src/util/password.test.c                 |  4 ++++
 9 files changed, 21 insertions(+), 11 deletions(-)
 rename src/util/crypto/{bcrypt.c => crypto.c} (99%)
 rename src/util/crypto/{bcrypt.h => crypto.h} (100%)

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 506f35473..9a7e4a8ab 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -28,7 +28,7 @@ IF (CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang")
     SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wsign-compare -Wall -Werror -Wno-unknown-pragmas -Wstrict-prototypes -Wpointer-arith -Wno-char-subscripts -Wno-long-long")
 #    SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c89")
 ELSEIF(MSVC)
-    SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W4 /WX /MP /Za /D_CRT_SECURE_NO_WARNINGS /D_USE_MATH_DEFINES")
+    SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W4 /WX /MP /D_CRT_SECURE_NO_WARNINGS /D_USE_MATH_DEFINES")
     set(CMAKE_EXE_LINKER_FLAGS_DEBUG
         "${CMAKE_EXE_LINKER_FLAGS_DEBUG} /NODEFAULTLIB:libc.lib /NODEFAULTLIB:libcmt.lib /NODEFAULTLIB:libcd.lib /NODEFAULTLIB:libcmtd.lib /NODEFAULTLIB:msvcrt.lib")
     set(CMAKE_EXE_LINKER_FLAGS_RELEASE
diff --git a/src/platform.h b/src/platform.h
index fb1ace65a..fdc3760f9 100644
--- a/src/platform.h
+++ b/src/platform.h
@@ -14,6 +14,7 @@
 #pragma warning(disable: 4457) // declaration hides function parameter
 #pragma warning(disable: 4459) // declaration hides global
 #pragma warning(disable: 4224) // formal parameter was previously defined as a type
+#pragma warning(disable: 4214) // bit field types other than int
 #endif
 
 /* @see https://insanecoding.blogspot.no/2007/11/pathmax-simply-isnt.html */
diff --git a/src/util/crypto/CMakeLists.txt b/src/util/crypto/CMakeLists.txt
index 925c73380..195eb02b4 100644
--- a/src/util/crypto/CMakeLists.txt
+++ b/src/util/crypto/CMakeLists.txt
@@ -7,7 +7,7 @@ IF (MSVC)
 ENDIF (MSVC)
 
 SET (LIB_SRC
-  bcrypt.c
+  crypto.c
   crypt_blowfish/wrapper.c
   crypt_blowfish/crypt_blowfish.c
   crypt_blowfish/crypt_gensalt.c
@@ -18,8 +18,7 @@ set (CRYPTO_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL "cJSON header
 set (CRYPTO_LIBRARIES crypto CACHE INTERNAL "crypto libraries")
 
 IF(WIN32)
-  FIND_LIBRARY(WIN32_CNG_LIBRARY bcrypt)
-  SET(CRYPTO_LIBRARIES ${CRYPTO_LIBRARIES} ${WIN32_CNG_LIBRARY} CACHE
+  SET(CRYPTO_LIBRARIES ${CRYPTO_LIBRARIES} bcrypt CACHE
     INTERNAL "crypto libraries")
 ENDIF()
             
diff --git a/src/util/crypto/crypt_blowfish/wrapper.c b/src/util/crypto/crypt_blowfish/wrapper.c
index 1e49c90d8..b69ba7ae6 100644
--- a/src/util/crypto/crypt_blowfish/wrapper.c
+++ b/src/util/crypto/crypt_blowfish/wrapper.c
@@ -243,13 +243,15 @@ char *__crypt_gensalt_ra(const char *prefix, unsigned long count,
 		input, size, output, sizeof(output));
 
 	if (retval) {
-		retval = strdup(retval);
+        size_t len = 1 + strlen(retval);
+        char * dst = malloc(len);
 #ifndef __GLIBC__
-		/* strdup(3) on glibc sets errno, so we don't need to bother */
-		if (!retval)
+		/* malloc(3) on glibc sets errno, so we don't need to bother */
+		if (!dst)
 			__set_errno(ENOMEM);
 #endif
-	}
+        retval = memcpy(dst, retval, len);
+    }
 
 	return retval;
 }
diff --git a/src/util/crypto/bcrypt.c b/src/util/crypto/crypto.c
similarity index 99%
rename from src/util/crypto/bcrypt.c
rename to src/util/crypto/crypto.c
index c8cc14e23..75129a826 100644
--- a/src/util/crypto/bcrypt.c
+++ b/src/util/crypto/crypto.c
@@ -24,7 +24,7 @@
 #include <unistd.h>
 #endif
 
-#include "bcrypt.h"
+#include "crypto.h"
 #include "crypt_blowfish/ow-crypt.h"
 
 #define RANDBYTES (16)
diff --git a/src/util/crypto/bcrypt.h b/src/util/crypto/crypto.h
similarity index 100%
rename from src/util/crypto/bcrypt.h
rename to src/util/crypto/crypto.h
diff --git a/src/util/password.c b/src/util/password.c
index 73e02c551..a7e14c98b 100644
--- a/src/util/password.c
+++ b/src/util/password.c
@@ -3,12 +3,14 @@
 #endif
 #include "password.h"
 
-#include "crypto/bcrypt.h"
+#include "crypto/crypto.h"
 
 #include <assert.h>
 #include <string.h>
 #include <stdio.h>
 
+int bcrypt_workfactor = 8;
+
 bool password_is_implemented(cryptalgo_t algo) {
     if (algo == PASSWORD_BCRYPT) return true;
     return algo == PASSWORD_PLAINTEXT;
@@ -19,7 +21,7 @@ const char * password_encode(const char * passwd, cryptalgo_t algo) {
         char salt[BCRYPT_HASHSIZE];
         static char hash[BCRYPT_HASHSIZE];
         int ret;
-        bcrypt_gensalt(12, salt);
+        bcrypt_gensalt(bcrypt_workfactor, salt);
         ret = bcrypt_hashpw(passwd, salt, hash);
         assert(ret == 0);
         return hash;
diff --git a/src/util/password.h b/src/util/password.h
index acd695954..7deb46430 100644
--- a/src/util/password.h
+++ b/src/util/password.h
@@ -7,6 +7,8 @@ typedef enum cryptalgo_t {
 } cryptalgo_t;
 #define PASSWORD_DEFAULT PASSWORD_PLAINTEXT
 
+extern int bcrypt_workfactor;
+
 #define VERIFY_OK 0
 #define VERIFY_FAIL 1
 #define VERIFY_UNKNOWN 2
diff --git a/src/util/password.test.c b/src/util/password.test.c
index 34a252531..9740b4080 100644
--- a/src/util/password.test.c
+++ b/src/util/password.test.c
@@ -7,11 +7,15 @@ static void test_passwords(CuTest *tc) {
     const char *hash;
     
     if (password_is_implemented(PASSWORD_BCRYPT)) {
+        bcrypt_workfactor = 4;
         hash = password_encode("password", PASSWORD_BCRYPT);
         CuAssertPtrNotNull(tc, hash);
         CuAssertIntEquals(tc, '$', hash[0]);
         CuAssertIntEquals(tc, '2', hash[1]);
         CuAssertIntEquals(tc, '$', hash[3]);
+        CuAssertIntEquals(tc, '0', hash[4]);
+        CuAssertIntEquals(tc, '4', hash[5]);
+        CuAssertIntEquals(tc, '$', hash[6]);
         CuAssertIntEquals(tc, VERIFY_OK, password_verify(hash, "password"));
         CuAssertIntEquals(tc, VERIFY_FAIL, password_verify(hash, "arseword"));
     }

From ae05d6d9e92904214806ef3c9cdca6afb78042c7 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Wed, 26 Sep 2018 20:08:38 +0200
Subject: [PATCH 38/81] work factor 12 is incredibly slow, don't use it in
 tests.

---
 src/economy.test.c       | 1 +
 src/kernel/save.test.c   | 5 ++---
 src/test_eressea.c       | 2 ++
 src/util/gamedata.h      | 5 ++---
 src/util/password.h      | 2 +-
 src/util/password.test.c | 2 ++
 6 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/src/economy.test.c b/src/economy.test.c
index 90a4bd260..1a40c03db 100644
--- a/src/economy.test.c
+++ b/src/economy.test.c
@@ -487,6 +487,7 @@ static void test_recruit_insect(CuTest *tc) {
 
     test_setup();
     test_create_calendar();
+    test_create_terrain("desert", -1);
     f = test_create_faction(test_create_race("insect"));
     u = test_create_unit(f, test_create_region(0, 0, NULL));
     u->thisorder = create_order(K_RECRUIT, f->locale, "%d", 1);
diff --git a/src/kernel/save.test.c b/src/kernel/save.test.c
index 4e6e0e2d4..036ad00c5 100644
--- a/src/kernel/save.test.c
+++ b/src/kernel/save.test.c
@@ -441,16 +441,15 @@ static void test_read_password_external(CuTest *tc) {
     data.strm.api->rewind(data.strm.handle);
     data.version = NOCRYPT_VERSION;
     _test_read_password(&data, f);
-    CuAssertStrEquals(tc, "newpassword", f->_password);
+    CuAssertTrue(tc, checkpasswd(f, "newpassword"));
     data.version = BADCRYPT_VERSION;
     _test_read_password(&data, f);
-    CuAssertStrEquals(tc, "secret", f->_password);
+    CuAssertTrue(tc, checkpasswd(f, "secret"));
     F = fopen(pwfile, "wt");
     fprintf(F, "%s:pwfile\n", itoa36(f->no));
     fclose(F);
     CuAssertTrue(tc, checkpasswd(f, "secret"));
     _test_read_password(&data, f);
-    CuAssertStrEquals(tc, "pwfile", f->_password);
     CuAssertTrue(tc, checkpasswd(f, "pwfile"));
     mstream_done(&data.strm);
     gamedata_done(&data);
diff --git a/src/test_eressea.c b/src/test_eressea.c
index 5684a8ad4..d91c225ae 100644
--- a/src/test_eressea.c
+++ b/src/test_eressea.c
@@ -7,6 +7,7 @@
 #include <string.h>
 #include <stdlib.h>
 #include <util/log.h>
+#include <util/password.h>
 #include <util/strings.h>
 #include <util/variant.h>
 
@@ -159,6 +160,7 @@ int RunAllTests(int argc, char *argv[])
         CuSuite *summary = CuSuiteNew();
         int fail_count;
         game_init();
+        bcrypt_workfactor = 4;
         while (suites) {
             suite *s = suites->next;
             RunTests(suites->csuite, suites->name);
diff --git a/src/util/gamedata.h b/src/util/gamedata.h
index 22c1d9052..769d44b90 100644
--- a/src/util/gamedata.h
+++ b/src/util/gamedata.h
@@ -36,10 +36,9 @@
 #define FAMILIAR_FIX_VERSION 359 /* familiar links are fixed */
 #define SKILLSORT_VERSION 360 /* u->skills is sorted */
 #define LANDDISPLAY_VERSION 360 /* r.display is now in r.land.display */
-/* unfinished: */
-#define CRYPT_VERSION 400 /* passwords are encrypted */
+#define CRYPT_VERSION 361 /* passwords are encrypted */
 
-#define RELEASE_VERSION LANDDISPLAY_VERSION /* current datafile */
+#define RELEASE_VERSION CRYPT_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/util/password.h b/src/util/password.h
index 7deb46430..61abc588f 100644
--- a/src/util/password.h
+++ b/src/util/password.h
@@ -5,7 +5,7 @@ typedef enum cryptalgo_t {
     PASSWORD_PLAINTEXT,
     PASSWORD_BCRYPT
 } cryptalgo_t;
-#define PASSWORD_DEFAULT PASSWORD_PLAINTEXT
+#define PASSWORD_DEFAULT PASSWORD_BCRYPT
 
 extern int bcrypt_workfactor;
 
diff --git a/src/util/password.test.c b/src/util/password.test.c
index 9740b4080..f22ef5971 100644
--- a/src/util/password.test.c
+++ b/src/util/password.test.c
@@ -7,6 +7,7 @@ static void test_passwords(CuTest *tc) {
     const char *hash;
     
     if (password_is_implemented(PASSWORD_BCRYPT)) {
+        int wf = bcrypt_workfactor;
         bcrypt_workfactor = 4;
         hash = password_encode("password", PASSWORD_BCRYPT);
         CuAssertPtrNotNull(tc, hash);
@@ -18,6 +19,7 @@ static void test_passwords(CuTest *tc) {
         CuAssertIntEquals(tc, '$', hash[6]);
         CuAssertIntEquals(tc, VERIFY_OK, password_verify(hash, "password"));
         CuAssertIntEquals(tc, VERIFY_FAIL, password_verify(hash, "arseword"));
+        bcrypt_workfactor = wf;
     }
     if (password_is_implemented(PASSWORD_PLAINTEXT)) {
         hash = password_encode("password", PASSWORD_PLAINTEXT);

From f513c2c68a3da9505a9cc6ddc1ead2b6313c3269 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Wed, 26 Sep 2018 20:19:59 +0200
Subject: [PATCH 39/81] skip excessive password generation in tests.

---
 src/gmtool.c              | 3 ++-
 src/kernel/faction.c      | 8 +++++---
 src/kernel/faction.test.c | 2 +-
 src/modules/autoseed.c    | 4 +++-
 4 files changed, 11 insertions(+), 6 deletions(-)

diff --git a/src/gmtool.c b/src/gmtool.c
index fdbfd3faa..e75f22612 100644
--- a/src/gmtool.c
+++ b/src/gmtool.c
@@ -934,7 +934,8 @@ static void seed_player(state *st, const newfaction *player) {
         if (r) {
             const char *at = strchr(player->email, '@');
             faction *f;
-            addplayer(r, f = addfaction(player->email, player->password,
+            const char *password = player->password ? player->password : itoa36(rng_int());
+            addplayer(r, f = addfaction(player->email, password,
                                         player->race, player->lang,
                                         player->subscription));
             if (at) {
diff --git a/src/kernel/faction.c b/src/kernel/faction.c
index b4dfe51ca..5e6c98602 100755
--- a/src/kernel/faction.c
+++ b/src/kernel/faction.c
@@ -245,6 +245,7 @@ faction *addfaction(const char *email, const char *password,
     f->alliance_joindate = turn;
     f->lastorders = turn;
     f->_alive = true;
+    f->_password = NULL;
     f->age = 0;
     f->race = frace;
     f->magiegebiet = 0;
@@ -252,9 +253,10 @@ faction *addfaction(const char *email, const char *password,
     f->subscription = subscription;
     f->flags = FFL_ISNEW|FFL_PWMSG;
 
-    if (!password) password = itoa36(rng_int());
-    faction_setpassword(f, password_encode(password, PASSWORD_DEFAULT));
-    ADDMSG(&f->msgs, msg_message("changepasswd", "value", password));
+    if (password) {
+        faction_setpassword(f, password_encode(password, PASSWORD_DEFAULT));
+        ADDMSG(&f->msgs, msg_message("changepasswd", "value", password));
+    }
 
     f->options =
         WANT_OPTION(O_REPORT) | WANT_OPTION(O_ZUGVORLAGE) |
diff --git a/src/kernel/faction.test.c b/src/kernel/faction.test.c
index 37ec70e50..75c455e7d 100644
--- a/src/kernel/faction.test.c
+++ b/src/kernel/faction.test.c
@@ -112,7 +112,7 @@ static void test_addfaction(CuTest *tc) {
     test_setup();
     rc = rc_get_or_create("human");
     lang = test_create_locale();
-    f = addfaction("test@eressea.de", "hurrdurr", rc, lang, 1234);
+    f = addfaction("test@eressea.de", NULL, rc, lang, 1234);
     CuAssertPtrNotNull(tc, f);
     CuAssertPtrNotNull(tc, f->name);
     CuAssertPtrEquals(tc, NULL, (void *)f->units);
diff --git a/src/modules/autoseed.c b/src/modules/autoseed.c
index 374b6379c..439bf35d1 100644
--- a/src/modules/autoseed.c
+++ b/src/modules/autoseed.c
@@ -550,13 +550,15 @@ 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);
-            u = addplayer(r, addfaction(nextf->email, nextf->password, nextf->race,
+            password = nextf->password ? nextf->password : itoa36(rng_int());
+            u = addplayer(r, addfaction(nextf->email, password, nextf->race,
                 nextf->lang, nextf->subscription));
             f = u->faction;
             fset(f, FFL_ISNEW);

From e234a0db6f4c0747dc7b2ff633ae0316a0cb926e Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Wed, 26 Sep 2018 20:21:56 +0200
Subject: [PATCH 40/81] write the htpasswd file, again

---
 scripts/run-turn.lua | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/scripts/run-turn.lua b/scripts/run-turn.lua
index 35303b038..0540d2321 100644
--- a/scripts/run-turn.lua
+++ b/scripts/run-turn.lua
@@ -97,7 +97,7 @@ end
 local function write_files(locales)
     write_database()
     write_passwords()
-    -- write_htpasswd()
+    write_htpasswd()
     write_reports()
     write_summary()
 end

From e462529596f8065119cbd038a952087c45bebf3a Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Wed, 26 Sep 2018 20:36:27 +0200
Subject: [PATCH 41/81] fix merge conflict choose sqlite as default database

---
 s/cmake-init           |  5 +----
 src/modules/autoseed.c | 11 +++++------
 src/modules/autoseed.h |  1 -
 3 files changed, 6 insertions(+), 11 deletions(-)

diff --git a/s/cmake-init b/s/cmake-init
index 337490f07..781db1ea7 100755
--- a/s/cmake-init
+++ b/s/cmake-init
@@ -1,10 +1,7 @@
 #!/bin/sh
 
 ERESSEA_DB=db
-if [ -e /usr/include/sqlite3.h ] ; then
-ERESSEA_DB=sqlite
-fi
-
+pkg-config --exists sqlite3 && ERESSEA_DB=sqlite
 # Parse command line arguments
 while [ ! -z "$1" ] ; do
 if [ "$1" = "--with-db" ] ; then
diff --git a/src/modules/autoseed.c b/src/modules/autoseed.c
index 2380e9bdd..88240d0b3 100644
--- a/src/modules/autoseed.c
+++ b/src/modules/autoseed.c
@@ -95,7 +95,7 @@ newfaction *read_newfactions(const char *filename)
         faction *f;
         char race[20], email[64], lang[8], password[16];
         newfaction *nf, **nfi;
-        int alliance = 0, uid = 0;
+        int alliance = 0;
 
         if (fgets(buf, sizeof(buf), F) == NULL)
             break;
@@ -103,8 +103,8 @@ newfaction *read_newfactions(const char *filename)
         email[0] = '\0';
         password[0] = '\0';
 
-        if (sscanf(buf, "%54s %19s %7s %15s %4d %4d", email, race, lang, 
-            password, &uid, &alliance) < 3) {
+        if (sscanf(buf, "%54s %19s %7s %15s %4d", email, race, lang, 
+            password, &alliance) < 3) {
             break;
         }
         if (email[0] == '#') {
@@ -137,13 +137,12 @@ newfaction *read_newfactions(const char *filename)
         if (check_email(email) == 0) {
             nf->email = str_strdup(email);
         } else {
-            log_error("Invalid email address for subscription %s: %s\n", itoa36(uid), email);
+            log_error("Invalid email address for new faction: %s\n", email);
             free(nf);
             continue;
         }
         nf->password = str_strdup(password);
         nf->race = rc_find(race);
-        nf->uid = uid;
         if (alliances != NULL) {
             struct alliance *al = findalliance(alliance);
             if (al == NULL) {
@@ -559,7 +558,7 @@ int autoseed(newfaction ** players, int nsize, int max_agediff)
             assert(r->land && r->units == 0);
             password = nextf->password ? nextf->password : itoa36(rng_int());
             u = addplayer(r, addfaction(nextf->email, password, nextf->race,
-                nextf->lang, nextf));
+                nextf->lang));
             f = u->faction;
             fset(f, FFL_ISNEW);
             f->alliance = nextf->allies;
diff --git a/src/modules/autoseed.h b/src/modules/autoseed.h
index 74c7409ad..b78a2df55 100644
--- a/src/modules/autoseed.h
+++ b/src/modules/autoseed.h
@@ -24,7 +24,6 @@ extern "C" {
         char *password;
         const struct locale *lang;
         const struct race *race;
-        int uid;
         bool oldregions;
         struct alliance *allies;
     } newfaction;

From 04b8068979527a501496b46ba65f208571de499f Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Wed, 26 Sep 2018 21:06:56 +0200
Subject: [PATCH 42/81] rename password functions to match PHP.

---
 src/bind_faction.c        | 2 +-
 src/kernel/faction.c      | 2 +-
 src/kernel/faction.test.c | 2 +-
 src/kernel/save.c         | 4 ++--
 src/kernel/save.test.c    | 4 ++--
 src/laws.c                | 2 +-
 src/util/password.c       | 2 +-
 src/util/password.h       | 2 +-
 src/util/password.test.c  | 4 ++--
 9 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/src/bind_faction.c b/src/bind_faction.c
index 850679933..632fcec3d 100644
--- a/src/bind_faction.c
+++ b/src/bind_faction.c
@@ -452,7 +452,7 @@ static int tolua_faction_set_password(lua_State * L)
 {
     faction *self = (faction *)tolua_tousertype(L, 1, 0);
     const char * passw = tolua_tostring(L, 2, 0);
-    faction_setpassword(self, password_encode(passw, PASSWORD_DEFAULT));
+    faction_setpassword(self, password_hash(passw, PASSWORD_DEFAULT));
     return 0;
 }
 
diff --git a/src/kernel/faction.c b/src/kernel/faction.c
index 7284db52d..6e85988f4 100755
--- a/src/kernel/faction.c
+++ b/src/kernel/faction.c
@@ -254,7 +254,7 @@ faction *addfaction(const char *email, const char *password,
     f->flags = FFL_ISNEW|FFL_PWMSG;
 
     if (password) {
-        faction_setpassword(f, password_encode(password, PASSWORD_DEFAULT));
+        faction_setpassword(f, password_hash(password, PASSWORD_DEFAULT));
         ADDMSG(&f->msgs, msg_message("changepasswd", "value", password));
     }
 
diff --git a/src/kernel/faction.test.c b/src/kernel/faction.test.c
index 04a2b1e97..9cd5d9de8 100644
--- a/src/kernel/faction.test.c
+++ b/src/kernel/faction.test.c
@@ -137,7 +137,7 @@ static void test_check_passwd(CuTest *tc) {
     faction *f;
     
     f = test_create_faction(NULL);
-    faction_setpassword(f, password_encode("password", PASSWORD_DEFAULT));
+    faction_setpassword(f, password_hash("password", PASSWORD_DEFAULT));
     CuAssertTrue(tc, checkpasswd(f, "password"));
     CuAssertTrue(tc, !checkpasswd(f, "assword"));
     CuAssertTrue(tc, !checkpasswd(f, "PASSWORD"));
diff --git a/src/kernel/save.c b/src/kernel/save.c
index 922fcc24f..e7cb90d2a 100644
--- a/src/kernel/save.c
+++ b/src/kernel/save.c
@@ -924,7 +924,7 @@ static void read_password(gamedata *data, faction *f) {
     if (name[0] == '$' && data->version == BADCRYPT_VERSION) {
         char * pass = getpasswd(f->no);
         if (pass) {
-            faction_setpassword(f, password_encode(pass, PASSWORD_DEFAULT));
+            faction_setpassword(f, password_hash(pass, PASSWORD_DEFAULT));
             free(pass); /* TODO: remove this allocation! */
         }
         else {
@@ -932,7 +932,7 @@ static void read_password(gamedata *data, faction *f) {
         }
     }
     else {
-        faction_setpassword(f, (data->version >= CRYPT_VERSION) ? name : password_encode(name, PASSWORD_DEFAULT));
+        faction_setpassword(f, (data->version >= CRYPT_VERSION) ? name : password_hash(name, PASSWORD_DEFAULT));
     }
     (void)_test_read_password;
 }
diff --git a/src/kernel/save.test.c b/src/kernel/save.test.c
index 036ad00c5..d9ba52862 100644
--- a/src/kernel/save.test.c
+++ b/src/kernel/save.test.c
@@ -407,7 +407,7 @@ static void test_read_password(CuTest *tc) {
 
     test_setup();
     f = test_create_faction(NULL);
-    faction_setpassword(f, password_encode("secret", PASSWORD_DEFAULT));
+    faction_setpassword(f, password_hash("secret", PASSWORD_DEFAULT));
     mstream_init(&data.strm);
     gamedata_init(&data, &store, RELEASE_VERSION);
     _test_write_password(&data, f);
@@ -431,7 +431,7 @@ static void test_read_password_external(CuTest *tc) {
         errno = 0;
     }
     f = test_create_faction(NULL);
-    faction_setpassword(f, password_encode("secret", PASSWORD_DEFAULT));
+    faction_setpassword(f, password_hash("secret", PASSWORD_DEFAULT));
     CuAssertPtrNotNull(tc, f->_password);
     mstream_init(&data.strm);
     gamedata_init(&data, &store, RELEASE_VERSION);
diff --git a/src/laws.c b/src/laws.c
index fe97931ad..d9e05917a 100644
--- a/src/laws.c
+++ b/src/laws.c
@@ -2135,7 +2135,7 @@ int password_cmd(unit * u, struct order *ord)
         cmistake(u, ord, 283, MSG_EVENT);
         str_strlcpy(pwbuf, itoa36(rng_int()), sizeof(pwbuf));
     }
-    faction_setpassword(u->faction, password_encode(pwbuf, PASSWORD_DEFAULT));
+    faction_setpassword(u->faction, password_hash(pwbuf, PASSWORD_DEFAULT));
     ADDMSG(&u->faction->msgs, msg_message("changepasswd",
         "value", pwbuf));
     u->faction->flags |= FFL_PWMSG;
diff --git a/src/util/password.c b/src/util/password.c
index a7e14c98b..61ae8f2a0 100644
--- a/src/util/password.c
+++ b/src/util/password.c
@@ -16,7 +16,7 @@ bool password_is_implemented(cryptalgo_t algo) {
     return algo == PASSWORD_PLAINTEXT;
 }
 
-const char * password_encode(const char * passwd, cryptalgo_t algo) {
+const char * password_hash(const char * passwd, cryptalgo_t algo) {
     if (algo == PASSWORD_BCRYPT) {
         char salt[BCRYPT_HASHSIZE];
         static char hash[BCRYPT_HASHSIZE];
diff --git a/src/util/password.h b/src/util/password.h
index 61abc588f..7309e0c0e 100644
--- a/src/util/password.h
+++ b/src/util/password.h
@@ -13,5 +13,5 @@ extern int bcrypt_workfactor;
 #define VERIFY_FAIL 1
 #define VERIFY_UNKNOWN 2
 int password_verify(const char *hash, const char *passwd);
-const char * password_encode(const char *passwd, cryptalgo_t algo);
+const char * password_hash(const char *passwd, cryptalgo_t algo);
 bool password_is_implemented(cryptalgo_t algo);
diff --git a/src/util/password.test.c b/src/util/password.test.c
index f22ef5971..7ce2d0682 100644
--- a/src/util/password.test.c
+++ b/src/util/password.test.c
@@ -9,7 +9,7 @@ static void test_passwords(CuTest *tc) {
     if (password_is_implemented(PASSWORD_BCRYPT)) {
         int wf = bcrypt_workfactor;
         bcrypt_workfactor = 4;
-        hash = password_encode("password", PASSWORD_BCRYPT);
+        hash = password_hash("password", PASSWORD_BCRYPT);
         CuAssertPtrNotNull(tc, hash);
         CuAssertIntEquals(tc, '$', hash[0]);
         CuAssertIntEquals(tc, '2', hash[1]);
@@ -22,7 +22,7 @@ static void test_passwords(CuTest *tc) {
         bcrypt_workfactor = wf;
     }
     if (password_is_implemented(PASSWORD_PLAINTEXT)) {
-        hash = password_encode("password", PASSWORD_PLAINTEXT);
+        hash = password_hash("password", PASSWORD_PLAINTEXT);
         CuAssertPtrNotNull(tc, hash);
         CuAssertStrEquals(tc, hash, "password");
         CuAssertIntEquals(tc, VERIFY_OK, password_verify(hash, "password"));

From 5a1c96bd936da8b330d5bd2392c34ba58659caa4 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Thu, 27 Sep 2018 16:57:39 +0200
Subject: [PATCH 43/81] make python password checks use the database and bcrypt

---
 process/checkpasswd.py    |  13 +++--
 process/epasswd.py        | 111 +++++++++++++++++++++++++-------------
 process/process-orders.py |   6 ++-
 process/sendreport.sh     |   6 ++-
 4 files changed, 92 insertions(+), 44 deletions(-)

diff --git a/process/checkpasswd.py b/process/checkpasswd.py
index f797dcfde..dd4924b32 100755
--- a/process/checkpasswd.py
+++ b/process/checkpasswd.py
@@ -6,14 +6,19 @@ from epasswd import EPasswd
 if len(sys.argv)<4:
     sys.exit(-2)
 
-passfile=sys.argv[1]
+filename=sys.argv[1]
 myfaction=sys.argv[2]
 mypasswd=sys.argv[3]
 
-if mypasswd[0]=='"':
-    mypasswd=mypasswd[1:len(mypasswd)-1]
+if mypasswd[0] == '"':
+    mypasswd = mypasswd.strip('"')
+
+pw_data = EPasswd()
+try:
+    pw_data.load_database(filename)
+except:
+    pw_data.load_file(filename)
 
-pw_data=EPasswd(passfile)
 if pw_data.fac_exists(myfaction):
     if pw_data.check(myfaction, mypasswd):
         sys.exit(0)
diff --git a/process/epasswd.py b/process/epasswd.py
index aa3d79fa6..4798967a9 100755
--- a/process/epasswd.py
+++ b/process/epasswd.py
@@ -4,47 +4,82 @@ from string import split
 from string import strip
 from string import lower
 import subprocess
+import bcrypt
+import sqlite3
+
+def baseconvert(n, base):
+    """convert positive decimal integer n to equivalent in another base (2-36)"""
+
+    digits = "0123456789abcdefghijkLmnopqrstuvwxyz"
+
+    try:
+        n = int(n)
+        base = int(base)
+    except:
+        return ""
+
+    if n < 0 or base < 2 or base > 36:
+        return ""
+
+    s = ""
+    while True:
+        r = n % base
+        s = digits[r] + s
+        n = n / base
+        if n == 0:
+            break
+
+    return s
 
 class EPasswd:
-	def _check_apr1(self, pwhash, pw):
-		spl = split(pwhash, '$')
-		salt = spl[2]
-		hash = subprocess.check_output(['openssl', 'passwd', '-apr1', '-salt', salt, pw]).decode('utf-8').strip()
-		return hash==pwhash
+    def __init__(self):
+        self.data = {}
 
-	def __init__(self, file):
-		self.data = {}
-		try:
-			fp = open(file,"r")
-		except:
-			fp = None
-		if fp != None:
-			while True:
-				line = fp.readline()
-				if not line: break
-				line = strip(line)
-				[id, email, passwd] = split(line, ":")[0:3]
-				lc_id = lower(id)
-				self.data[lc_id] = {}
-				self.data[lc_id]["id"] = id
-				self.data[lc_id]["email"] = email
-				self.data[lc_id]["passwd"] = passwd
-			fp.close()
+    def set_data(no, email, passwd):
+        lc_id = lower(no)
+        self.data[lc_id] = {}
+        self.data[lc_id]["id"] = no
+        self.data[lc_id]["email"] = email
+        self.data[lc_id]["passwd"] = passwd
 
-	def check(self, id, passwd):
-		pw = self.get_passwd(id)
-		if pw[0:6]=='$apr1$':
-			return self._check_apr1(pw, passwd)
-		return pw == passwd
+    def load_database(self, file):
+        conn = sqlite3.connect(file)
+        c = conn.cursor()
+        c.execute('SELECT MAX(turn) FROM factions')
+        args = c.fetchone()
+        for row in c.execute('SELECT no, email, password FROM factions WHERE turn=?', args):
+            (no, email, passwd) = row
+            self.set_data(baseconvert(no, 36), email, passwd)
+        conn.close()
 
-	def get_passwd(self, id):
-		return self.data[lower(id)]["passwd"]
-	
-	def get_email(self, id):
-		return self.data[lower(id)]["email"]
-	
-	def get_canon_id(self, id):
-		return self.data[lower(id)]["id"]
+    def load_file(self, file):
+        try:
+            fp = open(file,"r")
+        except:
+            fp = None
+        if fp != None:
+            while True:
+                line = fp.readline()
+                if not line: break
+                line = strip(line)
+                [id, email, passwd] = split(line, ":")[0:3]
+                self.set_data(id, email, passwd)
+            fp.close()
 
-	def fac_exists(self, id):
-		return self.data.has_key(lower(id))
+    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 pw == passwd
+
+    def get_passwd(self, id):
+        return self.data[lower(id)]["passwd"]
+    
+    def get_email(self, id):
+        return self.data[lower(id)]["email"]
+    
+    def get_canon_id(self, id):
+        return self.data[lower(id)]["id"]
+
+    def fac_exists(self, id):
+        return self.data.has_key(lower(id))
diff --git a/process/process-orders.py b/process/process-orders.py
index 8ed5e8625..3c741bfeb 100755
--- a/process/process-orders.py
+++ b/process/process-orders.py
@@ -128,7 +128,11 @@ def echeck(filename, locale, rules):
     return mail
 
 #print "reading password file..."
-pw_data = EPasswd(os.path.join(game_dir,"passwd"))
+pw_data = EPasswd()
+try:
+    pw_data.load_database(os.path.join(game_dir,"eressea.db"))
+except:
+    pw_data.load_file(os.path.join(game_dir,"passwd"))
 
 #print "reading orders.queue..."
 # move the queue file to a save space while locking it:
diff --git a/process/sendreport.sh b/process/sendreport.sh
index d98ed505e..d8fe79d47 100755
--- a/process/sendreport.sh
+++ b/process/sendreport.sh
@@ -30,7 +30,11 @@ LOCKFILE="$ERESSEA/.report.lock"
 echo "$(date):report:$GAME:$EMAIL:$FACTION:$PASSWD" >> "$ERESSEA/request.log"
 
 cd "$ERESSEA" || exit
-checkpasswd.py "game-$GAME/passwd" "$FACTION" "$PASSWD" || reply "Das Passwort fuer die Partei $FACTION ist ungueltig"
+PWFILE="game-$GAME/eressea.db"
+if [ ! -e "$PWFILE" ]; then
+  PWFILE="game-$GAME/passwd"
+fi
+checkpasswd.py "$PWFILE" "$FACTION" "$PASSWD" || reply "Das Passwort fuer die Partei $FACTION ist ungueltig"
 
 cd "$ERESSEA/game-$GAME/reports" || exit
 if [ ! -e "${FACTION}.sh" ]; then

From 88f0504f48572b721f766fe0cd344ac670bb06e3 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Thu, 27 Sep 2018 17:08:04 +0200
Subject: [PATCH 44/81] no such file sendpasswd.py (and no suppor for feature
 possible)

---
 process/procmail/rules | 20 --------------------
 1 file changed, 20 deletions(-)

diff --git a/process/procmail/rules b/process/procmail/rules
index 32626fe56..7c70c84bb 100644
--- a/process/procmail/rules
+++ b/process/procmail/rules
@@ -2,26 +2,6 @@
 ## Eressea Reportversand
 ##
 
-:0:server.lock
-* ^Subject:.*ERE.*2.*PASSWOR.*
-| sendpassword.py $HOME/eressea/game-2/passwd
-
-:0:server.lock
-* ^Subject:.*ERE.*3.*PASSWOR.*
-| sendpassword.py $HOME/eressea/game-3/passwd
-
-:0:server.lock
-* ^Subject:.*ERE.*4.*PASSWOR.*
-| sendpassword.py $HOME/eressea/game-4/passwd
-
-:0:server.lock
-* ^Subject:.*ERE.*PASSWOR.*
-| sendpassword.py $HOME/eressea/game-2/passwd
-
-:0:server.lock
-* ^Subject:.*E3.*PASSWOR.*
-| sendpassword.py $HOME/eressea/game-3/passwd
-
 :0:server.lock
 * ^Subject:.*ERE.*2.*REPORT \/.*
 * !From: .*eressea.*@eressea.de

From 17f7aa2c0af472331b0b54141526681e44830719 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Thu, 27 Sep 2018 19:52:54 +0200
Subject: [PATCH 45/81] start new branch for a syntax checker

---
 src/CMakeLists.txt | 10 +++++++---
 src/checker.c      |  8 ++++++++
 2 files changed, 15 insertions(+), 3 deletions(-)
 create mode 100644 src/checker.c

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index eacc879e5..e84a1bb18 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -140,7 +140,11 @@ set (ERESSEA_SRC
   ${KERNEL_SRC}
   ${DB_SRC}
   ${UTIL_SRC}
-)
+  )
+
+set(CHECK_SRC
+  checker.c
+  )
 
 set(SERVER_SRC
   bind_building.c
@@ -161,7 +165,7 @@ set(SERVER_SRC
   console.c
   helpers.c
   main.c
-)
+  )
 
 if (CURSES_FOUND)
 set (SERVER_SRC ${SERVER_SRC}
@@ -176,10 +180,10 @@ if(NOT IWYU_PATH)
 	message(STATUS "Could not find the program include-what-you-use")
 endif()
 
-
 add_library(version STATIC ${VERSION_SRC})
 add_library(game ${ERESSEA_SRC})
 add_executable(eressea ${SERVER_SRC})
+add_executable(checker ${CHECK_SRC})
 if (IWYU_PATH)
 set_property(TARGET eressea PROPERTY C_INCLUDE_WHAT_YOU_USE ${IWYU_PATH})
 endif(IWYU_PATH)
diff --git a/src/checker.c b/src/checker.c
new file mode 100644
index 000000000..eec1db26f
--- /dev/null
+++ b/src/checker.c
@@ -0,0 +1,8 @@
+#ifdef _MSV_VER
+#include <platform.h>
+#endif
+
+int main(int argc, char **argv) {
+    return 0;
+}
+

From 7b9e72e559f43a62c6fe38f22e90cd30354fc928 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Fri, 28 Sep 2018 20:50:24 +0200
Subject: [PATCH 46/81] reduce dependeny spaghetti for database code.

---
 src/CMakeLists.txt         |  1 +
 src/bind_eressea.c         |  9 +++++++-
 src/checker.c              | 14 ++++++++++++
 src/eressea.c              | 10 ++++-----
 src/gamedb.c               |  3 +--
 src/kernel/CMakeLists.txt  |  1 -
 src/kernel/database.c      | 46 --------------------------------------
 src/kernel/database.h      | 23 -------------------
 src/kernel/database.test.c |  6 ++---
 src/kernel/db/berkeley.c   | 45 ++++++++++++++++++-------------------
 src/kernel/db/driver.h     |  6 ++++-
 src/kernel/db/sqlite.c     | 12 +++++-----
 src/kernel/orderdb.c       | 28 ++++++++++++++++++++---
 src/kernel/orderdb.h       |  3 +++
 src/orderfile.c            |  9 +-------
 src/orderfile.h            |  4 ++--
 src/test_eressea.c         |  1 -
 tests/orders.txt           |  3 +++
 18 files changed, 98 insertions(+), 126 deletions(-)
 delete mode 100644 src/kernel/database.c
 delete mode 100644 src/kernel/database.h
 create mode 100644 tests/orders.txt

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index e84a1bb18..fb21a9d50 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -144,6 +144,7 @@ set (ERESSEA_SRC
 
 set(CHECK_SRC
   checker.c
+  orderfile.c
   )
 
 set(SERVER_SRC
diff --git a/src/bind_eressea.c b/src/bind_eressea.c
index 9f73c4a29..34640137b 100755
--- a/src/bind_eressea.c
+++ b/src/bind_eressea.c
@@ -12,6 +12,7 @@
 #include <kernel/save.h>
 
 #include <util/language.h>
+#include <util/log.h>
 
 #include <stream.h>
 #include <stdio.h>
@@ -34,7 +35,13 @@ int eressea_write_game(const char * filename) {
 }
 
 int eressea_read_orders(const char * filename) {
-    return readorders(filename);
+    FILE * F = fopen(filename, "r");
+    if (!F) {
+        perror(filename);
+        return -1;
+    }
+    log_info("reading orders from %s", filename);
+    return readorders(F);
 }
 
 int eressea_export_json(const char * filename, int flags) {
diff --git a/src/checker.c b/src/checker.c
index eec1db26f..1a07897a0 100644
--- a/src/checker.c
+++ b/src/checker.c
@@ -2,7 +2,21 @@
 #include <platform.h>
 #endif
 
+#include <stdio.h>
+#include "orderfile.h"
+
 int main(int argc, char **argv) {
+    FILE * F = stdin;
+    if (argc >= 1) {
+        const char *filename = argv[1];
+        F = fopen(filename, "r");
+        if (!F) {
+            perror(filename);
+            return -1;
+        }
+        readorders(F);
+        fclose(F);
+    }
     return 0;
 }
 
diff --git a/src/eressea.c b/src/eressea.c
index 0bf1454ee..382e23fa3 100644
--- a/src/eressea.c
+++ b/src/eressea.c
@@ -1,14 +1,14 @@
 #include <platform.h>
 #include "eressea.h"
 
+#include "kernel/building.h"
 #include "kernel/calendar.h"
 #include "kernel/config.h"
 #include "kernel/curse.h"
-#include "kernel/faction.h"
-#include "kernel/building.h"
 #include "kernel/equipment.h"
+#include "kernel/faction.h"
 #include "kernel/item.h"
-#include "kernel/database.h"
+#include "kernel/orderdb.h"
 
 #include "util/functions.h"
 #include "util/language.h"
@@ -54,12 +54,12 @@ void game_done(void)
     free_locales();
 #endif
     kernel_done();
-    dblib_close();
+    orderdb_close();
 }
 
 void game_init(void)
 {
-    dblib_open();
+    orderdb_open();
     errno = 0;
     kernel_init();
     register_triggers();
diff --git a/src/gamedb.c b/src/gamedb.c
index e570d61e8..2ca2dba73 100644
--- a/src/gamedb.c
+++ b/src/gamedb.c
@@ -6,7 +6,6 @@
 
 #include "kernel/config.h"
 #include "kernel/calendar.h"
-#include "kernel/database.h"
 #include "kernel/faction.h"
 #include "kernel/db/driver.h"
 
@@ -21,7 +20,7 @@ int gamedb_update(void)
     err = db_driver_open(DB_GAME, dbname);
     if (err == 0) {
         for (f = factions; f; f = f->next) {
-            int uid = dblib_save_faction(f, turn);
+            int uid = db_driver_faction_save(f->uid, f->no, turn, f->email, f->_password);
             if (uid > 0) {
                 f->uid = uid;
             }
diff --git a/src/kernel/CMakeLists.txt b/src/kernel/CMakeLists.txt
index db448bf11..53161efe7 100644
--- a/src/kernel/CMakeLists.txt
+++ b/src/kernel/CMakeLists.txt
@@ -55,7 +55,6 @@ command.c
 config.c
 connection.c
 curse.c
-database.c
 equipment.c
 faction.c
 group.c
diff --git a/src/kernel/database.c b/src/kernel/database.c
deleted file mode 100644
index 137665e31..000000000
--- a/src/kernel/database.c
+++ /dev/null
@@ -1,46 +0,0 @@
-#include <platform.h>
-#include "database.h"
-
-#include <platform.h>
-
-#include <kernel/config.h>
-#include <kernel/faction.h>
-#include <kernel/database.h>
-#include <kernel/orderdb.h>
-
-#include <util/log.h>
-
-#include "db/driver.h"
-
-order_data *dblib_load_order(int id)
-{
-    if (id > 0) {
-        return db_driver_order_load(id);
-    }
-    return NULL;
-}
-
-int dblib_save_order(order_data *od)
-{
-    if (od->_str) {
-        return db_driver_order_save(od);
-    }
-    return 0;
-}
-
-int dblib_save_faction(const faction *f, int turn) {
-    return db_driver_faction_save(f->uid, f->no, turn, f->email, f->_password);
-}
-
-void dblib_open(void)
-{
-    const char *dbname;
-
-    dbname = config_get("game.dbswap");
-    db_driver_open(DB_SWAP, dbname);
-}
-
-void dblib_close(void)
-{
-    db_driver_close(DB_SWAP);
-}
diff --git a/src/kernel/database.h b/src/kernel/database.h
deleted file mode 100644
index e3bdf11d1..000000000
--- a/src/kernel/database.h
+++ /dev/null
@@ -1,23 +0,0 @@
-#ifndef H_DATABASE
-#define H_DATABASE
-
-#include <stddef.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-    struct order_data;
-    struct faction;
-
-    void dblib_open(void);
-    void dblib_close(void);
-
-    struct order_data *dblib_load_order(int id);
-    int dblib_save_order(struct order_data *od);
-    int dblib_save_faction(const struct faction *f, int turn);
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/src/kernel/database.test.c b/src/kernel/database.test.c
index cde4edc11..df777a580 100644
--- a/src/kernel/database.test.c
+++ b/src/kernel/database.test.c
@@ -2,7 +2,7 @@
 #include <kernel/config.h>
 #include <kernel/faction.h>
 
-#include "database.h"
+#include "db/driver.h"
 #include "orderdb.h"
 
 #include <CuTest.h>
@@ -39,9 +39,9 @@ static void test_update_faction(CuTest *tc) {
 
     test_setup();
     f = test_create_faction(NULL);
-    uid = dblib_save_faction(f, 0);
+    uid = db_driver_faction_save(f->uid, f->no, 0, f->email, f->_password);
     f->uid = uid;
-    uid = dblib_save_faction(f, 0);
+    uid = db_driver_faction_save(f->uid, f->no, 0, f->email, f->_password);
     CuAssertIntEquals(tc, f->uid, uid);
     test_teardown();
 }
diff --git a/src/kernel/db/berkeley.c b/src/kernel/db/berkeley.c
index 778e0bfe7..9a10e4bf8 100644
--- a/src/kernel/db/berkeley.c
+++ b/src/kernel/db/berkeley.c
@@ -4,36 +4,35 @@
 #include <platform.h>
 #include "driver.h"
 
-#include <kernel/config.h>
-#include <kernel/orderdb.h>
-
 #include <assert.h>
 #include <string.h>
 
 static DB *g_dbp;
 
-void db_driver_open(void)
+void db_driver_open(database_t db, const char *dbname)
 {
-    int ret;
-    u_int32_t flags = DB_CREATE;
-    const char * dbname;
+    if (db == DB_SWAP) {
+        int ret;
+        u_int32_t flags = DB_CREATE;
 
-    dbname = config_get("game.dbname");
-    ret = db_create(&g_dbp, NULL, 0);
-    assert(ret==0);
+        ret = db_create(&g_dbp, NULL, 0);
+        assert(ret == 0);
 
-    ret = g_dbp->open(g_dbp, NULL, dbname, NULL, DB_RECNO, flags, 0);
-    assert(ret==0);
+        ret = g_dbp->open(g_dbp, NULL, dbname, NULL, DB_RECNO, flags, 0);
+        assert(ret == 0);
+    }
 }
 
-void db_driver_close(void)
+void db_driver_close(database_t db)
 {
-    int ret;
-    ret = g_dbp->close(g_dbp, 0);
-    assert(ret==0);
+    if (db == DB_SWAP) {
+        int ret;
+        ret = g_dbp->close(g_dbp, 0);
+        assert(ret == 0);
+    }
 }
 
-int db_driver_order_save(struct order_data *od)
+int db_driver_order_save(const char *str)
 {
     int ret;
     DBT key, data;
@@ -46,18 +45,13 @@ int db_driver_order_save(struct order_data *od)
     key.size = key.ulen = sizeof(recno);
     key.flags = DB_DBT_USERMEM;
     data.data = (void *)od->_str;
-    data.size = data.ulen = strlen(od->_str) + 1;
+    data.size = data.ulen = strlen(str) + 1;
     data.flags = DB_DBT_USERMEM;
     ret = g_dbp->put(g_dbp, NULL, &key, &data, DB_APPEND);
     assert(ret == 0);
     return (int)recno;
 }
 
-int db_driver_faction_save(int id, int no, int turn, const char *email, const char *password)
-{
-    return -1;
-}
-
 struct order_data *db_driver_order_load(int id)
 {
     int ret;
@@ -79,3 +73,8 @@ struct order_data *db_driver_order_load(int id)
     return od;
 }
 
+int db_driver_faction_save(int id, int no, int turn, const char *email, const char *password)
+{
+    return -1;
+}
+
diff --git a/src/kernel/db/driver.h b/src/kernel/db/driver.h
index 26b0461e3..9632cb5db 100644
--- a/src/kernel/db/driver.h
+++ b/src/kernel/db/driver.h
@@ -1,7 +1,11 @@
 #pragma once
 
+#include <stddef.h>
+
 struct order_data;
 
+extern void odata_create(struct order_data **pdata, size_t len, const char *str);
+
 typedef enum database_t {
     DB_SWAP,
     DB_GAME,
@@ -9,6 +13,6 @@ typedef enum database_t {
 
 int db_driver_open(database_t db, const char *dbname);
 void db_driver_close(database_t db);
-int db_driver_order_save(struct order_data *od);
+int db_driver_order_save(const char *str);
 struct order_data *db_driver_order_load(int id);
 int db_driver_faction_save(int id, int no, int turn, const char *email, const char *password);
diff --git a/src/kernel/db/sqlite.c b/src/kernel/db/sqlite.c
index 70cacaf48..ffdcc8e67 100644
--- a/src/kernel/db/sqlite.c
+++ b/src/kernel/db/sqlite.c
@@ -1,8 +1,6 @@
 #include <platform.h>
 
 #include <kernel/config.h>
-#include <kernel/database.h>
-#include <kernel/orderdb.h>
 
 #include <util/log.h>
 
@@ -25,9 +23,9 @@ static sqlite3_stmt * g_stmt_insert_faction;
 static int g_order_batchsize;
 static int g_order_tx_size;
 
-order_data *db_driver_order_load(int id)
+struct order_data *db_driver_order_load(int id)
 {
-    order_data * od = NULL;
+    struct order_data * od = NULL;
     int err;
 
     ERRNO_CHECK();
@@ -58,12 +56,12 @@ order_data *db_driver_order_load(int id)
     return NULL;
 }
 
-int db_driver_order_save(order_data *od)
+int db_driver_order_save(const char *str)
 {
     int err;
     sqlite3_int64 id;
     
-    assert(od && od->_str);
+    assert(str);
    
     ERRNO_CHECK();
 
@@ -76,7 +74,7 @@ int db_driver_order_save(order_data *od)
     
     err = sqlite3_reset(g_stmt_insert_order);
     assert(err == SQLITE_OK);
-    err = sqlite3_bind_text(g_stmt_insert_order, 1, od->_str, -1, SQLITE_STATIC);
+    err = sqlite3_bind_text(g_stmt_insert_order, 1, str, -1, SQLITE_STATIC);
     assert(err == SQLITE_OK);
     err = sqlite3_step(g_stmt_insert_order);
     assert(err == SQLITE_DONE);
diff --git a/src/kernel/orderdb.c b/src/kernel/orderdb.c
index b30131be4..c4c4746f0 100644
--- a/src/kernel/orderdb.c
+++ b/src/kernel/orderdb.c
@@ -1,5 +1,8 @@
 #include <platform.h>
-#include "database.h"
+
+#include "config.h"
+#include "db/driver.h"
+
 #include "orderdb.h"
 
 #include <util/log.h>
@@ -10,6 +13,19 @@
 #include <stdlib.h>
 #include <string.h>
 
+void orderdb_open(void)
+{
+    const char *dbname;
+
+    dbname = config_get("game.dbswap");
+    db_driver_open(DB_SWAP, dbname);
+}
+
+void orderdb_close(void)
+{
+    db_driver_close(DB_SWAP);
+}
+
 void odata_create(order_data **pdata, size_t len, const char *str)
 {
     order_data *data;
@@ -42,10 +58,16 @@ void odata_addref(order_data *od)
 
 order_data *odata_load(int id)
 {
-    return dblib_load_order(id);
+    if (id > 0) {
+        return db_driver_order_load(id);
+    }
+    return NULL;
 }
 
 int odata_save(order_data *od)
 {
-    return dblib_save_order(od);
+    if (od->_str) {
+        return db_driver_order_save(od->_str);
+    }
+    return 0;
 }
diff --git a/src/kernel/orderdb.h b/src/kernel/orderdb.h
index 800732c5e..33f8b6fce 100644
--- a/src/kernel/orderdb.h
+++ b/src/kernel/orderdb.h
@@ -19,6 +19,9 @@ extern "C" {
     order_data *odata_load(int id);
     int odata_save(order_data *od);
 
+    void orderdb_open(void);
+    void orderdb_close(void);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/orderfile.c b/src/orderfile.c
index 9771b7e14..a2c7a6c87 100644
--- a/src/orderfile.c
+++ b/src/orderfile.c
@@ -226,20 +226,13 @@ static const char * file_getbuf(void *data)
     return getbuf(F, ENCODING_UTF8);
 }
 
-int readorders(const char *filename)
+int readorders(FILE *F)
 {
     input in;
     int result;
-    FILE *F = fopen(filename, "r");
 
-    if (!F) {
-        perror(filename);
-        return -1;
-    }
-    log_info("reading orders from %s", filename);
     in.getbuf = file_getbuf;
     in.data = F;
     result = read_orders(&in);
-    fclose(F);
     return result;
 }
diff --git a/src/orderfile.h b/src/orderfile.h
index 43b86042e..fa051993e 100644
--- a/src/orderfile.h
+++ b/src/orderfile.h
@@ -1,7 +1,7 @@
 #ifndef H_ORDERFILE
 #define H_ORDERFILE
 
-#include <skill.h>
+#include <stdio.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -13,7 +13,7 @@ extern "C" {
     } input;
 
     int read_orders(struct input *in);
-    int readorders(const char *filename);
+    int readorders(FILE *F);
 
 #ifdef __cplusplus
 }
diff --git a/src/test_eressea.c b/src/test_eressea.c
index d91c225ae..439fee1d6 100644
--- a/src/test_eressea.c
+++ b/src/test_eressea.c
@@ -1,7 +1,6 @@
 #include <platform.h>
 #include <eressea.h>
 #include <kernel/config.h>
-#include <kernel/database.h>
 #include <CuTest.h>
 #include <stdio.h>
 #include <string.h>
diff --git a/tests/orders.txt b/tests/orders.txt
new file mode 100644
index 000000000..a4a4f7456
--- /dev/null
+++ b/tests/orders.txt
@@ -0,0 +1,3 @@
+ERESSEA uhfr "Hodor"
+EINHEIT 8bz3
+BENENNEN EINHEIT 'Goldene Herde'

From 91c49659ef2983edd5f0fba814f3fdf13f2a5667 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Fri, 28 Sep 2018 21:02:32 +0200
Subject: [PATCH 47/81] orderdb is glue code, belongs outside of kernel.

---
 src/CMakeLists.txt              |  2 ++
 src/eressea.c                   |  2 +-
 src/kernel/CMakeLists.txt       |  2 --
 src/kernel/database.test.c      |  1 +
 src/kernel/order.c              | 31 +++++++++++++++++++++++-
 src/kernel/order.h              | 12 +++++++++
 src/kernel/orderdb.c            | 34 ++------------------------
 src/kernel/orderdb.h            | 12 ---------
 src/orderdb.c                   | 43 +++++++++++++++++++++++++++++++++
 src/orderdb.h                   | 25 +++++++++++++++++++
 src/{kernel => }/orderdb.test.c |  0
 11 files changed, 116 insertions(+), 48 deletions(-)
 create mode 100644 src/orderdb.c
 create mode 100644 src/orderdb.h
 rename src/{kernel => }/orderdb.test.c (100%)

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index fb21a9d50..5800d1814 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -113,6 +113,7 @@ set (ERESSEA_SRC
   morale.c
   move.c
   names.c
+  orderdb.c
   orderfile.c
   piracy.c
   prefix.c
@@ -221,6 +222,7 @@ set(TESTS_SRC
   monsters.test.c
   move.test.c
   names.test.c
+  orderdb.test.c
   orderfile.test.c
   piracy.test.c
   prefix.test.c
diff --git a/src/eressea.c b/src/eressea.c
index 382e23fa3..e1767811c 100644
--- a/src/eressea.c
+++ b/src/eressea.c
@@ -8,7 +8,6 @@
 #include "kernel/equipment.h"
 #include "kernel/faction.h"
 #include "kernel/item.h"
-#include "kernel/orderdb.h"
 
 #include "util/functions.h"
 #include "util/language.h"
@@ -28,6 +27,7 @@
 #include "creport.h"
 #include "report.h"
 #include "names.h"
+#include "orderdb.h"
 #include "reports.h"
 #include "spells.h"
 #include "vortex.h"
diff --git a/src/kernel/CMakeLists.txt b/src/kernel/CMakeLists.txt
index 53161efe7..562562d8a 100644
--- a/src/kernel/CMakeLists.txt
+++ b/src/kernel/CMakeLists.txt
@@ -27,7 +27,6 @@ group.test.c
 item.test.c
 messages.test.c
 order.test.c
-orderdb.test.c
 # pathfinder.test.c
 plane.test.c
 pool.test.c
@@ -61,7 +60,6 @@ group.c
 item.c
 messages.c
 order.c
-orderdb.c
 pathfinder.c
 plane.c
 pool.c
diff --git a/src/kernel/database.test.c b/src/kernel/database.test.c
index df777a580..3ec44896e 100644
--- a/src/kernel/database.test.c
+++ b/src/kernel/database.test.c
@@ -1,6 +1,7 @@
 #include <platform.h>
 #include <kernel/config.h>
 #include <kernel/faction.h>
+#include <kernel/order.h>
 
 #include "db/driver.h"
 #include "orderdb.h"
diff --git a/src/kernel/order.c b/src/kernel/order.c
index 2fd7c6eb8..e30ea6097 100644
--- a/src/kernel/order.c
+++ b/src/kernel/order.c
@@ -14,7 +14,6 @@
 #include <kernel/config.h>
 #include "order.h"
 
-#include "orderdb.h"
 #include "skill.h"
 #include "keyword.h"
 
@@ -36,6 +35,36 @@
 # define ORD_KEYWORD(ord) (keyword_t)((ord)->command & 0xFFFF)
 # define OD_STRING(odata) ((odata) ? (odata)->_str : NULL)
 
+void odata_create(order_data **pdata, size_t len, const char *str)
+{
+    order_data *data;
+    char *result;
+
+    assert(pdata);
+    data = malloc(sizeof(order_data) + len + 1);
+    data->_refcount = 1;
+    result = (char *)(data + 1);
+    data->_str = (len > 0) ? result : NULL;
+    if (str) {
+        strcpy(result, str);
+    }
+    *pdata = data;
+}
+
+void odata_release(order_data * od)
+{
+    if (od) {
+        if (--od->_refcount == 0) {
+            free(od);
+        }
+    }
+}
+
+void odata_addref(order_data *od)
+{
+    ++od->_refcount;
+}
+
 void replace_order(order ** dlist, order * orig, const order * src)
 {
     assert(src);
diff --git a/src/kernel/order.h b/src/kernel/order.h
index b0d771b67..c5406b39e 100644
--- a/src/kernel/order.h
+++ b/src/kernel/order.h
@@ -37,6 +37,18 @@ extern "C" {
 #define CMD_PERSIST 0x020000
 #define CMD_DEFAULT 0x040000
 
+    typedef struct order_data {
+        const char *_str;
+        int _refcount;
+    } order_data;
+
+    extern order_data *odata_load(int id);
+    extern int odata_save(order_data *od);
+
+    void odata_create(order_data **pdata, size_t len, const char *str);
+    void odata_release(order_data * od);
+    void odata_addref(order_data *od);
+
     typedef struct order {
         struct order *next;
         /* do not access this data: */
diff --git a/src/kernel/orderdb.c b/src/kernel/orderdb.c
index c4c4746f0..42248c0ef 100644
--- a/src/kernel/orderdb.c
+++ b/src/kernel/orderdb.c
@@ -1,7 +1,7 @@
 #include <platform.h>
 
-#include "config.h"
-#include "db/driver.h"
+#include "kernel/config.h"
+#include "kernel/db/driver.h"
 
 #include "orderdb.h"
 
@@ -26,36 +26,6 @@ void orderdb_close(void)
     db_driver_close(DB_SWAP);
 }
 
-void odata_create(order_data **pdata, size_t len, const char *str)
-{
-    order_data *data;
-    char *result;
-
-    assert(pdata);
-    data = malloc(sizeof(order_data) + len + 1);
-    data->_refcount = 1;
-    result = (char *)(data + 1);
-    data->_str = (len > 0) ? result : NULL;
-    if (str) {
-        strcpy(result, str);
-    }
-    *pdata = data;
-}
-
-void odata_release(order_data * od)
-{
-    if (od) {
-        if (--od->_refcount == 0) {
-            free(od);
-        }
-    }
-}
-
-void odata_addref(order_data *od)
-{
-    ++od->_refcount;
-}
-
 order_data *odata_load(int id)
 {
     if (id > 0) {
diff --git a/src/kernel/orderdb.h b/src/kernel/orderdb.h
index 33f8b6fce..e17bdfea8 100644
--- a/src/kernel/orderdb.h
+++ b/src/kernel/orderdb.h
@@ -7,18 +7,6 @@
 extern "C" {
 #endif
 
-    typedef struct order_data {
-        const char *_str;
-        int _refcount;
-    } order_data;
-
-    void odata_create(order_data **pdata, size_t len, const char *str);
-    void odata_release(order_data * od);
-    void odata_addref(order_data *od);
-
-    order_data *odata_load(int id);
-    int odata_save(order_data *od);
-
     void orderdb_open(void);
     void orderdb_close(void);
 
diff --git a/src/orderdb.c b/src/orderdb.c
new file mode 100644
index 000000000..42248c0ef
--- /dev/null
+++ b/src/orderdb.c
@@ -0,0 +1,43 @@
+#include <platform.h>
+
+#include "kernel/config.h"
+#include "kernel/db/driver.h"
+
+#include "orderdb.h"
+
+#include <util/log.h>
+
+#include <critbit.h>
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+void orderdb_open(void)
+{
+    const char *dbname;
+
+    dbname = config_get("game.dbswap");
+    db_driver_open(DB_SWAP, dbname);
+}
+
+void orderdb_close(void)
+{
+    db_driver_close(DB_SWAP);
+}
+
+order_data *odata_load(int id)
+{
+    if (id > 0) {
+        return db_driver_order_load(id);
+    }
+    return NULL;
+}
+
+int odata_save(order_data *od)
+{
+    if (od->_str) {
+        return db_driver_order_save(od->_str);
+    }
+    return 0;
+}
diff --git a/src/orderdb.h b/src/orderdb.h
new file mode 100644
index 000000000..cc809b1a6
--- /dev/null
+++ b/src/orderdb.h
@@ -0,0 +1,25 @@
+#ifndef H_ORDERDB
+#define H_ORDERDB
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+    typedef struct order_data {
+        const char *_str;
+        int _refcount;
+    } order_data;
+
+    void odata_create(order_data **pdata, size_t len, const char *str);
+    void odata_release(order_data * od);
+    void odata_addref(order_data *od);
+
+    void orderdb_open(void);
+    void orderdb_close(void);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/kernel/orderdb.test.c b/src/orderdb.test.c
similarity index 100%
rename from src/kernel/orderdb.test.c
rename to src/orderdb.test.c

From b47a41541f9da29186523a5b7367894c304f3050 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Fri, 28 Sep 2018 21:43:20 +0200
Subject: [PATCH 48/81] write a new (expensive) in-memory db driver for orders.

---
 src/kernel/CMakeLists.txt |  2 +-
 src/kernel/db/critbit.c   | 72 ---------------------------------------
 src/kernel/db/memory.c    | 69 +++++++++++++++++++++++++++++++++++++
 3 files changed, 70 insertions(+), 73 deletions(-)
 delete mode 100644 src/kernel/db/critbit.c
 create mode 100644 src/kernel/db/memory.c

diff --git a/src/kernel/CMakeLists.txt b/src/kernel/CMakeLists.txt
index 562562d8a..756f691cc 100644
--- a/src/kernel/CMakeLists.txt
+++ b/src/kernel/CMakeLists.txt
@@ -1,7 +1,7 @@
 cmake_minimum_required(VERSION 2.6)
 project(kernel C)
 
-SET(_DBFILES db/critbit.c)
+SET(_DBFILES db/memory.c)
 
 IF(SQLITE3_FOUND)
 SET(_DBFILES db/sqlite.c)
diff --git a/src/kernel/db/critbit.c b/src/kernel/db/critbit.c
deleted file mode 100644
index 69bac159e..000000000
--- a/src/kernel/db/critbit.c
+++ /dev/null
@@ -1,72 +0,0 @@
-#include <platform.h>
-#include "driver.h"
-
-#include <kernel/orderdb.h>
-#include <util/log.h>
-
-#include <critbit.h>
-
-#include <assert.h>
-#include <stdlib.h>
-#include <string.h>
-
-static critbit_tree cb_orders = { 0 };
-static int auto_id = -1;
-
-struct cb_entry {
-    int id;
-    order_data *data;
-};
-
-order_data *db_driver_order_load(int id)
-{
-    void * match;
-
-    assert(id>0);
-    if (cb_find_prefix(&cb_orders, &id, sizeof(id), &match, 1, 0) > 0) {
-        struct cb_entry *ent = (struct cb_entry *)match;
-        order_data * od = ent->data;
-        ++od->_refcount;
-        return od;
-    }
-    return NULL;
-}
-
-int db_driver_order_save(order_data *od)
-{
-    struct cb_entry ent;
-
-    assert(od && od->_str);
-    ++od->_refcount;
-    ent.id = ++auto_id;
-    ent.data = od;
-    cb_insert(&cb_orders, &ent, sizeof(ent));
-    return ent.id;
-}
-
-int db_driver_faction_save(int id, int no, int turn, const char *email, const char *password)
-{
-    return -1;
-}
-
-static int free_data_cb(const void *match, const void *key, size_t keylen,
-    void *udata)
-{
-    struct cb_entry * ent = (struct cb_entry *)match;
-    order_data *od = ent->data;
-    odata_release(od);
-    return 0;
-}
-
-void db_driver_open(void)
-{
-    assert(auto_id == -1);
-    auto_id = 0;
-}
-
-void db_driver_close(void)
-{
-    cb_foreach(&cb_orders, NULL, 0, free_data_cb, NULL);
-    cb_clear(&cb_orders);
-    auto_id = -1;
-}
diff --git a/src/kernel/db/memory.c b/src/kernel/db/memory.c
new file mode 100644
index 000000000..5fbaade4c
--- /dev/null
+++ b/src/kernel/db/memory.c
@@ -0,0 +1,69 @@
+#include <platform.h>
+#include "driver.h"
+
+#include <util/log.h>
+#include <util/strings.h>
+
+#include <selist.h>
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+static selist * g_orders;
+static int auto_id = -1;
+
+struct order_data *db_driver_order_load(int id)
+{
+    void * match;
+
+    assert(id>0);
+    match = selist_get(g_orders, id - 1);
+    if (match) {
+        char * str = (char *)match;
+        struct order_data * od = NULL;
+        odata_create(&od, strlen(str), str);
+        return od;
+    }
+    return NULL;
+}
+
+int db_driver_order_save(const char * str)
+{
+    assert(str);
+    selist_push(&g_orders, str_strdup(str));
+    return ++auto_id;
+}
+
+int db_driver_faction_save(int id, int no, int turn, const char *email, const char *password)
+{
+    return -1;
+}
+
+static int free_data_cb(const void *match)
+{
+    char *str = (char *)match;
+    free(str);
+    return 0;
+}
+
+int db_driver_open(database_t db, const char *dbname)
+{
+    (void)dbname;
+    if (db == DB_SWAP) {
+        assert(auto_id == -1);
+        auto_id = 0;
+        return 0;
+    }
+    return -1;
+}
+
+void db_driver_close(database_t db)
+{
+    if (db == DB_SWAP) {
+        selist_foreach(g_orders, free_data_cb);
+        selist_free(g_orders);
+        g_orders = NULL;
+        auto_id = -1;
+    }
+}

From b18f8ca9fb96a48ab752c82c6c2da0953da1154f Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sat, 29 Sep 2018 09:56:05 +0200
Subject: [PATCH 49/81] change database selection, fix in-memory db

---
 s/cmake-init           | 35 ++++++++++++++++++++++++++++++++++-
 src/CMakeLists.txt     |  4 +++-
 src/kernel/db/memory.c |  5 +++--
 3 files changed, 40 insertions(+), 4 deletions(-)

diff --git a/s/cmake-init b/s/cmake-init
index 781db1ea7..eea222334 100755
--- a/s/cmake-init
+++ b/s/cmake-init
@@ -1,13 +1,46 @@
 #!/bin/sh
 
-ERESSEA_DB=db
+ERESSEA_DB=memory
 pkg-config --exists sqlite3 && ERESSEA_DB=sqlite
+
+GETOPT=getopt
+GETOPT_LONG=1
+
+if [ "Darwin" = "$(uname)" ] ; then
+  if [ -x "/usr/local/opt/gnu-getopt/bin/getopt" ] ; then
+    GETOPT="/usr/local/opt/gnu-getopt/bin/getopt"
+  else
+    GETOPT_LONG=0
+  fi
+fi
+
+if [ $GETOPT_LONG -eq 1 ]; then
+  options=$(${GETOPT} -o d: -l db: -- "$@")
+else # assume GNU getopt (long arguments)
+  options=$(${GETOPT} d: "$@")
+fi
+
 # Parse command line arguments
+eval set -- "$options"
+until [ -z "$1" ] ; do
+  case $1 in
+    -d|--db)
+      ERESSEA_DB=$2
+      shift
+    ;;
+    --) shift; break;;
+    (-*) echo "$0: error - unrecognized option $1" 1>&2; exit 1;;
+    (*) break;;
+  esac
+  shift
+done
 while [ ! -z "$1" ] ; do
 if [ "$1" = "--with-db" ] ; then
 ERESSEA_DB=db
 elif [ "$1" = "--with-sqlite" ] ; then
 ERESSEA_DB=sqlite
+elif [ "$1" = "--with-memory" ] ; then
+ERESSEA_DB=memory
 fi
 shift 1
 done
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 5800d1814..d819675b8 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -184,8 +184,10 @@ endif()
 
 add_library(version STATIC ${VERSION_SRC})
 add_library(game ${ERESSEA_SRC})
+
+#add_executable(checker ${CHECK_SRC})
+
 add_executable(eressea ${SERVER_SRC})
-add_executable(checker ${CHECK_SRC})
 if (IWYU_PATH)
 set_property(TARGET eressea PROPERTY C_INCLUDE_WHAT_YOU_USE ${IWYU_PATH})
 endif(IWYU_PATH)
diff --git a/src/kernel/db/memory.c b/src/kernel/db/memory.c
index 5fbaade4c..0f572a99e 100644
--- a/src/kernel/db/memory.c
+++ b/src/kernel/db/memory.c
@@ -1,4 +1,6 @@
+#ifdef _MSC_VER
 #include <platform.h>
+#endif
 #include "driver.h"
 
 #include <util/log.h>
@@ -40,11 +42,10 @@ int db_driver_faction_save(int id, int no, int turn, const char *email, const ch
     return -1;
 }
 
-static int free_data_cb(const void *match)
+static void free_data_cb(void *match)
 {
     char *str = (char *)match;
     free(str);
-    return 0;
 }
 
 int db_driver_open(database_t db, const char *dbname)

From 735c890eceafb24304427bfefb35b7b05d387574 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sat, 29 Sep 2018 09:58:23 +0200
Subject: [PATCH 50/81] explicitly build sqlite on travis

---
 .travis.yml    | 1 +
 s/travis-build | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/.travis.yml b/.travis.yml
index 62e60194f..c6a21d0e4 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -8,6 +8,7 @@ addons:
   apt:
     packages:
       - libbsd-dev
+      - libdb-dev
       - liblua5.1-dev
       - libtolua-dev
       - libncurses5-dev
diff --git a/s/travis-build b/s/travis-build
index a678b1de2..64b278710 100755
--- a/s/travis-build
+++ b/s/travis-build
@@ -31,8 +31,8 @@ cppcheck_tests() {
 
 set -e
 [ -z $BUILD ] && BUILD=Debug ; export BUILD
-s/cmake-init
 # cppcheck_tests
+s/cmake-init --db=sqlite
 s/build
 cd process
 make

From 5dcb9075ac7a1f5a9bc32020af84250ee7cb9b7b Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sat, 29 Sep 2018 11:19:59 +0200
Subject: [PATCH 51/81] we have a library that contains the parser

---
 src/CMakeLists.txt | 21 ++++++++++++++-------
 1 file changed, 14 insertions(+), 7 deletions(-)

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index d819675b8..be26a30a4 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -85,6 +85,11 @@ TOLUA_BINDING(eressea.pkg bind_eressea.h)
 TOLUA_BINDING(settings.pkg kenel/config.h)
 ENDIF()
 
+set (PARSER_SRC
+  ${DB_SRC}
+  ${UTIL_SRC}
+  )
+
 set (ERESSEA_SRC
   vortex.c
   academy.c
@@ -139,13 +144,10 @@ set (ERESSEA_SRC
   ${TRIGGERS_SRC}
   ${ATTRIBUTES_SRC}
   ${KERNEL_SRC}
-  ${DB_SRC}
-  ${UTIL_SRC}
   )
 
 set(CHECK_SRC
   checker.c
-  orderfile.c
   )
 
 set(SERVER_SRC
@@ -183,22 +185,28 @@ if(NOT IWYU_PATH)
 endif()
 
 add_library(version STATIC ${VERSION_SRC})
-add_library(game ${ERESSEA_SRC})
+add_library(parser ${PARSER_SRC})
+target_link_libraries(parser
+  ${CRYPTO_LIBRARIES}
+  )
+
 
 #add_executable(checker ${CHECK_SRC})
+#target_link_libraries(checker parser)
+
+add_library(game ${ERESSEA_SRC})
+target_link_libraries(game parser version)
 
 add_executable(eressea ${SERVER_SRC})
 if (IWYU_PATH)
 set_property(TARGET eressea PROPERTY C_INCLUDE_WHAT_YOU_USE ${IWYU_PATH})
 endif(IWYU_PATH)
-target_link_libraries(game version)
 target_link_libraries(eressea
   game
   ${TOLUA_LIBRARIES}
   ${LUA_LIBRARIES}
   ${STORAGE_LIBRARIES}
   ${CLIBS_LIBRARIES}
-  ${CRYPTO_LIBRARIES}
   ${CJSON_LIBRARIES}
   ${INIPARSER_LIBRARIES}
 )
@@ -260,7 +268,6 @@ target_link_libraries(test_eressea
   ${LUA_LIBRARIES}
   ${CLIBS_LIBRARIES}
   ${STORAGE_LIBRARIES}
-  ${CRYPTO_LIBRARIES}
   ${CJSON_LIBRARIES}
   ${INIPARSER_LIBRARIES}
   )

From a373807189538a2299b6705587d0aa6f91f41820 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sat, 29 Sep 2018 11:37:17 +0200
Subject: [PATCH 52/81] move attrib and event modules to kernel

---
 src/alchemy.c                      |  2 +-
 src/attributes/attributes.c        |  4 ++--
 src/attributes/dict.c              |  2 +-
 src/attributes/follow.c            |  2 +-
 src/attributes/hate.c              |  2 +-
 src/attributes/iceberg.c           |  2 +-
 src/attributes/key.c               |  2 +-
 src/attributes/key.test.c          |  2 +-
 src/attributes/movement.c          |  2 +-
 src/attributes/otherfaction.c      |  2 +-
 src/attributes/otherfaction.test.c |  2 +-
 src/attributes/overrideroads.c     |  2 +-
 src/attributes/racename.c          |  2 +-
 src/attributes/raceprefix.c        |  2 +-
 src/attributes/reduceproduction.c  |  2 +-
 src/attributes/seenspell.c         |  2 +-
 src/attributes/stealth.c           |  2 +-
 src/attributes/targetregion.c      |  2 +-
 src/battle.c                       |  2 +-
 src/bind_region.c                  |  2 +-
 src/bind_ship.c                    |  2 +-
 src/bind_unit.c                    |  4 ++--
 src/bindings.c                     |  2 +-
 src/chaos.c                        |  2 +-
 src/creport.c                      |  2 +-
 src/economy.c                      |  4 ++--
 src/economy.test.c                 |  2 +-
 src/give.c                         |  4 ++--
 src/gmtool.c                       |  2 +-
 src/helpers.c                      |  4 ++--
 src/items.c                        |  4 ++--
 src/items/speedsail.c              |  2 +-
 src/jsonconf.c                     |  2 +-
 src/kernel/CMakeLists.txt          |  4 ++++
 src/kernel/alliance.c              |  2 +-
 src/kernel/ally.c                  |  2 +-
 src/{util => kernel}/attrib.c      | 10 +++++-----
 src/{util => kernel}/attrib.h      |  2 +-
 src/{util => kernel}/attrib.test.c |  0
 src/kernel/build.c                 |  4 ++--
 src/kernel/building.c              |  4 ++--
 src/kernel/config.c                |  4 ++--
 src/kernel/config.test.c           |  2 +-
 src/kernel/connection.c            |  2 +-
 src/kernel/curse.c                 |  2 +-
 src/kernel/curse.test.c            |  2 +-
 src/{util => kernel}/event.c       |  8 ++++----
 src/{util => kernel}/event.h       |  2 +-
 src/kernel/faction.c               |  4 ++--
 src/kernel/group.c                 |  2 +-
 src/kernel/group.test.c            |  2 +-
 src/kernel/item.c                  |  2 +-
 src/kernel/plane.c                 |  2 +-
 src/kernel/race.c                  |  2 +-
 src/kernel/region.c                |  2 +-
 src/kernel/save.c                  |  4 ++--
 src/kernel/save.test.c             |  4 ++--
 src/kernel/ship.c                  |  4 ++--
 src/kernel/ship.test.c             |  2 +-
 src/kernel/skills.c                |  2 +-
 src/kernel/terrain.c               |  2 +-
 src/kernel/unit.c                  |  4 ++--
 src/kernel/unit.test.c             |  2 +-
 src/laws.c                         |  4 ++--
 src/laws.test.c                    |  2 +-
 src/lighthouse.c                   |  2 +-
 src/lighthouse.test.c              |  2 +-
 src/magic.c                        |  4 ++--
 src/magic.test.c                   |  2 +-
 src/market.c                       |  2 +-
 src/modules/autoseed.c             |  2 +-
 src/modules/gmcmd.c                |  2 +-
 src/modules/museum.c               |  2 +-
 src/modules/xmas.c                 |  4 ++--
 src/monsters.c                     |  4 ++--
 src/monsters.test.c                |  2 +-
 src/move.c                         |  2 +-
 src/move.test.c                    |  2 +-
 src/piracy.c                       |  2 +-
 src/races/races.c                  |  2 +-
 src/randenc.c                      |  2 +-
 src/renumber.c                     |  2 +-
 src/report.c                       |  2 +-
 src/reports.c                      |  2 +-
 src/reports.test.c                 |  2 +-
 src/spells.c                       |  4 ++--
 src/spells.test.c                  |  2 +-
 src/spells/borders.c               |  2 +-
 src/spells/combatspells.c          |  2 +-
 src/spells/magicresistance.test.c  |  2 +-
 src/spy.c                          |  2 +-
 src/spy.test.c                     |  2 +-
 src/study.c                        |  2 +-
 src/study.test.c                   |  2 +-
 src/travelthru.c                   |  2 +-
 src/travelthru.test.c              |  2 +-
 src/triggers/changefaction.c       |  4 ++--
 src/triggers/changerace.c          |  4 ++--
 src/triggers/clonedied.c           |  4 ++--
 src/triggers/createcurse.c         |  4 ++--
 src/triggers/createunit.c          |  4 ++--
 src/triggers/gate.c                |  4 ++--
 src/triggers/giveitem.c            |  4 ++--
 src/triggers/killunit.c            |  4 ++--
 src/triggers/shock.c               |  4 ++--
 src/triggers/shock.test.c          |  2 +-
 src/triggers/timeout.c             |  4 ++--
 src/triggers/triggers.c            |  2 +-
 src/util/CMakeLists.txt            |  4 ----
 src/volcano.c                      |  2 +-
 src/volcano.test.c                 |  2 +-
 src/vortex.c                       |  2 +-
 src/wormhole.c                     |  2 +-
 src/wormhole.test.c                |  2 +-
 114 files changed, 151 insertions(+), 151 deletions(-)
 rename src/{util => kernel}/attrib.c (99%)
 rename src/{util => kernel}/attrib.h (99%)
 rename src/{util => kernel}/attrib.test.c (100%)
 rename src/{util => kernel}/event.c (98%)
 rename src/{util => kernel}/event.h (99%)

diff --git a/src/alchemy.c b/src/alchemy.c
index 4b7e961a6..fb0516359 100644
--- a/src/alchemy.c
+++ b/src/alchemy.c
@@ -33,7 +33,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <kernel/unit.h>
 
 /* util includes */
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/gamedata.h>
 #include <util/base36.h>
 #include <util/log.h>
diff --git a/src/attributes/attributes.c b/src/attributes/attributes.c
index 6bf78da63..cf75efc58 100644
--- a/src/attributes/attributes.c
+++ b/src/attributes/attributes.c
@@ -53,8 +53,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <kernel/building.h>
 
 /* util includes */
-#include <util/attrib.h>
-#include <util/event.h>
+#include <kernel/attrib.h>
+#include <kernel/event.h>
 #include <util/gamedata.h>
 #include <util/macros.h>
 #include <util/resolve.h>
diff --git a/src/attributes/dict.c b/src/attributes/dict.c
index bc5e94204..aa34886a6 100644
--- a/src/attributes/dict.c
+++ b/src/attributes/dict.c
@@ -29,7 +29,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <kernel/unit.h>
 
 /* util includes */
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/base36.h>
 #include <util/log.h>
 #include <util/gamedata.h>
diff --git a/src/attributes/follow.c b/src/attributes/follow.c
index 8c5e14526..07fffbfd6 100644
--- a/src/attributes/follow.c
+++ b/src/attributes/follow.c
@@ -22,7 +22,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <kernel/config.h>
 #include <kernel/unit.h>
 
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/gamedata.h>
 #include <util/variant.h>
 
diff --git a/src/attributes/hate.c b/src/attributes/hate.c
index c260de335..aff71d0e7 100644
--- a/src/attributes/hate.c
+++ b/src/attributes/hate.c
@@ -22,7 +22,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
 #include <kernel/unit.h>
 
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/gamedata.h>
 #include <util/macros.h>
 #include <util/resolve.h>
diff --git a/src/attributes/iceberg.c b/src/attributes/iceberg.c
index e36e6303a..192ae9032 100644
--- a/src/attributes/iceberg.c
+++ b/src/attributes/iceberg.c
@@ -20,7 +20,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <kernel/config.h>
 #include "iceberg.h"
 
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 
 attrib_type at_iceberg = {
     "iceberg_drift",
diff --git a/src/attributes/key.c b/src/attributes/key.c
index 1808c561f..462c7a63b 100644
--- a/src/attributes/key.c
+++ b/src/attributes/key.c
@@ -20,7 +20,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <kernel/config.h>
 #include "key.h"
 
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/gamedata.h>
 #include <util/log.h>
 #include <storage.h>
diff --git a/src/attributes/key.test.c b/src/attributes/key.test.c
index 79a7bde1d..fc09fc391 100644
--- a/src/attributes/key.test.c
+++ b/src/attributes/key.test.c
@@ -2,7 +2,7 @@
 #include "key.h"
 #include "dict.h"
 
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/base36.h>
 #include <CuTest.h>
 #include <stdlib.h>
diff --git a/src/attributes/movement.c b/src/attributes/movement.c
index 7b49291c2..552ff51aa 100644
--- a/src/attributes/movement.c
+++ b/src/attributes/movement.c
@@ -20,7 +20,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <kernel/config.h>
 #include "movement.h"
 
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/gamedata.h>
 #include <util/macros.h>
 
diff --git a/src/attributes/otherfaction.c b/src/attributes/otherfaction.c
index 343460057..87b29f252 100644
--- a/src/attributes/otherfaction.c
+++ b/src/attributes/otherfaction.c
@@ -23,7 +23,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <kernel/ally.h>
 #include <kernel/faction.h>
 #include <kernel/unit.h>
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/gamedata.h>
 
 #include <storage.h>
diff --git a/src/attributes/otherfaction.test.c b/src/attributes/otherfaction.test.c
index 8417ed3e3..e4f7c95b9 100644
--- a/src/attributes/otherfaction.test.c
+++ b/src/attributes/otherfaction.test.c
@@ -7,7 +7,7 @@
 #include <kernel/region.h>
 #include <kernel/faction.h>
 
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 
 #include <CuTest.h>
 #include <tests.h>
diff --git a/src/attributes/overrideroads.c b/src/attributes/overrideroads.c
index ef466de2d..d96d115d9 100644
--- a/src/attributes/overrideroads.c
+++ b/src/attributes/overrideroads.c
@@ -20,7 +20,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <kernel/config.h>
 #include "overrideroads.h"
 
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 
 attrib_type at_overrideroads = {
     "roads_override", NULL, NULL, NULL, a_writestring, a_readstring
diff --git a/src/attributes/racename.c b/src/attributes/racename.c
index c46fb0c4b..9374f1238 100644
--- a/src/attributes/racename.c
+++ b/src/attributes/racename.c
@@ -20,7 +20,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <kernel/config.h>
 #include "racename.h"
 
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/strings.h>
 
 /* libc includes */
diff --git a/src/attributes/raceprefix.c b/src/attributes/raceprefix.c
index 233d17e40..84997b909 100644
--- a/src/attributes/raceprefix.c
+++ b/src/attributes/raceprefix.c
@@ -20,7 +20,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <kernel/config.h>
 #include "raceprefix.h"
 
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/strings.h>
 
 #include <assert.h>
diff --git a/src/attributes/reduceproduction.c b/src/attributes/reduceproduction.c
index 01041380a..0ae0abbea 100644
--- a/src/attributes/reduceproduction.c
+++ b/src/attributes/reduceproduction.c
@@ -22,7 +22,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <kernel/region.h>
 #include <kernel/messages.h>
 #include <util/message.h>
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <assert.h>
 
 static int age_reduceproduction(attrib * a, void *owner)
diff --git a/src/attributes/seenspell.c b/src/attributes/seenspell.c
index 82bdf22ca..6108465cd 100644
--- a/src/attributes/seenspell.c
+++ b/src/attributes/seenspell.c
@@ -23,7 +23,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <kernel/faction.h>
 #include <kernel/spell.h>
 #include <kernel/spellbook.h>
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/gamedata.h>
 #include <util/log.h>
 #include <util/macros.h>
diff --git a/src/attributes/stealth.c b/src/attributes/stealth.c
index db2ec5304..ae00e8721 100644
--- a/src/attributes/stealth.c
+++ b/src/attributes/stealth.c
@@ -1,7 +1,7 @@
 #include <platform.h>
 #include <kernel/unit.h>
 #include <kernel/region.h>
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <attributes/stealth.h>
 
 #include <stdlib.h>
diff --git a/src/attributes/targetregion.c b/src/attributes/targetregion.c
index 7ef1fe84a..f67689052 100644
--- a/src/attributes/targetregion.c
+++ b/src/attributes/targetregion.c
@@ -22,7 +22,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <kernel/config.h>
 #include <kernel/region.h>
 
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/gamedata.h>
 #include <util/resolve.h>
 
diff --git a/src/battle.c b/src/battle.c
index aa5de9f71..ae914ab05 100644
--- a/src/battle.c
+++ b/src/battle.c
@@ -60,7 +60,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
 /* util includes */
 #include <util/assert.h>
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/base36.h>
 #include <util/language.h>
 #include <util/lists.h>
diff --git a/src/bind_region.c b/src/bind_region.c
index 3b0e7f3a3..9d7897829 100644
--- a/src/bind_region.c
+++ b/src/bind_region.c
@@ -22,7 +22,7 @@
 #include <kernel/terrain.h>
 #include <kernel/messages.h>
 
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/base36.h>
 #include <util/log.h>
 #include <util/macros.h>
diff --git a/src/bind_ship.c b/src/bind_ship.c
index 2a1d75271..d335d996d 100644
--- a/src/bind_ship.c
+++ b/src/bind_ship.c
@@ -14,7 +14,7 @@
 #include <kernel/ship.h>
 #include <kernel/build.h>
 
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/language.h>
 #include <util/log.h>
 #include <util/macros.h>
diff --git a/src/bind_unit.c b/src/bind_unit.c
index 9f6c39163..3f2a037ea 100644
--- a/src/bind_unit.c
+++ b/src/bind_unit.c
@@ -11,9 +11,9 @@
 #include "skill.h"
 
 /*  util includes */
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/base36.h>
-#include <util/event.h>
+#include <kernel/event.h>
 #include <util/log.h>
 #include <util/macros.h>
 #include "util/variant.h"
diff --git a/src/bindings.c b/src/bindings.c
index b2da38eba..caac5b99c 100755
--- a/src/bindings.c
+++ b/src/bindings.c
@@ -47,7 +47,7 @@
 
 #include <modules/score.h>
 
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/base36.h>
 #include <util/language.h>
 #include <util/log.h>
diff --git a/src/chaos.c b/src/chaos.c
index 1ec431b7e..615113656 100644
--- a/src/chaos.c
+++ b/src/chaos.c
@@ -34,7 +34,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <kernel/terrainid.h>
 #include <kernel/unit.h>
 
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/rng.h>
 
 #include <stdlib.h>
diff --git a/src/creport.c b/src/creport.c
index ce67493da..475a04b1e 100644
--- a/src/creport.c
+++ b/src/creport.c
@@ -64,7 +64,7 @@ without prior permission by the authors of Eressea.
 #include "kernel/unit.h"
 
 /* util includes */
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/base36.h>
 #include <util/crmessage.h>
 #include <util/strings.h>
diff --git a/src/economy.c b/src/economy.c
index f0c930a3f..15b907a25 100644
--- a/src/economy.c
+++ b/src/economy.c
@@ -64,9 +64,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include "kernel/unit.h"
 
 /* util includes */
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/base36.h>
-#include <util/event.h>
+#include <kernel/event.h>
 #include <util/goodies.h>
 #include <util/language.h>
 #include <util/lists.h>
diff --git a/src/economy.test.c b/src/economy.test.c
index 1a40c03db..0b213ba7e 100644
--- a/src/economy.test.c
+++ b/src/economy.test.c
@@ -19,7 +19,7 @@
 #include <kernel/terrainid.h>
 #include <kernel/unit.h>
 
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/language.h>
 #include <util/macros.h>
 
diff --git a/src/give.c b/src/give.c
index c47f9b9e2..02d5c622d 100644
--- a/src/give.c
+++ b/src/give.c
@@ -41,9 +41,9 @@
 #include <kernel/unit.h>
 
 /* util includes */
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/base36.h>
-#include <util/event.h>
+#include <kernel/event.h>
 #include <util/log.h>
 #include <util/macros.h>
 #include <util/parser.h>
diff --git a/src/gmtool.c b/src/gmtool.c
index 270f0f677..cd0580fcc 100644
--- a/src/gmtool.c
+++ b/src/gmtool.c
@@ -30,7 +30,7 @@
 #include "kernel/ship.h"
 #include "kernel/terrain.h"
 
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/base36.h>
 #include <util/lists.h>
 #include <util/macros.h>
diff --git a/src/helpers.c b/src/helpers.c
index 01fa19abc..2835b153d 100644
--- a/src/helpers.c
+++ b/src/helpers.c
@@ -19,8 +19,8 @@ without prior permission by the authors of Eressea.
 #include "alchemy.h"
 #include "magic.h"
 
-#include <util/attrib.h>
-#include <util/event.h>
+#include <kernel/attrib.h>
+#include <kernel/event.h>
 #include <util/functions.h>
 #include <util/gamedata.h>
 #include <util/log.h>
diff --git a/src/items.c b/src/items.c
index 574c1da3b..665220e8f 100644
--- a/src/items.c
+++ b/src/items.c
@@ -33,8 +33,8 @@
 #include <triggers/changerace.h>
 #include <triggers/timeout.h>
 
-#include <util/attrib.h>
-#include <util/event.h>
+#include <kernel/attrib.h>
+#include <kernel/event.h>
 #include <util/macros.h>
 #include <util/parser.h>
 #include <util/rand.h>
diff --git a/src/items/speedsail.c b/src/items/speedsail.c
index b224d6d6d..e6d3d1386 100644
--- a/src/items/speedsail.c
+++ b/src/items/speedsail.c
@@ -31,7 +31,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <attributes/movement.h>
 
 /* util includes */
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/log.h>
 #include <util/macros.h>
 
diff --git a/src/jsonconf.c b/src/jsonconf.c
index 51116691f..dc11ee563 100644
--- a/src/jsonconf.c
+++ b/src/jsonconf.c
@@ -29,7 +29,7 @@ without prior permission by the authors of Eressea.
 #include "kernel/spellbook.h"
 
 /* util includes */
-#include "util/attrib.h"
+#include "kernel/attrib.h"
 #include "util/crmessage.h"
 #include "util/functions.h"
 #include "util/language.h"
diff --git a/src/kernel/CMakeLists.txt b/src/kernel/CMakeLists.txt
index 756f691cc..093a41429 100644
--- a/src/kernel/CMakeLists.txt
+++ b/src/kernel/CMakeLists.txt
@@ -12,6 +12,7 @@ ENDIF(SQLITE3_FOUND)
 SET(_TEST_FILES
 alliance.test.c
 ally.test.c
+attrib.test.c
 build.test.c
 building.test.c
 # callbacks.test.c
@@ -22,6 +23,7 @@ config.test.c
 curse.test.c
 database.test.c
 equipment.test.c
+# event.test.c
 faction.test.c
 group.test.c
 item.test.c
@@ -46,6 +48,7 @@ SET(_FILES
 ${_DBFILES}
 alliance.c
 ally.c
+attrib.c
 build.c
 building.c
 callbacks.c
@@ -55,6 +58,7 @@ config.c
 connection.c
 curse.c
 equipment.c
+event.c
 faction.c
 group.c
 item.c
diff --git a/src/kernel/alliance.c b/src/kernel/alliance.c
index d5dda0143..1996c5aad 100644
--- a/src/kernel/alliance.c
+++ b/src/kernel/alliance.c
@@ -27,7 +27,7 @@ without prior permission by the authors of Eressea.
 #include <attributes/key.h>
 
 /* util includes */
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/base36.h>
 #include <util/language.h>
 #include <util/parser.h>
diff --git a/src/kernel/ally.c b/src/kernel/ally.c
index 4fadf9c04..a2536c7d9 100644
--- a/src/kernel/ally.c
+++ b/src/kernel/ally.c
@@ -10,7 +10,7 @@
 #include "objtypes.h"
 #include "plane.h"
 
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/strings.h>
 #include <util/gamedata.h>
 
diff --git a/src/util/attrib.c b/src/kernel/attrib.c
similarity index 99%
rename from src/util/attrib.c
rename to src/kernel/attrib.c
index defb4ff1e..375997df4 100644
--- a/src/util/attrib.c
+++ b/src/kernel/attrib.c
@@ -19,12 +19,12 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <platform.h>
 #include "attrib.h"
 
-#include "gamedata.h"
-#include "log.h"
-#include "variant.h"
-#include "storage.h"
-#include "strings.h"
+#include <util/log.h>
+#include <util/strings.h>
+#include <util/variant.h>
+#include <util/gamedata.h>
 
+#include <storage.h>
 #include <critbit.h>
 
 #include <assert.h>
diff --git a/src/util/attrib.h b/src/kernel/attrib.h
similarity index 99%
rename from src/util/attrib.h
rename to src/kernel/attrib.h
index b7a081d8c..65c41aa71 100644
--- a/src/util/attrib.h
+++ b/src/kernel/attrib.h
@@ -20,7 +20,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #define ATTRIB_H
 
 #include <stdbool.h>
-#include "variant.h"
+#include <util/variant.h>
 #ifdef __cplusplus
 extern "C" {
 #endif
diff --git a/src/util/attrib.test.c b/src/kernel/attrib.test.c
similarity index 100%
rename from src/util/attrib.test.c
rename to src/kernel/attrib.test.c
diff --git a/src/kernel/build.c b/src/kernel/build.c
index 4e3dc4721..0891f1005 100644
--- a/src/kernel/build.c
+++ b/src/kernel/build.c
@@ -52,9 +52,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <kernel/unit.h>
 
 /* from libutil */
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/base36.h>
-#include <util/event.h>
+#include <kernel/event.h>
 #include <util/goodies.h>
 #include <util/language.h>
 #include <util/log.h>
diff --git a/src/kernel/building.c b/src/kernel/building.c
index 75cad30f7..9627567ab 100644
--- a/src/kernel/building.c
+++ b/src/kernel/building.c
@@ -38,9 +38,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include "lighthouse.h"
 
 /* util includes */
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/base36.h>
-#include <util/event.h>
+#include <kernel/event.h>
 #include <util/functions.h>
 #include <util/gamedata.h>
 #include <util/language.h>
diff --git a/src/kernel/config.c b/src/kernel/config.c
index eee2ec0f5..e31564b8d 100644
--- a/src/kernel/config.c
+++ b/src/kernel/config.c
@@ -50,10 +50,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include "unit.h"
 
 /* util includes */
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/base36.h>
 #include <util/crmessage.h>
-#include <util/event.h>
+#include <kernel/event.h>
 #include <util/language.h>
 #include <util/functions.h>
 #include <util/log.h>
diff --git a/src/kernel/config.test.c b/src/kernel/config.test.c
index e99ba9d08..e060a838e 100644
--- a/src/kernel/config.test.c
+++ b/src/kernel/config.test.c
@@ -7,7 +7,7 @@
 #include <kernel/order.h>
 #include <util/language.h>
 #include <util/base36.h>
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 
 #include <iniparser.h>
 
diff --git a/src/kernel/connection.c b/src/kernel/connection.c
index ddaf163c1..c66bd06e0 100644
--- a/src/kernel/connection.c
+++ b/src/kernel/connection.c
@@ -26,7 +26,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include "terrain.h"
 #include "unit.h"
 
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/base36.h>
 #include <util/gamedata.h>
 #include <util/language.h>
diff --git a/src/kernel/curse.c b/src/kernel/curse.c
index f6be51dac..5f0c4a776 100644
--- a/src/kernel/curse.c
+++ b/src/kernel/curse.c
@@ -34,7 +34,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include "unit.h"
 
 /* util includes */
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/base36.h>
 #include <util/gamedata.h>
 #include <util/goodies.h>
diff --git a/src/kernel/curse.test.c b/src/kernel/curse.test.c
index 9c74544e1..23a5ad54f 100644
--- a/src/kernel/curse.test.c
+++ b/src/kernel/curse.test.c
@@ -4,7 +4,7 @@
 #include <kernel/region.h>
 #include <kernel/save.h>
 #include <kernel/unit.h>
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/rng.h>
 #include <util/gamedata.h>
 #include <util/message.h>
diff --git a/src/util/event.c b/src/kernel/event.c
similarity index 98%
rename from src/util/event.c
rename to src/kernel/event.c
index d6aa6f338..ab095a008 100644
--- a/src/util/event.c
+++ b/src/kernel/event.c
@@ -18,12 +18,12 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
 #include <platform.h>
 #include "event.h"
+#include "attrib.h"
 
 /* util includes */
-#include "attrib.h"
-#include "gamedata.h"
-#include "log.h"
-#include "strings.h"
+#include <util/gamedata.h>
+#include <util/log.h>
+#include <util/strings.h>
 
 #include <storage.h>
 
diff --git a/src/util/event.h b/src/kernel/event.h
similarity index 99%
rename from src/util/event.h
rename to src/kernel/event.h
index ad4ca373d..c6c880c4c 100644
--- a/src/util/event.h
+++ b/src/kernel/event.h
@@ -22,7 +22,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 extern "C" {
 #endif
 
-#include "variant.h"
+#include <util/variant.h>
 
     struct attrib;
     struct trigger;
diff --git a/src/kernel/faction.c b/src/kernel/faction.c
index 6e85988f4..dea4ca54f 100755
--- a/src/kernel/faction.c
+++ b/src/kernel/faction.c
@@ -42,9 +42,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <attributes/racename.h>
 
 /* util includes */
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/base36.h>
-#include <util/event.h>
+#include <kernel/event.h>
 #include <util/gamedata.h>
 #include <util/goodies.h>
 #include <util/lists.h>
diff --git a/src/kernel/group.c b/src/kernel/group.c
index 48434ff5a..9ebbf244d 100755
--- a/src/kernel/group.c
+++ b/src/kernel/group.c
@@ -30,7 +30,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <attributes/raceprefix.h>
 
 /* util includes */
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/base36.h>
 #include <util/gamedata.h>
 #include <util/resolve.h>
diff --git a/src/kernel/group.test.c b/src/kernel/group.test.c
index 5581fee69..5d1a28f6b 100644
--- a/src/kernel/group.test.c
+++ b/src/kernel/group.test.c
@@ -9,7 +9,7 @@
 #include "save.h"
 
 #include <util/gamedata.h>
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <attributes/key.h>
 
 #include <stream.h>
diff --git a/src/kernel/item.c b/src/kernel/item.c
index 4e707a48c..aab734759 100644
--- a/src/kernel/item.c
+++ b/src/kernel/item.c
@@ -35,7 +35,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include "unit.h"
 
 /* util includes */
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/base36.h>
 #include <util/functions.h>
 #include <util/goodies.h>
diff --git a/src/kernel/plane.c b/src/kernel/plane.c
index 533dab92a..71c0dbd86 100644
--- a/src/kernel/plane.c
+++ b/src/kernel/plane.c
@@ -25,7 +25,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include "faction.h"
 
 /* util includes */
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/resolve.h>
 #include <util/strings.h>
 #include <util/lists.h>
diff --git a/src/kernel/race.c b/src/kernel/race.c
index ecdb7ae3d..31d437992 100644
--- a/src/kernel/race.c
+++ b/src/kernel/race.c
@@ -37,7 +37,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include "unit.h"
 
 /* util includes */
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/functions.h>
 #include <util/umlaut.h>
 #include <util/language.h>
diff --git a/src/kernel/region.c b/src/kernel/region.c
index 29f7222e1..2cb93b4a3 100644
--- a/src/kernel/region.c
+++ b/src/kernel/region.c
@@ -42,7 +42,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
 /* util includes */
 #include <util/assert.h>
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/gamedata.h>
 #include <util/strings.h>
 #include <util/lists.h>
diff --git a/src/kernel/save.c b/src/kernel/save.c
index e7cb90d2a..eb731e8d7 100644
--- a/src/kernel/save.c
+++ b/src/kernel/save.c
@@ -57,9 +57,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
 /* util includes */
 #include <util/assert.h>
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/base36.h>
-#include <util/event.h>
+#include <kernel/event.h>
 #include <util/filereader.h>
 #include <util/gamedata.h>
 #include <util/goodies.h>
diff --git a/src/kernel/save.test.c b/src/kernel/save.test.c
index d9ba52862..04ef9b1bb 100644
--- a/src/kernel/save.test.c
+++ b/src/kernel/save.test.c
@@ -17,9 +17,9 @@
 #include <triggers/changefaction.h>
 #include <triggers/createunit.h>
 #include <triggers/timeout.h>
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/base36.h>
-#include <util/event.h>
+#include <kernel/event.h>
 #include <util/gamedata.h>
 #include <util/password.h>
 #include <util/path.h>
diff --git a/src/kernel/ship.c b/src/kernel/ship.c
index 4719945b0..20ed49d05 100644
--- a/src/kernel/ship.c
+++ b/src/kernel/ship.c
@@ -34,9 +34,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include "skill.h"
 
 /* util includes */
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/base36.h>
-#include <util/event.h>
+#include <kernel/event.h>
 #include <util/language.h>
 #include <util/lists.h>
 #include <util/log.h>
diff --git a/src/kernel/ship.test.c b/src/kernel/ship.test.c
index 074876dd5..c50fdfa8d 100644
--- a/src/kernel/ship.test.c
+++ b/src/kernel/ship.test.c
@@ -7,7 +7,7 @@
 #include <kernel/unit.h>
 #include <kernel/curse.h>
 
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 
 #include <spells/shipcurse.h>
 #include <attributes/movement.h>
diff --git a/src/kernel/skills.c b/src/kernel/skills.c
index a15fb4463..ea2022872 100644
--- a/src/kernel/skills.c
+++ b/src/kernel/skills.c
@@ -24,7 +24,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include "region.h"
 #include "unit.h"
 
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/goodies.h>
 #include <util/language.h>
 #include <util/log.h>
diff --git a/src/kernel/terrain.c b/src/kernel/terrain.c
index c7e007891..bec8fa8e8 100644
--- a/src/kernel/terrain.c
+++ b/src/kernel/terrain.c
@@ -30,7 +30,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include "terrainid.h"
 
 #include <util/log.h>
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/strings.h>
 
 /* libc includes */
diff --git a/src/kernel/unit.c b/src/kernel/unit.c
index 30971310d..13b2b1bf2 100644
--- a/src/kernel/unit.c
+++ b/src/kernel/unit.c
@@ -50,9 +50,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include "guard.h"
 
 /* util includes */
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/base36.h>
-#include <util/event.h>
+#include <kernel/event.h>
 #include <util/gamedata.h>
 #include <util/strings.h>
 #include <util/language.h>
diff --git a/src/kernel/unit.test.c b/src/kernel/unit.test.c
index 4b0ba2af6..29596f866 100644
--- a/src/kernel/unit.test.c
+++ b/src/kernel/unit.test.c
@@ -9,7 +9,7 @@
 #include <kernel/region.h>
 #include <kernel/spell.h>
 #include <kernel/terrain.h>
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/base36.h>
 #include <util/language.h>
 #include <util/macros.h>
diff --git a/src/laws.c b/src/laws.c
index d9e05917a..d7f8c53de 100644
--- a/src/laws.c
+++ b/src/laws.c
@@ -71,9 +71,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include "kernel/unit.h"
 
 /* util includes */
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/base36.h>
-#include <util/event.h>
+#include <kernel/event.h>
 #include <util/goodies.h>
 #include <util/language.h>
 #include <util/lists.h>
diff --git a/src/laws.test.c b/src/laws.test.c
index 778ee3323..5c799a393 100644
--- a/src/laws.test.c
+++ b/src/laws.test.c
@@ -20,7 +20,7 @@
 #include <kernel/terrainid.h>
 #include <kernel/unit.h>
 
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/base36.h>
 #include <util/language.h>
 #include <util/message.h>
diff --git a/src/lighthouse.c b/src/lighthouse.c
index 4ef830cfc..c6c7b9915 100644
--- a/src/lighthouse.c
+++ b/src/lighthouse.c
@@ -9,7 +9,7 @@
 #include <kernel/terrain.h>
 #include <kernel/unit.h>
 #include <util/log.h>
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 
 #include <assert.h>
 #include <math.h>
diff --git a/src/lighthouse.test.c b/src/lighthouse.test.c
index d9accd49e..9dc6d2999 100644
--- a/src/lighthouse.test.c
+++ b/src/lighthouse.test.c
@@ -2,7 +2,7 @@
 
 #include "lighthouse.h"
 
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <kernel/config.h>
 #include <kernel/faction.h>
 #include <kernel/unit.h>
diff --git a/src/magic.c b/src/magic.c
index 7464e286d..41aa0dbce 100644
--- a/src/magic.c
+++ b/src/magic.c
@@ -62,9 +62,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <kernel/unit.h>
 
 /* util includes */
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/base36.h>
-#include <util/event.h>
+#include <kernel/event.h>
 #include <util/gamedata.h>
 #include <util/language.h>
 #include <util/lists.h>
diff --git a/src/magic.test.c b/src/magic.test.c
index 95c2d250d..1b64cdf53 100644
--- a/src/magic.test.c
+++ b/src/magic.test.c
@@ -17,7 +17,7 @@
 #include <kernel/unit.h>
 #include <kernel/pool.h>
 
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/language.h>
 #include <util/strings.h>
 
diff --git a/src/market.c b/src/market.c
index 87be18f95..0bd2fd647 100644
--- a/src/market.c
+++ b/src/market.c
@@ -16,7 +16,7 @@ without prior permission by the authors of Eressea.
 
 #include <assert.h>
 
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <selist.h>
 #include <util/rng.h>
 
diff --git a/src/modules/autoseed.c b/src/modules/autoseed.c
index 88240d0b3..65585441c 100644
--- a/src/modules/autoseed.c
+++ b/src/modules/autoseed.c
@@ -31,7 +31,7 @@
 #include <attributes/key.h>
 
 /* util includes */
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/base36.h>
 #include <util/goodies.h>
 #include <util/language.h>
diff --git a/src/modules/gmcmd.c b/src/modules/gmcmd.c
index 20e090114..56386f2a6 100644
--- a/src/modules/gmcmd.c
+++ b/src/modules/gmcmd.c
@@ -32,7 +32,7 @@
 #include <kernel/unit.h>
 
 /* util includes */
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/gamedata.h>
 #include <util/macros.h>
 
diff --git a/src/modules/museum.c b/src/modules/museum.c
index 67ce12bd1..b5cbf05ce 100644
--- a/src/modules/museum.c
+++ b/src/modules/museum.c
@@ -38,7 +38,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <move.h>
 
 /* util includes */
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/base36.h>
 #include <util/functions.h>
 #include <util/gamedata.h>
diff --git a/src/modules/xmas.c b/src/modules/xmas.c
index b76f14eab..b4fd2cd24 100644
--- a/src/modules/xmas.c
+++ b/src/modules/xmas.c
@@ -25,9 +25,9 @@
 #include <move.h>
 
 /* util includes */
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/base36.h>
-#include <util/event.h>
+#include <kernel/event.h>
 #include <util/gamedata.h>
 #include <util/goodies.h>
 #include <util/resolve.h>
diff --git a/src/monsters.c b/src/monsters.c
index d009f8bda..505c6c272 100644
--- a/src/monsters.c
+++ b/src/monsters.c
@@ -52,9 +52,9 @@
 #include "kernel/unit.h"
 
 /* util includes */
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/base36.h>
-#include <util/event.h>
+#include <kernel/event.h>
 #include <util/language.h>
 #include <util/lists.h>
 #include <util/log.h>
diff --git a/src/monsters.test.c b/src/monsters.test.c
index 54b3f7f87..4ea3a32a3 100644
--- a/src/monsters.test.c
+++ b/src/monsters.test.c
@@ -18,7 +18,7 @@
 #include "skill.h"
 #include "study.h"
 
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/language.h>
 #include <util/message.h>
 #include <util/nrmessage.h>
diff --git a/src/move.c b/src/move.c
index 63453d970..b633d0ff7 100644
--- a/src/move.c
+++ b/src/move.c
@@ -72,7 +72,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
 /* util includes */
 #include <util/assert.h>
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/base36.h>
 #include <util/gamedata.h>
 #include <util/language.h>
diff --git a/src/move.test.c b/src/move.test.c
index f01915e2a..4e9e4760d 100644
--- a/src/move.test.c
+++ b/src/move.test.c
@@ -17,7 +17,7 @@
 #include <kernel/race.h>
 #include <kernel/order.h>
 
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/language.h>
 #include <util/message.h>
 #include <util/base36.h>
diff --git a/src/piracy.c b/src/piracy.c
index 46977c3d8..86b9b4904 100644
--- a/src/piracy.c
+++ b/src/piracy.c
@@ -15,7 +15,7 @@
 #include <kernel/terrain.h>
 #include <kernel/unit.h>
 
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/base36.h>
 #include <util/goodies.h>
 #include <util/language.h>
diff --git a/src/races/races.c b/src/races/races.c
index 44ca5d95e..7eede1b38 100644
--- a/src/races/races.c
+++ b/src/races/races.c
@@ -21,7 +21,7 @@
 #include <kernel/terrain.h>
 #include <kernel/unit.h>
 
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/functions.h>
 #include <util/rng.h>
 
diff --git a/src/randenc.c b/src/randenc.c
index 820d3760f..79998c14b 100644
--- a/src/randenc.c
+++ b/src/randenc.c
@@ -56,7 +56,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include "kernel/unit.h"
 
 /* util includes */
-#include "util/attrib.h"
+#include "kernel/attrib.h"
 #include "util/language.h"
 #include "util/lists.h"
 #include "util/log.h"
diff --git a/src/renumber.c b/src/renumber.c
index 45ee0cccc..8a72be2a5 100644
--- a/src/renumber.c
+++ b/src/renumber.c
@@ -9,7 +9,7 @@
 #include <kernel/order.h>
 #include <kernel/messages.h>
 
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/base36.h>
 #include <util/parser.h>
 
diff --git a/src/report.c b/src/report.c
index 29f124cef..bc47cb1a4 100644
--- a/src/report.c
+++ b/src/report.c
@@ -77,7 +77,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include "kernel/alliance.h"
 
 /* util includes */
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/base36.h>
 #include "util/bsdstring.h"
 #include <util/goodies.h>
diff --git a/src/reports.c b/src/reports.c
index 25c331a9f..879e7ad3d 100644
--- a/src/reports.c
+++ b/src/reports.c
@@ -62,7 +62,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include "kernel/unit.h"
 
 /* util includes */
-#include "util/attrib.h"
+#include "kernel/attrib.h"
 #include "util/base36.h"
 #include "util/bsdstring.h"
 #include "util/functions.h"
diff --git a/src/reports.test.c b/src/reports.test.c
index 65b5b06b0..29f14c634 100644
--- a/src/reports.test.c
+++ b/src/reports.test.c
@@ -25,7 +25,7 @@
 #include "kernel/spellbook.h"
 #include "kernel/terrain.h"
 
-#include "util/attrib.h"
+#include "kernel/attrib.h"
 #include "util/language.h"
 #include "util/lists.h"
 #include "util/message.h"
diff --git a/src/spells.c b/src/spells.c
index 02cbe43b5..1238c1dae 100644
--- a/src/spells.c
+++ b/src/spells.c
@@ -70,9 +70,9 @@
 
 /* util includes */
 #include <util/assert.h>
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/base36.h>
-#include <util/event.h>
+#include <kernel/event.h>
 #include <util/gamedata.h>
 #include <util/language.h>
 #include <util/macros.h>
diff --git a/src/spells.test.c b/src/spells.test.c
index e6150cb46..5950fab16 100644
--- a/src/spells.test.c
+++ b/src/spells.test.c
@@ -12,7 +12,7 @@
 #include <kernel/region.h>
 #include <kernel/spell.h>
 #include <kernel/unit.h>
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/language.h>
 #include <util/message.h>
 #include <spells/regioncurse.h>
diff --git a/src/spells/borders.c b/src/spells/borders.c
index c30726641..ff15ea971 100644
--- a/src/spells/borders.c
+++ b/src/spells/borders.c
@@ -13,7 +13,7 @@
 #include <kernel/terrain.h>
 #include <kernel/unit.h>
 
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/gamedata.h>
 #include <util/language.h>
 #include <util/macros.h>
diff --git a/src/spells/combatspells.c b/src/spells/combatspells.c
index 06a78c4f4..6d6b846c3 100644
--- a/src/spells/combatspells.c
+++ b/src/spells/combatspells.c
@@ -36,7 +36,7 @@
 #include <move.h>
 
 /* util includes */
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/base36.h>
 #include <util/log.h>
 #include <util/macros.h>
diff --git a/src/spells/magicresistance.test.c b/src/spells/magicresistance.test.c
index cbfdeb4af..390134c56 100644
--- a/src/spells/magicresistance.test.c
+++ b/src/spells/magicresistance.test.c
@@ -8,7 +8,7 @@
 #include <kernel/unit.h>
 #include <util/message.h>
 #include <util/language.h>
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <spells/regioncurse.h>
 #include "spells.h"
 
diff --git a/src/spy.c b/src/spy.c
index 9dc9de35a..98245e806 100644
--- a/src/spy.c
+++ b/src/spy.c
@@ -44,7 +44,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <attributes/stealth.h>
 
 /* util includes */
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/base36.h>
 #include <util/parser.h>
 #include <util/rand.h>
diff --git a/src/spy.test.c b/src/spy.test.c
index d8b879e3f..dfe2886e7 100644
--- a/src/spy.test.c
+++ b/src/spy.test.c
@@ -11,7 +11,7 @@
 #include <kernel/order.h>
 #include <kernel/item.h>
 #include <kernel/messages.h>
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/language.h>
 #include <util/message.h>
 #include <util/crmessage.h>
diff --git a/src/study.c b/src/study.c
index c978e69ad..a3dfa2e33 100644
--- a/src/study.c
+++ b/src/study.c
@@ -46,7 +46,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <kernel/unit.h>
 
 /* util includes */
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/base36.h>
 #include <util/language.h>
 #include <util/log.h>
diff --git a/src/study.test.c b/src/study.test.c
index a63be7cf1..3a94bf810 100644
--- a/src/study.test.c
+++ b/src/study.test.c
@@ -11,7 +11,7 @@
 #include <kernel/race.h>
 #include <kernel/region.h>
 #include <kernel/unit.h>
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/rand.h>
 #include <util/message.h>
 #include <util/language.h>
diff --git a/src/travelthru.c b/src/travelthru.c
index fa6293f53..5a1af28eb 100644
--- a/src/travelthru.c
+++ b/src/travelthru.c
@@ -27,7 +27,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <kernel/ship.h>
 #include <kernel/region.h>
 #include <kernel/faction.h>
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/log.h>
 #include <util/language.h>
 
diff --git a/src/travelthru.test.c b/src/travelthru.test.c
index 8a38891b1..b4f0e3dca 100644
--- a/src/travelthru.test.c
+++ b/src/travelthru.test.c
@@ -3,7 +3,7 @@
 #include <kernel/region.h>
 #include <kernel/unit.h>
 #include <kernel/faction.h>
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/macros.h>
 
 #include "travelthru.h"
diff --git a/src/triggers/changefaction.c b/src/triggers/changefaction.c
index f34cb98bd..44edec269 100644
--- a/src/triggers/changefaction.c
+++ b/src/triggers/changefaction.c
@@ -24,9 +24,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <kernel/faction.h>
 
 /* util includes */
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/base36.h>
-#include <util/event.h>
+#include <kernel/event.h>
 #include <util/gamedata.h>
 #include <util/log.h>
 #include <util/macros.h>
diff --git a/src/triggers/changerace.c b/src/triggers/changerace.c
index abc605c35..758df4dc6 100644
--- a/src/triggers/changerace.c
+++ b/src/triggers/changerace.c
@@ -24,9 +24,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <kernel/race.h>
 
 /* util includes */
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/base36.h>
-#include <util/event.h>
+#include <kernel/event.h>
 #include <util/gamedata.h>
 #include <util/log.h>
 #include <util/macros.h>
diff --git a/src/triggers/clonedied.c b/src/triggers/clonedied.c
index 62c4c3343..5713a2b6c 100644
--- a/src/triggers/clonedied.c
+++ b/src/triggers/clonedied.c
@@ -26,9 +26,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <kernel/unit.h>
 
 /* util includes */
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/base36.h>
-#include <util/event.h>
+#include <kernel/event.h>
 #include <util/gamedata.h>
 #include <util/log.h>
 #include <util/macros.h>
diff --git a/src/triggers/createcurse.c b/src/triggers/createcurse.c
index bd7422587..666c82a0f 100644
--- a/src/triggers/createcurse.c
+++ b/src/triggers/createcurse.c
@@ -24,9 +24,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <kernel/unit.h>
 
 /* util includes */
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/base36.h>
-#include <util/event.h>
+#include <kernel/event.h>
 #include <util/gamedata.h>
 #include <util/log.h>
 #include <util/macros.h>
diff --git a/src/triggers/createunit.c b/src/triggers/createunit.c
index f152d3766..4ce2730dc 100644
--- a/src/triggers/createunit.c
+++ b/src/triggers/createunit.c
@@ -26,9 +26,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <kernel/region.h>
 
 /* util includes */
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/base36.h>
-#include <util/event.h>
+#include <kernel/event.h>
 #include <util/gamedata.h>
 #include <util/log.h>
 #include <util/macros.h>
diff --git a/src/triggers/gate.c b/src/triggers/gate.c
index 4c2c7a9cd..8690d5752 100644
--- a/src/triggers/gate.c
+++ b/src/triggers/gate.c
@@ -18,8 +18,8 @@
 #include <kernel/unit.h>
 
 /* util includes */
-#include <util/attrib.h>
-#include <util/event.h>
+#include <kernel/attrib.h>
+#include <kernel/event.h>
 #include <util/gamedata.h>
 #include <util/log.h>
 #include <util/macros.h>
diff --git a/src/triggers/giveitem.c b/src/triggers/giveitem.c
index 08e4f0147..7815350a1 100644
--- a/src/triggers/giveitem.c
+++ b/src/triggers/giveitem.c
@@ -24,9 +24,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <kernel/unit.h>
 
 /* util includes */
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/base36.h>
-#include <util/event.h>
+#include <kernel/event.h>
 #include <util/gamedata.h>
 #include <util/log.h>
 #include <util/macros.h>
diff --git a/src/triggers/killunit.c b/src/triggers/killunit.c
index bca630177..37e55b25b 100644
--- a/src/triggers/killunit.c
+++ b/src/triggers/killunit.c
@@ -23,9 +23,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <kernel/unit.h>
 
 /* util includes */
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/base36.h>
-#include <util/event.h>
+#include <kernel/event.h>
 #include <util/gamedata.h>
 #include <util/log.h>
 #include <util/macros.h>
diff --git a/src/triggers/shock.c b/src/triggers/shock.c
index 7eae6f31a..767f0fd17 100644
--- a/src/triggers/shock.c
+++ b/src/triggers/shock.c
@@ -29,9 +29,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <kernel/unit.h>
 
 /* util includes */
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/base36.h>
-#include <util/event.h>
+#include <kernel/event.h>
 #include <util/gamedata.h>
 #include <util/log.h>
 #include <util/macros.h>
diff --git a/src/triggers/shock.test.c b/src/triggers/shock.test.c
index 43b8d394b..4bbd4de88 100644
--- a/src/triggers/shock.test.c
+++ b/src/triggers/shock.test.c
@@ -5,7 +5,7 @@
 #include <kernel/unit.h>
 #include <kernel/faction.h>
 
-#include <util/event.h>
+#include <kernel/event.h>
 #include <util/message.h>
 
 #include <tests.h>
diff --git a/src/triggers/timeout.c b/src/triggers/timeout.c
index 5179bd832..8acaaa38b 100644
--- a/src/triggers/timeout.c
+++ b/src/triggers/timeout.c
@@ -20,8 +20,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include "timeout.h"
 
 /* util includes */
-#include <util/attrib.h>
-#include <util/event.h>
+#include <kernel/attrib.h>
+#include <kernel/event.h>
 #include <util/gamedata.h>
 #include <util/log.h>
 #include <util/macros.h>
diff --git a/src/triggers/triggers.c b/src/triggers/triggers.c
index 8826fcba2..13504f216 100644
--- a/src/triggers/triggers.c
+++ b/src/triggers/triggers.c
@@ -31,7 +31,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <triggers/clonedied.h>
 
 /* util includes */
-#include <util/event.h>
+#include <kernel/event.h>
 
 /* libc includes */
 #include <stdio.h>
diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt
index 90059666a..d0e505af2 100644
--- a/src/util/CMakeLists.txt
+++ b/src/util/CMakeLists.txt
@@ -3,12 +3,10 @@ project(util C)
 add_subdirectory (crypto)
 
 SET(_TEST_FILES
-attrib.test.c
 base36.test.c
 # bsdstring.test.c
 # crmessage.test.c
 # dice.test.c
-# event.test.c
 # filereader.test.c
 functions.test.c
 gamedata.test.c
@@ -33,12 +31,10 @@ variant.test.c
 )
 
 SET(_FILES
-attrib.c
 base36.c
 bsdstring.c
 crmessage.c
 dice.c
-event.c
 filereader.c
 functions.c
 gamedata.c
diff --git a/src/volcano.c b/src/volcano.c
index 7bddd6097..d4d045045 100644
--- a/src/volcano.c
+++ b/src/volcano.c
@@ -36,7 +36,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <attributes/reduceproduction.h>
 
 /* util includes */
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/log.h>
 #include <util/rand.h>
 #include <util/message.h>
diff --git a/src/volcano.test.c b/src/volcano.test.c
index c62febc0d..3ca670c7c 100644
--- a/src/volcano.test.c
+++ b/src/volcano.test.c
@@ -8,7 +8,7 @@
 #include <kernel/unit.h>
 #include <kernel/messages.h>
 
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 
 #include <attributes/reduceproduction.h>
 
diff --git a/src/vortex.c b/src/vortex.c
index 69d767c1b..948ad80fc 100644
--- a/src/vortex.c
+++ b/src/vortex.c
@@ -4,7 +4,7 @@
 #include <kernel/config.h>
 #include <kernel/region.h>
 
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/gamedata.h>
 #include <util/language.h>
 #include <util/log.h>
diff --git a/src/wormhole.c b/src/wormhole.c
index 2000018ab..5cf044d92 100644
--- a/src/wormhole.c
+++ b/src/wormhole.c
@@ -24,7 +24,7 @@
 #include <kernel/unit.h>
 
 /* util includes */
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/gamedata.h>
 #include <util/language.h>
 #include <util/macros.h>
diff --git a/src/wormhole.test.c b/src/wormhole.test.c
index b8baaa79a..bec4a5ff8 100644
--- a/src/wormhole.test.c
+++ b/src/wormhole.test.c
@@ -8,7 +8,7 @@
 #include <kernel/region.h>
 #include <kernel/terrain.h>
 
-#include <util/attrib.h>
+#include <kernel/attrib.h>
 #include <util/message.h>
 
 #include <selist.h>

From b22d838a578b1729721efe2c99c0b773803065e4 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sat, 29 Sep 2018 13:21:46 +0200
Subject: [PATCH 53/81] move gamedata.c to kernel

---
 src/alchemy.c                        | 2 +-
 src/attributes/attributes.c          | 2 +-
 src/attributes/dict.c                | 2 +-
 src/attributes/follow.c              | 2 +-
 src/attributes/hate.c                | 2 +-
 src/attributes/key.c                 | 2 +-
 src/attributes/movement.c            | 2 +-
 src/attributes/otherfaction.c        | 2 +-
 src/attributes/seenspell.c           | 2 +-
 src/attributes/targetregion.c        | 2 +-
 src/bind_storage.c                   | 2 +-
 src/helpers.c                        | 2 +-
 src/kernel/CMakeLists.txt            | 2 ++
 src/kernel/ally.c                    | 2 +-
 src/kernel/attrib.c                  | 2 +-
 src/kernel/attrib.test.c             | 2 +-
 src/kernel/building.c                | 2 +-
 src/kernel/connection.c              | 2 +-
 src/kernel/curse.c                   | 2 +-
 src/kernel/curse.test.c              | 2 +-
 src/kernel/event.c                   | 2 +-
 src/kernel/faction.c                 | 2 +-
 src/{util => kernel}/gamedata.c      | 3 ++-
 src/{util => kernel}/gamedata.h      | 0
 src/{util => kernel}/gamedata.test.c | 0
 src/kernel/group.c                   | 2 +-
 src/kernel/group.test.c              | 2 +-
 src/kernel/region.c                  | 2 +-
 src/kernel/save.c                    | 4 ++--
 src/kernel/save.test.c               | 2 +-
 src/kernel/spellbook.c               | 2 +-
 src/kernel/unit.c                    | 2 +-
 src/magic.c                          | 2 +-
 src/modules/gmcmd.c                  | 2 +-
 src/modules/museum.c                 | 2 +-
 src/modules/xmas.c                   | 2 +-
 src/move.c                           | 2 +-
 src/spells.c                         | 2 +-
 src/spells/borders.c                 | 2 +-
 src/spells/flyingship.c              | 2 +-
 src/spells/unitcurse.c               | 2 +-
 src/triggers/changefaction.c         | 2 +-
 src/triggers/changerace.c            | 2 +-
 src/triggers/clonedied.c             | 2 +-
 src/triggers/createcurse.c           | 2 +-
 src/triggers/createunit.c            | 2 +-
 src/triggers/gate.c                  | 2 +-
 src/triggers/giveitem.c              | 2 +-
 src/triggers/killunit.c              | 2 +-
 src/triggers/shock.c                 | 2 +-
 src/triggers/timeout.c               | 2 +-
 src/util/CMakeLists.txt              | 2 --
 src/vortex.c                         | 2 +-
 src/wormhole.c                       | 2 +-
 tests/orders.txt                     | 3 ---
 55 files changed, 54 insertions(+), 56 deletions(-)
 rename src/{util => kernel}/gamedata.c (98%)
 rename src/{util => kernel}/gamedata.h (100%)
 rename src/{util => kernel}/gamedata.test.c (100%)
 delete mode 100644 tests/orders.txt

diff --git a/src/alchemy.c b/src/alchemy.c
index fb0516359..d2dd64a04 100644
--- a/src/alchemy.c
+++ b/src/alchemy.c
@@ -34,7 +34,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
 /* util includes */
 #include <kernel/attrib.h>
-#include <util/gamedata.h>
+#include <kernel/gamedata.h>
 #include <util/base36.h>
 #include <util/log.h>
 #include <util/macros.h>
diff --git a/src/attributes/attributes.c b/src/attributes/attributes.c
index cf75efc58..400282ae7 100644
--- a/src/attributes/attributes.c
+++ b/src/attributes/attributes.c
@@ -55,7 +55,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 /* util includes */
 #include <kernel/attrib.h>
 #include <kernel/event.h>
-#include <util/gamedata.h>
+#include <kernel/gamedata.h>
 #include <util/macros.h>
 #include <util/resolve.h>
 
diff --git a/src/attributes/dict.c b/src/attributes/dict.c
index aa34886a6..70e88219d 100644
--- a/src/attributes/dict.c
+++ b/src/attributes/dict.c
@@ -32,7 +32,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <kernel/attrib.h>
 #include <util/base36.h>
 #include <util/log.h>
-#include <util/gamedata.h>
+#include <kernel/gamedata.h>
 #include <util/resolve.h>
 #include <util/strings.h>
 
diff --git a/src/attributes/follow.c b/src/attributes/follow.c
index 07fffbfd6..caeecee54 100644
--- a/src/attributes/follow.c
+++ b/src/attributes/follow.c
@@ -23,7 +23,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <kernel/unit.h>
 
 #include <kernel/attrib.h>
-#include <util/gamedata.h>
+#include <kernel/gamedata.h>
 #include <util/variant.h>
 
 #include <storage.h>
diff --git a/src/attributes/hate.c b/src/attributes/hate.c
index aff71d0e7..cef483cf6 100644
--- a/src/attributes/hate.c
+++ b/src/attributes/hate.c
@@ -23,7 +23,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <kernel/unit.h>
 
 #include <kernel/attrib.h>
-#include <util/gamedata.h>
+#include <kernel/gamedata.h>
 #include <util/macros.h>
 #include <util/resolve.h>
 
diff --git a/src/attributes/key.c b/src/attributes/key.c
index 462c7a63b..76a18c876 100644
--- a/src/attributes/key.c
+++ b/src/attributes/key.c
@@ -21,7 +21,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include "key.h"
 
 #include <kernel/attrib.h>
-#include <util/gamedata.h>
+#include <kernel/gamedata.h>
 #include <util/log.h>
 #include <storage.h>
 
diff --git a/src/attributes/movement.c b/src/attributes/movement.c
index 552ff51aa..01c75ffae 100644
--- a/src/attributes/movement.c
+++ b/src/attributes/movement.c
@@ -21,7 +21,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include "movement.h"
 
 #include <kernel/attrib.h>
-#include <util/gamedata.h>
+#include <kernel/gamedata.h>
 #include <util/macros.h>
 
 #include <storage.h>
diff --git a/src/attributes/otherfaction.c b/src/attributes/otherfaction.c
index 87b29f252..fcf05da05 100644
--- a/src/attributes/otherfaction.c
+++ b/src/attributes/otherfaction.c
@@ -24,7 +24,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <kernel/faction.h>
 #include <kernel/unit.h>
 #include <kernel/attrib.h>
-#include <util/gamedata.h>
+#include <kernel/gamedata.h>
 
 #include <storage.h>
 #include <assert.h>
diff --git a/src/attributes/seenspell.c b/src/attributes/seenspell.c
index 6108465cd..ae46980c3 100644
--- a/src/attributes/seenspell.c
+++ b/src/attributes/seenspell.c
@@ -24,7 +24,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <kernel/spell.h>
 #include <kernel/spellbook.h>
 #include <kernel/attrib.h>
-#include <util/gamedata.h>
+#include <kernel/gamedata.h>
 #include <util/log.h>
 #include <util/macros.h>
 
diff --git a/src/attributes/targetregion.c b/src/attributes/targetregion.c
index f67689052..600d2e184 100644
--- a/src/attributes/targetregion.c
+++ b/src/attributes/targetregion.c
@@ -23,7 +23,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <kernel/region.h>
 
 #include <kernel/attrib.h>
-#include <util/gamedata.h>
+#include <kernel/gamedata.h>
 #include <util/resolve.h>
 
 #include <storage.h>
diff --git a/src/bind_storage.c b/src/bind_storage.c
index aa7935312..5df148bb4 100644
--- a/src/bind_storage.c
+++ b/src/bind_storage.c
@@ -6,7 +6,7 @@
 
 #include <kernel/save.h>
 
-#include <util/gamedata.h>
+#include <kernel/gamedata.h>
 #include <util/log.h>
 #include <util/macros.h>
 
diff --git a/src/helpers.c b/src/helpers.c
index 2835b153d..223089c9c 100644
--- a/src/helpers.c
+++ b/src/helpers.c
@@ -22,7 +22,7 @@ without prior permission by the authors of Eressea.
 #include <kernel/attrib.h>
 #include <kernel/event.h>
 #include <util/functions.h>
-#include <util/gamedata.h>
+#include <kernel/gamedata.h>
 #include <util/log.h>
 #include <util/macros.h>
 #include <util/parser.h>
diff --git a/src/kernel/CMakeLists.txt b/src/kernel/CMakeLists.txt
index 093a41429..06f58fc1b 100644
--- a/src/kernel/CMakeLists.txt
+++ b/src/kernel/CMakeLists.txt
@@ -25,6 +25,7 @@ database.test.c
 equipment.test.c
 # event.test.c
 faction.test.c
+gamedata.test.c
 group.test.c
 item.test.c
 messages.test.c
@@ -60,6 +61,7 @@ curse.c
 equipment.c
 event.c
 faction.c
+gamedata.c
 group.c
 item.c
 messages.c
diff --git a/src/kernel/ally.c b/src/kernel/ally.c
index a2536c7d9..1fd7c0efd 100644
--- a/src/kernel/ally.c
+++ b/src/kernel/ally.c
@@ -12,7 +12,7 @@
 
 #include <kernel/attrib.h>
 #include <util/strings.h>
-#include <util/gamedata.h>
+#include <kernel/gamedata.h>
 
 #include <storage.h>
 
diff --git a/src/kernel/attrib.c b/src/kernel/attrib.c
index 375997df4..d84a8c8e9 100644
--- a/src/kernel/attrib.c
+++ b/src/kernel/attrib.c
@@ -22,7 +22,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <util/log.h>
 #include <util/strings.h>
 #include <util/variant.h>
-#include <util/gamedata.h>
+#include <kernel/gamedata.h>
 
 #include <storage.h>
 #include <critbit.h>
diff --git a/src/kernel/attrib.test.c b/src/kernel/attrib.test.c
index d266196e6..918b768fd 100644
--- a/src/kernel/attrib.test.c
+++ b/src/kernel/attrib.test.c
@@ -1,7 +1,7 @@
 #include <platform.h>
 #include "attrib.h"
 
-#include <util/gamedata.h>
+#include <kernel/gamedata.h>
 #include <util/strings.h>
 
 #include <storage.h>
diff --git a/src/kernel/building.c b/src/kernel/building.c
index 9627567ab..215c304e7 100644
--- a/src/kernel/building.c
+++ b/src/kernel/building.c
@@ -42,7 +42,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <util/base36.h>
 #include <kernel/event.h>
 #include <util/functions.h>
-#include <util/gamedata.h>
+#include <kernel/gamedata.h>
 #include <util/language.h>
 #include <util/log.h>
 #include <util/resolve.h>
diff --git a/src/kernel/connection.c b/src/kernel/connection.c
index c66bd06e0..7fc1213e0 100644
--- a/src/kernel/connection.c
+++ b/src/kernel/connection.c
@@ -28,7 +28,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
 #include <kernel/attrib.h>
 #include <util/base36.h>
-#include <util/gamedata.h>
+#include <kernel/gamedata.h>
 #include <util/language.h>
 #include <util/log.h>
 #include <util/macros.h>
diff --git a/src/kernel/curse.c b/src/kernel/curse.c
index 5f0c4a776..62e7ab9b2 100644
--- a/src/kernel/curse.c
+++ b/src/kernel/curse.c
@@ -36,7 +36,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 /* util includes */
 #include <kernel/attrib.h>
 #include <util/base36.h>
-#include <util/gamedata.h>
+#include <kernel/gamedata.h>
 #include <util/goodies.h>
 #include <util/language.h>
 #include <util/log.h>
diff --git a/src/kernel/curse.test.c b/src/kernel/curse.test.c
index 23a5ad54f..da0806914 100644
--- a/src/kernel/curse.test.c
+++ b/src/kernel/curse.test.c
@@ -6,7 +6,7 @@
 #include <kernel/unit.h>
 #include <kernel/attrib.h>
 #include <util/rng.h>
-#include <util/gamedata.h>
+#include <kernel/gamedata.h>
 #include <util/message.h>
 #include <binarystore.h>
 #include <filestream.h>
diff --git a/src/kernel/event.c b/src/kernel/event.c
index ab095a008..f1ff825f5 100644
--- a/src/kernel/event.c
+++ b/src/kernel/event.c
@@ -21,7 +21,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include "attrib.h"
 
 /* util includes */
-#include <util/gamedata.h>
+#include <kernel/gamedata.h>
 #include <util/log.h>
 #include <util/strings.h>
 
diff --git a/src/kernel/faction.c b/src/kernel/faction.c
index dea4ca54f..a78cd943a 100755
--- a/src/kernel/faction.c
+++ b/src/kernel/faction.c
@@ -45,7 +45,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <kernel/attrib.h>
 #include <util/base36.h>
 #include <kernel/event.h>
-#include <util/gamedata.h>
+#include <kernel/gamedata.h>
 #include <util/goodies.h>
 #include <util/lists.h>
 #include <util/language.h>
diff --git a/src/util/gamedata.c b/src/kernel/gamedata.c
similarity index 98%
rename from src/util/gamedata.c
rename to src/kernel/gamedata.c
index cd3fa01a7..4173332c4 100644
--- a/src/util/gamedata.c
+++ b/src/kernel/gamedata.c
@@ -1,7 +1,8 @@
 #include <platform.h>
 
 #include "gamedata.h"
-#include "log.h"
+
+#include <util/log.h>
 
 #include <storage.h>
 #include <filestream.h>
diff --git a/src/util/gamedata.h b/src/kernel/gamedata.h
similarity index 100%
rename from src/util/gamedata.h
rename to src/kernel/gamedata.h
diff --git a/src/util/gamedata.test.c b/src/kernel/gamedata.test.c
similarity index 100%
rename from src/util/gamedata.test.c
rename to src/kernel/gamedata.test.c
diff --git a/src/kernel/group.c b/src/kernel/group.c
index 9ebbf244d..54aa87aeb 100755
--- a/src/kernel/group.c
+++ b/src/kernel/group.c
@@ -32,7 +32,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 /* util includes */
 #include <kernel/attrib.h>
 #include <util/base36.h>
-#include <util/gamedata.h>
+#include <kernel/gamedata.h>
 #include <util/resolve.h>
 #include <util/strings.h>
 #include <util/unicode.h>
diff --git a/src/kernel/group.test.c b/src/kernel/group.test.c
index 5d1a28f6b..1c6d6339e 100644
--- a/src/kernel/group.test.c
+++ b/src/kernel/group.test.c
@@ -8,7 +8,7 @@
 #include "region.h"
 #include "save.h"
 
-#include <util/gamedata.h>
+#include <kernel/gamedata.h>
 #include <kernel/attrib.h>
 #include <attributes/key.h>
 
diff --git a/src/kernel/region.c b/src/kernel/region.c
index 2cb93b4a3..377bf1e22 100644
--- a/src/kernel/region.c
+++ b/src/kernel/region.c
@@ -43,7 +43,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 /* util includes */
 #include <util/assert.h>
 #include <kernel/attrib.h>
-#include <util/gamedata.h>
+#include <kernel/gamedata.h>
 #include <util/strings.h>
 #include <util/lists.h>
 #include <util/log.h>
diff --git a/src/kernel/save.c b/src/kernel/save.c
index eb731e8d7..3bef185c3 100644
--- a/src/kernel/save.c
+++ b/src/kernel/save.c
@@ -61,9 +61,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <util/base36.h>
 #include <kernel/event.h>
 #include <util/filereader.h>
-#include <util/gamedata.h>
+#include <kernel/gamedata.h>
 #include <util/goodies.h>
-#include <util/gamedata.h>
+#include <kernel/gamedata.h>
 #include <util/language.h>
 #include <util/lists.h>
 #include <util/log.h>
diff --git a/src/kernel/save.test.c b/src/kernel/save.test.c
index 04ef9b1bb..8e738863f 100644
--- a/src/kernel/save.test.c
+++ b/src/kernel/save.test.c
@@ -20,7 +20,7 @@
 #include <kernel/attrib.h>
 #include <util/base36.h>
 #include <kernel/event.h>
-#include <util/gamedata.h>
+#include <kernel/gamedata.h>
 #include <util/password.h>
 #include <util/path.h>
 #include <util/strings.h>
diff --git a/src/kernel/spellbook.c b/src/kernel/spellbook.c
index 868f9757c..d230992cf 100644
--- a/src/kernel/spellbook.c
+++ b/src/kernel/spellbook.c
@@ -4,7 +4,7 @@
 #include <kernel/spell.h>
 
 #include <util/log.h>
-#include <util/gamedata.h>
+#include <kernel/gamedata.h>
 #include <util/strings.h>
 
 #include "spellbook.h"
diff --git a/src/kernel/unit.c b/src/kernel/unit.c
index 13b2b1bf2..00d0aeece 100644
--- a/src/kernel/unit.c
+++ b/src/kernel/unit.c
@@ -53,7 +53,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <kernel/attrib.h>
 #include <util/base36.h>
 #include <kernel/event.h>
-#include <util/gamedata.h>
+#include <kernel/gamedata.h>
 #include <util/strings.h>
 #include <util/language.h>
 #include <util/lists.h>
diff --git a/src/magic.c b/src/magic.c
index 41aa0dbce..047ed167b 100644
--- a/src/magic.c
+++ b/src/magic.c
@@ -65,7 +65,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <kernel/attrib.h>
 #include <util/base36.h>
 #include <kernel/event.h>
-#include <util/gamedata.h>
+#include <kernel/gamedata.h>
 #include <util/language.h>
 #include <util/lists.h>
 #include <util/log.h>
diff --git a/src/modules/gmcmd.c b/src/modules/gmcmd.c
index 56386f2a6..4cc573f16 100644
--- a/src/modules/gmcmd.c
+++ b/src/modules/gmcmd.c
@@ -33,7 +33,7 @@
 
 /* util includes */
 #include <kernel/attrib.h>
-#include <util/gamedata.h>
+#include <kernel/gamedata.h>
 #include <util/macros.h>
 
 #include <storage.h>
diff --git a/src/modules/museum.c b/src/modules/museum.c
index b5cbf05ce..7e3a04f2d 100644
--- a/src/modules/museum.c
+++ b/src/modules/museum.c
@@ -41,7 +41,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <kernel/attrib.h>
 #include <util/base36.h>
 #include <util/functions.h>
-#include <util/gamedata.h>
+#include <kernel/gamedata.h>
 #include <util/strings.h>
 #include <util/language.h>
 #include <util/macros.h>
diff --git a/src/modules/xmas.c b/src/modules/xmas.c
index b4fd2cd24..aa296866a 100644
--- a/src/modules/xmas.c
+++ b/src/modules/xmas.c
@@ -28,7 +28,7 @@
 #include <kernel/attrib.h>
 #include <util/base36.h>
 #include <kernel/event.h>
-#include <util/gamedata.h>
+#include <kernel/gamedata.h>
 #include <util/goodies.h>
 #include <util/resolve.h>
 
diff --git a/src/move.c b/src/move.c
index b633d0ff7..8de997480 100644
--- a/src/move.c
+++ b/src/move.c
@@ -74,7 +74,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <util/assert.h>
 #include <kernel/attrib.h>
 #include <util/base36.h>
-#include <util/gamedata.h>
+#include <kernel/gamedata.h>
 #include <util/language.h>
 #include <util/lists.h>
 #include <util/log.h>
diff --git a/src/spells.c b/src/spells.c
index 1238c1dae..00f256f26 100644
--- a/src/spells.c
+++ b/src/spells.c
@@ -73,7 +73,7 @@
 #include <kernel/attrib.h>
 #include <util/base36.h>
 #include <kernel/event.h>
-#include <util/gamedata.h>
+#include <kernel/gamedata.h>
 #include <util/language.h>
 #include <util/macros.h>
 #include <util/message.h>
diff --git a/src/spells/borders.c b/src/spells/borders.c
index ff15ea971..5d99b1307 100644
--- a/src/spells/borders.c
+++ b/src/spells/borders.c
@@ -14,7 +14,7 @@
 #include <kernel/unit.h>
 
 #include <kernel/attrib.h>
-#include <util/gamedata.h>
+#include <kernel/gamedata.h>
 #include <util/language.h>
 #include <util/macros.h>
 #include <util/rand.h>
diff --git a/src/spells/flyingship.c b/src/spells/flyingship.c
index e23f6906b..2b830da2e 100644
--- a/src/spells/flyingship.c
+++ b/src/spells/flyingship.c
@@ -11,7 +11,7 @@
 #include <kernel/unit.h>
 #include <kernel/ship.h>
 
-#include <util/gamedata.h>
+#include <kernel/gamedata.h>
 
 #include <magic.h>
 
diff --git a/src/spells/unitcurse.c b/src/spells/unitcurse.c
index a99eb082c..d0b381050 100644
--- a/src/spells/unitcurse.c
+++ b/src/spells/unitcurse.c
@@ -23,7 +23,7 @@
 #include <kernel/objtypes.h>
 
 /* util includes */
-#include <util/gamedata.h>
+#include <kernel/gamedata.h>
 #include <util/language.h>
 #include <util/nrmessage.h>
 #include <util/macros.h>
diff --git a/src/triggers/changefaction.c b/src/triggers/changefaction.c
index 44edec269..8aa73168d 100644
--- a/src/triggers/changefaction.c
+++ b/src/triggers/changefaction.c
@@ -27,7 +27,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <kernel/attrib.h>
 #include <util/base36.h>
 #include <kernel/event.h>
-#include <util/gamedata.h>
+#include <kernel/gamedata.h>
 #include <util/log.h>
 #include <util/macros.h>
 #include <util/resolve.h>
diff --git a/src/triggers/changerace.c b/src/triggers/changerace.c
index 758df4dc6..5a834314a 100644
--- a/src/triggers/changerace.c
+++ b/src/triggers/changerace.c
@@ -27,7 +27,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <kernel/attrib.h>
 #include <util/base36.h>
 #include <kernel/event.h>
-#include <util/gamedata.h>
+#include <kernel/gamedata.h>
 #include <util/log.h>
 #include <util/macros.h>
 #include <util/resolve.h>
diff --git a/src/triggers/clonedied.c b/src/triggers/clonedied.c
index 5713a2b6c..c6593c2a4 100644
--- a/src/triggers/clonedied.c
+++ b/src/triggers/clonedied.c
@@ -29,7 +29,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <kernel/attrib.h>
 #include <util/base36.h>
 #include <kernel/event.h>
-#include <util/gamedata.h>
+#include <kernel/gamedata.h>
 #include <util/log.h>
 #include <util/macros.h>
 #include <util/resolve.h>
diff --git a/src/triggers/createcurse.c b/src/triggers/createcurse.c
index 666c82a0f..544b9aafe 100644
--- a/src/triggers/createcurse.c
+++ b/src/triggers/createcurse.c
@@ -27,7 +27,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <kernel/attrib.h>
 #include <util/base36.h>
 #include <kernel/event.h>
-#include <util/gamedata.h>
+#include <kernel/gamedata.h>
 #include <util/log.h>
 #include <util/macros.h>
 #include <util/resolve.h>
diff --git a/src/triggers/createunit.c b/src/triggers/createunit.c
index 4ce2730dc..d4dd8f983 100644
--- a/src/triggers/createunit.c
+++ b/src/triggers/createunit.c
@@ -29,7 +29,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <kernel/attrib.h>
 #include <util/base36.h>
 #include <kernel/event.h>
-#include <util/gamedata.h>
+#include <kernel/gamedata.h>
 #include <util/log.h>
 #include <util/macros.h>
 #include <util/resolve.h>
diff --git a/src/triggers/gate.c b/src/triggers/gate.c
index 8690d5752..065be8cf8 100644
--- a/src/triggers/gate.c
+++ b/src/triggers/gate.c
@@ -20,7 +20,7 @@
 /* util includes */
 #include <kernel/attrib.h>
 #include <kernel/event.h>
-#include <util/gamedata.h>
+#include <kernel/gamedata.h>
 #include <util/log.h>
 #include <util/macros.h>
 #include <util/resolve.h>
diff --git a/src/triggers/giveitem.c b/src/triggers/giveitem.c
index 7815350a1..118497c86 100644
--- a/src/triggers/giveitem.c
+++ b/src/triggers/giveitem.c
@@ -27,7 +27,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <kernel/attrib.h>
 #include <util/base36.h>
 #include <kernel/event.h>
-#include <util/gamedata.h>
+#include <kernel/gamedata.h>
 #include <util/log.h>
 #include <util/macros.h>
 #include <util/resolve.h>
diff --git a/src/triggers/killunit.c b/src/triggers/killunit.c
index 37e55b25b..0338da4af 100644
--- a/src/triggers/killunit.c
+++ b/src/triggers/killunit.c
@@ -26,7 +26,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <kernel/attrib.h>
 #include <util/base36.h>
 #include <kernel/event.h>
-#include <util/gamedata.h>
+#include <kernel/gamedata.h>
 #include <util/log.h>
 #include <util/macros.h>
 #include <util/resolve.h>
diff --git a/src/triggers/shock.c b/src/triggers/shock.c
index 767f0fd17..9a9d1c74b 100644
--- a/src/triggers/shock.c
+++ b/src/triggers/shock.c
@@ -32,7 +32,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <kernel/attrib.h>
 #include <util/base36.h>
 #include <kernel/event.h>
-#include <util/gamedata.h>
+#include <kernel/gamedata.h>
 #include <util/log.h>
 #include <util/macros.h>
 #include <util/resolve.h>
diff --git a/src/triggers/timeout.c b/src/triggers/timeout.c
index 8acaaa38b..8e8a6b9bf 100644
--- a/src/triggers/timeout.c
+++ b/src/triggers/timeout.c
@@ -22,7 +22,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 /* util includes */
 #include <kernel/attrib.h>
 #include <kernel/event.h>
-#include <util/gamedata.h>
+#include <kernel/gamedata.h>
 #include <util/log.h>
 #include <util/macros.h>
 
diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt
index d0e505af2..4258a5edc 100644
--- a/src/util/CMakeLists.txt
+++ b/src/util/CMakeLists.txt
@@ -9,7 +9,6 @@ base36.test.c
 # dice.test.c
 # filereader.test.c
 functions.test.c
-gamedata.test.c
 # goodies.test.c
 language.test.c
 # lists.test.c
@@ -37,7 +36,6 @@ crmessage.c
 dice.c
 filereader.c
 functions.c
-gamedata.c
 goodies.c
 language.c
 lists.c
diff --git a/src/vortex.c b/src/vortex.c
index 948ad80fc..805b407c4 100644
--- a/src/vortex.c
+++ b/src/vortex.c
@@ -5,7 +5,7 @@
 #include <kernel/region.h>
 
 #include <kernel/attrib.h>
-#include <util/gamedata.h>
+#include <kernel/gamedata.h>
 #include <util/language.h>
 #include <util/log.h>
 #include <util/strings.h>
diff --git a/src/wormhole.c b/src/wormhole.c
index 5cf044d92..382e64d16 100644
--- a/src/wormhole.c
+++ b/src/wormhole.c
@@ -25,7 +25,7 @@
 
 /* util includes */
 #include <kernel/attrib.h>
-#include <util/gamedata.h>
+#include <kernel/gamedata.h>
 #include <util/language.h>
 #include <util/macros.h>
 #include <util/resolve.h>
diff --git a/tests/orders.txt b/tests/orders.txt
deleted file mode 100644
index a4a4f7456..000000000
--- a/tests/orders.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-ERESSEA uhfr "Hodor"
-EINHEIT 8bz3
-BENENNEN EINHEIT 'Goldene Herde'

From 991fe8fd8da2e8b0d466b0941360561cbdce798f Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sat, 29 Sep 2018 13:35:49 +0200
Subject: [PATCH 54/81] enable checker build. remove getid aliases from
 parser.h

---
 src/CMakeLists.txt | 4 ++--
 src/checker.c      | 4 ++--
 src/kernel/build.c | 2 +-
 src/laws.c         | 2 +-
 src/move.c         | 4 ++--
 src/util/parser.h  | 3 ---
 6 files changed, 8 insertions(+), 11 deletions(-)

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index be26a30a4..e6b83cfe1 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -191,8 +191,8 @@ target_link_libraries(parser
   )
 
 
-#add_executable(checker ${CHECK_SRC})
-#target_link_libraries(checker parser)
+add_executable(checker ${CHECK_SRC})
+target_link_libraries(checker parser)
 
 add_library(game ${ERESSEA_SRC})
 target_link_libraries(game parser version)
diff --git a/src/checker.c b/src/checker.c
index 1a07897a0..302c80390 100644
--- a/src/checker.c
+++ b/src/checker.c
@@ -2,8 +2,9 @@
 #include <platform.h>
 #endif
 
+#include "util/parser.h"
+
 #include <stdio.h>
-#include "orderfile.h"
 
 int main(int argc, char **argv) {
     FILE * F = stdin;
@@ -14,7 +15,6 @@ int main(int argc, char **argv) {
             perror(filename);
             return -1;
         }
-        readorders(F);
         fclose(F);
     }
     return 0;
diff --git a/src/kernel/build.c b/src/kernel/build.c
index 0891f1005..82c629b0b 100644
--- a/src/kernel/build.c
+++ b/src/kernel/build.c
@@ -79,7 +79,7 @@ struct building *getbuilding(const struct region *r)
 
 ship *getship(const struct region * r)
 {
-    ship *sh, *sx = findship(getshipid());
+    ship *sh, *sx = findship(getid());
     for (sh = r->ships; sh; sh = sh->next) {
         if (sh == sx)
             return sh;
diff --git a/src/laws.c b/src/laws.c
index d7f8c53de..67e4567a9 100644
--- a/src/laws.c
+++ b/src/laws.c
@@ -1952,7 +1952,7 @@ int mail_cmd(unit * u, struct order *ord)
             }
 
         case P_FACTION:
-            n = getfactionid();
+            n = getid();
 
             for (u2 = r->units; u2; u2 = u2->next) {
                 if (u2->faction->no == n && seefaction(u->faction, r, u2, 0)) {
diff --git a/src/move.c b/src/move.c
index 8de997480..124b846ca 100644
--- a/src/move.c
+++ b/src/move.c
@@ -2265,7 +2265,7 @@ int follow_ship(unit * u, order * ord)
         return 0;
     }
 
-    id = getshipid();
+    id = getid();
 
     if (id <= 0) {
         cmistake(u, ord, 20, MSG_MOVE);
@@ -2549,7 +2549,7 @@ void follow_unit(unit * u)
                 }
             }
             else if (p == P_SHIP) {
-                id = getshipid();
+                id = getid();
                 if (id <= 0) {
                     /*	cmistake(u, ord, 20, MSG_MOVE); */
                 }
diff --git a/src/util/parser.h b/src/util/parser.h
index 7242da1bb..a540aa2ac 100644
--- a/src/util/parser.h
+++ b/src/util/parser.h
@@ -33,9 +33,6 @@ extern "C" {
     int getid(void);
     unsigned int atoip(const char *s);
 
-#define getshipid() getid()
-#define getfactionid() getid()
-
 #ifdef __cplusplus
 }
 #endif

From bc5f2ea6d1c83db0325d1b2538a4d0d30f2c220f Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sat, 29 Sep 2018 18:13:32 +0200
Subject: [PATCH 55/81] move keyword.[hc] to util

---
 src/CMakeLists.txt            |  2 --
 src/automate.c                |  2 +-
 src/battle.test.c             |  2 +-
 src/bind_process.c            | 18 ++++++++++--------
 src/creport.test.c            |  2 +-
 src/items.c                   |  2 +-
 src/jsonconf.c                |  2 +-
 src/jsonconf.test.c           |  2 +-
 src/kernel/config.c           |  5 +++--
 src/kernel/order.c            |  2 +-
 src/kernel/order.h            |  3 ++-
 src/laws.c                    |  2 +-
 src/monsters.c                |  8 ++++----
 src/piracy.c                  |  4 ++--
 src/util/CMakeLists.txt       |  4 ++++
 src/{ => util}/keyword.c      |  0
 src/{ => util}/keyword.h      |  0
 src/{ => util}/keyword.test.c |  0
 src/util/order_parser.c       | 33 +++++++++++++++++++++++++++++++++
 src/util/order_parser.h       | 34 ++++++++++++++++++++++++++++++++++
 src/util/parser.c             |  2 ++
 21 files changed, 102 insertions(+), 27 deletions(-)
 rename src/{ => util}/keyword.c (100%)
 rename src/{ => util}/keyword.h (100%)
 rename src/{ => util}/keyword.test.c (100%)
 create mode 100644 src/util/order_parser.c
 create mode 100644 src/util/order_parser.h

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index e6b83cfe1..9ed0011e6 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -109,7 +109,6 @@ set (ERESSEA_SRC
   items.c
   json.c
   jsonconf.c
-  keyword.c
   laws.c
   lighthouse.c
   magic.c
@@ -224,7 +223,6 @@ set(TESTS_SRC
   guard.test.c
   json.test.c
   jsonconf.test.c
-  keyword.test.c
   laws.test.c
   lighthouse.test.c
   magic.test.c
diff --git a/src/automate.c b/src/automate.c
index 6af40d649..530b9ee39 100644
--- a/src/automate.c
+++ b/src/automate.c
@@ -6,10 +6,10 @@
 #include "kernel/region.h"
 #include "kernel/unit.h"
 
+#include "util/keyword.h"
 #include "util/log.h"
 
 #include "automate.h"
-#include "keyword.h"
 #include "laws.h"
 #include "study.h"
 
diff --git a/src/battle.test.c b/src/battle.test.c
index 8cfbb0d2a..a2ea561d4 100644
--- a/src/battle.test.c
+++ b/src/battle.test.c
@@ -3,7 +3,6 @@
 #include "battle.h"
 
 #include "guard.h"
-#include "keyword.h"
 #include "reports.h"
 #include "skill.h"
 
@@ -22,6 +21,7 @@
 
 #include <util/base36.h>
 #include <util/functions.h>
+#include "util/keyword.h"
 #include <util/language.h>
 #include <util/message.h>
 #include <util/rand.h>
diff --git a/src/bind_process.c b/src/bind_process.c
index 58f90076f..f9f99284e 100755
--- a/src/bind_process.c
+++ b/src/bind_process.c
@@ -4,20 +4,22 @@
 
 #include "bind_process.h"
 
+#include "battle.h"
+#include "economy.h"
+#include "laws.h"
+#include "magic.h"
+#include "market.h"
+#include "move.h"
+#include "study.h"
+
 #include <kernel/alliance.h>
 #include <kernel/config.h>
 #include <kernel/order.h>
 #include <kernel/region.h>
 #include <kernel/terrain.h>
 #include <kernel/unit.h>
-#include "battle.h"
-#include "economy.h"
-#include "keyword.h"
-#include "laws.h"
-#include "magic.h"
-#include "market.h"
-#include "move.h"
-#include "study.h"
+
+#include "util/keyword.h"
 
 #define PROC_LAND_REGION 0x0001
 #define PROC_LONG_ORDER 0x0002
diff --git a/src/creport.test.c b/src/creport.test.c
index bacf8def0..6bd5bfba8 100644
--- a/src/creport.test.c
+++ b/src/creport.test.c
@@ -3,7 +3,6 @@
 #include "move.h"
 #include "spy.h"
 #include "travelthru.h"
-#include "keyword.h"
 
 #include <kernel/ally.h>
 #include <kernel/building.h>
@@ -17,6 +16,7 @@
 #include <kernel/spell.h>
 #include <kernel/spellbook.h>
 
+#include "util/keyword.h"
 #include <util/language.h>
 #include <util/lists.h>
 #include <util/message.h>
diff --git a/src/items.c b/src/items.c
index 665220e8f..72bd6d713 100644
--- a/src/items.c
+++ b/src/items.c
@@ -5,7 +5,6 @@
 
 #include "alchemy.h"
 #include "skill.h"
-#include "keyword.h"
 #include "direction.h"
 #include "study.h"
 #include "economy.h"
@@ -35,6 +34,7 @@
 
 #include <kernel/attrib.h>
 #include <kernel/event.h>
+#include <util/keyword.h>
 #include <util/macros.h>
 #include <util/parser.h>
 #include <util/rand.h>
diff --git a/src/jsonconf.c b/src/jsonconf.c
index dc11ee563..ff442f990 100644
--- a/src/jsonconf.c
+++ b/src/jsonconf.c
@@ -32,6 +32,7 @@ without prior permission by the authors of Eressea.
 #include "kernel/attrib.h"
 #include "util/crmessage.h"
 #include "util/functions.h"
+#include "util/keyword.h"
 #include "util/language.h"
 #include "util/log.h"
 #include "util/message.h"
@@ -42,7 +43,6 @@ without prior permission by the authors of Eressea.
 
 /* game modules */
 #include "direction.h"
-#include "keyword.h"
 #include "move.h"
 #include "prefix.h"
 #include "skill.h"
diff --git a/src/jsonconf.test.c b/src/jsonconf.test.c
index 9e0e8f6b6..1fc27d3e6 100644
--- a/src/jsonconf.test.c
+++ b/src/jsonconf.test.c
@@ -15,11 +15,11 @@
 #include "kernel/order.h"
 #include "kernel/terrain.h"
 
+#include "util/keyword.h"
 #include "util/language.h"
 
 #include "kernel/calendar.h"
 #include "direction.h"
-#include "keyword.h"
 #include "move.h"
 #include "prefix.h"
 
diff --git a/src/kernel/config.c b/src/kernel/config.c
index e31564b8d..842324fe8 100644
--- a/src/kernel/config.c
+++ b/src/kernel/config.c
@@ -33,7 +33,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include "faction.h"
 #include "group.h"
 #include "item.h"
-#include "keyword.h"
 #include "messages.h"
 #include "move.h"
 #include "objtypes.h"
@@ -51,9 +50,11 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
 /* util includes */
 #include <kernel/attrib.h>
+#include <kernel/event.h>
+
 #include <util/base36.h>
 #include <util/crmessage.h>
-#include <kernel/event.h>
+#include <util/keyword.h>
 #include <util/language.h>
 #include <util/functions.h>
 #include <util/log.h>
diff --git a/src/kernel/order.c b/src/kernel/order.c
index e30ea6097..6015b823d 100644
--- a/src/kernel/order.c
+++ b/src/kernel/order.c
@@ -15,9 +15,9 @@
 #include "order.h"
 
 #include "skill.h"
-#include "keyword.h"
 
 #include <util/base36.h>
+#include "util/keyword.h"
 #include <util/language.h>
 #include <util/log.h>
 #include <util/parser.h>
diff --git a/src/kernel/order.h b/src/kernel/order.h
index c5406b39e..ca57d0179 100644
--- a/src/kernel/order.h
+++ b/src/kernel/order.h
@@ -13,7 +13,8 @@
 #ifndef KRNL_ORDER_H
 #define KRNL_ORDER_H
 
-#include "keyword.h"
+#include <util/keyword.h>
+
 #include <stddef.h>
 #include <stdbool.h>
 
diff --git a/src/laws.c b/src/laws.c
index 67e4567a9..8cec1e51b 100644
--- a/src/laws.c
+++ b/src/laws.c
@@ -29,7 +29,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include "automate.h"
 #include "battle.h"
 #include "economy.h"
-#include "keyword.h"
 #include "market.h"
 #include "morale.h"
 #include "monsters.h"
@@ -75,6 +74,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <util/base36.h>
 #include <kernel/event.h>
 #include <util/goodies.h>
+#include "util/keyword.h"
 #include <util/language.h>
 #include <util/lists.h>
 #include <util/log.h>
diff --git a/src/monsters.c b/src/monsters.c
index 505c6c272..867d601c6 100644
--- a/src/monsters.c
+++ b/src/monsters.c
@@ -27,17 +27,18 @@
 #include "give.h"
 #include "guard.h"
 #include "laws.h"
-#include "keyword.h"
 #include "study.h"
 #include "move.h"
 
 /* kernel includes */
+#include "kernel/attrib.h"
 #include "kernel/build.h"
 #include "kernel/building.h"
 #include "kernel/calendar.h"
 #include "kernel/config.h"
 #include "kernel/curse.h"
 #include "kernel/equipment.h"
+#include "kernel/event.h"
 #include "kernel/faction.h"
 #include "kernel/item.h"
 #include "kernel/messages.h"
@@ -52,10 +53,9 @@
 #include "kernel/unit.h"
 
 /* util includes */
-#include <kernel/attrib.h>
 #include <util/base36.h>
-#include <kernel/event.h>
-#include <util/language.h>
+#include "util/keyword.h"
+#include "util/language.h"
 #include <util/lists.h>
 #include <util/log.h>
 #include <util/rand.h>
diff --git a/src/piracy.c b/src/piracy.c
index 86b9b4904..b7307c070 100644
--- a/src/piracy.c
+++ b/src/piracy.c
@@ -2,10 +2,10 @@
 #include "piracy.h"
 
 #include "direction.h"
-#include "keyword.h"
 #include "move.h"
 
 #include <kernel/ally.h>
+#include <kernel/attrib.h>
 #include <kernel/faction.h>
 #include <kernel/messages.h>
 #include <kernel/order.h>
@@ -15,9 +15,9 @@
 #include <kernel/terrain.h>
 #include <kernel/unit.h>
 
-#include <kernel/attrib.h>
 #include <util/base36.h>
 #include <util/goodies.h>
+#include "util/keyword.h"
 #include <util/language.h>
 #include <util/parser.h>
 #include <util/rng.h>
diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt
index 4258a5edc..61e2cf745 100644
--- a/src/util/CMakeLists.txt
+++ b/src/util/CMakeLists.txt
@@ -10,11 +10,13 @@ base36.test.c
 # filereader.test.c
 functions.test.c
 # goodies.test.c
+keyword.test.c
 language.test.c
 # lists.test.c
 # log.test.c
 message.test.c
 # nrmessage.test.c
+# order_parser.test.c
 parser.test.c
 password.test.c
 # rand.test.c
@@ -37,12 +39,14 @@ dice.c
 filereader.c
 functions.c
 goodies.c
+keyword.c
 language.c
 lists.c
 log.c
 message.c
 mt19937ar.c
 nrmessage.c
+order_parser.c
 parser.c
 password.c
 path.c
diff --git a/src/keyword.c b/src/util/keyword.c
similarity index 100%
rename from src/keyword.c
rename to src/util/keyword.c
diff --git a/src/keyword.h b/src/util/keyword.h
similarity index 100%
rename from src/keyword.h
rename to src/util/keyword.h
diff --git a/src/keyword.test.c b/src/util/keyword.test.c
similarity index 100%
rename from src/keyword.test.c
rename to src/util/keyword.test.c
diff --git a/src/util/order_parser.c b/src/util/order_parser.c
new file mode 100644
index 000000000..691686276
--- /dev/null
+++ b/src/util/order_parser.c
@@ -0,0 +1,33 @@
+#ifdef _MSC_VER
+#include <platform.h>
+#endif
+
+#include "order_parser.h"
+
+#include <stdlib.h>
+
+struct OrderParserStruct {
+    void *m_userData;
+    char *m_buffer;
+    char *m_bufferPtr;
+    const char *m_bufferEnd;
+    OP_FactionHandler m_factionHandler;
+    OP_UnitHandler m_unitHandler;
+    OP_OrderHandler m_orderHandler;
+    enum CR_Error m_errorCode;
+    int m_lineNumber;
+};
+
+OP_Parser OP_ParserCreate(void)
+{
+    return NULL;
+}
+
+void OP_ParserFree(OP_Parser op) {
+    free(op);
+}
+
+enum OP_Status OP_Parse(OP_Parser op, const char *s, int len, int isFinal)
+{
+    return OP_STATUS_OK;
+}
diff --git a/src/util/order_parser.h b/src/util/order_parser.h
new file mode 100644
index 000000000..ee98b72a6
--- /dev/null
+++ b/src/util/order_parser.h
@@ -0,0 +1,34 @@
+#pragma once
+/* 
+ * +-------------------+  Christian Schlittchen <corwin@amber.kn-bremen.de>
+ * |                   |  Enno Rehling <enno@eressea.de>
+ * | Eressea PBEM host |  Katja Zedel <katze@felidae.kn-bremen.de>
+ * | (c) 1998 - 2007   |
+ * |                   |  This program may not be used, modified or distributed
+ * +-------------------+  without prior permission by the authors of Eressea.
+ *
+ */
+
+#ifndef UTIL_ORDER_PARSER_H
+#define UTIL_ORDER_PARSER_H
+
+#include <stddef.h>
+#include <stdbool.h>
+
+struct OrderParserStruct;
+typedef struct OrderParserStruct *OP_Parser;
+
+enum OP_Status {
+    OP_STATUS_ERROR = 0,
+    OP_STATUS_OK = 1
+};
+
+typedef void(*OP_FactionHandler) (void *userData, int no, const char *password);
+typedef void(*OP_UnitHandler) (void *userData, int no);
+typedef void(*OP_OrderHandler) (void *userData, const char *str, size_t len);
+
+OP_Parser OP_ParserCreate(void);
+void OP_ParserFree(OP_Parser op);
+enum OP_Status OP_Parse(OP_Parser op, const char *s, int len, int isFinal);
+
+#endif
diff --git a/src/util/parser.c b/src/util/parser.c
index 1ba913c2c..edcb5e3d6 100644
--- a/src/util/parser.c
+++ b/src/util/parser.c
@@ -1,4 +1,6 @@
+#ifdef _MSC_VER
 #include <platform.h>
+#endif
 #include "parser.h"
 #include "unicode.h"
 #include "base36.h"

From d3a37179efd165d5ebb0c92d39346519ae3d0348 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sat, 29 Sep 2018 19:32:39 +0200
Subject: [PATCH 56/81] add param.[hc], at last.

---
 src/economy.c            |   8 ++-
 src/give.c               |   5 +-
 src/give.test.c          |   1 +
 src/kernel/build.c       |   7 +-
 src/kernel/build.test.c  |  23 ++++---
 src/kernel/building.c    |   1 +
 src/kernel/config.c      | 132 +-------------------------------------
 src/kernel/config.h      |   9 ---
 src/kernel/config.test.c |   5 +-
 src/kernel/order.c       |   1 +
 src/kernel/order.test.c  |   1 +
 src/kernel/ship.c        |   1 +
 src/kernel/types.h       |  54 ----------------
 src/kernel/unit.c        |  15 ++---
 src/laws.c               |  13 +++-
 src/laws.h               |   5 +-
 src/laws.test.c          |   1 +
 src/magic.c              |   1 +
 src/move.c               |   5 +-
 src/orderfile.c          |  25 +++++---
 src/renumber.c           |   5 +-
 src/renumber.test.c      |   1 +
 src/report.c             |   7 +-
 src/reports.test.c       |   2 +-
 src/skill.c              |   2 +
 src/spy.c                |   3 +-
 src/spy.test.c           |   2 +
 src/study.c              |   3 +-
 src/tests.c              |   6 +-
 src/tests.h              |   5 +-
 src/util/CMakeLists.txt  |   2 +
 src/util/keyword.h       |   1 -
 src/util/param.c         | 134 +++++++++++++++++++++++++++++++++++++++
 src/util/param.h         |  77 ++++++++++++++++++++++
 34 files changed, 317 insertions(+), 246 deletions(-)
 create mode 100644 src/util/param.c
 create mode 100644 src/util/param.h

diff --git a/src/economy.c b/src/economy.c
index 15b907a25..1d3f6685f 100644
--- a/src/economy.c
+++ b/src/economy.c
@@ -20,7 +20,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #ifdef _MSC_VER
 #include <platform.h>
 #endif
-#include <kernel/config.h>
+
 #include "economy.h"
 
 #include "alchemy.h"
@@ -45,10 +45,13 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
 /* kernel includes */
 #include "kernel/ally.h"
+#include "kernel/attrib.h"
 #include "kernel/building.h"
 #include "kernel/calendar.h"
+#include "kernel/config.h"
 #include "kernel/curse.h"
 #include "kernel/equipment.h"
+#include "kernel/event.h"
 #include "kernel/faction.h"
 #include "kernel/item.h"
 #include "kernel/messages.h"
@@ -64,13 +67,12 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include "kernel/unit.h"
 
 /* util includes */
-#include <kernel/attrib.h>
 #include <util/base36.h>
-#include <kernel/event.h>
 #include <util/goodies.h>
 #include <util/language.h>
 #include <util/lists.h>
 #include <util/log.h>
+#include "util/param.h"
 #include <util/parser.h>
 #include <util/rng.h>
 
diff --git a/src/give.c b/src/give.c
index 02d5c622d..4b1dbb0ac 100644
--- a/src/give.c
+++ b/src/give.c
@@ -25,6 +25,8 @@
 #include <attributes/racename.h>
 
  /* kernel includes */
+#include <kernel/attrib.h>
+#include <kernel/event.h>
 #include <kernel/ally.h>
 #include <kernel/build.h>
 #include <kernel/curse.h>
@@ -41,11 +43,10 @@
 #include <kernel/unit.h>
 
 /* util includes */
-#include <kernel/attrib.h>
 #include <util/base36.h>
-#include <kernel/event.h>
 #include <util/log.h>
 #include <util/macros.h>
+#include <util/param.h>
 #include <util/parser.h>
 
 /* libc includes */
diff --git a/src/give.test.c b/src/give.test.c
index 9c07c8cd0..06c0ecf96 100644
--- a/src/give.test.c
+++ b/src/give.test.c
@@ -16,6 +16,7 @@
 #include <util/base36.h>
 #include <util/language.h>
 #include <util/message.h>
+#include <util/param.h>
 
 #include <CuTest.h>
 #include <tests.h>
diff --git a/src/kernel/build.c b/src/kernel/build.c
index 82c629b0b..a3b1c0e50 100644
--- a/src/kernel/build.c
+++ b/src/kernel/build.c
@@ -33,10 +33,12 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 /* kernel includes */
 #include <kernel/ally.h>
 #include <kernel/alliance.h>
-#include <kernel/connection.h>
+#include <kernel/attrib.h>
 #include <kernel/building.h>
 #include <kernel/config.h>
+#include <kernel/connection.h>
 #include <kernel/curse.h>
+#include <kernel/event.h>
 #include <kernel/faction.h>
 #include <kernel/group.h>
 #include <kernel/item.h>
@@ -52,12 +54,11 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <kernel/unit.h>
 
 /* from libutil */
-#include <kernel/attrib.h>
 #include <util/base36.h>
-#include <kernel/event.h>
 #include <util/goodies.h>
 #include <util/language.h>
 #include <util/log.h>
+#include <util/param.h>
 #include <util/parser.h>
 #include <util/resolve.h>
 
diff --git a/src/kernel/build.test.c b/src/kernel/build.test.c
index 9bae742c2..2607b2dfb 100644
--- a/src/kernel/build.test.c
+++ b/src/kernel/build.test.c
@@ -1,19 +1,24 @@
+#ifdef _MSC_VER
 #include <platform.h>
-#include <kernel/config.h>
+#endif
 
-#include <kernel/messages.h>
 #include "alchemy.h"
-#include "types.h"
 #include "build.h"
-#include "guard.h"
-#include "order.h"
-#include "unit.h"
 #include "building.h"
+#include "config.h"
 #include "faction.h"
-#include "region.h"
-#include "race.h"
+#include "guard.h"
 #include "item.h"
-#include <util/language.h>
+#include "messages.h"
+#include "order.h"
+#include "race.h"
+#include "region.h"
+#include "types.h"
+#include "unit.h"
+
+#include "util/language.h"
+#include "util/param.h"
+
 #include <CuTest.h>
 #include <tests.h>
 
diff --git a/src/kernel/building.c b/src/kernel/building.c
index 215c304e7..d97085345 100644
--- a/src/kernel/building.c
+++ b/src/kernel/building.c
@@ -45,6 +45,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <kernel/gamedata.h>
 #include <util/language.h>
 #include <util/log.h>
+#include <util/param.h>
 #include <util/resolve.h>
 #include <util/strings.h>
 #include <util/umlaut.h>
diff --git a/src/kernel/config.c b/src/kernel/config.c
index 842324fe8..75601e831 100644
--- a/src/kernel/config.c
+++ b/src/kernel/config.c
@@ -60,6 +60,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <util/log.h>
 #include <util/lists.h>
 #include <util/macros.h>
+#include <util/param.h>
 #include <util/parser.h>
 #include <util/path.h>
 #include <util/rand.h>
@@ -92,54 +93,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #endif
 struct settings global;
 
-const char *parameters[MAXPARAMS] = {
-    "LOCALE",
-    "ALLES",
-    "JEDEM",
-    "BAUERN",
-    "BURG",
-    "EINHEIT",
-    "PRIVAT",
-    "HINTEN",
-    "KOMMANDO",
-    "KRAEUTER",
-    "NICHT",
-    "NAECHSTER",
-    "PARTEI",
-    "ERESSEA",
-    "PERSONEN",
-    "REGION",
-    "SCHIFF",
-    "SILBER",
-    "STRASSEN",
-    "TEMP",
-    "FLIEHE",
-    "GEBAEUDE",
-    "GIB",                        /* HELFE GIB */
-    "KAEMPFE",
-    "DURCHREISE",
-    "BEWACHE",
-    "ZAUBER",
-    "PAUSE",
-    "VORNE",
-    "AGGRESSIV",
-    "DEFENSIV",
-    "STUFE",
-    "HELFE",
-    "FREMDES",
-    "AURA",
-    "HINTER",
-    "VOR",
-    "ANZAHL",
-    "GEGENSTAENDE",
-    "TRAENKE",
-    "GRUPPE",
-    "PARTEITARNUNG",
-    "BAEUME",
-    "ALLIANZ",
-    "AUTO"
-};
-
 int findoption(const char *s, const struct locale *lang)
 {
     void **tokens = get_translations(lang, UT_OPTIONS);
@@ -151,78 +104,6 @@ int findoption(const char *s, const struct locale *lang)
     return NODIRECTION;
 }
 
-param_t findparam(const char *s, const struct locale * lang)
-{
-    param_t result = NOPARAM;
-    char buffer[64];
-    char * str = s ? transliterate(buffer, sizeof(buffer) - sizeof(int), s) : 0;
-
-    if (str && *str) {
-        int i;
-        void * match;
-        void **tokens = get_translations(lang, UT_PARAMS);
-        critbit_tree *cb = (critbit_tree *)*tokens;
-        if (!cb) {
-            log_warning("no parameters defined in locale %s", locale_name(lang));
-        }
-        else if (cb_find_prefix(cb, str, strlen(str), &match, 1, 0)) {
-            cb_get_kv(match, &i, sizeof(int));
-            result = (param_t)i;
-        }
-    }
-    return result;
-}
-
-param_t findparam_block(const char *s, const struct locale *lang, bool any_locale)
-{
-    param_t p;
-    if (!s || s[0] == '@') {
-        return NOPARAM;
-    }
-    p = findparam(s, lang);
-    if (any_locale && p==NOPARAM) {
-        const struct locale *loc;
-        for (loc=locales;loc;loc=nextlocale(loc)) {
-            if (loc!=lang) {
-                p = findparam(s, loc);
-                if (p==P_FACTION || p==P_GAMENAME) {
-                    break;
-                }
-            }
-        }
-    }
-    return p;
-}
-
-param_t findparam_ex(const char *s, const struct locale * lang)
-{
-    param_t result = findparam(s, lang);
-
-    if (result == NOPARAM) {
-        const building_type *btype = findbuildingtype(s, lang);
-        if (btype != NULL)
-            return P_GEBAEUDE;
-    }
-    return (result == P_BUILDING) ? P_GEBAEUDE : result;
-}
-
-bool isparam(const char *s, const struct locale * lang, param_t param)
-{
-    assert(s);
-    if (s[0] > '@') {
-        param_t p = (param == P_GEBAEUDE) ? findparam_ex(s, lang) : findparam(s, lang);
-        return p == param;
-    }
-    return false;
-}
-
-param_t getparam(const struct locale * lang)
-{
-    char token[64];
-    const char *s = gettoken(token, sizeof(token));
-    return s ? findparam(s, lang) : NOPARAM;
-}
-
 /* -- Erschaffung neuer Einheiten ------------------------------ */
 
 static const char *forbidden[] = { "t", "te", "tem", "temp", NULL };
@@ -268,17 +149,6 @@ int newcontainerid(void)
     return random_no;
 }
 
-static const char * parameter_key(int i)
-{
-    assert(i < MAXPARAMS && i >= 0);
-    return parameters[i];
-}
-
-void init_parameters(struct locale *lang) {
-    init_translations(lang, UT_PARAMS, parameter_key, MAXPARAMS);
-}
-
-
 void init_terrains_translation(const struct locale *lang) {
     void **tokens;
     const terrain_type *terrain;
diff --git a/src/kernel/config.h b/src/kernel/config.h
index e104d4a1a..95df10ae9 100644
--- a/src/kernel/config.h
+++ b/src/kernel/config.h
@@ -44,12 +44,6 @@ extern "C" {
 
     int findoption(const char *s, const struct locale *lang);
 
-    param_t findparam(const char *s, const struct locale *lang);
-    param_t findparam_block(const char *s, const struct locale *lang, bool any_locale);
-    param_t findparam_ex(const char *s, const struct locale * lang);
-    bool isparam(const char *s, const struct locale * lang, param_t param);
-    param_t getparam(const struct locale *lang);
-
     const char * game_name(void);
     const char * game_mailcmd(void);
     int game_id(void);
@@ -132,12 +126,9 @@ extern "C" {
 
     struct order *default_order(const struct locale *lang);
 
-    void init_parameters(struct locale *lang);
-
     void free_gamedata(void);
     void free_config(void);
 
-    extern const char *parameters[];
     extern settings global;
 
 #ifdef __cplusplus
diff --git a/src/kernel/config.test.c b/src/kernel/config.test.c
index e060a838e..f5d29877a 100644
--- a/src/kernel/config.test.c
+++ b/src/kernel/config.test.c
@@ -5,8 +5,11 @@
 #include <kernel/terrain.h>
 #include <kernel/unit.h>
 #include <kernel/order.h>
-#include <util/language.h>
+
 #include <util/base36.h>
+#include <util/language.h>
+#include <util/param.h>
+
 #include <kernel/attrib.h>
 
 #include <iniparser.h>
diff --git a/src/kernel/order.c b/src/kernel/order.c
index 6015b823d..c0c1e82fb 100644
--- a/src/kernel/order.c
+++ b/src/kernel/order.c
@@ -20,6 +20,7 @@
 #include "util/keyword.h"
 #include <util/language.h>
 #include <util/log.h>
+#include <util/param.h>
 #include <util/parser.h>
 #include <util/strings.h>
 
diff --git a/src/kernel/order.test.c b/src/kernel/order.test.c
index c4a55177b..d1dd6a371 100644
--- a/src/kernel/order.test.c
+++ b/src/kernel/order.test.c
@@ -5,6 +5,7 @@
 #include <kernel/skills.h>
 #include <kernel/unit.h>
 
+#include "util/param.h"
 #include <util/parser.h>
 #include <util/language.h>
 
diff --git a/src/kernel/ship.c b/src/kernel/ship.c
index 20ed49d05..6fcea4935 100644
--- a/src/kernel/ship.c
+++ b/src/kernel/ship.c
@@ -40,6 +40,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <util/language.h>
 #include <util/lists.h>
 #include <util/log.h>
+#include <util/param.h>
 #include <util/strings.h>
 #include <util/umlaut.h>
 
diff --git a/src/kernel/types.h b/src/kernel/types.h
index 48a4326fa..d4f46ae8d 100644
--- a/src/kernel/types.h
+++ b/src/kernel/types.h
@@ -83,58 +83,6 @@ typedef enum {
   ST_FLEE
 } status_t;
 
-/* ----------------- Parameter --------------------------------- */
-
-typedef enum {
-  P_LOCALE,
-  P_ANY,
-  P_EACH,
-  P_PEASANT,
-  P_BUILDING,
-  P_UNIT,
-  P_PRIVAT,
-  P_BEHIND,
-  P_CONTROL,
-  P_HERBS,
-  P_NOT,
-  P_NEXT,
-  P_FACTION,
-  P_GAMENAME,
-  P_PERSON,
-  P_REGION,
-  P_SHIP,
-  P_MONEY,
-  P_ROAD,
-  P_TEMP,
-  P_FLEE,
-  P_GEBAEUDE,
-  P_GIVE,
-  P_FIGHT,
-  P_TRAVEL,
-  P_GUARD,
-  P_ZAUBER,
-  P_PAUSE,
-  P_VORNE,
-  P_AGGRO,
-  P_CHICKEN,
-  P_LEVEL,
-  P_HELP,
-  P_FOREIGN,
-  P_AURA,
-  P_AFTER,
-  P_BEFORE,
-  P_NUMBER,
-  P_ITEMS,
-  P_POTIONS,
-  P_GROUP,
-  P_FACTIONSTEALTH,
-  P_TREES,
-  P_ALLIANCE,
-  P_AUTO,
-  MAXPARAMS,
-  NOPARAM 
-} param_t;
-
 typedef enum {                  /* Fehler und Meldungen im Report */
   MSG_BATTLE,
   MSG_EVENT,
@@ -156,8 +104,6 @@ enum {                          /* Message-Level */
   ML_MAX
 };
 
-extern const char *parameters[MAXPARAMS];
-
 /* --------------- Reports Typen ------------------------------- */
 
 enum {
diff --git a/src/kernel/unit.c b/src/kernel/unit.c
index 00d0aeece..9b6c3e9ee 100644
--- a/src/kernel/unit.c
+++ b/src/kernel/unit.c
@@ -21,12 +21,16 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include "unit.h"
 
 #include "ally.h"
+#include "attrib.h"
 #include "building.h"
 #include "calendar.h"
-#include "faction.h"
-#include "group.h"
 #include "connection.h"
 #include "curse.h"
+#include "event.h"
+#include "faction.h"
+#include "gamedata.h"
+#include "group.h"
+#include "guard.h"
 #include "item.h"
 #include "move.h"
 #include "order.h"
@@ -47,18 +51,13 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <spells/unitcurse.h>
 #include <spells/regioncurse.h>
 
-#include "guard.h"
-
 /* util includes */
-#include <kernel/attrib.h>
 #include <util/base36.h>
-#include <kernel/event.h>
-#include <kernel/gamedata.h>
-#include <util/strings.h>
 #include <util/language.h>
 #include <util/lists.h>
 #include <util/log.h>
 #include <util/macros.h>
+#include <util/param.h>
 #include <util/parser.h>
 #include <util/rand.h>
 #include <util/resolve.h>
diff --git a/src/laws.c b/src/laws.c
index 8cec1e51b..7e2250a59 100644
--- a/src/laws.c
+++ b/src/laws.c
@@ -80,6 +80,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <util/log.h>
 #include <util/macros.h>
 #include <util/message.h>
+#include <util/param.h>
 #include <util/parser.h>
 #include <util/password.h>
 #include <util/path.h>
@@ -127,7 +128,17 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #define DMRISE         0.1F     /* weekly chance that demand goes up */
 #define DMRISEHAFEN    0.2F     /* weekly chance that demand goes up with harbor */
 
-/* - exported global symbols ----------------------------------- */
+param_t findparam_ex(const char *s, const struct locale * lang)
+{
+    param_t result = findparam(s, lang);
+
+    if (result == NOPARAM) {
+        const building_type *btype = findbuildingtype(s, lang);
+        if (btype != NULL)
+            return P_GEBAEUDE;
+    }
+    return (result == P_BUILDING) ? P_GEBAEUDE : result;
+}
 
 int NewbieImmunity(void)
 {
diff --git a/src/laws.h b/src/laws.h
index 383b099ae..c30479b38 100755
--- a/src/laws.h
+++ b/src/laws.h
@@ -19,13 +19,14 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #ifndef H_GC_LAWS
 #define H_GC_LAWS
 
-#include <kernel/types.h>
 #include <stdbool.h>
 
 #ifdef __cplusplus
 extern "C" {
 #endif
+    enum param_t;
 
+    struct locale;
     struct unit;
     struct region;
     struct building;
@@ -115,6 +116,8 @@ extern "C" {
     bool IsImmune(const struct faction *f);
     bool help_enter(struct unit *uo, struct unit *u);
 
+    enum param_t findparam_ex(const char *s, const struct locale * lang);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/laws.test.c b/src/laws.test.c
index 5c799a393..774ed6ecf 100644
--- a/src/laws.test.c
+++ b/src/laws.test.c
@@ -24,6 +24,7 @@
 #include <util/base36.h>
 #include <util/language.h>
 #include <util/message.h>
+#include <util/param.h>
 #include <util/rand.h>
 
 #include <CuTest.h>
diff --git a/src/magic.c b/src/magic.c
index 047ed167b..99a9ecf86 100644
--- a/src/magic.c
+++ b/src/magic.c
@@ -70,6 +70,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <util/lists.h>
 #include <util/log.h>
 #include <util/macros.h>
+#include <util/param.h>
 #include <util/parser.h>
 #include <util/rand.h>
 #include <util/resolve.h>
diff --git a/src/move.c b/src/move.c
index 124b846ca..222588651 100644
--- a/src/move.c
+++ b/src/move.c
@@ -23,6 +23,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
 /* kernel includes */
 #include "kernel/ally.h"
+#include "kernel/attrib.h"
 #include "kernel/build.h"
 #include "kernel/building.h"
 #include "kernel/calendar.h"
@@ -30,6 +31,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include "kernel/connection.h"
 #include "kernel/curse.h"
 #include "kernel/faction.h"
+#include "kernel/gamedata.h"
 #include "kernel/item.h"
 #include "kernel/messages.h"
 #include "kernel/order.h"
@@ -72,13 +74,12 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
 /* util includes */
 #include <util/assert.h>
-#include <kernel/attrib.h>
 #include <util/base36.h>
-#include <kernel/gamedata.h>
 #include <util/language.h>
 #include <util/lists.h>
 #include <util/log.h>
 #include <util/macros.h>
+#include <util/param.h>
 #include <util/parser.h>
 #include <util/rand.h>
 #include <util/rng.h>
diff --git a/src/orderfile.c b/src/orderfile.c
index a2c7a6c87..97008f4db 100644
--- a/src/orderfile.c
+++ b/src/orderfile.c
@@ -1,5 +1,4 @@
 #include <platform.h>
-#include <kernel/config.h>
 #include "orderfile.h"
 
 #include "kernel/calendar.h"
@@ -8,12 +7,14 @@
 #include "kernel/order.h"
 #include "kernel/unit.h"
 
-#include <util/base36.h>
-#include <util/message.h>
-#include <util/language.h>
-#include <util/log.h>
-#include <util/filereader.h>
-#include <util/parser.h>
+#include "util/base36.h"
+#include "util/message.h"
+#include "util/language.h"
+#include "util/log.h"
+#include "util/filereader.h"
+#include "util/param.h"
+#include "util/parser.h"
+#include "util/order_parser.h"
 
 #include <assert.h>
 #include <stdio.h>
@@ -33,9 +34,9 @@ static unit *unitorders(input *in, faction *f)
     if (u && u->faction == f) {
         order **ordp;
 
-        if (!fval(u, UFL_ORDERS)) {
+        if (u->flags & UFL_ORDERS) {
             /* alle wiederholbaren, langen befehle werden gesichert: */
-            fset(u, UFL_ORDERS);
+            u->flags |= UFL_ORDERS;
             u->old_orders = u->orders;
             ordp = &u->old_orders;
             while (*ordp) {
@@ -125,7 +126,7 @@ static faction *factionorders(void)
     int fid = getid();
     faction *f = findfaction(fid);
 
-    if (f != NULL && !fval(f, FFL_NPC)) {
+    if (f != NULL && (f->flags & FFL_NPC) == 0) {
         char token[128];
         const char *pass = gettoken(token, sizeof(token));
 
@@ -151,6 +152,10 @@ int read_orders(input *in)
     int nfactions = 0;
     struct faction *f = NULL;
     const struct locale *lang = default_locale;
+    OP_Parser parser;
+
+    parser = OP_ParserCreate();
+    OP_ParserFree(parser);
 
     /* TODO: recognize UTF8 BOM */
     b = in->getbuf(in->data);
diff --git a/src/renumber.c b/src/renumber.c
index 8a72be2a5..a4653e1a0 100644
--- a/src/renumber.c
+++ b/src/renumber.c
@@ -1,6 +1,9 @@
 #include <platform.h>
 #include "renumber.h"
 
+#include "laws.h"
+
+#include <kernel/attrib.h>
 #include <kernel/config.h>
 #include <kernel/faction.h>
 #include <kernel/building.h>
@@ -9,8 +12,8 @@
 #include <kernel/order.h>
 #include <kernel/messages.h>
 
-#include <kernel/attrib.h>
 #include <util/base36.h>
+#include <util/param.h>
 #include <util/parser.h>
 
 #include <assert.h>
diff --git a/src/renumber.test.c b/src/renumber.test.c
index 98ca9b48b..8d44b92da 100644
--- a/src/renumber.test.c
+++ b/src/renumber.test.c
@@ -10,6 +10,7 @@
 #include <util/base36.h>
 #include <util/language.h>
 #include <util/message.h>
+#include <util/param.h>
 
 #include <stddef.h>
 #include <CuTest.h>
diff --git a/src/report.c b/src/report.c
index bc47cb1a4..1d40941c4 100644
--- a/src/report.c
+++ b/src/report.c
@@ -19,7 +19,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #ifdef _MSC_VER
 #include <platform.h>
 #endif
-#include <kernel/config.h>
 
 #include "report.h"
 #include "reports.h"
@@ -50,8 +49,11 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include "teleport.h"
 
 /* kernel includes */
+#include "kernel/alliance.h"
 #include "kernel/ally.h"
+#include "kernel/attrib.h"
 #include "kernel/calendar.h"
+#include "kernel/config.h"
 #include "kernel/connection.h"
 #include "kernel/build.h"
 #include "kernel/building.h"
@@ -74,10 +76,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include "kernel/terrain.h"
 #include "kernel/terrainid.h"
 #include "kernel/unit.h"
-#include "kernel/alliance.h"
 
 /* util includes */
-#include <kernel/attrib.h>
 #include <util/base36.h>
 #include "util/bsdstring.h"
 #include <util/goodies.h>
@@ -86,6 +86,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <util/log.h>
 #include <util/message.h>
 #include <util/nrmessage.h>
+#include "util/param.h"
 #include <util/rng.h>
 #include <util/strings.h>
 
diff --git a/src/reports.test.c b/src/reports.test.c
index 29f14c634..0f5ca6b1f 100644
--- a/src/reports.test.c
+++ b/src/reports.test.c
@@ -2,7 +2,7 @@
 #include "reports.h"
 
 #include "guard.h"
-#include "keyword.h"
+#include "util/keyword.h"
 #include "lighthouse.h"
 #include "laws.h"
 #include "move.h"
diff --git a/src/skill.c b/src/skill.c
index b279ab488..3d91a2598 100644
--- a/src/skill.c
+++ b/src/skill.c
@@ -5,6 +5,8 @@
 #include <util/umlaut.h>
 #include <util/language.h>
 #include <util/log.h>
+#include <util/param.h>
+
 #include <critbit.h>
 
 #include <string.h>
diff --git a/src/spy.c b/src/spy.c
index 98245e806..53a5b4321 100644
--- a/src/spy.c
+++ b/src/spy.c
@@ -27,6 +27,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include "study.h"
 
 /* kernel includes */
+#include <kernel/attrib.h>
 #include <kernel/config.h>
 #include <kernel/item.h>
 #include <kernel/faction.h>
@@ -44,8 +45,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <attributes/stealth.h>
 
 /* util includes */
-#include <kernel/attrib.h>
 #include <util/base36.h>
+#include <util/param.h>
 #include <util/parser.h>
 #include <util/rand.h>
 #include <util/rng.h>
diff --git a/src/spy.test.c b/src/spy.test.c
index dfe2886e7..d1f616fab 100644
--- a/src/spy.test.c
+++ b/src/spy.test.c
@@ -12,8 +12,10 @@
 #include <kernel/item.h>
 #include <kernel/messages.h>
 #include <kernel/attrib.h>
+
 #include <util/language.h>
 #include <util/message.h>
+#include "util/param.h"
 #include <util/crmessage.h>
 #include <tests.h>
 
diff --git a/src/study.c b/src/study.c
index a3dfa2e33..ff961dc13 100644
--- a/src/study.c
+++ b/src/study.c
@@ -32,6 +32,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <spells/regioncurse.h>
 
 #include <kernel/ally.h>
+#include <kernel/attrib.h>
 #include <kernel/building.h>
 #include <kernel/curse.h>
 #include <kernel/faction.h>
@@ -46,10 +47,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include <kernel/unit.h>
 
 /* util includes */
-#include <kernel/attrib.h>
 #include <util/base36.h>
 #include <util/language.h>
 #include <util/log.h>
+#include <util/param.h>
 #include <util/parser.h>
 #include <util/rand.h>
 #include <util/rng.h>
diff --git a/src/tests.c b/src/tests.c
index 2dc5bccc6..f270d9c58 100644
--- a/src/tests.c
+++ b/src/tests.c
@@ -1,11 +1,10 @@
 #include <platform.h>
 #include "tests.h"
-#include "keyword.h"
 #include "prefix.h"
 #include "reports.h"
-#include "kernel/calendar.h"
 #include "vortex.h"
 
+#include "kernel/calendar.h"
 #include <kernel/config.h>
 #include <kernel/alliance.h>
 #include <kernel/equipment.h>
@@ -24,11 +23,14 @@
 #include <kernel/spell.h>
 #include <kernel/spellbook.h>
 #include <kernel/terrain.h>
+
 #include <util/functions.h>
+#include "util/keyword.h"
 #include <util/language.h>
 #include <util/lists.h>
 #include <util/message.h>
 #include <util/log.h>
+#include "util/param.h"
 #include <util/rand.h>
 #include <util/assert.h>
 
diff --git a/src/tests.h b/src/tests.h
index 441db9e16..0f3af1972 100644
--- a/src/tests.h
+++ b/src/tests.h
@@ -1,7 +1,6 @@
 #ifndef ERESSEA_TESTS_H
 #define ERESSEA_TESTS_H
 
-#include <kernel/types.h>
 #include <stdlib.h>
 
 #ifdef __cplusplus
@@ -10,6 +9,8 @@ extern "C" {
 
     #define ASSERT_DBL_DELTA 0.001
 
+    enum param_t;
+
     struct region;
     struct unit;
     struct faction;
@@ -61,7 +62,7 @@ extern "C" {
     struct spell * test_create_spell(void);
     int test_set_item(struct unit * u, const struct item_type *itype, int value);
 
-    void test_translate_param(const struct locale *lang, param_t param, const char *text);
+    void test_translate_param(const struct locale *lang, enum param_t param, const char *text);
     const char * test_get_messagetype(const struct message *msg);
     struct message * test_find_messagetype_ex(struct message_list *msgs, const char *name, struct message *prev);
     struct message * test_find_messagetype(struct message_list *msgs, const char *name);
diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt
index 61e2cf745..b4d067f57 100644
--- a/src/util/CMakeLists.txt
+++ b/src/util/CMakeLists.txt
@@ -17,6 +17,7 @@ language.test.c
 message.test.c
 # nrmessage.test.c
 # order_parser.test.c
+# param.test.c
 parser.test.c
 password.test.c
 # rand.test.c
@@ -47,6 +48,7 @@ message.c
 mt19937ar.c
 nrmessage.c
 order_parser.c
+param.c
 parser.c
 password.c
 path.c
diff --git a/src/util/keyword.h b/src/util/keyword.h
index bd4ab02d0..7bb11c485 100644
--- a/src/util/keyword.h
+++ b/src/util/keyword.h
@@ -1,7 +1,6 @@
 #ifndef H_KEYWORD_H
 #define H_KEYWORD_H
 
-#include "kernel/types.h"
 #include <stdbool.h>
 
 #ifdef __cplusplus
diff --git a/src/util/param.c b/src/util/param.c
new file mode 100644
index 000000000..31066a4a9
--- /dev/null
+++ b/src/util/param.c
@@ -0,0 +1,134 @@
+#ifdef _MSC_VER
+#include <platform.h>
+#endif
+
+#include "language.h"
+#include "log.h"
+#include "param.h"
+#include "parser.h"
+#include "umlaut.h"
+
+#include <critbit.h>
+
+#include <assert.h>
+#include <string.h>
+
+const char *parameters[MAXPARAMS] = {
+    "LOCALE",
+    "ALLES",
+    "JEDEM",
+    "BAUERN",
+    "BURG",
+    "EINHEIT",
+    "PRIVAT",
+    "HINTEN",
+    "KOMMANDO",
+    "KRAEUTER",
+    "NICHT",
+    "NAECHSTER",
+    "PARTEI",
+    "ERESSEA",
+    "PERSONEN",
+    "REGION",
+    "SCHIFF",
+    "SILBER",
+    "STRASSEN",
+    "TEMP",
+    "FLIEHE",
+    "GEBAEUDE",
+    "GIB",                        /* HELFE GIB */
+    "KAEMPFE",
+    "DURCHREISE",
+    "BEWACHE",
+    "ZAUBER",
+    "PAUSE",
+    "VORNE",
+    "AGGRESSIV",
+    "DEFENSIV",
+    "STUFE",
+    "HELFE",
+    "FREMDES",
+    "AURA",
+    "HINTER",
+    "VOR",
+    "ANZAHL",
+    "GEGENSTAENDE",
+    "TRAENKE",
+    "GRUPPE",
+    "PARTEITARNUNG",
+    "BAEUME",
+    "ALLIANZ",
+    "AUTO"
+};
+
+param_t findparam(const char *s, const struct locale * lang)
+{
+    param_t result = NOPARAM;
+    char buffer[64];
+    char * str = s ? transliterate(buffer, sizeof(buffer) - sizeof(int), s) : 0;
+
+    if (str && *str) {
+        int i;
+        void * match;
+        void **tokens = get_translations(lang, UT_PARAMS);
+        critbit_tree *cb = (critbit_tree *)*tokens;
+        if (!cb) {
+            log_warning("no parameters defined in locale %s", locale_name(lang));
+        }
+        else if (cb_find_prefix(cb, str, strlen(str), &match, 1, 0)) {
+            cb_get_kv(match, &i, sizeof(int));
+            result = (param_t)i;
+        }
+    }
+    return result;
+}
+
+param_t findparam_block(const char *s, const struct locale *lang, bool any_locale)
+{
+    param_t p;
+    if (!s || s[0] == '@') {
+        return NOPARAM;
+    }
+    p = findparam(s, lang);
+    if (any_locale && p == NOPARAM) {
+        const struct locale *loc;
+        for (loc = locales; loc; loc = nextlocale(loc)) {
+            if (loc != lang) {
+                p = findparam(s, loc);
+                if (p == P_FACTION || p == P_GAMENAME) {
+                    break;
+                }
+            }
+        }
+    }
+    return p;
+}
+
+bool isparam(const char *s, const struct locale * lang, param_t param)
+{
+    assert(s);
+    assert(param != P_GEBAEUDE);
+    assert(param != P_BUILDING);
+    if (s[0] > '@') {
+        param_t p = findparam(s, lang);
+        return p == param;
+    }
+    return false;
+}
+
+param_t getparam(const struct locale * lang)
+{
+    char token[64];
+    const char *s = gettoken(token, sizeof(token));
+    return s ? findparam(s, lang) : NOPARAM;
+}
+
+static const char * parameter_key(int i)
+{
+    assert(i < MAXPARAMS && i >= 0);
+    return parameters[i];
+}
+
+void init_parameters(struct locale *lang) {
+    init_translations(lang, UT_PARAMS, parameter_key, MAXPARAMS);
+}
diff --git a/src/util/param.h b/src/util/param.h
new file mode 100644
index 000000000..42d34ee57
--- /dev/null
+++ b/src/util/param.h
@@ -0,0 +1,77 @@
+#pragma once
+
+#ifndef H_PARAM_H
+#define H_PARAM_H
+
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+    struct locale;
+
+    typedef enum param_t {
+        P_LOCALE,
+        P_ANY,
+        P_EACH,
+        P_PEASANT,
+        P_BUILDING,
+        P_UNIT,
+        P_PRIVAT,
+        P_BEHIND,
+        P_CONTROL,
+        P_HERBS,
+        P_NOT,
+        P_NEXT,
+        P_FACTION,
+        P_GAMENAME,
+        P_PERSON,
+        P_REGION,
+        P_SHIP,
+        P_MONEY,
+        P_ROAD,
+        P_TEMP,
+        P_FLEE,
+        P_GEBAEUDE,
+        P_GIVE,
+        P_FIGHT,
+        P_TRAVEL,
+        P_GUARD,
+        P_ZAUBER,
+        P_PAUSE,
+        P_VORNE,
+        P_AGGRO,
+        P_CHICKEN,
+        P_LEVEL,
+        P_HELP,
+        P_FOREIGN,
+        P_AURA,
+        P_AFTER,
+        P_BEFORE,
+        P_NUMBER,
+        P_ITEMS,
+        P_POTIONS,
+        P_GROUP,
+        P_FACTIONSTEALTH,
+        P_TREES,
+        P_ALLIANCE,
+        P_AUTO,
+        MAXPARAMS,
+        NOPARAM
+    } param_t;
+
+    extern const char *parameters[MAXPARAMS];
+
+    param_t findparam(const char *s, const struct locale *lang);
+    param_t findparam_block(const char *s, const struct locale *lang, bool any_locale);
+    bool isparam(const char *s, const struct locale * lang, param_t param);
+    param_t getparam(const struct locale *lang);
+
+    void init_parameters(struct locale *lang);
+
+#ifdef __cplusplus
+}
+#endif
+#endif

From b03da543b658dddbea4d7225f9b4a9692c4a5c5b Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sat, 29 Sep 2018 20:06:58 +0200
Subject: [PATCH 57/81] make findparam_ex part of laws, where building names
 are known.

---
 src/kernel/building.c | 60 ++++++++++++++++++++++++++++++-------------
 src/laws.test.c       | 22 ++++++++++++++++
 src/tests.c           |  4 ++-
 3 files changed, 67 insertions(+), 19 deletions(-)

diff --git a/src/kernel/building.c b/src/kernel/building.c
index d97085345..fe28b3752 100644
--- a/src/kernel/building.c
+++ b/src/kernel/building.c
@@ -129,14 +129,6 @@ static void free_buildingtype(void *ptr) {
     free(btype);
 }
 
-void free_buildingtypes(void) {
-    cb_clear(&cb_bldgtypes);
-    selist_foreach(buildingtypes, free_buildingtype);
-    selist_free(buildingtypes);
-    buildingtypes = 0;
-    ++bt_changes;
-}
-
 building_type *bt_get_or_create(const char *name)
 {
     assert(name && name[0]);
@@ -265,17 +257,28 @@ building *findbuilding(int i)
 
 static local_names *bnames;
 
-/* Find the building type for a given localized name (as seen by the user). Useful for parsing
- * orders. The inverse of locale_string(lang, btype->_name), sort of. */
-const building_type *findbuildingtype(const char *name,
-    const struct locale *lang)
-{
-    variant type;
-    local_names *bn = bnames;
+static void free_bnames() {
+    while (bnames) {
+        local_names *bn = bnames;
+        bnames = bnames->next;
+        freetokens(bn->names);
+        free(bn);
+    }
+}
 
+static local_names *get_bnames(const struct locale *lang)
+{
+    static int config;
+    local_names *bn;
+
+    if (bt_changed(&config)) {
+        free_bnames();
+    }
+    bn = bnames;
     while (bn) {
-        if (bn->lang == lang)
+        if (bn->lang == lang) {
             break;
+        }
         bn = bn->next;
     }
     if (!bn) {
@@ -292,14 +295,26 @@ const building_type *findbuildingtype(const char *name,
             const char *n = LOC(lang, btype->_name);
             if (!n) {
                 log_error("building type %s has no translation in %s",
-                          btype->_name, locale_name(lang));
-            } else {
+                    btype->_name, locale_name(lang));
+            }
+            else {
+                variant type;
                 type.v = (void *)btype;
                 addtoken((struct tnode **)&bn->names, n, type);
             }
         }
         bnames = bn;
     }
+    return bn;
+}
+
+/* Find the building type for a given localized name (as seen by the user). Useful for parsing
+ * orders. The inverse of locale_string(lang, btype->_name), sort of. */
+const building_type *findbuildingtype(const char *name,
+    const struct locale *lang)
+{
+    variant type;
+    local_names *bn = get_bnames(lang);
     if (findtoken(bn->names, name, &type) == E_TOK_NOMATCH)
         return NULL;
     return (const building_type *)type.v;
@@ -871,3 +886,12 @@ int cmp_current_owner(const building * b, const building * a)
     }
     return 0;
 }
+
+void free_buildingtypes(void) {
+    free_bnames();
+    cb_clear(&cb_bldgtypes);
+    selist_foreach(buildingtypes, free_buildingtype);
+    selist_free(buildingtypes);
+    buildingtypes = 0;
+    ++bt_changes;
+}
diff --git a/src/laws.test.c b/src/laws.test.c
index 774ed6ecf..bb26ed872 100644
--- a/src/laws.test.c
+++ b/src/laws.test.c
@@ -392,6 +392,27 @@ static void test_unit_limit(CuTest * tc)
     test_teardown();
 }
 
+static void test_findparam_ex(CuTest *tc)
+{
+    struct locale *lang;
+    struct building_type *btype;
+    test_setup();
+    lang = test_create_locale();
+    locale_setstring(lang, "temple", "TEMPEL");
+    btype = test_create_buildingtype("temple");
+
+    CuAssertIntEquals(tc, P_GEBAEUDE, findparam_ex("TEMPEL", lang));
+    CuAssertIntEquals(tc, P_GEBAEUDE, findparam_ex(
+        locale_string(lang, parameters[P_BUILDING], false), lang));
+    CuAssertIntEquals(tc, P_SHIP, findparam_ex(
+        locale_string(lang, parameters[P_SHIP], false), lang));
+    CuAssertIntEquals(tc, P_FACTION, findparam_ex(
+        locale_string(lang, parameters[P_FACTION], false), lang));
+    CuAssertIntEquals(tc, P_UNIT, findparam_ex(
+        locale_string(lang, parameters[P_UNIT], false), lang));
+    test_teardown();
+}
+
 static void test_maketemp(CuTest * tc)
 {
     faction *f;
@@ -1762,6 +1783,7 @@ CuSuite *get_laws_suite(void)
     CuSuite *suite = CuSuiteNew();
     SUITE_ADD_TEST(suite, test_maketemp_default_order);
     SUITE_ADD_TEST(suite, test_maketemp);
+    SUITE_ADD_TEST(suite, test_findparam_ex);
     SUITE_ADD_TEST(suite, test_nmr_warnings);
     SUITE_ADD_TEST(suite, test_ally_cmd);
     SUITE_ADD_TEST(suite, test_name_cmd);
diff --git a/src/tests.c b/src/tests.c
index f270d9c58..cad296e57 100644
--- a/src/tests.c
+++ b/src/tests.c
@@ -420,7 +420,9 @@ building_type * test_create_buildingtype(const char * name)
         con->materials[0].rtype = get_resourcetype(R_STONE);
     }
     if (default_locale) {
-        locale_setstring(default_locale, name, name);
+        if (locale_getstring(default_locale, name) == NULL) {
+            locale_setstring(default_locale, name, name);
+        }
     }
     return btype;
 }

From 965c8ce990d774e43644536c41c102e038d54913 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sat, 29 Sep 2018 21:19:24 +0200
Subject: [PATCH 58/81] start putting the new parser into the server.

---
 src/orderfile.c         | 148 ++++++++++++++++++++++++++++++++--------
 src/util/order_parser.c |  20 +++++-
 src/util/order_parser.h |   6 +-
 3 files changed, 145 insertions(+), 29 deletions(-)

diff --git a/src/orderfile.c b/src/orderfile.c
index 97008f4db..a4f47a4e3 100644
--- a/src/orderfile.c
+++ b/src/orderfile.c
@@ -20,6 +20,32 @@
 #include <stdio.h>
 #include <string.h>
 
+static void begin_orders(unit *u) {
+    if (u->flags & UFL_ORDERS) {
+        order **ordp;
+        /* alle wiederholbaren, langen befehle werden gesichert: */
+        u->flags |= UFL_ORDERS;
+        u->old_orders = u->orders;
+        ordp = &u->old_orders;
+        while (*ordp) {
+            order *ord = *ordp;
+            keyword_t kwd = getkeyword(ord);
+            if (!is_repeated(kwd)) {
+                *ordp = ord->next;
+                ord->next = NULL;
+                free_order(ord);
+            }
+            else {
+                ordp = &ord->next;
+            }
+        }
+    }
+    else {
+        free_orders(&u->orders);
+    }
+    u->orders = NULL;
+}
+
 static unit *unitorders(input *in, faction *f)
 {
     int i;
@@ -34,29 +60,7 @@ static unit *unitorders(input *in, faction *f)
     if (u && u->faction == f) {
         order **ordp;
 
-        if (u->flags & UFL_ORDERS) {
-            /* alle wiederholbaren, langen befehle werden gesichert: */
-            u->flags |= UFL_ORDERS;
-            u->old_orders = u->orders;
-            ordp = &u->old_orders;
-            while (*ordp) {
-                order *ord = *ordp;
-                keyword_t kwd = getkeyword(ord);
-                if (!is_repeated(kwd)) {
-                    *ordp = ord->next;
-                    ord->next = NULL;
-                    free_order(ord);
-                }
-                else {
-                    ordp = &ord->next;
-                }
-            }
-        }
-        else {
-            free_orders(&u->orders);
-        }
-        u->orders = 0;
-
+        begin_orders(u);
         ordp = &u->orders;
 
         for (;;) {
@@ -152,10 +156,6 @@ int read_orders(input *in)
     int nfactions = 0;
     struct faction *f = NULL;
     const struct locale *lang = default_locale;
-    OP_Parser parser;
-
-    parser = OP_ParserCreate();
-    OP_ParserFree(parser);
 
     /* TODO: recognize UTF8 BOM */
     b = in->getbuf(in->data);
@@ -231,8 +231,101 @@ static const char * file_getbuf(void *data)
     return getbuf(F, ENCODING_UTF8);
 }
 
+typedef struct parser_state {
+    unit *u;
+    faction *f;
+    order **next_order;
+} parser_state;
+
+static void handle_faction(void *userData, int no, const char *password) {
+    parser_state *state = (parser_state *)userData;
+    faction * f = state->f = findfaction(no);
+    if (!f) {
+        log_debug("orders for unknown faction %s", itoa36(no));
+    }
+    else {
+        if (!checkpasswd(f, password)) {
+            log_debug("invalid password for faction %s", itoa36(no));
+            ADDMSG(&f->msgs, msg_message("wrongpasswd", "password", password));
+        }
+    }
+}
+
+static void handle_unit(void *userData, int no) {
+    parser_state *state = (parser_state *)userData;
+    unit * u = findunit(no);
+
+    state->u = NULL;
+    if (!u) {
+        /* TODO: error message */
+    }
+    else if (u->faction != state->f) {
+        /* TODO: error message */
+    }
+    else {
+        state->u = u;
+        begin_orders(u);
+        state->next_order = &u->orders;
+    }
+}
+
+static void handle_order(void *userData, const char *str) {
+    parser_state *state = (parser_state *)userData;
+    unit * u = state->u;
+    order *ord;
+
+    ord = parse_order(str, u->faction->locale);
+    if (ord) {
+        *state->next_order = ord;
+        state->next_order = &ord->next;
+    }
+    else {
+        ADDMSG(&u->faction->msgs, msg_message("parse_error", "unit command", u, str));
+    }
+}
+
+
+int parseorders(FILE *F)
+{
+    char buf[2048];
+    int done = 0, err = 0;
+    OP_Parser parser;
+    parser_state state = { NULL, NULL };
+
+    parser = OP_ParserCreate();
+    if (!parser) {
+        /* TODO: error message */
+        return errno;
+    }
+    OP_SetUnitHandler(parser, handle_unit);
+    OP_SetFactionHandler(parser, handle_faction);
+    OP_SetOrderHandler(parser, handle_order);
+    OP_SetUserData(parser, &state);
+
+    while (!done) {
+        size_t len = (int)fread(buf, 1, sizeof(buf), F);
+        if (ferror(F)) {
+            /* TODO: error message */
+            err = errno;
+            break;
+        }
+        done = feof(F);
+        if (OP_Parse(parser, buf, len, done) == OP_STATUS_ERROR) {
+            /* TODO: error message */
+            err = -1;
+            break;
+        }
+    }
+    OP_ParserFree(parser);
+    return err;
+}
+
 int readorders(FILE *F)
 {
+#undef NEW_PARSER
+#ifdef NEW_PARSER
+    return parseorders(F);
+#else
     input in;
     int result;
 
@@ -240,4 +333,5 @@ int readorders(FILE *F)
     in.data = F;
     result = read_orders(&in);
     return result;
+#endif
 }
diff --git a/src/util/order_parser.c b/src/util/order_parser.c
index 691686276..363f12c92 100644
--- a/src/util/order_parser.c
+++ b/src/util/order_parser.c
@@ -18,9 +18,27 @@ struct OrderParserStruct {
     int m_lineNumber;
 };
 
+void OP_SetUnitHandler(OP_Parser op, OP_UnitHandler handler)
+{
+    op->m_unitHandler = handler;
+}
+
+void OP_SetFactionHandler(OP_Parser op, OP_FactionHandler handler) {
+    op->m_factionHandler = handler;
+}
+
+void OP_SetOrderHandler(OP_Parser op, OP_OrderHandler handler) {
+    op->m_orderHandler = handler;
+}
+
+void OP_SetUserData(OP_Parser op, void *userData) {
+    op->m_userData = userData;
+}
+
 OP_Parser OP_ParserCreate(void)
 {
-    return NULL;
+    OP_Parser parser = calloc(1, sizeof(struct OrderParserStruct));
+    return parser;
 }
 
 void OP_ParserFree(OP_Parser op) {
diff --git a/src/util/order_parser.h b/src/util/order_parser.h
index ee98b72a6..7600ee3da 100644
--- a/src/util/order_parser.h
+++ b/src/util/order_parser.h
@@ -25,10 +25,14 @@ enum OP_Status {
 
 typedef void(*OP_FactionHandler) (void *userData, int no, const char *password);
 typedef void(*OP_UnitHandler) (void *userData, int no);
-typedef void(*OP_OrderHandler) (void *userData, const char *str, size_t len);
+typedef void(*OP_OrderHandler) (void *userData, const char *str);
 
 OP_Parser OP_ParserCreate(void);
 void OP_ParserFree(OP_Parser op);
 enum OP_Status OP_Parse(OP_Parser op, const char *s, int len, int isFinal);
+void OP_SetUnitHandler(OP_Parser op, OP_UnitHandler handler);
+void OP_SetFactionHandler(OP_Parser op, OP_FactionHandler handler);
+void OP_SetOrderHandler(OP_Parser op, OP_OrderHandler handler);
+void OP_SetUserData(OP_Parser op, void *userData);
 
 #endif

From 4a6957378683831f7768d1ed9425c42953fb78f6 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sun, 30 Sep 2018 13:36:34 +0200
Subject: [PATCH 59/81] change database selection, fix in-memory db

---
 s/cmake-init       | 35 ++++++++++++++++++++++++++++++++++-
 src/CMakeLists.txt |  3 +++
 2 files changed, 37 insertions(+), 1 deletion(-)

diff --git a/s/cmake-init b/s/cmake-init
index 781db1ea7..eea222334 100755
--- a/s/cmake-init
+++ b/s/cmake-init
@@ -1,13 +1,46 @@
 #!/bin/sh
 
-ERESSEA_DB=db
+ERESSEA_DB=memory
 pkg-config --exists sqlite3 && ERESSEA_DB=sqlite
+
+GETOPT=getopt
+GETOPT_LONG=1
+
+if [ "Darwin" = "$(uname)" ] ; then
+  if [ -x "/usr/local/opt/gnu-getopt/bin/getopt" ] ; then
+    GETOPT="/usr/local/opt/gnu-getopt/bin/getopt"
+  else
+    GETOPT_LONG=0
+  fi
+fi
+
+if [ $GETOPT_LONG -eq 1 ]; then
+  options=$(${GETOPT} -o d: -l db: -- "$@")
+else # assume GNU getopt (long arguments)
+  options=$(${GETOPT} d: "$@")
+fi
+
 # Parse command line arguments
+eval set -- "$options"
+until [ -z "$1" ] ; do
+  case $1 in
+    -d|--db)
+      ERESSEA_DB=$2
+      shift
+    ;;
+    --) shift; break;;
+    (-*) echo "$0: error - unrecognized option $1" 1>&2; exit 1;;
+    (*) break;;
+  esac
+  shift
+done
 while [ ! -z "$1" ] ; do
 if [ "$1" = "--with-db" ] ; then
 ERESSEA_DB=db
 elif [ "$1" = "--with-sqlite" ] ; then
 ERESSEA_DB=sqlite
+elif [ "$1" = "--with-memory" ] ; then
+ERESSEA_DB=memory
 fi
 shift 1
 done
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index eacc879e5..8a7edbcc4 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -179,6 +179,9 @@ endif()
 
 add_library(version STATIC ${VERSION_SRC})
 add_library(game ${ERESSEA_SRC})
+
+#add_executable(checker ${CHECK_SRC})
+
 add_executable(eressea ${SERVER_SRC})
 if (IWYU_PATH)
 set_property(TARGET eressea PROPERTY C_INCLUDE_WHAT_YOU_USE ${IWYU_PATH})

From 0c6ec475987a589451a99786959c1aaff450f592 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sun, 30 Sep 2018 13:45:19 +0200
Subject: [PATCH 60/81] fix compilation

---
 src/kernel/building.c   | 2 +-
 src/laws.test.c         | 4 ++--
 src/move.test.c         | 6 +++---
 src/orderfile.c         | 1 +
 src/report.test.c       | 3 ++-
 src/util/order_parser.c | 2 +-
 src/util/order_parser.h | 6 ++++++
 7 files changed, 16 insertions(+), 8 deletions(-)

diff --git a/src/kernel/building.c b/src/kernel/building.c
index fe28b3752..f5698eaa9 100644
--- a/src/kernel/building.c
+++ b/src/kernel/building.c
@@ -257,7 +257,7 @@ building *findbuilding(int i)
 
 static local_names *bnames;
 
-static void free_bnames() {
+static void free_bnames(void) {
     while (bnames) {
         local_names *bn = bnames;
         bnames = bnames->next;
diff --git a/src/laws.test.c b/src/laws.test.c
index bb26ed872..e7951a7ce 100644
--- a/src/laws.test.c
+++ b/src/laws.test.c
@@ -395,11 +395,11 @@ static void test_unit_limit(CuTest * tc)
 static void test_findparam_ex(CuTest *tc)
 {
     struct locale *lang;
-    struct building_type *btype;
+
     test_setup();
     lang = test_create_locale();
     locale_setstring(lang, "temple", "TEMPEL");
-    btype = test_create_buildingtype("temple");
+    test_create_buildingtype("temple");
 
     CuAssertIntEquals(tc, P_GEBAEUDE, findparam_ex("TEMPEL", lang));
     CuAssertIntEquals(tc, P_GEBAEUDE, findparam_ex(
diff --git a/src/move.test.c b/src/move.test.c
index 4e9e4760d..e782bb748 100644
--- a/src/move.test.c
+++ b/src/move.test.c
@@ -2,12 +2,12 @@
 #include <stdlib.h>
 #include "move.h"
 
-#include "keyword.h"
 #include "lighthouse.h"
 
-#include <kernel/config.h>
+#include <kernel/attrib.h>
 #include <kernel/ally.h>
 #include <kernel/building.h>
+#include <kernel/config.h>
 #include <kernel/faction.h>
 #include <kernel/region.h>
 #include <kernel/ship.h>
@@ -17,7 +17,7 @@
 #include <kernel/race.h>
 #include <kernel/order.h>
 
-#include <kernel/attrib.h>
+#include "util/keyword.h"
 #include <util/language.h>
 #include <util/message.h>
 #include <util/base36.h>
diff --git a/src/orderfile.c b/src/orderfile.c
index a4f47a4e3..48cc26a83 100644
--- a/src/orderfile.c
+++ b/src/orderfile.c
@@ -17,6 +17,7 @@
 #include "util/order_parser.h"
 
 #include <assert.h>
+#include <errno.h>
 #include <stdio.h>
 #include <string.h>
 
diff --git a/src/report.test.c b/src/report.test.c
index 4fa97825c..3c49b14fc 100644
--- a/src/report.test.c
+++ b/src/report.test.c
@@ -2,7 +2,6 @@
 #include "report.h"
 #include "move.h"
 #include "travelthru.h"
-#include "keyword.h"
 
 #include <kernel/building.h>
 #include <kernel/faction.h>
@@ -15,6 +14,8 @@
 #include <kernel/spell.h>
 #include <kernel/spellbook.h>
 
+#include "util/keyword.h"
+#include "util/param.h"
 #include <util/language.h>
 #include <util/lists.h>
 #include <util/message.h>
diff --git a/src/util/order_parser.c b/src/util/order_parser.c
index 363f12c92..b0d6d2d10 100644
--- a/src/util/order_parser.c
+++ b/src/util/order_parser.c
@@ -14,7 +14,7 @@ struct OrderParserStruct {
     OP_FactionHandler m_factionHandler;
     OP_UnitHandler m_unitHandler;
     OP_OrderHandler m_orderHandler;
-    enum CR_Error m_errorCode;
+    enum OP_Error m_errorCode;
     int m_lineNumber;
 };
 
diff --git a/src/util/order_parser.h b/src/util/order_parser.h
index 7600ee3da..c8f20e89e 100644
--- a/src/util/order_parser.h
+++ b/src/util/order_parser.h
@@ -23,6 +23,12 @@ enum OP_Status {
     OP_STATUS_OK = 1
 };
 
+enum OP_Error {
+    OP_ERROR_NONE,
+    OP_ERROR_NO_MEMORY,
+    OP_ERROR_SYNTAX
+};
+
 typedef void(*OP_FactionHandler) (void *userData, int no, const char *password);
 typedef void(*OP_UnitHandler) (void *userData, int no);
 typedef void(*OP_OrderHandler) (void *userData, const char *str);

From f53b1f50ae7a64a0f612d690f41f6656c3889f9e Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno@kn-bremen.de>
Date: Sun, 30 Sep 2018 14:54:13 +0200
Subject: [PATCH 61/81] cmake init after pull

---
 s/preview | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/s/preview b/s/preview
index 39d5466d0..c4c9a5d42 100755
--- a/s/preview
+++ b/s/preview
@@ -22,11 +22,12 @@ exit $2 # otherwise
 function build() {
 assert_dir $SOURCE
 cd $SOURCE
-rm -rf crypto tolua
+rm -rf tolua
 git fetch || abort "failed to update source. do you have local changes?"
 [ -z $1 ] || git checkout $1
 git pull -q
 git submodule update
+s/cmake-init
 s/build > /dev/null || abort "build failed."
 }
 

From fb8507e0d2fc87313006db5bd766394bb74ea07e Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sun, 30 Sep 2018 15:02:03 +0200
Subject: [PATCH 62/81] support for non-utf8 encodings has rotted, kill it.

---
 src/kernel/save.c     |   3 -
 src/orderfile.c       |   2 +-
 src/util/filereader.c | 150 +-----------------------------------------
 src/util/filereader.h |   5 +-
 4 files changed, 4 insertions(+), 156 deletions(-)

diff --git a/src/kernel/save.c b/src/kernel/save.c
index 3bef185c3..cdc951fad 100644
--- a/src/kernel/save.c
+++ b/src/kernel/save.c
@@ -101,9 +101,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 /* exported symbols symbols */
 int firstx = 0, firsty = 0;
 
-/* TODO: is this still important? */
-int enc_gamedata = ENCODING_UTF8;
-
 static void read_alliances(gamedata *data)
 {
     storage *store = data->store;
diff --git a/src/orderfile.c b/src/orderfile.c
index 48cc26a83..316724338 100644
--- a/src/orderfile.c
+++ b/src/orderfile.c
@@ -229,7 +229,7 @@ int read_orders(input *in)
 static const char * file_getbuf(void *data)
 {
     FILE *F = (FILE *)data;
-    return getbuf(F, ENCODING_UTF8);
+    return getbuf(F);
 }
 
 typedef struct parser_state {
diff --git a/src/util/filereader.c b/src/util/filereader.c
index e477b445c..5ead2166f 100644
--- a/src/util/filereader.c
+++ b/src/util/filereader.c
@@ -39,150 +39,6 @@ static int eatwhite(const char *ptr, size_t * total_size)
     return ret;
 }
 
-static const char *getbuf_latin1(FILE * F)
-{
-    bool cont = false;
-    char quote = 0;
-    bool comment = false;
-    char *cp = fbuf;
-    char *tail = lbuf + MAXLINE - 2;
-
-    tail[1] = '@';                /* if this gets overwritten by fgets then the line was very long. */
-    do {
-        const char *bp = fgets(lbuf, MAXLINE, F);
-
-        if (bp == NULL)
-            return NULL;
-        while (*bp && isspace(*(unsigned char *)bp))
-            ++bp;                     /* eatwhite */
-
-        comment = (bool)(comment && cont);
-        quote = (bool)(quote && cont);
-
-        if (tail[1] == 0) {
-            /* we read he maximum number of bytes! */
-            if (tail[0] != '\n') {
-                /* it wasn't enough space to finish the line, eat the rest */
-                for (;;) {
-                    tail[1] = '@';
-                    bp = fgets(lbuf, MAXLINE, F);
-                    if (bp == NULL)
-                        return NULL;
-                    if (tail[1]) {
-                        /* read enough this time to end the line */
-                        break;
-                    }
-                }
-                comment = false;
-                cont = false;
-                bp = NULL;
-                continue;
-            }
-            else {
-                tail[1] = '@';
-            }
-        }
-        cont = false;
-        while (*bp && cp < fbuf + MAXLINE) {
-            int c = *(unsigned char *)bp;
-
-            if (c == '\n' || c == '\r') {
-                /* line breaks, shmine breaks */
-                break;
-            }
-            if (c == COMMENT_CHAR && !quote) {
-                /* comment begins. we need to keep going, to look for CONTINUE_CHAR */
-                comment = true;
-                ++bp;
-                continue;
-            }
-            if (!comment && (c == '"' || c == '\'')) {
-                if (quote == c) {
-                    quote = 0;
-                    if (cp < fbuf + MAXLINE)
-                        *cp++ = *bp;
-                    ++bp;
-                    continue;
-                }
-                else if (!quote) {
-                    quote = *bp++;
-                    if (cp < fbuf + MAXLINE)
-                        *cp++ = quote;
-                    continue;
-                }
-            }
-
-            if (iscntrl(c)) {
-                if (!comment && cp < fbuf + MAXLINE) {
-                    *cp++ = isspace(c) ? ' ' : '?';
-                }
-                ++bp;
-                continue;
-            }
-            else if (isspace(c)) {
-                if (!quote) {
-                    ++bp;
-                    while (*bp && isspace(*(unsigned char *)bp))
-                        ++bp;               /* eatwhite */
-                    if (!comment && *bp && *bp != COMMENT_CHAR && cp < fbuf + MAXLINE)
-                        *(cp++) = ' ';
-                }
-                else if (!comment && cp + 1 <= fbuf + MAXLINE) {
-                    *(cp++) = *(bp++);
-                }
-                else {
-                    ++bp;
-                }
-                continue;
-            }
-            else if (c == CONTINUE_CHAR) {
-                const char *handle_end = ++bp;
-                while (*handle_end && isspace(*(unsigned char *)handle_end))
-                    ++handle_end;                /* eatwhite */
-                if (*handle_end == '\0') {
-                    bp = handle_end;
-                    cont = true;
-                    continue;
-                }
-                if (comment) {
-                    ++bp;
-                    continue;
-                }
-            }
-            else if (comment) {
-                ++bp;
-                continue;
-            }
-
-            if (c < 0x80) {
-                if (cp + 1 <= fbuf + MAXLINE) {
-                    *(cp++) = *(bp++);
-                }
-            }
-            else {
-                char inbuf = (char)c;
-                size_t inbytes = 1;
-                size_t outbytes = MAXLINE - (cp - fbuf);
-                int ret = unicode_latin1_to_utf8(cp, &outbytes, &inbuf, &inbytes);
-                if (ret > 0)
-                    cp += ret;
-                else {
-                    log_error("input data was not iso-8859-1! assuming utf-8\n");
-                    return NULL;
-                }
-
-                ++bp;
-                continue;
-            }
-        }
-        if (cp == fbuf + MAXLINE) {
-            --cp;
-        }
-        *cp = 0;
-    } while (cont || cp == fbuf);
-    return fbuf;
-}
-
 static const char *getbuf_utf8(FILE * F)
 {
     bool cont = false;
@@ -336,9 +192,7 @@ static const char *getbuf_utf8(FILE * F)
     return fbuf;
 }
 
-const char *getbuf(FILE * F, int encoding)
+const char *getbuf(FILE * F)
 {
-    if (encoding == ENCODING_UTF8)
-        return getbuf_utf8(F);
-    return getbuf_latin1(F);
+    return getbuf_utf8(F);
 }
diff --git a/src/util/filereader.h b/src/util/filereader.h
index eb09d14e1..a80afa65f 100644
--- a/src/util/filereader.h
+++ b/src/util/filereader.h
@@ -15,10 +15,7 @@
 extern "C" {
 #endif
 
-#define ENCODING_UTF8   0
-#define ENCODING_LATIN1 1
-
-    const char *getbuf(FILE *, int encoding);
+    const char *getbuf(FILE *);
 
 #ifdef __cplusplus
 }

From a4f6c6f0053160884f7be547dc43d99d2465f6b2 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sun, 30 Sep 2018 16:16:32 +0200
Subject: [PATCH 63/81] fix libbsd linking

---
 src/CMakeLists.txt | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 9ed0011e6..0e4c342d4 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -186,6 +186,7 @@ endif()
 add_library(version STATIC ${VERSION_SRC})
 add_library(parser ${PARSER_SRC})
 target_link_libraries(parser
+  bsd
   ${CRYPTO_LIBRARIES}
   )
 
@@ -297,8 +298,7 @@ if (HAVE_STRDUP)
 endif(HAVE_STRDUP)
 
 if (HAVE_LIBBSD)
-target_link_libraries(test_eressea bsd)
-target_link_libraries(eressea bsd)
+target_link_libraries(parser bsd)
 endif (HAVE_LIBBSD)
 
 if (SQLITE3_FOUND)

From 0c4d1ec2b246b907d1867407111dfb81b334a184 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sun, 30 Sep 2018 16:18:06 +0200
Subject: [PATCH 64/81] fix libbsd linking (MSVC)

---
 src/CMakeLists.txt | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 0e4c342d4..8bb751258 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -186,7 +186,6 @@ endif()
 add_library(version STATIC ${VERSION_SRC})
 add_library(parser ${PARSER_SRC})
 target_link_libraries(parser
-  bsd
   ${CRYPTO_LIBRARIES}
   )
 

From b1cd9bcfef32668c5daf3b9a3d3b4da1e83781d7 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sun, 30 Sep 2018 19:47:34 +0200
Subject: [PATCH 65/81] Pretty good progress on the OrderParser implementaiton.
 Still finding bugs by unit-testing, though.

---
 .gitignore                   |   1 +
 src/test_eressea.c           |   1 +
 src/util/CMakeLists.txt      |   2 +-
 src/util/order_parser.c      | 199 +++++++++++++++++++++++++++++++++--
 src/util/order_parser.h      |  13 +--
 src/util/order_parser.test.c |  65 ++++++++++++
 6 files changed, 263 insertions(+), 18 deletions(-)
 create mode 100644 src/util/order_parser.test.c

diff --git a/.gitignore b/.gitignore
index d5e8e1b10..3dcf24224 100644
--- a/.gitignore
+++ b/.gitignore
@@ -36,6 +36,7 @@ Thumbs.db
 *.cfg
 *.cmd
 tmp/
+tests/orders.txt
 tests/config.lua
 tests/reports/
 tests/data/185.dat
diff --git a/src/test_eressea.c b/src/test_eressea.c
index 439fee1d6..9897c4bf0 100644
--- a/src/test_eressea.c
+++ b/src/test_eressea.c
@@ -81,6 +81,7 @@ int RunAllTests(int argc, char *argv[])
     ADD_SUITE(functions);
     ADD_SUITE(gamedata);
     ADD_SUITE(language);
+    ADD_SUITE(order_parser);
     ADD_SUITE(parser);
     ADD_SUITE(password);
     ADD_SUITE(umlaut);
diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt
index b4d067f57..362ee4fb2 100644
--- a/src/util/CMakeLists.txt
+++ b/src/util/CMakeLists.txt
@@ -16,7 +16,7 @@ language.test.c
 # log.test.c
 message.test.c
 # nrmessage.test.c
-# order_parser.test.c
+order_parser.test.c
 # param.test.c
 parser.test.c
 password.test.c
diff --git a/src/util/order_parser.c b/src/util/order_parser.c
index b0d6d2d10..ec40f5615 100644
--- a/src/util/order_parser.c
+++ b/src/util/order_parser.c
@@ -4,7 +4,10 @@
 
 #include "order_parser.h"
 
+#include <assert.h>
+#include <ctype.h>
 #include <stdlib.h>
+#include <string.h>
 
 struct OrderParserStruct {
     void *m_userData;
@@ -18,34 +21,208 @@ struct OrderParserStruct {
     int m_lineNumber;
 };
 
-void OP_SetUnitHandler(OP_Parser op, OP_UnitHandler handler)
+void OP_SetUnitHandler(OP_Parser parser, OP_UnitHandler handler)
 {
-    op->m_unitHandler = handler;
+    parser->m_unitHandler = handler;
 }
 
-void OP_SetFactionHandler(OP_Parser op, OP_FactionHandler handler) {
-    op->m_factionHandler = handler;
+void OP_SetFactionHandler(OP_Parser parser, OP_FactionHandler handler) {
+    parser->m_factionHandler = handler;
 }
 
-void OP_SetOrderHandler(OP_Parser op, OP_OrderHandler handler) {
-    op->m_orderHandler = handler;
+void OP_SetOrderHandler(OP_Parser parser, OP_OrderHandler handler) {
+    parser->m_orderHandler = handler;
 }
 
-void OP_SetUserData(OP_Parser op, void *userData) {
-    op->m_userData = userData;
+void OP_SetUserData(OP_Parser parser, void *userData) {
+    parser->m_userData = userData;
 }
 
+static void buffer_free(OP_Parser parser)
+{
+    /* TODO: recycle buffers, reduce mallocs. */
+    free(parser->m_buffer);
+    parser->m_bufferEnd = parser->m_bufferPtr = parser->m_buffer = NULL;
+}
+
+void OP_ParserReset(OP_Parser parser) {
+    parser->m_lineNumber = 1;
+    buffer_free(parser);
+}
+
+
 OP_Parser OP_ParserCreate(void)
 {
     OP_Parser parser = calloc(1, sizeof(struct OrderParserStruct));
+    OP_ParserReset(parser);
     return parser;
 }
 
-void OP_ParserFree(OP_Parser op) {
-    free(op);
+void OP_ParserFree(OP_Parser parser) {
+    free(parser->m_buffer);
+    free(parser);
 }
 
-enum OP_Status OP_Parse(OP_Parser op, const char *s, int len, int isFinal)
+static enum OP_Error buffer_append(OP_Parser parser, const char *s, int len)
 {
+    if (parser->m_buffer == NULL) {
+        parser->m_buffer = malloc(len + 1);
+        if (!parser->m_buffer) {
+            return OP_ERROR_NO_MEMORY;
+        }
+        memcpy(parser->m_buffer, s, len);
+        parser->m_buffer[len] = '\0';
+        parser->m_bufferPtr = parser->m_buffer;
+        parser->m_bufferEnd = parser->m_buffer + len;
+    }
+    else {
+        size_t total = len;
+        char * buffer;
+        total += (parser->m_bufferEnd - parser->m_bufferPtr);
+        /* TODO: recycle buffers, reduce mallocs. */
+        buffer = malloc(total + 1);
+        memcpy(buffer, parser->m_bufferPtr, total - len);
+        memcpy(buffer + total - len, s, len);
+        buffer[total] = '\0';
+        free(parser->m_buffer);
+        parser->m_buffer = buffer;
+        if (!parser->m_buffer) {
+            return OP_ERROR_NO_MEMORY;
+        }
+        parser->m_bufferPtr = parser->m_buffer;
+        parser->m_bufferEnd = parser->m_buffer + total;
+    }
+    return OP_ERROR_NONE;
+}
+
+static enum OP_Error handle_line(OP_Parser parser) {
+    if (parser->m_orderHandler) {
+        parser->m_orderHandler(parser->m_userData, parser->m_bufferPtr);
+    }
+    return OP_ERROR_NONE;
+}
+
+static char *skip_spaces(char *pos) {
+    char *next;
+    for (next = pos; *next && *next != '\n'; ++next) {
+        /* TODO: handle unicode whitespace */
+        if (!isspace(*next)) break;
+    }
+    return next;
+}
+
+static enum OP_Status parse_buffer(OP_Parser parser, int isFinal)
+{
+    char * pos = strpbrk(parser->m_bufferPtr, "\\;\n");
+    while (pos) {
+        enum OP_Error code;
+        size_t len = pos - parser->m_bufferPtr;
+        char *next;
+
+        switch (*pos) {
+        case '\n':
+            *pos = '\0';
+            code = handle_line(parser);
+            ++parser->m_lineNumber;
+            if (code != OP_ERROR_NONE) {
+                parser->m_errorCode = code;
+                return OP_STATUS_ERROR;
+            }
+            parser->m_bufferPtr = pos + 1;
+            pos = strpbrk(parser->m_bufferPtr, "\\;\n");
+            break;
+        case '\\':
+            /* if this is the last non-space before the line break, then lines need to be joined */
+            next = skip_spaces(pos + 1);
+            if (*next == '\n') {
+                ptrdiff_t shift = (next + 1 - pos);
+                assert(shift > 0);
+                memmove(parser->m_bufferPtr + shift, parser->m_bufferPtr, len);
+                parser->m_bufferPtr += shift;
+                pos = strpbrk(next + 1, "\\;\n");
+                ++parser->m_lineNumber;
+            }
+            else {
+                /* this is not multi-line input yet, so do nothing */
+                pos = strpbrk(pos + 1, "\\;\n");
+            }
+            break;
+        case ';':
+            /* the current line ends in a comment */
+            *pos++ = '\0';
+            handle_line(parser);
+            /* find the end of the comment so we can skip it.
+             * obs: multi-line comments are possible with a backslash. */
+            do {
+                next = strpbrk(pos, "\\\n");
+                if (next) {
+                    if (*next == '\n') {
+                        /* no more lines in this comment, we're done: */
+                        pos = next + 1;
+                        ++parser->m_lineNumber;
+                        break;
+                    }
+                    else {
+                        /* is this backslash the final character? */
+                        next = skip_spaces(pos + 1);
+                        if (*next == '\n') {
+                            /* we have a multi-line comment! */
+                            pos = next + 1;
+                            ++parser->m_lineNumber;
+                        }
+                        else {
+                            /* keep looking for a backslash */
+                            pos = next;
+                        }
+                    }
+                }
+            } while (next && *next);
+
+            if (next && pos < parser->m_bufferEnd) {
+                /* we skip the comment, and there is more data in the buffer */
+                parser->m_bufferPtr = pos;
+            }
+            else {
+                /* we exhausted the buffer before we got to the end of the comment */
+                if (isFinal) {
+                    /* the input ended on this comment line, which is fine */
+                    return OP_STATUS_OK;
+                }
+                else {
+                    /* skip what we have of the comment, keep the semicolon, keep going */
+                    ptrdiff_t skip = parser->m_bufferEnd - parser->m_bufferPtr;
+                    if (skip > 1) {
+                        parser->m_bufferPtr += (skip - 1);
+                        parser->m_bufferPtr[0] = ';';
+                    }
+                }
+            }
+            break;
+        default:
+            parser->m_errorCode = OP_ERROR_SYNTAX;
+            return OP_STATUS_ERROR;
+        }
+    }
+    if (isFinal && parser->m_bufferPtr < parser->m_bufferEnd) {
+        /* this line ends without a line break */
+        handle_line(parser);
+    }
     return OP_STATUS_OK;
 }
+
+enum OP_Status OP_Parse(OP_Parser parser, const char *s, int len, int isFinal)
+{
+    enum OP_Error code;
+
+    if (parser->m_bufferPtr >= parser->m_bufferEnd) {
+        buffer_free(parser);
+    }
+
+    code = buffer_append(parser, s, len);
+    if (code != OP_ERROR_NONE) {
+        parser->m_errorCode = code;
+        return OP_STATUS_ERROR;
+    }
+
+    return parse_buffer(parser, isFinal);
+}
diff --git a/src/util/order_parser.h b/src/util/order_parser.h
index c8f20e89e..10a258875 100644
--- a/src/util/order_parser.h
+++ b/src/util/order_parser.h
@@ -34,11 +34,12 @@ typedef void(*OP_UnitHandler) (void *userData, int no);
 typedef void(*OP_OrderHandler) (void *userData, const char *str);
 
 OP_Parser OP_ParserCreate(void);
-void OP_ParserFree(OP_Parser op);
-enum OP_Status OP_Parse(OP_Parser op, const char *s, int len, int isFinal);
-void OP_SetUnitHandler(OP_Parser op, OP_UnitHandler handler);
-void OP_SetFactionHandler(OP_Parser op, OP_FactionHandler handler);
-void OP_SetOrderHandler(OP_Parser op, OP_OrderHandler handler);
-void OP_SetUserData(OP_Parser op, void *userData);
+void OP_ParserFree(OP_Parser parser);
+void OP_ParserReset(OP_Parser parser);
+enum OP_Status OP_Parse(OP_Parser parser, const char *s, int len, int isFinal);
+void OP_SetUnitHandler(OP_Parser parser, OP_UnitHandler handler);
+void OP_SetFactionHandler(OP_Parser parser, OP_FactionHandler handler);
+void OP_SetOrderHandler(OP_Parser parser, OP_OrderHandler handler);
+void OP_SetUserData(OP_Parser parser, void *userData);
 
 #endif
diff --git a/src/util/order_parser.test.c b/src/util/order_parser.test.c
new file mode 100644
index 000000000..a4bc58e97
--- /dev/null
+++ b/src/util/order_parser.test.c
@@ -0,0 +1,65 @@
+#ifdef _MSC_VER
+#include <platform.h>
+#endif
+
+#include "order_parser.h"
+#include "strings.h"
+
+#include <CuTest.h>
+
+#include <string.h>
+
+static void test_parse_noop(CuTest *tc) {
+    OP_Parser parser;
+    parser = OP_ParserCreate();
+    CuAssertPtrNotNull(tc, parser);
+    CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Hello World", 11, 1));
+    OP_ParserFree(parser);
+}
+
+static void copy_line(void *udata, const char *str) {
+    char *dst = (char *)udata;
+    if (dst) {
+        strcpy(dst, str);
+    }
+}
+
+static void test_parse_orders(CuTest *tc) {
+    OP_Parser parser;
+    char lastline[1024];
+
+    parser = OP_ParserCreate();
+    OP_SetUserData(parser, lastline);
+    OP_SetOrderHandler(parser, copy_line);
+    CuAssertPtrNotNull(tc, parser);
+    CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Hello World", 11, 1));
+    CuAssertStrEquals(tc, "Hello World", lastline);
+    OP_ParserReset(parser);
+    CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Hello World\n", 12, 1));
+    CuAssertStrEquals(tc, "Hello World", lastline);
+    OP_ParserReset(parser);
+    CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Hello\\\n World", 13, 1));
+    CuAssertStrEquals(tc, "Hello World", lastline);
+    OP_ParserReset(parser);
+    CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Hello;World", 11, 1));
+    CuAssertStrEquals(tc, "Hello", lastline);
+    OP_ParserReset(parser);
+    CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Hello\\World", 11, 1));
+    CuAssertStrEquals(tc, "Hello\\World", lastline);
+    OP_ParserReset(parser);
+    CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Hello ", 6, 0));
+    CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "World", 5, 1));
+    CuAssertStrEquals(tc, "Hello World", lastline);
+    OP_ParserReset(parser);
+    CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Hello\\World  \\", 14, 1));
+    CuAssertStrEquals(tc, "Hello\\World  ", lastline);
+    OP_ParserFree(parser);
+}
+
+CuSuite *get_order_parser_suite(void)
+{
+    CuSuite *suite = CuSuiteNew();
+    SUITE_ADD_TEST(suite, test_parse_noop);
+    SUITE_ADD_TEST(suite, test_parse_orders);
+    return suite;
+}

From 90b80aba898cc68e18a42270223e520b880f6427 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Mon, 1 Oct 2018 02:26:31 +0200
Subject: [PATCH 66/81] fix some more issues with buffer ending before
 decisions are finished.

---
 src/util/order_parser.c      | 16 +++++++++++++++-
 src/util/order_parser.test.c | 12 ++++++++++++
 2 files changed, 27 insertions(+), 1 deletion(-)

diff --git a/src/util/order_parser.c b/src/util/order_parser.c
index ec40f5615..8bf4c7e8d 100644
--- a/src/util/order_parser.c
+++ b/src/util/order_parser.c
@@ -144,7 +144,21 @@ static enum OP_Status parse_buffer(OP_Parser parser, int isFinal)
             }
             else {
                 /* this is not multi-line input yet, so do nothing */
-                pos = strpbrk(pos + 1, "\\;\n");
+                if (pos[1] == '\0') {
+                    /* end of available input */
+                    if (isFinal) {
+                        /* input ends on a pointless backslash, kill it */
+                        pos[0] = '\0';
+                        pos = NULL;
+                    }
+                    else {
+                        /* backslash is followed by data that we do not know */
+                        pos = NULL;
+                    }
+                }
+                else {
+                    pos = strpbrk(pos + 1, "\\;\n");
+                }
             }
             break;
         case ';':
diff --git a/src/util/order_parser.test.c b/src/util/order_parser.test.c
index a4bc58e97..e9a37fa76 100644
--- a/src/util/order_parser.test.c
+++ b/src/util/order_parser.test.c
@@ -32,27 +32,39 @@ static void test_parse_orders(CuTest *tc) {
     OP_SetUserData(parser, lastline);
     OP_SetOrderHandler(parser, copy_line);
     CuAssertPtrNotNull(tc, parser);
+    lastline[0] = 0;
     CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Hello World", 11, 1));
     CuAssertStrEquals(tc, "Hello World", lastline);
     OP_ParserReset(parser);
+    lastline[0] = 0;
     CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Hello World\n", 12, 1));
     CuAssertStrEquals(tc, "Hello World", lastline);
     OP_ParserReset(parser);
+    lastline[0] = 0;
     CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Hello\\\n World", 13, 1));
     CuAssertStrEquals(tc, "Hello World", lastline);
     OP_ParserReset(parser);
+    lastline[0] = 0;
     CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Hello;World", 11, 1));
     CuAssertStrEquals(tc, "Hello", lastline);
     OP_ParserReset(parser);
+    lastline[0] = 0;
     CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Hello\\World", 11, 1));
     CuAssertStrEquals(tc, "Hello\\World", lastline);
     OP_ParserReset(parser);
+    lastline[0] = 0;
     CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Hello ", 6, 0));
     CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "World", 5, 1));
     CuAssertStrEquals(tc, "Hello World", lastline);
     OP_ParserReset(parser);
+    lastline[0] = 0;
     CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Hello\\World  \\", 14, 1));
     CuAssertStrEquals(tc, "Hello\\World  ", lastline);
+    OP_ParserReset(parser);
+    lastline[0] = 0;
+    CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Hello \\", 7, 0));
+    CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "\nWorld", 6, 1));
+    CuAssertStrEquals(tc, "Hello World", lastline);
     OP_ParserFree(parser);
 }
 

From eed3ab3acfc54dce5082a75aa458e0291029ea92 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Mon, 1 Oct 2018 21:32:59 +0200
Subject: [PATCH 67/81] finish new order parser, maybe?

---
 src/orderfile.c         | 50 +++++++++++++++++++++++++++++++----------
 src/util/order_parser.c | 28 +++++++++--------------
 src/util/order_parser.h |  4 ----
 3 files changed, 48 insertions(+), 34 deletions(-)

diff --git a/src/orderfile.c b/src/orderfile.c
index 316724338..ff19014ea 100644
--- a/src/orderfile.c
+++ b/src/orderfile.c
@@ -249,6 +249,8 @@ static void handle_faction(void *userData, int no, const char *password) {
             log_debug("invalid password for faction %s", itoa36(no));
             ADDMSG(&f->msgs, msg_message("wrongpasswd", "password", password));
         }
+        state->u = NULL;
+        state->next_order = NULL;
     }
 }
 
@@ -272,20 +274,46 @@ static void handle_unit(void *userData, int no) {
 
 static void handle_order(void *userData, const char *str) {
     parser_state *state = (parser_state *)userData;
-    unit * u = state->u;
-    order *ord;
+    const char * tok, *input = str;
+    char buffer[16];
+    const struct locale *lang;
+    param_t p;
+    faction * f = state->f;
 
-    ord = parse_order(str, u->faction->locale);
-    if (ord) {
-        *state->next_order = ord;
-        state->next_order = &ord->next;
+    lang = f ? f->locale : default_locale;
+    tok = parse_token(&input, buffer, sizeof(buffer));
+    p = findparam(tok, lang);
+    if (p == P_FACTION || p == P_GAMENAME) {
+        tok = parse_token(&input, buffer, sizeof(buffer));
+        if (tok) {
+            int no = atoi36(tok);
+            tok = parse_token(&input, buffer, sizeof(buffer));
+            handle_faction(userData, no, tok);
+        }
+        else {
+            /* TODO: log_error() */
+        }
     }
-    else {
-        ADDMSG(&u->faction->msgs, msg_message("parse_error", "unit command", u, str));
+    else if (p == P_UNIT) {
+        tok = parse_token(&input, buffer, sizeof(buffer));
+        if (tok) {
+            int no = atoi36(tok);
+            handle_unit(userData, no);
+        }
+    }
+    else if (state->u) {
+        unit * u = state->u;
+        order * ord = parse_order(str, lang);
+        if (ord) {
+            *state->next_order = ord;
+            state->next_order = &ord->next;
+        }
+        else {
+            ADDMSG(&u->faction->msgs, msg_message("parse_error", "unit command", u, str));
+        }
     }
 }
 
-
 int parseorders(FILE *F)
 {
     char buf[2048];
@@ -298,8 +326,6 @@ int parseorders(FILE *F)
         /* TODO: error message */
         return errno;
     }
-    OP_SetUnitHandler(parser, handle_unit);
-    OP_SetFactionHandler(parser, handle_faction);
     OP_SetOrderHandler(parser, handle_order);
     OP_SetUserData(parser, &state);
 
@@ -323,7 +349,7 @@ int parseorders(FILE *F)
 
 int readorders(FILE *F)
 {
-#undef NEW_PARSER
+#define NEW_PARSER
 #ifdef NEW_PARSER
     return parseorders(F);
 #else
diff --git a/src/util/order_parser.c b/src/util/order_parser.c
index 8bf4c7e8d..f303ff3f1 100644
--- a/src/util/order_parser.c
+++ b/src/util/order_parser.c
@@ -14,22 +14,11 @@ struct OrderParserStruct {
     char *m_buffer;
     char *m_bufferPtr;
     const char *m_bufferEnd;
-    OP_FactionHandler m_factionHandler;
-    OP_UnitHandler m_unitHandler;
     OP_OrderHandler m_orderHandler;
     enum OP_Error m_errorCode;
     int m_lineNumber;
 };
 
-void OP_SetUnitHandler(OP_Parser parser, OP_UnitHandler handler)
-{
-    parser->m_unitHandler = handler;
-}
-
-void OP_SetFactionHandler(OP_Parser parser, OP_FactionHandler handler) {
-    parser->m_factionHandler = handler;
-}
-
 void OP_SetOrderHandler(OP_Parser parser, OP_OrderHandler handler) {
     parser->m_orderHandler = handler;
 }
@@ -95,13 +84,6 @@ static enum OP_Error buffer_append(OP_Parser parser, const char *s, int len)
     return OP_ERROR_NONE;
 }
 
-static enum OP_Error handle_line(OP_Parser parser) {
-    if (parser->m_orderHandler) {
-        parser->m_orderHandler(parser->m_userData, parser->m_bufferPtr);
-    }
-    return OP_ERROR_NONE;
-}
-
 static char *skip_spaces(char *pos) {
     char *next;
     for (next = pos; *next && *next != '\n'; ++next) {
@@ -111,6 +93,16 @@ static char *skip_spaces(char *pos) {
     return next;
 }
 
+static enum OP_Error handle_line(OP_Parser parser) {
+    if (parser->m_orderHandler) {
+        char * str = skip_spaces(parser->m_bufferPtr);
+        if (*str) {
+            parser->m_orderHandler(parser->m_userData, str);
+        }
+    }
+    return OP_ERROR_NONE;
+}
+
 static enum OP_Status parse_buffer(OP_Parser parser, int isFinal)
 {
     char * pos = strpbrk(parser->m_bufferPtr, "\\;\n");
diff --git a/src/util/order_parser.h b/src/util/order_parser.h
index 10a258875..fde29a380 100644
--- a/src/util/order_parser.h
+++ b/src/util/order_parser.h
@@ -29,16 +29,12 @@ enum OP_Error {
     OP_ERROR_SYNTAX
 };
 
-typedef void(*OP_FactionHandler) (void *userData, int no, const char *password);
-typedef void(*OP_UnitHandler) (void *userData, int no);
 typedef void(*OP_OrderHandler) (void *userData, const char *str);
 
 OP_Parser OP_ParserCreate(void);
 void OP_ParserFree(OP_Parser parser);
 void OP_ParserReset(OP_Parser parser);
 enum OP_Status OP_Parse(OP_Parser parser, const char *s, int len, int isFinal);
-void OP_SetUnitHandler(OP_Parser parser, OP_UnitHandler handler);
-void OP_SetFactionHandler(OP_Parser parser, OP_FactionHandler handler);
 void OP_SetOrderHandler(OP_Parser parser, OP_OrderHandler handler);
 void OP_SetUserData(OP_Parser parser, void *userData);
 

From e6b93ce79a70d6629ac9accccb64e29620785b9f Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Tue, 2 Oct 2018 18:57:21 +0200
Subject: [PATCH 68/81] reset state when we meet the NEXT command.

---
 src/orderfile.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/src/orderfile.c b/src/orderfile.c
index ff19014ea..8fdc75485 100644
--- a/src/orderfile.c
+++ b/src/orderfile.c
@@ -301,6 +301,15 @@ static void handle_order(void *userData, const char *str) {
             handle_unit(userData, no);
         }
     }
+    else if (p == P_NEXT) {
+        state->f = NULL;
+        state->u = NULL;
+        state->next_order = NULL;
+    }
+    else if (p == P_REGION) {
+        state->u = NULL;
+        state->next_order = NULL;
+    }
     else if (state->u) {
         unit * u = state->u;
         order * ord = parse_order(str, lang);

From b439e48a22418b81a15c4b741cff7283c853d70b Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Tue, 2 Oct 2018 19:02:22 +0200
Subject: [PATCH 69/81] some failing tests

---
 src/util/order_parser.test.c | 27 ++++++++++++++++++++++++---
 1 file changed, 24 insertions(+), 3 deletions(-)

diff --git a/src/util/order_parser.test.c b/src/util/order_parser.test.c
index e9a37fa76..2d113655a 100644
--- a/src/util/order_parser.test.c
+++ b/src/util/order_parser.test.c
@@ -36,31 +36,52 @@ static void test_parse_orders(CuTest *tc) {
     CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Hello World", 11, 1));
     CuAssertStrEquals(tc, "Hello World", lastline);
     OP_ParserReset(parser);
+
     lastline[0] = 0;
     CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Hello World\n", 12, 1));
     CuAssertStrEquals(tc, "Hello World", lastline);
     OP_ParserReset(parser);
+
     lastline[0] = 0;
     CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Hello\\\n World", 13, 1));
     CuAssertStrEquals(tc, "Hello World", lastline);
     OP_ParserReset(parser);
+
     lastline[0] = 0;
     CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Hello;World", 11, 1));
     CuAssertStrEquals(tc, "Hello", lastline);
     OP_ParserReset(parser);
+
     lastline[0] = 0;
     CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Hello\\World", 11, 1));
     CuAssertStrEquals(tc, "Hello\\World", lastline);
     OP_ParserReset(parser);
+
     lastline[0] = 0;
-    CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Hello ", 6, 0));
-    CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "World", 5, 1));
-    CuAssertStrEquals(tc, "Hello World", lastline);
+    CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, ";Hello \\", 8, 0));
+    CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "\nWorld\n", 7, 1));
+    CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Enno", 4, 1));
+    CuAssertStrEquals(tc, "Enno", lastline);
     OP_ParserReset(parser);
+
+    lastline[0] = 0;
+    CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, ";Hello", 6, 0));
+    CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "World\n", 6, 1));
+    CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Enno", 4, 1));
+    CuAssertStrEquals(tc, "Enno", lastline);
+    OP_ParserReset(parser);
+
     lastline[0] = 0;
     CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Hello\\World  \\", 14, 1));
     CuAssertStrEquals(tc, "Hello\\World  ", lastline);
     OP_ParserReset(parser);
+
+    lastline[0] = 0;
+    CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Hello\n", 6, 0));
+    CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "World\n", 6, 1));
+    CuAssertStrEquals(tc, "World", lastline);
+    OP_ParserReset(parser);
+
     lastline[0] = 0;
     CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Hello \\", 7, 0));
     CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "\nWorld", 6, 1));

From 6c1d266c1279d6230067eca5934012a3c65da91a Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Tue, 2 Oct 2018 21:40:14 +0200
Subject: [PATCH 70/81] fix comment parsing at end of input

---
 src/orderfile.c              |  2 +-
 src/util/order_parser.c      | 56 +++++++++++++++++++++++++-----------
 src/util/order_parser.h      |  1 +
 src/util/order_parser.test.c | 15 ++++++++--
 4 files changed, 54 insertions(+), 20 deletions(-)

diff --git a/src/orderfile.c b/src/orderfile.c
index 8fdc75485..33a9c19f7 100644
--- a/src/orderfile.c
+++ b/src/orderfile.c
@@ -348,7 +348,7 @@ int parseorders(FILE *F)
         done = feof(F);
         if (OP_Parse(parser, buf, len, done) == OP_STATUS_ERROR) {
             /* TODO: error message */
-            err = -1;
+            err = (int)OP_GetErrorCode(parser);
             break;
         }
     }
diff --git a/src/util/order_parser.c b/src/util/order_parser.c
index f303ff3f1..88a42f0ab 100644
--- a/src/util/order_parser.c
+++ b/src/util/order_parser.c
@@ -5,7 +5,7 @@
 #include "order_parser.h"
 
 #include <assert.h>
-#include <ctype.h>
+#include <wctype.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -19,6 +19,10 @@ struct OrderParserStruct {
     int m_lineNumber;
 };
 
+enum OP_Error OP_GetErrorCode(OP_Parser parser) {
+    return parser->m_errorCode;
+}
+
 void OP_SetOrderHandler(OP_Parser parser, OP_OrderHandler handler) {
     parser->m_orderHandler = handler;
 }
@@ -87,8 +91,9 @@ static enum OP_Error buffer_append(OP_Parser parser, const char *s, int len)
 static char *skip_spaces(char *pos) {
     char *next;
     for (next = pos; *next && *next != '\n'; ++next) {
+        wint_t wch = *(unsigned char *)next;
         /* TODO: handle unicode whitespace */
-        if (!isspace(*next)) break;
+        if (!iswspace(wch)) break;
     }
     return next;
 }
@@ -110,6 +115,7 @@ static enum OP_Status parse_buffer(OP_Parser parser, int isFinal)
         enum OP_Error code;
         size_t len = pos - parser->m_bufferPtr;
         char *next;
+        int continue_comment = 0;
 
         switch (*pos) {
         case '\n':
@@ -164,9 +170,8 @@ static enum OP_Status parse_buffer(OP_Parser parser, int isFinal)
                 if (next) {
                     if (*next == '\n') {
                         /* no more lines in this comment, we're done: */
-                        pos = next + 1;
                         ++parser->m_lineNumber;
-                        break;
+                        break; /* exit loop */
                     }
                     else {
                         /* is this backslash the final character? */
@@ -184,25 +189,42 @@ static enum OP_Status parse_buffer(OP_Parser parser, int isFinal)
                 }
             } while (next && *next);
 
-            if (next && pos < parser->m_bufferEnd) {
-                /* we skip the comment, and there is more data in the buffer */
-                parser->m_bufferPtr = pos;
-            }
-            else {
-                /* we exhausted the buffer before we got to the end of the comment */
+            if (!next) {
+                /* we exhausted the buffer before we finished the line */
                 if (isFinal) {
-                    /* the input ended on this comment line, which is fine */
+                    /* this comment was at the end of the file, it just has no newline. done! */
                     return OP_STATUS_OK;
                 }
                 else {
-                    /* skip what we have of the comment, keep the semicolon, keep going */
-                    ptrdiff_t skip = parser->m_bufferEnd - parser->m_bufferPtr;
-                    if (skip > 1) {
-                        parser->m_bufferPtr += (skip - 1);
-                        parser->m_bufferPtr[0] = ';';
-                    }
+                    /* there is more of this line in the next buffer, save the semicolon */
+                    continue_comment = 1;
                 }
             }
+            else { 
+                if (*next) {
+                    /* end comment parsing, begin parsing a new line */
+                    pos = next + 1;
+                    continue_comment = 0;
+                }
+                else {
+                    /* reached end of input naturally, need more data to finish */
+                    continue_comment = 1;
+                }
+            }
+
+            if (continue_comment) {
+                ptrdiff_t skip = parser->m_bufferEnd - parser->m_bufferPtr;
+                continue_comment = 0;
+                if (skip > 0) {
+                    /* should always be true */
+                    parser->m_bufferPtr += (skip - 1);
+                    parser->m_bufferPtr[0] = ';';
+                }
+                return OP_STATUS_OK;
+            }
+            /* continue the outer loop */
+            parser->m_bufferPtr = pos;
+            pos = strpbrk(pos, "\\;\n");
             break;
         default:
             parser->m_errorCode = OP_ERROR_SYNTAX;
diff --git a/src/util/order_parser.h b/src/util/order_parser.h
index fde29a380..159fd6594 100644
--- a/src/util/order_parser.h
+++ b/src/util/order_parser.h
@@ -37,5 +37,6 @@ void OP_ParserReset(OP_Parser parser);
 enum OP_Status OP_Parse(OP_Parser parser, const char *s, int len, int isFinal);
 void OP_SetOrderHandler(OP_Parser parser, OP_OrderHandler handler);
 void OP_SetUserData(OP_Parser parser, void *userData);
+enum OP_Error OP_GetErrorCode(OP_Parser parser);
 
 #endif
diff --git a/src/util/order_parser.test.c b/src/util/order_parser.test.c
index 2d113655a..630bcc4d4 100644
--- a/src/util/order_parser.test.c
+++ b/src/util/order_parser.test.c
@@ -57,16 +57,22 @@ static void test_parse_orders(CuTest *tc) {
     CuAssertStrEquals(tc, "Hello\\World", lastline);
     OP_ParserReset(parser);
 
+    lastline[0] = 0;
+    CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, ";\n", 2, 0));
+    CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Hello World", 11, 1));
+    CuAssertStrEquals(tc, "Hello World", lastline);
+    OP_ParserReset(parser);
+
     lastline[0] = 0;
     CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, ";Hello \\", 8, 0));
-    CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "\nWorld\n", 7, 1));
+    CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "\nWorld\n", 7, 0));
     CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Enno", 4, 1));
     CuAssertStrEquals(tc, "Enno", lastline);
     OP_ParserReset(parser);
 
     lastline[0] = 0;
     CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, ";Hello", 6, 0));
-    CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "World\n", 6, 1));
+    CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "World\n", 6, 0));
     CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Enno", 4, 1));
     CuAssertStrEquals(tc, "Enno", lastline);
     OP_ParserReset(parser);
@@ -82,6 +88,11 @@ static void test_parse_orders(CuTest *tc) {
     CuAssertStrEquals(tc, "World", lastline);
     OP_ParserReset(parser);
 
+    lastline[0] = 0;
+    CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Hello\n", 6, 0));
+    CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "World\n", 6, 1));
+    CuAssertStrEquals(tc, "World", lastline);
+    OP_ParserReset(parser);
     lastline[0] = 0;
     CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Hello \\", 7, 0));
     CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "\nWorld", 6, 1));

From 854decc4f10548127aa2814d83b014826fc47f1f Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Wed, 3 Oct 2018 10:37:34 +0200
Subject: [PATCH 71/81] comments split by a backslash are not handled right.

---
 src/util/order_parser.test.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/src/util/order_parser.test.c b/src/util/order_parser.test.c
index 630bcc4d4..1034e3d0a 100644
--- a/src/util/order_parser.test.c
+++ b/src/util/order_parser.test.c
@@ -32,11 +32,17 @@ static void test_parse_orders(CuTest *tc) {
     OP_SetUserData(parser, lastline);
     OP_SetOrderHandler(parser, copy_line);
     CuAssertPtrNotNull(tc, parser);
+
     lastline[0] = 0;
     CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Hello World", 11, 1));
     CuAssertStrEquals(tc, "Hello World", lastline);
     OP_ParserReset(parser);
 
+    lastline[0] = 0;
+    CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Hello World;\nError", 18, 1));
+    CuAssertStrEquals(tc, "Hello World", lastline);
+    OP_ParserReset(parser);
+
     lastline[0] = 0;
     CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Hello World\n", 12, 1));
     CuAssertStrEquals(tc, "Hello World", lastline);

From fbce8f326af1d5ed11da3aafcc773747f584186c Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Wed, 3 Oct 2018 19:47:32 +0200
Subject: [PATCH 72/81] fix error in multi-line comments at stream border.

---
 src/orderfile.c              | 47 ++++++++++++++++++++++++++++--------
 src/util/order_parser.c      | 18 ++++++++++----
 src/util/order_parser.test.c | 19 ++++++++++++++-
 3 files changed, 68 insertions(+), 16 deletions(-)

diff --git a/src/orderfile.c b/src/orderfile.c
index 33a9c19f7..450e1b0c1 100644
--- a/src/orderfile.c
+++ b/src/orderfile.c
@@ -21,6 +21,9 @@
 #include <stdio.h>
 #include <string.h>
 
+static FILE *dlog;
+static int orders_parsed, units_parsed, factions_parsed;
+
 static void begin_orders(unit *u) {
     if (u->flags & UFL_ORDERS) {
         order **ordp;
@@ -52,6 +55,7 @@ static unit *unitorders(input *in, faction *f)
     int i;
     unit *u;
 
+    ++units_parsed;
     if (!f)
         return NULL;
 
@@ -109,6 +113,11 @@ static unit *unitorders(input *in, faction *f)
                     }
                 }
                 /* Nun wird der Befehl erzeut und eingeh�ngt */
+                ++orders_parsed;
+                if (dlog) {
+                    fputs(s, dlog);
+                    fputc('\n', dlog);
+                }
                 *ordp = parse_order(s, u->faction->locale);
                 if (*ordp) {
                     ordp = &(*ordp)->next;
@@ -131,6 +140,7 @@ static faction *factionorders(void)
     int fid = getid();
     faction *f = findfaction(fid);
 
+    ++factions_parsed;
     if (f != NULL && (f->flags & FFL_NPC) == 0) {
         char token[128];
         const char *pass = gettoken(token, sizeof(token));
@@ -241,6 +251,7 @@ typedef struct parser_state {
 static void handle_faction(void *userData, int no, const char *password) {
     parser_state *state = (parser_state *)userData;
     faction * f = state->f = findfaction(no);
+    ++factions_parsed;
     if (!f) {
         log_debug("orders for unknown faction %s", itoa36(no));
     }
@@ -258,6 +269,7 @@ static void handle_unit(void *userData, int no) {
     parser_state *state = (parser_state *)userData;
     unit * u = findunit(no);
 
+    ++units_parsed;
     state->u = NULL;
     if (!u) {
         /* TODO: error message */
@@ -313,6 +325,11 @@ static void handle_order(void *userData, const char *str) {
     else if (state->u) {
         unit * u = state->u;
         order * ord = parse_order(str, lang);
+        ++orders_parsed;
+        if (dlog) {
+            fputs(str, dlog);
+            fputc('\n', dlog);
+        }
         if (ord) {
             *state->next_order = ord;
             state->next_order = &ord->next;
@@ -325,7 +342,7 @@ static void handle_order(void *userData, const char *str) {
 
 int parseorders(FILE *F)
 {
-    char buf[2048];
+    char buf[4096];
     int done = 0, err = 0;
     OP_Parser parser;
     parser_state state = { NULL, NULL };
@@ -356,18 +373,28 @@ int parseorders(FILE *F)
     return err;
 }
 
+#define NEW_PARSER
 int readorders(FILE *F)
 {
-#define NEW_PARSER
-#ifdef NEW_PARSER
-    return parseorders(F);
-#else
-    input in;
     int result;
 
-    in.getbuf = file_getbuf;
-    in.data = F;
-    result = read_orders(&in);
-    return result;
+    orders_parsed = 0;
+    units_parsed = 0;
+    factions_parsed = 0;
+
+#ifdef NEW_PARSER
+    dlog = fopen("orders.new.log", "w+");
+    result = parseorders(F);
+#else
+    dlog = fopen("orders.old.log", "w+");
+    {
+        input in;
+        in.getbuf = file_getbuf;
+        in.data = F;
+        result = read_orders(&in);
+    }
 #endif
+    fclose(dlog);
+    log_debug("%d orders read.", orders_parsed);
+    return result;
 }
diff --git a/src/util/order_parser.c b/src/util/order_parser.c
index 88a42f0ab..55b03accd 100644
--- a/src/util/order_parser.c
+++ b/src/util/order_parser.c
@@ -175,12 +175,16 @@ static enum OP_Status parse_buffer(OP_Parser parser, int isFinal)
                     }
                     else {
                         /* is this backslash the final character? */
-                        next = skip_spaces(pos + 1);
+                        next = skip_spaces(next + 1);
                         if (*next == '\n') {
                             /* we have a multi-line comment! */
                             pos = next + 1;
                             ++parser->m_lineNumber;
                         }
+                        else if (*next == '\0') {
+                            /* cannot find the EOL char yet, stream is dry. keep ; and \ */
+                            continue_comment = 2;
+                        }
                         else {
                             /* keep looking for a backslash */
                             pos = next;
@@ -206,7 +210,7 @@ static enum OP_Status parse_buffer(OP_Parser parser, int isFinal)
                     pos = next + 1;
                     continue_comment = 0;
                 }
-                else {
+                else if (!continue_comment) {
                     /* reached end of input naturally, need more data to finish */
                     continue_comment = 1;
                 }
@@ -214,12 +218,16 @@ static enum OP_Status parse_buffer(OP_Parser parser, int isFinal)
 
             if (continue_comment) {
                 ptrdiff_t skip = parser->m_bufferEnd - parser->m_bufferPtr;
-                continue_comment = 0;
-                if (skip > 0) {
+                assert(skip >= continue_comment);
+                if (skip >= continue_comment) {
                     /* should always be true */
-                    parser->m_bufferPtr += (skip - 1);
+                    parser->m_bufferPtr += (skip - continue_comment);
                     parser->m_bufferPtr[0] = ';';
                 }
+                if (continue_comment == 2) {
+                    parser->m_bufferPtr[1] = '\\';
+                }
+                continue_comment = 0;
                 return OP_STATUS_OK;
             }
             /* continue the outer loop */
diff --git a/src/util/order_parser.test.c b/src/util/order_parser.test.c
index 1034e3d0a..d43f661fb 100644
--- a/src/util/order_parser.test.c
+++ b/src/util/order_parser.test.c
@@ -39,7 +39,24 @@ static void test_parse_orders(CuTest *tc) {
     OP_ParserReset(parser);
 
     lastline[0] = 0;
-    CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Hello World;\nError", 18, 1));
+    CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Error;\nHello World", 18, 1));
+    CuAssertStrEquals(tc, "Hello World", lastline);
+    OP_ParserReset(parser);
+
+    lastline[0] = 0;
+    CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Hello World;\\\nError", 19, 1));
+    CuAssertStrEquals(tc, "Hello World", lastline);
+    OP_ParserReset(parser);
+
+    lastline[0] = 0;
+    CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Hello World;\\", 13, 0));
+    CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "\nError", 6, 1));
+    CuAssertStrEquals(tc, "Hello World", lastline);
+    OP_ParserReset(parser);
+
+    lastline[0] = 0;
+    CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "Hello \\", 7, 0));
+    CuAssertIntEquals(tc, OP_STATUS_OK, OP_Parse(parser, "\nWorld", 6, 1));
     CuAssertStrEquals(tc, "Hello World", lastline);
     OP_ParserReset(parser);
 

From 730b94fa4afd0d0384569b9d3800b08a41f35dfe Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Wed, 3 Oct 2018 20:29:45 +0200
Subject: [PATCH 73/81] reuse the internal buffer when we don't have to malloc.

---
 src/util/order_parser.c | 55 +++++++++++++++++++++++++++++------------
 1 file changed, 39 insertions(+), 16 deletions(-)

diff --git a/src/util/order_parser.c b/src/util/order_parser.c
index 55b03accd..21268f163 100644
--- a/src/util/order_parser.c
+++ b/src/util/order_parser.c
@@ -13,6 +13,7 @@ struct OrderParserStruct {
     void *m_userData;
     char *m_buffer;
     char *m_bufferPtr;
+    size_t m_bufferSize;
     const char *m_bufferEnd;
     OP_OrderHandler m_orderHandler;
     enum OP_Error m_errorCode;
@@ -35,6 +36,7 @@ static void buffer_free(OP_Parser parser)
 {
     /* TODO: recycle buffers, reduce mallocs. */
     free(parser->m_buffer);
+    parser->m_bufferSize = 0;
     parser->m_bufferEnd = parser->m_bufferPtr = parser->m_buffer = NULL;
 }
 
@@ -58,8 +60,28 @@ void OP_ParserFree(OP_Parser parser) {
 
 static enum OP_Error buffer_append(OP_Parser parser, const char *s, int len)
 {
+    size_t total = len + 1;
+    size_t remain = parser->m_bufferEnd - parser->m_bufferPtr;
+    total += remain;
+    if (remain > 0) {
+        /* there is remaining data in the buffer, should we move it to the front? */
+        if (total <= parser->m_bufferSize) {
+            /* reuse existing buffer */
+            memmove(parser->m_buffer, parser->m_bufferPtr, remain);
+            memcpy(parser->m_buffer + remain, s, len);
+            parser->m_buffer[total - 1] = '\0';
+            parser->m_bufferPtr = parser->m_buffer;
+            parser->m_bufferEnd = parser->m_bufferPtr + total - 1;
+            return OP_ERROR_NONE;
+        }
+    }
+    else if (parser->m_bufferPtr >= parser->m_bufferEnd) {
+        buffer_free(parser);
+    }
+
     if (parser->m_buffer == NULL) {
-        parser->m_buffer = malloc(len + 1);
+        parser->m_bufferSize = len + 1;
+        parser->m_buffer = malloc(parser->m_bufferSize);
         if (!parser->m_buffer) {
             return OP_ERROR_NO_MEMORY;
         }
@@ -69,21 +91,26 @@ static enum OP_Error buffer_append(OP_Parser parser, const char *s, int len)
         parser->m_bufferEnd = parser->m_buffer + len;
     }
     else {
-        size_t total = len;
         char * buffer;
-        total += (parser->m_bufferEnd - parser->m_bufferPtr);
         /* TODO: recycle buffers, reduce mallocs. */
-        buffer = malloc(total + 1);
-        memcpy(buffer, parser->m_bufferPtr, total - len);
-        memcpy(buffer + total - len, s, len);
-        buffer[total] = '\0';
-        free(parser->m_buffer);
-        parser->m_buffer = buffer;
-        if (!parser->m_buffer) {
-            return OP_ERROR_NO_MEMORY;
+        if (parser->m_bufferSize < total) {
+            parser->m_bufferSize = total;
+            buffer = malloc(parser->m_bufferSize);
+            if (!buffer) {
+                return OP_ERROR_NO_MEMORY;
+            }
+            memcpy(buffer, parser->m_bufferPtr, total - len - 1);
+            memcpy(buffer + total - len - 1, s, len);
+            free(parser->m_buffer);
+            parser->m_buffer = buffer;
         }
+        else {
+            memcpy(parser->m_buffer, parser->m_bufferPtr, total - len);
+            memcpy(parser->m_buffer + total - len, s, len);
+        }
+        parser->m_buffer[total - 1] = '\0';
         parser->m_bufferPtr = parser->m_buffer;
-        parser->m_bufferEnd = parser->m_buffer + total;
+        parser->m_bufferEnd = parser->m_buffer + total - 1;
     }
     return OP_ERROR_NONE;
 }
@@ -250,10 +277,6 @@ enum OP_Status OP_Parse(OP_Parser parser, const char *s, int len, int isFinal)
 {
     enum OP_Error code;
 
-    if (parser->m_bufferPtr >= parser->m_bufferEnd) {
-        buffer_free(parser);
-    }
-
     code = buffer_append(parser, s, len);
     if (code != OP_ERROR_NONE) {
         parser->m_errorCode = code;

From bbd57b6ae99604e131305338f36390513bf78964 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Wed, 3 Oct 2018 20:33:53 +0200
Subject: [PATCH 74/81] remove debug stuff, use new parser for the game.

---
 src/bind_eressea.c |  2 +-
 src/orderfile.c    | 40 ++++------------------------------------
 src/orderfile.h    |  1 +
 3 files changed, 6 insertions(+), 37 deletions(-)

diff --git a/src/bind_eressea.c b/src/bind_eressea.c
index 34640137b..e5acbac99 100755
--- a/src/bind_eressea.c
+++ b/src/bind_eressea.c
@@ -41,7 +41,7 @@ int eressea_read_orders(const char * filename) {
         return -1;
     }
     log_info("reading orders from %s", filename);
-    return readorders(F);
+    return parseorders(F);
 }
 
 int eressea_export_json(const char * filename, int flags) {
diff --git a/src/orderfile.c b/src/orderfile.c
index 450e1b0c1..1677321eb 100644
--- a/src/orderfile.c
+++ b/src/orderfile.c
@@ -21,9 +21,6 @@
 #include <stdio.h>
 #include <string.h>
 
-static FILE *dlog;
-static int orders_parsed, units_parsed, factions_parsed;
-
 static void begin_orders(unit *u) {
     if (u->flags & UFL_ORDERS) {
         order **ordp;
@@ -55,7 +52,6 @@ static unit *unitorders(input *in, faction *f)
     int i;
     unit *u;
 
-    ++units_parsed;
     if (!f)
         return NULL;
 
@@ -113,11 +109,6 @@ static unit *unitorders(input *in, faction *f)
                     }
                 }
                 /* Nun wird der Befehl erzeut und eingeh�ngt */
-                ++orders_parsed;
-                if (dlog) {
-                    fputs(s, dlog);
-                    fputc('\n', dlog);
-                }
                 *ordp = parse_order(s, u->faction->locale);
                 if (*ordp) {
                     ordp = &(*ordp)->next;
@@ -140,7 +131,6 @@ static faction *factionorders(void)
     int fid = getid();
     faction *f = findfaction(fid);
 
-    ++factions_parsed;
     if (f != NULL && (f->flags & FFL_NPC) == 0) {
         char token[128];
         const char *pass = gettoken(token, sizeof(token));
@@ -251,7 +241,6 @@ typedef struct parser_state {
 static void handle_faction(void *userData, int no, const char *password) {
     parser_state *state = (parser_state *)userData;
     faction * f = state->f = findfaction(no);
-    ++factions_parsed;
     if (!f) {
         log_debug("orders for unknown faction %s", itoa36(no));
     }
@@ -269,7 +258,6 @@ static void handle_unit(void *userData, int no) {
     parser_state *state = (parser_state *)userData;
     unit * u = findunit(no);
 
-    ++units_parsed;
     state->u = NULL;
     if (!u) {
         /* TODO: error message */
@@ -325,11 +313,6 @@ static void handle_order(void *userData, const char *str) {
     else if (state->u) {
         unit * u = state->u;
         order * ord = parse_order(str, lang);
-        ++orders_parsed;
-        if (dlog) {
-            fputs(str, dlog);
-            fputc('\n', dlog);
-        }
         if (ord) {
             *state->next_order = ord;
             state->next_order = &ord->next;
@@ -373,28 +356,13 @@ int parseorders(FILE *F)
     return err;
 }
 
-#define NEW_PARSER
 int readorders(FILE *F)
 {
     int result;
 
-    orders_parsed = 0;
-    units_parsed = 0;
-    factions_parsed = 0;
-
-#ifdef NEW_PARSER
-    dlog = fopen("orders.new.log", "w+");
-    result = parseorders(F);
-#else
-    dlog = fopen("orders.old.log", "w+");
-    {
-        input in;
-        in.getbuf = file_getbuf;
-        in.data = F;
-        result = read_orders(&in);
-    }
-#endif
-    fclose(dlog);
-    log_debug("%d orders read.", orders_parsed);
+    input in;
+    in.getbuf = file_getbuf;
+    in.data = F;
+    result = read_orders(&in);
     return result;
 }
diff --git a/src/orderfile.h b/src/orderfile.h
index fa051993e..f4260aa67 100644
--- a/src/orderfile.h
+++ b/src/orderfile.h
@@ -14,6 +14,7 @@ extern "C" {
 
     int read_orders(struct input *in);
     int readorders(FILE *F);
+    int parseorders(FILE *F);
 
 #ifdef __cplusplus
 }

From 6b983079b7a92f9e7af9367df39836b47922f97d Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Thu, 4 Oct 2018 04:47:20 +0200
Subject: [PATCH 75/81] remember to set faction.lastorders (NMR count was off).
 checker just removes comments now.

---
 src/checker.c   | 46 ++++++++++++++++++++++++++++++++++++++++++++--
 src/orderfile.c |  5 ++++-
 2 files changed, 48 insertions(+), 3 deletions(-)

diff --git a/src/checker.c b/src/checker.c
index 302c80390..f87b91891 100644
--- a/src/checker.c
+++ b/src/checker.c
@@ -2,10 +2,50 @@
 #include <platform.h>
 #endif
 
-#include "util/parser.h"
+#include "util/order_parser.h"
 
 #include <stdio.h>
 
+typedef struct parser_state {
+    FILE * F;
+} parser_state;
+
+static void handle_order(void *userData, const char *str) {
+    parser_state * state = (parser_state*)userData;
+    fputs(str, state->F);
+    fputc('\n', state->F);
+}
+
+int parsefile(FILE *F) {
+    OP_Parser parser;
+    char buf[1024];
+    int done = 0, err = 0;
+    parser_state state = { NULL };
+
+    state.F = stdout;
+
+    parser = OP_ParserCreate();
+    OP_SetOrderHandler(parser, handle_order);
+    OP_SetUserData(parser, &state);
+
+    while (!done) {
+        size_t len = (int)fread(buf, 1, sizeof(buf), F);
+        if (ferror(F)) {
+            /* TODO: error message */
+            err = errno;
+            break;
+        }
+        done = feof(F);
+        if (OP_Parse(parser, buf, len, done) == OP_STATUS_ERROR) {
+            /* TODO: error message */
+            err = (int)OP_GetErrorCode(parser);
+            break;
+        }
+    }
+    OP_ParserFree(parser);
+    return err;
+}
+
 int main(int argc, char **argv) {
     FILE * F = stdin;
     if (argc >= 1) {
@@ -15,8 +55,10 @@ int main(int argc, char **argv) {
             perror(filename);
             return -1;
         }
+    }
+    parsefile(F);
+    if (F != stdin) {
         fclose(F);
     }
     return 0;
 }
-
diff --git a/src/orderfile.c b/src/orderfile.c
index 1677321eb..90b44477b 100644
--- a/src/orderfile.c
+++ b/src/orderfile.c
@@ -245,7 +245,10 @@ static void handle_faction(void *userData, int no, const char *password) {
         log_debug("orders for unknown faction %s", itoa36(no));
     }
     else {
-        if (!checkpasswd(f, password)) {
+        if (checkpasswd(f, password)) {
+            f->lastorders = turn;
+        }
+        else {
             log_debug("invalid password for faction %s", itoa36(no));
             ADDMSG(&f->msgs, msg_message("wrongpasswd", "password", password));
         }

From 9a1bdf444439d0dfb7d18f0c37d3bea6b26a6f00 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno@eressea.de>
Date: Thu, 4 Oct 2018 10:49:53 +0200
Subject: [PATCH 76/81] fix checker build and arg parsing

---
 src/checker.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/checker.c b/src/checker.c
index f87b91891..4138a372a 100644
--- a/src/checker.c
+++ b/src/checker.c
@@ -4,6 +4,7 @@
 
 #include "util/order_parser.h"
 
+#include <errno.h>
 #include <stdio.h>
 
 typedef struct parser_state {
@@ -48,7 +49,7 @@ int parsefile(FILE *F) {
 
 int main(int argc, char **argv) {
     FILE * F = stdin;
-    if (argc >= 1) {
+    if (argc > 1) {
         const char *filename = argv[1];
         F = fopen(filename, "r");
         if (!F) {

From 4f8dd4cb0f017323688f9bb7bcf30fdc407e920b Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sat, 6 Oct 2018 20:47:23 +0200
Subject: [PATCH 77/81] checker is going to use locales, fix them up, too.

---
 src/CMakeLists.txt  |  2 +-
 src/bind_eressea.c  |  2 +-
 src/checker.c       | 26 ++++++++++++++++++++++++++
 src/kernel/config.c |  1 +
 src/platform.h      |  7 -------
 src/util/language.c | 15 +++------------
 src/util/language.h |  4 ++--
 src/util/log.c      |  3 ++-
 src/util/path.h     |  6 ++++++
 9 files changed, 42 insertions(+), 24 deletions(-)

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 8bb751258..4e8db8bf9 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -186,6 +186,7 @@ endif()
 add_library(version STATIC ${VERSION_SRC})
 add_library(parser ${PARSER_SRC})
 target_link_libraries(parser
+  ${CLIBS_LIBRARIES}
   ${CRYPTO_LIBRARIES}
   )
 
@@ -205,7 +206,6 @@ target_link_libraries(eressea
   ${TOLUA_LIBRARIES}
   ${LUA_LIBRARIES}
   ${STORAGE_LIBRARIES}
-  ${CLIBS_LIBRARIES}
   ${CJSON_LIBRARIES}
   ${INIPARSER_LIBRARIES}
 )
diff --git a/src/bind_eressea.c b/src/bind_eressea.c
index e5acbac99..4d3918899 100755
--- a/src/bind_eressea.c
+++ b/src/bind_eressea.c
@@ -22,7 +22,7 @@
 void eressea_free_game(void) {
     free_gamedata();
     init_resources();
-    init_locales();
+    init_locales(init_locale);
 }
 
 int eressea_read_game(const char * filename) {
diff --git a/src/checker.c b/src/checker.c
index 4138a372a..a2c29dd7c 100644
--- a/src/checker.c
+++ b/src/checker.c
@@ -3,9 +3,14 @@
 #endif
 
 #include "util/order_parser.h"
+#include "util/keyword.h"
+#include "util/language.h"
+#include "util/path.h"
+#include "util/pofile.h"
 
 #include <errno.h>
 #include <stdio.h>
+#include <string.h>
 
 typedef struct parser_state {
     FILE * F;
@@ -47,6 +52,26 @@ int parsefile(FILE *F) {
     return err;
 }
 
+static int handle_po(const char *msgid, const char *msgstr, const char *msgctxt, void *data) {
+    struct locale *lang = (struct locale *)data;
+    if (msgctxt) {
+        if (strcmp(msgctxt, "keyword") == 0) {
+            keyword_t kwd = findkeyword(msgid);
+            init_keyword(lang, kwd, msgstr);
+            locale_setstring(lang, mkname("keyword", keywords[kwd]), msgstr);
+        }
+    }
+    return 0;
+}
+
+static void read_config(const char *respath) {
+    char path[PATH_MAX];
+    struct locale *lang;
+    lang = get_or_create_locale("de");
+    path_join(respath, "translations/strings.de.po", path, sizeof(path));
+    pofile_read(path, handle_po, lang);
+}
+
 int main(int argc, char **argv) {
     FILE * F = stdin;
     if (argc > 1) {
@@ -57,6 +82,7 @@ int main(int argc, char **argv) {
             return -1;
         }
     }
+    read_config("../git");
     parsefile(F);
     if (F != stdin) {
         fclose(F);
diff --git a/src/kernel/config.c b/src/kernel/config.c
index 75601e831..15387dca7 100644
--- a/src/kernel/config.c
+++ b/src/kernel/config.c
@@ -239,6 +239,7 @@ static void init_magic(struct locale *lang)
         free(sstr);
     }
 }
+
 void init_locale(struct locale *lang)
 {
     init_magic(lang);
diff --git a/src/platform.h b/src/platform.h
index fdc3760f9..7b52782e3 100644
--- a/src/platform.h
+++ b/src/platform.h
@@ -4,8 +4,6 @@
 #define _LP64 0 /* fix a warning in pdcurses 3.4 */
 #endif
 
-#ifdef _MSC_VER
-
 /* @see https://developercommunity.visualstudio.com/content/problem/69874/warning-c4001-in-standard-library-stringh-header.html */
 #if _MSC_VER >= 1900
 #pragma warning(disable: 4710 4820 4001)
@@ -17,10 +15,5 @@
 #pragma warning(disable: 4214) // bit field types other than int
 #endif
 
-/* @see https://insanecoding.blogspot.no/2007/11/pathmax-simply-isnt.html */
-#define PATH_MAX 260
-
-#endif
-
 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
 #define MAX(a, b) (((a) > (b)) ? (a) : (b))
diff --git a/src/util/language.c b/src/util/language.c
index 77a7d2a4e..afc9d01d0 100644
--- a/src/util/language.c
+++ b/src/util/language.c
@@ -353,29 +353,20 @@ void *get_translation(const struct locale *lang, const char *str, int index) {
     return NULL;
 }
 
-void locale_foreach(void(*callback)(const struct locale *, const char *)) {
-    const locale * lang;
-    for (lang = locales; lang; lang = lang->next) {
-        callback(lang, lang->name);
-    }
-}
-
 const char *localenames[] = {
     "de", "en",
     NULL
 };
 
-extern void init_locale(struct locale *lang);
-
 static int locale_init = 0;
 
-void init_locales(void)
+void init_locales(locale_handler init)
 {
     locale * lang;
     if (locale_init) return;
     assert(locales);
-    for (lang = locales; lang; lang = lang->next) {
-        init_locale(lang);
+    for (lang = locales; lang; lang = nextlocale(lang)) {
+        init(lang);
     }
     locale_init = 1;
 }
diff --git a/src/util/language.h b/src/util/language.h
index f269a5f06..735fd4a95 100644
--- a/src/util/language.h
+++ b/src/util/language.h
@@ -39,7 +39,8 @@ extern "C" {
     /** managing multiple locales: **/
     struct locale *get_locale(const char *name);
     struct locale *get_or_create_locale(const char *key);
-    void init_locales(void);
+    typedef void(*locale_handler)(struct locale *lang);
+    void init_locales(locale_handler callback);
     void free_locales(void);
     void reset_locales(void);
 
@@ -57,7 +58,6 @@ extern "C" {
 
     void make_locales(const char *str);
 
-    void locale_foreach(void(*callback)(const struct locale *lang, const char *name));
     void po_write_msg(FILE *F, const char *id, const char *str, const char *ctxt);
 
 #define LOC(lang, s) (lang?locale_string(lang, s, true):s)
diff --git a/src/util/log.c b/src/util/log.c
index 4b29332a8..b8549d60e 100644
--- a/src/util/log.c
+++ b/src/util/log.c
@@ -12,8 +12,9 @@ without prior permission by the authors of Eressea.
 #include <platform.h>
 #include "log.h"
 
-#include "unicode.h"
+#include "path.h"
 #include "strings.h"
+#include "unicode.h"
 
 #include <assert.h>
 #include <errno.h>
diff --git a/src/util/path.h b/src/util/path.h
index 5a4e22270..649777171 100644
--- a/src/util/path.h
+++ b/src/util/path.h
@@ -1,4 +1,10 @@
+#pragma once
 
 #include <stddef.h>
 
+#ifdef _MSC_VER
+/* @see https://insanecoding.blogspot.no/2007/11/pathmax-simply-isnt.html */
+#define PATH_MAX 260
+#endif
+
 char * path_join(const char *p1, const char *p2, char *dst, size_t len);

From 5964d551e3540e350e025662072a27643ff53047 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sat, 6 Oct 2018 20:53:26 +0200
Subject: [PATCH 78/81] PATH_MAX is just a stupid constant

---
 src/checker.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/checker.c b/src/checker.c
index a2c29dd7c..27648e7af 100644
--- a/src/checker.c
+++ b/src/checker.c
@@ -9,6 +9,7 @@
 #include "util/pofile.h"
 
 #include <errno.h>
+#include <limits.h>
 #include <stdio.h>
 #include <string.h>
 

From 0398a1b705f5977352a6fa0038c7d77a12e00382 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sun, 7 Oct 2018 08:22:56 +0200
Subject: [PATCH 79/81] Bug 2497: LERNE AUTO was subtly broken.

---
 src/automate.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/automate.c b/src/automate.c
index 6af40d649..1a553df29 100644
--- a/src/automate.c
+++ b/src/automate.c
@@ -81,13 +81,13 @@ void autostudy_run(scholar scholars[], int nscholars)
             int mint;
             ts += scholars[se].u->number; /* count total scholars */
             mint = (ts + 10) / 11; /* need a minimum of ceil(ts/11) teachers */
-            for (; mint > tt && si != nscholars; ++si) {
+            for (; mint > tt && si != nscholars && scholars[si].sk == sk; ++si) {
                 tt += scholars[si].u->number;
             }
         }
         /* now si splits the teachers and students 1:10 */
         /* first student must be 2 levels below first teacher: */
-        for (; si != se && scholars[ti].level - TEACHDIFFERENCE > scholars[si].level; ++si) {
+        for (; si != se && scholars[ti].level - TEACHDIFFERENCE > scholars[si].level && scholars[si].sk == sk; ++si) {
             tt += scholars[si].u->number;
         }
         if (si == se) {
@@ -134,7 +134,7 @@ void autostudy_run(scholar scholars[], int nscholars)
                             learning(scholars + s, (n - i));
                             i = 0;
                             if (++s == se) {
-                                continue;
+                                break;
                             }
                             n = scholars[s].u->number;
                         } while (scholars[t].level - TEACHDIFFERENCE < scholars[s].level);

From 3327e996e5b2bb7540c5dd52f997f9ad0811b35f Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno@kn-bremen.de>
Date: Tue, 9 Oct 2018 19:27:33 +0200
Subject: [PATCH 80/81] Bei Neuauswertungen die Befehlsdatei neu erzeugen

---
 process/create-orders | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/process/create-orders b/process/create-orders
index 4740dec2f..58235e2c9 100755
--- a/process/create-orders
+++ b/process/create-orders
@@ -16,6 +16,7 @@ else
   mv orders.dir "orders.dir.$TURN"
   mkdir -p orders.dir
 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"
@@ -23,7 +24,7 @@ done
 
 lockfile -r3 -l120 orders.queue.lock
 if [ -e orders.queue ] ; then
-  mv orders.queue "orders.dir.$TURN/orders.queue"
+  mv orders.queue "orders.queue.bak.$TURN"
 fi
 rm -f orders.queue.lock
 

From ef3ccc8d104271644a10a6d7eacd0d9d6d4acfc0 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno@kn-bremen.de>
Date: Tue, 9 Oct 2018 19:40:26 +0200
Subject: [PATCH 81/81] fix use of new database for sendreport et al

---
 .gitignore             |  1 +
 process/CMakeLists.txt |  4 ++--
 process/epasswd.py     |  2 +-
 process/getemail.py    | 22 ++++++++++++++++++++++
 process/sendreport.sh  | 12 ++++--------
 5 files changed, 30 insertions(+), 11 deletions(-)
 create mode 100755 process/getemail.py

diff --git a/.gitignore b/.gitignore
index 3dcf24224..75ec9a227 100644
--- a/.gitignore
+++ b/.gitignore
@@ -25,6 +25,7 @@ ipch/
 *.user
 
 *~
+*.pyc
 *.bak
 bin/
 build*/
diff --git a/process/CMakeLists.txt b/process/CMakeLists.txt
index 0ffb7b4a2..bbd9b8c38 100644
--- a/process/CMakeLists.txt
+++ b/process/CMakeLists.txt
@@ -1,7 +1,7 @@
 install(PROGRAMS create-orders backup-eressea run-turn send-zip-report
 send-bz2-report compress.py compress.sh epasswd.py orders-process
-process-orders.py accept-orders.py
-checkpasswd.py sendreport.sh sendreports.sh orders-accept DESTINATION bin)
+process-orders.py accept-orders.py getemail.py checkpasswd.py
+sendreport.sh sendreports.sh orders-accept DESTINATION bin)
 
 install(DIRECTORY cron/ DESTINATION bin USE_SOURCE_PERMISSIONS
 FILES_MATCHING PATTERN "*.cron")
diff --git a/process/epasswd.py b/process/epasswd.py
index 4798967a9..4cac6e1ce 100755
--- a/process/epasswd.py
+++ b/process/epasswd.py
@@ -35,7 +35,7 @@ class EPasswd:
     def __init__(self):
         self.data = {}
 
-    def set_data(no, email, passwd):
+    def set_data(self, no, email, passwd):
         lc_id = lower(no)
         self.data[lc_id] = {}
         self.data[lc_id]["id"] = no
diff --git a/process/getemail.py b/process/getemail.py
new file mode 100755
index 000000000..d9951bcb0
--- /dev/null
+++ b/process/getemail.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+
+import sys, re
+from epasswd import EPasswd
+
+if len(sys.argv)<3:
+    sys.exit(-2)
+
+filename=sys.argv[1]
+myfaction=sys.argv[2]
+
+pw_data = EPasswd()
+try:
+    pw_data.load_database(filename)
+except:
+    pw_data.load_file(filename)
+
+if pw_data.fac_exists(myfaction):
+    email = pw_data.get_email(myfaction)
+    print(email)
+    sys.exit(0)
+sys.exit(-1)
diff --git a/process/sendreport.sh b/process/sendreport.sh
index d8fe79d47..7b1afccf0 100755
--- a/process/sendreport.sh
+++ b/process/sendreport.sh
@@ -45,12 +45,8 @@ fi
 
 bash "${FACTION}.sh" "$EMAIL" || reply "Unbekannte Partei $FACTION"
 
-if [ -e "$ERESSEA/game-$GAME/eressea.db" ]; then
-  SQL="select email from faction f left join faction_data fd on fd.faction_id=f.id where f.game_id=$GAME AND fd.code='$FACTION' and fd.turn=(select max(turn) from faction_data fx where fx.faction_id=f.id)"
-  OWNER=$(sqlite3 "$ERESSEA/game-$GAME/eressea.db" "$SQL")
-  if [ ! -z "$OWNER" ]; then
-    echo "Der Report Deiner Partei wurde an ${EMAIL} gesandt." \
-    | mutt -s "Reportnachforderung Partei ${FACTION}" "$OWNER"
-  fi
+OWNER=$(getfaction.py "$PWFILE" "$FACTION")
+if [ ! -z "$OWNER" ]; then
+  echo "Der Report Deiner Partei wurde an ${EMAIL} gesandt." \
+  | mutt -s "Reportnachforderung Partei ${FACTION}" "$OWNER"
 fi
-