forked from github/server
Merge branch 'develop' of github.com:eressea/server into develop
This commit is contained in:
commit
31f989d6c6
22 changed files with 263 additions and 301 deletions
|
@ -32,7 +32,7 @@ without prior permission by the authors of Eressea.
|
|||
static int tolua_storage_create(lua_State * L)
|
||||
{
|
||||
const char *filename = tolua_tostring(L, 1, 0);
|
||||
const char *type = tolua_tostring(L, 2, "rb");
|
||||
const char *type = tolua_tostring(L, 2, "r");
|
||||
gamedata *data;
|
||||
|
||||
data = gamedata_open(filename, type);
|
||||
|
|
|
@ -640,9 +640,43 @@ int check_param(const struct param *p, const char *key, const char *searchvalue)
|
|||
return result;
|
||||
}
|
||||
|
||||
const char * relpath(char *buf, size_t sz, const char *path) {
|
||||
strlcpy(buf, basepath(), sz);
|
||||
strlcat(buf, path, sz);
|
||||
static const char *g_basedir;
|
||||
const char *basepath(void)
|
||||
{
|
||||
if (g_basedir)
|
||||
return g_basedir;
|
||||
return ".";
|
||||
}
|
||||
|
||||
void set_basepath(const char *path)
|
||||
{
|
||||
g_basedir = path;
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
#define PATH_DELIM '\\'
|
||||
#else
|
||||
#define PATH_DELIM '/'
|
||||
#endif
|
||||
|
||||
|
||||
char * join_path(const char *p1, const char *p2, char *dst, size_t len) {
|
||||
size_t sz;
|
||||
assert(p1 && p2);
|
||||
sz = strlcpy(dst, p1, len);
|
||||
assert(sz < len);
|
||||
dst[sz++] = PATH_DELIM;
|
||||
strlcpy(dst + sz, p2, len - sz);
|
||||
return dst;
|
||||
}
|
||||
|
||||
static const char * relpath(char *buf, size_t sz, const char *path) {
|
||||
if (g_basedir) {
|
||||
join_path(g_basedir, path, buf, sz);
|
||||
}
|
||||
else {
|
||||
strlcpy(buf, path, sz);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
@ -652,7 +686,7 @@ const char *datapath(void)
|
|||
static char zText[MAX_PATH]; // FIXME: static return value
|
||||
if (g_datadir)
|
||||
return g_datadir;
|
||||
return relpath(zText, sizeof(zText), "/data");
|
||||
return relpath(zText, sizeof(zText), "data");
|
||||
}
|
||||
|
||||
void set_datapath(const char *path)
|
||||
|
@ -666,7 +700,7 @@ const char *reportpath(void)
|
|||
static char zText[MAX_PATH]; // FIXME: static return value
|
||||
if (g_reportdir)
|
||||
return g_reportdir;
|
||||
return relpath(zText, sizeof(zText), "/reports");
|
||||
return relpath(zText, sizeof(zText), "reports");
|
||||
}
|
||||
|
||||
void set_reportpath(const char *path)
|
||||
|
@ -674,17 +708,18 @@ void set_reportpath(const char *path)
|
|||
g_reportdir = path;
|
||||
}
|
||||
|
||||
static const char *g_basedir;
|
||||
const char *basepath(void)
|
||||
{
|
||||
if (g_basedir)
|
||||
return g_basedir;
|
||||
return ".";
|
||||
}
|
||||
|
||||
void set_basepath(const char *path)
|
||||
{
|
||||
g_basedir = path;
|
||||
int create_directories(void) {
|
||||
int err;
|
||||
err = _mkdir(datapath());
|
||||
if (err) {
|
||||
if (errno == EEXIST) errno = 0;
|
||||
else return err;
|
||||
}
|
||||
err = _mkdir(reportpath());
|
||||
if (err && errno == EEXIST) {
|
||||
errno = 0;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
double get_param_flt(const struct param *p, const char *key, double def)
|
||||
|
|
|
@ -148,6 +148,8 @@ struct param;
|
|||
const char *reportpath(void);
|
||||
void set_reportpath(const char *);
|
||||
|
||||
int create_directories(void);
|
||||
|
||||
void kernel_init(void);
|
||||
void kernel_done(void);
|
||||
|
||||
|
@ -185,6 +187,7 @@ struct param;
|
|||
double config_get_flt(const char *key, double def);
|
||||
bool config_token(const char *key, const char *tok);
|
||||
|
||||
char * join_path(const char *p1, const char *p2, char *dst, size_t len);
|
||||
bool ExpensiveMigrants(void);
|
||||
int NMRTimeout(void);
|
||||
int LongHunger(const struct unit *u);
|
||||
|
|
|
@ -23,7 +23,7 @@ static void test_group_readwrite(CuTest * tc)
|
|||
FILE *F;
|
||||
stream strm;
|
||||
|
||||
F = fopen("test.dat", "wb");
|
||||
F = fopen("test.dat", "w");
|
||||
fstream_init(&strm, F);
|
||||
binstore_init(&store, &strm);
|
||||
test_cleanup();
|
||||
|
@ -36,7 +36,7 @@ static void test_group_readwrite(CuTest * tc)
|
|||
binstore_done(&store);
|
||||
fstream_done(&strm);
|
||||
|
||||
F = fopen("test.dat", "rb");
|
||||
F = fopen("test.dat", "r");
|
||||
fstream_init(&strm, F);
|
||||
binstore_init(&store, &strm);
|
||||
f->groups = 0;
|
||||
|
|
|
@ -114,7 +114,7 @@ static void json_maintenance_i(cJSON *json, maintenance *mt) {
|
|||
}
|
||||
break;
|
||||
default:
|
||||
log_error("maintenance contains unknown attribute %s", child->string);
|
||||
log_error("maintenance contains unknown attribute %s of type %d", child->string, child->type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -139,7 +139,9 @@ static void json_maintenance(cJSON *json, maintenance **mtp) {
|
|||
}
|
||||
}
|
||||
}
|
||||
json_maintenance_i(json, mt);
|
||||
else {
|
||||
json_maintenance_i(json, mt);
|
||||
}
|
||||
}
|
||||
|
||||
static void json_construction(cJSON *json, construction **consp) {
|
||||
|
|
|
@ -90,7 +90,7 @@ struct message *msg_feedback(const struct unit *u, struct order *ord,
|
|||
ord = u->thisorder;
|
||||
|
||||
if (!mtype) {
|
||||
log_error("trying to create message of unknown type \"%s\"\n", name);
|
||||
log_warning("trying to create message of unknown type \"%s\"\n", name);
|
||||
if (!mt_find("missing_feedback")) {
|
||||
mt_register(mt_new_va("missing_feedback", "unit:unit", "region:region", "command:order", "name:string", 0));
|
||||
}
|
||||
|
|
|
@ -256,7 +256,7 @@ int readorders(const char *filename)
|
|||
int nfactions = 0;
|
||||
struct faction *f = NULL;
|
||||
|
||||
F = fopen(filename, "rb");
|
||||
F = fopen(filename, "r");
|
||||
if (!F) {
|
||||
perror(filename);
|
||||
return -1;
|
||||
|
@ -1407,7 +1407,7 @@ int readgame(const char *filename, bool backup)
|
|||
create_backup(path);
|
||||
}
|
||||
|
||||
F = fopen(path, "rb");
|
||||
F = fopen(path, "r");
|
||||
if (!F) {
|
||||
perror(path);
|
||||
return -1;
|
||||
|
@ -1747,21 +1747,16 @@ int writegame(const char *filename)
|
|||
stream strm;
|
||||
FILE *F;
|
||||
|
||||
sprintf(path, "%s/%s", datapath(), filename);
|
||||
create_directories();
|
||||
join_path(datapath(), filename, path, sizeof(path));
|
||||
#ifdef HAVE_UNISTD_H
|
||||
/* make sure we don't overwrite an existing file (hard links) */
|
||||
unlink(path);
|
||||
#endif
|
||||
F = fopen(path, "wb");
|
||||
F = fopen(path, "w");
|
||||
if (!F) {
|
||||
/* we might be missing the directory, let's try creating it */
|
||||
int err = _mkdir(datapath());
|
||||
if (err) return err;
|
||||
F = fopen(path, "wb");
|
||||
if (!F) {
|
||||
perror(path);
|
||||
return -1;
|
||||
}
|
||||
perror(path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
gdata.store = &store;
|
||||
|
|
|
@ -32,16 +32,17 @@ static void test_readwrite_unit(CuTest * tc)
|
|||
struct region *r;
|
||||
struct faction *f;
|
||||
int fno;
|
||||
/* FIXME: at some point during this test, errno is set to 17 (File exists), why? */
|
||||
|
||||
create_directories();
|
||||
test_cleanup();
|
||||
r = test_create_region(0, 0, 0);
|
||||
f = test_create_faction(0);
|
||||
fno = f->no;
|
||||
u = test_create_unit(f, r);
|
||||
_mkdir(datapath());
|
||||
sprintf(path, "%s/%s", datapath(), filename);
|
||||
join_path(datapath(), filename, path, sizeof(path));
|
||||
|
||||
data = gamedata_open(path, "wb");
|
||||
data = gamedata_open(path, "w");
|
||||
CuAssertPtrNotNull(tc, data); // TODO: intermittent test
|
||||
write_unit(data, u);
|
||||
gamedata_close(data);
|
||||
|
@ -49,7 +50,7 @@ static void test_readwrite_unit(CuTest * tc)
|
|||
free_gamedata();
|
||||
f = test_create_faction(0);
|
||||
renumber_faction(f, fno);
|
||||
data = gamedata_open(path, "rb");
|
||||
data = gamedata_open(path, "r");
|
||||
u = read_unit(data);
|
||||
gamedata_close(data);
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <quicklist.h>
|
||||
#include <kernel/spell.h>
|
||||
#include <util/log.h>
|
||||
|
||||
#include <CuTest.h>
|
||||
#include <tests.h>
|
||||
|
@ -24,6 +25,7 @@ static void test_create_a_spell(CuTest * tc)
|
|||
static void test_create_duplicate_spell(CuTest * tc)
|
||||
{
|
||||
spell *sp;
|
||||
/* FIXME: this test emits ERROR messages (duplicate spells), inject a logger to verify that */
|
||||
|
||||
test_cleanup();
|
||||
CuAssertPtrEquals(tc, 0, find_spell("testspell"));
|
||||
|
@ -36,6 +38,7 @@ static void test_create_duplicate_spell(CuTest * tc)
|
|||
static void test_create_spell_with_id(CuTest * tc)
|
||||
{
|
||||
spell *sp;
|
||||
/* FIXME: this test emits ERROR messages (duplicate spells), inject a logger to verify that */
|
||||
|
||||
test_cleanup();
|
||||
CuAssertPtrEquals(tc, 0, find_spellbyid(42));
|
||||
|
|
28
src/laws.c
28
src/laws.c
|
@ -710,22 +710,20 @@ void immigration(void)
|
|||
}
|
||||
/* Genereate some (0-6 depending on the income) peasants out of nothing */
|
||||
/* if less than 50 are in the region and there is space and no monster or demon units in the region */
|
||||
int peasants = rpeasants(r);
|
||||
int income = wage(r, NULL, NULL, turn) - maintenance_cost(NULL);
|
||||
if (repopulate && r->land && (peasants < repopulate) && maxworkingpeasants(r) > (peasants + 30) * 2 && income >= 0) {
|
||||
int badunit = 0;
|
||||
unit *u;
|
||||
for (u = r->units; u; u = u->next) {
|
||||
if (!playerrace(u_race(u)) || u_race(u) == get_race(RC_DAEMON)) {
|
||||
badunit = 1;
|
||||
break;
|
||||
if (repopulate) {
|
||||
int peasants = rpeasants(r);
|
||||
int income = wage(r, NULL, NULL, turn) - maintenance_cost(NULL) + 1;
|
||||
if (income >= 0 && r->land && (peasants < repopulate) && maxworkingpeasants(r) >(peasants + 30) * 2) {
|
||||
int badunit = 0;
|
||||
unit *u;
|
||||
for (u = r->units; u; u = u->next) {
|
||||
if (!playerrace(u_race(u)) || u_race(u) == get_race(RC_DAEMON)) {
|
||||
badunit = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (badunit == 0)
|
||||
{
|
||||
int x = wage(r, NULL, NULL, turn) - 9;
|
||||
if (x>0) {
|
||||
peasants += (int)(rng_double()*x);
|
||||
if (badunit == 0) {
|
||||
peasants += (int)(rng_double()*income);
|
||||
rsetpeasants(r, peasants);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1229,6 +1229,8 @@ static void test_show_without_item(CuTest *tc)
|
|||
test_cleanup();
|
||||
|
||||
loc = get_or_create_locale("de");
|
||||
locale_setstring(loc, parameters[P_ANY], "ALLE");
|
||||
init_parameters(loc);
|
||||
|
||||
r = test_create_region(0, 0, test_create_terrain("testregion", LAND_REGION));
|
||||
f = test_create_faction(test_create_race("human"));
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "magic.h"
|
||||
#include "teleport.h"
|
||||
|
||||
#include <kernel/config.h>
|
||||
#include <kernel/race.h>
|
||||
#include <kernel/faction.h>
|
||||
#include <kernel/order.h>
|
||||
|
@ -388,6 +389,8 @@ void test_multi_cast(CuTest *tc) {
|
|||
|
||||
u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
|
||||
u->faction->locale = lang = get_or_create_locale("de");
|
||||
locale_setstring(lang, parameters[P_ANY], "ALLE");
|
||||
init_parameters(lang);
|
||||
locale_setstring(lang, mkname("spell", sp->sname), "Feuerball");
|
||||
CuAssertStrEquals(tc, "Feuerball", spell_name(sp, lang));
|
||||
set_level(u, SK_MAGIC, 10);
|
||||
|
|
10
src/main.c
10
src/main.c
|
@ -130,7 +130,7 @@ static int get_arg(int argc, char **argv, size_t len, int index, const char **re
|
|||
|
||||
static int parse_args(int argc, char **argv, int *exitcode)
|
||||
{
|
||||
int i;
|
||||
int i, log_stderr = 0;
|
||||
|
||||
for (i = 1; i != argc; ++i) {
|
||||
char *argi = argv[i];
|
||||
|
@ -210,6 +210,10 @@ static int parse_args(int argc, char **argv, int *exitcode)
|
|||
break;
|
||||
}
|
||||
|
||||
if (log_stderr) {
|
||||
log_to_file(log_stderr | LOG_FLUSH | LOG_BRIEF, stderr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -284,10 +288,6 @@ int main(int argc, char **argv)
|
|||
int err = 0;
|
||||
lua_State *L;
|
||||
setup_signal_handler();
|
||||
/* parse args once to read config file location */
|
||||
if (parse_args(argc, argv, &err) != 0) {
|
||||
return err;
|
||||
}
|
||||
/* ini file sets defaults for arguments*/
|
||||
parse_config(inifile);
|
||||
if (!global.inifile) {
|
||||
|
|
|
@ -1540,16 +1540,6 @@ static void prepare_report(struct report_context *ctx, faction *f)
|
|||
ctx->last = lastregion(f);
|
||||
}
|
||||
|
||||
static void mkreportdir(const char *rpath) {
|
||||
if (_mkdir(rpath) != 0) {
|
||||
if (_access(rpath, 0) < 0) {
|
||||
log_error("could not create reports directory %s: %s", rpath, strerror(errno));
|
||||
abort();
|
||||
}
|
||||
}
|
||||
errno = 0;
|
||||
}
|
||||
|
||||
int write_reports(faction * f, time_t ltime)
|
||||
{
|
||||
unsigned int backup = 1, maxbackup = 128 * 1000;
|
||||
|
@ -1557,14 +1547,12 @@ int write_reports(faction * f, time_t ltime)
|
|||
struct report_context ctx;
|
||||
const char *encoding = "UTF-8";
|
||||
report_type *rtype;
|
||||
const char *path = reportpath();
|
||||
|
||||
if (noreports) {
|
||||
return false;
|
||||
}
|
||||
prepare_report(&ctx, f);
|
||||
get_addresses(&ctx);
|
||||
mkreportdir(path); // FIXME: too many mkdir calls! init_reports is enough
|
||||
log_debug("Reports for %s:", factionname(f));
|
||||
for (rtype = report_types; rtype != NULL; rtype = rtype->next) {
|
||||
if (f->options & rtype->flag) {
|
||||
|
@ -1635,14 +1623,8 @@ static void check_messages_exist(void) {
|
|||
int init_reports(void)
|
||||
{
|
||||
check_messages_exist();
|
||||
|
||||
create_directories();
|
||||
prepare_reports();
|
||||
{
|
||||
if (_access(reportpath(), 0) != 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
mkreportdir(reportpath());
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1659,8 +1641,7 @@ int reports(void)
|
|||
report_donations();
|
||||
remove_empty_units();
|
||||
|
||||
mkreportdir(rpath); // FIXME: init_reports already does this?
|
||||
sprintf(path, "%s/reports.txt", rpath);
|
||||
join_path(rpath, "reports.txt", path, sizeof(path));
|
||||
mailit = fopen(path, "w");
|
||||
if (mailit == NULL) {
|
||||
log_error("%s could not be opened!\n", path);
|
||||
|
|
|
@ -253,6 +253,7 @@ static void test_write_unit(CuTest *tc) {
|
|||
race *rc;
|
||||
struct locale *lang;
|
||||
char buffer[1024];
|
||||
/* FIXME: test emits ERROR: no translation for combat status status_aggressive in locale de */
|
||||
|
||||
test_cleanup();
|
||||
rc = rc_get_or_create("human");
|
||||
|
@ -261,6 +262,7 @@ static void test_write_unit(CuTest *tc) {
|
|||
locale_setstring(lang, "nr_skills", "Talente");
|
||||
locale_setstring(lang, "skill::sailing", "Segeln");
|
||||
locale_setstring(lang, "skill::alchemy", "Alchemie");
|
||||
locale_setstring(lang, "status_aggressive", "aggressiv");
|
||||
init_skills(lang);
|
||||
u = test_create_unit(test_create_faction(rc), test_create_region(0, 0, 0));
|
||||
u->faction->locale = lang;
|
||||
|
@ -270,15 +272,15 @@ static void test_write_unit(CuTest *tc) {
|
|||
unit_setid(u, 1);
|
||||
|
||||
bufunit(u->faction, u, 0, 0, buffer, sizeof(buffer));
|
||||
CuAssertStrEquals(tc, "Hodor (1), 1 human, status_aggressive.", buffer);
|
||||
CuAssertStrEquals(tc, "Hodor (1), 1 human, aggressiv.", buffer);
|
||||
|
||||
set_level(u, SK_SAILING, 1);
|
||||
bufunit(u->faction, u, 0, 0, buffer, sizeof(buffer));
|
||||
CuAssertStrEquals(tc, "Hodor (1), 1 human, status_aggressive, Talente: Segeln 1.", buffer);
|
||||
CuAssertStrEquals(tc, "Hodor (1), 1 human, aggressiv, Talente: Segeln 1.", buffer);
|
||||
|
||||
set_level(u, SK_ALCHEMY, 1);
|
||||
bufunit(u->faction, u, 0, 0, buffer, sizeof(buffer));
|
||||
CuAssertStrEquals(tc, "Hodor (1), 1 human, status_aggressive, Talente: Segeln 1, Alchemie 2.", buffer);
|
||||
CuAssertStrEquals(tc, "Hodor (1), 1 human, aggressiv, Talente: Segeln 1, Alchemie 2.", buffer);
|
||||
|
||||
f = test_create_faction(0);
|
||||
f->locale = get_or_create_locale("de");
|
||||
|
|
|
@ -100,7 +100,7 @@ static void test_sabotage_self(CuTest *tc) {
|
|||
order *ord;
|
||||
|
||||
setup_sabotage();
|
||||
r = test_create_region(0, 0, NULL);
|
||||
r = findregion(0, 0);
|
||||
assert(r);
|
||||
u = test_create_unit(test_create_faction(NULL), r);
|
||||
assert(u && u->faction && u->region == r);
|
||||
|
@ -122,7 +122,7 @@ static void test_sabotage_other_fail(CuTest *tc) {
|
|||
message *msg;
|
||||
|
||||
setup_sabotage();
|
||||
r = test_create_region(0, 0, NULL);
|
||||
r = findregion(0, 0);
|
||||
assert(r);
|
||||
u = test_create_unit(test_create_faction(NULL), r);
|
||||
u2 = test_create_unit(test_create_faction(NULL), r);
|
||||
|
@ -151,7 +151,7 @@ static void test_sabotage_other_success(CuTest *tc) {
|
|||
order *ord;
|
||||
|
||||
setup_sabotage();
|
||||
r = test_create_region(0, 0, NULL);
|
||||
r = findregion(0, 0);
|
||||
assert(r);
|
||||
u = test_create_unit(test_create_faction(NULL), r);
|
||||
u2 = test_create_unit(test_create_faction(NULL), r);
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <kernel/unit.h>
|
||||
#include <kernel/faction.h>
|
||||
#include <kernel/order.h>
|
||||
#include <kernel/region.h>
|
||||
#include <util/message.h>
|
||||
#include <util/language.h>
|
||||
#include <util/base36.h>
|
||||
|
@ -29,7 +30,7 @@ static void setup_study(study_fixture *fix, skill_t sk) {
|
|||
test_cleanup();
|
||||
config_set("study.random_progress", "0");
|
||||
test_create_world();
|
||||
r = test_create_region(0, 0, 0);
|
||||
r = findregion(0, 0);
|
||||
f = test_create_faction(0);
|
||||
lang = get_or_create_locale(locale_name(f->locale));
|
||||
locale_setstring(lang, mkname("skill", skillnames[sk]), skillnames[sk]);
|
||||
|
|
|
@ -156,7 +156,7 @@ int RunAllTests(int argc, char *argv[])
|
|||
}
|
||||
|
||||
int main(int argc, char ** argv) {
|
||||
log_stderr = 0;
|
||||
log_to_file(LOG_CPERROR, stderr);
|
||||
++argv;
|
||||
--argc;
|
||||
if (argc > 0 && strcmp("--list", argv[0]) == 0) {
|
||||
|
|
17
src/tests.c
17
src/tests.c
|
@ -45,14 +45,19 @@ struct race *test_create_race(const char *name)
|
|||
|
||||
struct region *test_create_region(int x, int y, const terrain_type *terrain)
|
||||
{
|
||||
region *r = new_region(x, y, NULL, 0);
|
||||
region *r = findregion(x, y);
|
||||
if (!r) {
|
||||
r = new_region(x, y, NULL, 0);
|
||||
}
|
||||
if (!terrain) {
|
||||
terrain_type *t = get_or_create_terrain("plain");
|
||||
t->size = 1000;
|
||||
fset(t, LAND_REGION|CAVALRY_REGION|FOREST_REGION);
|
||||
terraform_region(r, t);
|
||||
} else
|
||||
}
|
||||
else {
|
||||
terraform_region(r, terrain);
|
||||
}
|
||||
rsettrees(r, 0, 0);
|
||||
rsettrees(r, 1, 0);
|
||||
rsettrees(r, 2, 0);
|
||||
|
@ -103,7 +108,7 @@ void test_cleanup(void)
|
|||
if (errno) {
|
||||
int error = errno;
|
||||
errno = 0;
|
||||
log_error("errno: %d", error);
|
||||
log_error("errno: %d (%s)", error, strerror(error));
|
||||
}
|
||||
|
||||
random_source_reset();
|
||||
|
@ -255,6 +260,12 @@ void test_create_world(void)
|
|||
struct locale * loc;
|
||||
|
||||
loc = get_or_create_locale("de");
|
||||
|
||||
locale_setstring(loc, parameters[P_SHIP], "SCHIFF");
|
||||
locale_setstring(loc, parameters[P_ANY], "ALLE");
|
||||
init_parameters(loc);
|
||||
|
||||
locale_setstring(loc, "status_aggressive", "aggressiv");
|
||||
locale_setstring(loc, keyword(K_RESERVE), "RESERVIEREN");
|
||||
locale_setstring(loc, "money", "SILBER");
|
||||
init_resources();
|
||||
|
|
327
src/util/log.c
327
src/util/log.c
|
@ -24,29 +24,33 @@ without prior permission by the authors of Eressea.
|
|||
|
||||
/* TODO: set from external function */
|
||||
int log_flags = LOG_FLUSH | LOG_CPERROR | LOG_CPWARNING | LOG_CPDEBUG;
|
||||
int log_stderr = LOG_FLUSH | LOG_CPERROR | LOG_CPWARNING;
|
||||
|
||||
#ifdef STDIO_CP
|
||||
static int stdio_codepage = STDIO_CP;
|
||||
#else
|
||||
static int stdio_codepage = 0;
|
||||
#endif
|
||||
static FILE *logfile;
|
||||
|
||||
typedef struct logger {
|
||||
void(*log)(void *data, int level, const char *module, const char *format, va_list args);
|
||||
void *data;
|
||||
int flags;
|
||||
struct logger *next;
|
||||
} logger;
|
||||
|
||||
static logger *loggers;
|
||||
|
||||
void log_create(int flags, void *data, log_fun call) {
|
||||
logger *lgr = malloc(sizeof(logger));
|
||||
lgr->log = call;
|
||||
lgr->flags = flags;
|
||||
lgr->data = data;
|
||||
lgr->next = loggers;
|
||||
loggers = lgr;
|
||||
}
|
||||
|
||||
#define MAXLENGTH 4096 /* because I am lazy, CP437 output is limited to this many chars */
|
||||
#define LOG_MAXBACKUPS 5
|
||||
void log_flush(void)
|
||||
{
|
||||
if (logfile) fflush(logfile);
|
||||
}
|
||||
|
||||
void log_puts(const char *str)
|
||||
{
|
||||
fflush(stdout);
|
||||
if (logfile) {
|
||||
fputs(str, logfile);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
cp_convert(const char *format, char *buffer, size_t length, int codepage)
|
||||
|
@ -100,38 +104,17 @@ void log_rotate(const char *filename, int maxindex)
|
|||
}
|
||||
}
|
||||
|
||||
void log_open(const char *filename)
|
||||
{
|
||||
if (logfile) {
|
||||
log_close();
|
||||
}
|
||||
log_rotate(filename, LOG_MAXBACKUPS);
|
||||
logfile = fopen(filename, "a");
|
||||
if (logfile) {
|
||||
/* Get UNIX-style time and display as number and string. */
|
||||
time_t ltime;
|
||||
time(<ime);
|
||||
fprintf(logfile, "===\n=== Logfile started at %s===\n", ctime(<ime));
|
||||
}
|
||||
static const char *log_prefix(int level) {
|
||||
const char * prefix = "ERROR";
|
||||
if (level == LOG_CPWARNING) prefix = "WARNING";
|
||||
else if (level == LOG_CPDEBUG) prefix = "DEBUG";
|
||||
else if (level == LOG_CPINFO) prefix = "INFO";
|
||||
return prefix;
|
||||
}
|
||||
|
||||
void log_close(void)
|
||||
static int check_dupe(const char *format, int type)
|
||||
{
|
||||
if (!logfile || logfile == stderr || logfile == stdout)
|
||||
return;
|
||||
if (logfile) {
|
||||
/* Get UNIX-style time and display as number and string. */
|
||||
time_t ltime;
|
||||
time(<ime);
|
||||
fprintf(logfile, "===\n=== Logfile closed at %s===\n\n", ctime(<ime));
|
||||
fclose(logfile);
|
||||
}
|
||||
logfile = 0;
|
||||
}
|
||||
|
||||
static int check_dupe(const char *format, const char *type)
|
||||
{
|
||||
static const char *last_type; /* STATIC_XCALL: used across calls */
|
||||
static int last_type; /* STATIC_XCALL: used across calls */
|
||||
static char last_message[32]; /* STATIC_XCALL: used across calls */
|
||||
static int dupes = 0; /* STATIC_XCALL: used across calls */
|
||||
if (strncmp(last_message, format, sizeof(last_message)) == 0) {
|
||||
|
@ -140,7 +123,7 @@ static int check_dupe(const char *format, const char *type)
|
|||
}
|
||||
if (dupes) {
|
||||
if (log_flags & LOG_CPERROR) {
|
||||
fprintf(stderr, "%s: last message repeated %d times\n", last_type,
|
||||
fprintf(stderr, "%s: last message repeated %d times\n", log_prefix(last_type),
|
||||
dupes + 1);
|
||||
}
|
||||
dupes = 0;
|
||||
|
@ -150,202 +133,136 @@ static int check_dupe(const char *format, const char *type)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void _log_write(FILE * stream, int codepage, const char * prefix, const char *format, va_list args)
|
||||
static void _log_write(FILE * stream, int codepage, const char *format, va_list args)
|
||||
{
|
||||
if (stream) {
|
||||
fprintf(stream, "%s: ", prefix);
|
||||
if (codepage) {
|
||||
char buffer[MAXLENGTH];
|
||||
char converted[MAXLENGTH];
|
||||
if (codepage) {
|
||||
char buffer[MAXLENGTH];
|
||||
char converted[MAXLENGTH];
|
||||
|
||||
vsnprintf(buffer, sizeof(buffer), format, args);
|
||||
if (cp_convert(buffer, converted, MAXLENGTH, codepage) == 0) {
|
||||
fputs(converted, stream);
|
||||
}
|
||||
else {
|
||||
/* fall back to non-converted output */
|
||||
vfprintf(stream, format, args);
|
||||
}
|
||||
vsnprintf(buffer, sizeof(buffer), format, args);
|
||||
if (cp_convert(buffer, converted, MAXLENGTH, codepage) == 0) {
|
||||
fputs(converted, stream);
|
||||
}
|
||||
else {
|
||||
/* fall back to non-converted output */
|
||||
vfprintf(stream, format, args);
|
||||
}
|
||||
}
|
||||
else {
|
||||
vfprintf(stream, format, args);
|
||||
}
|
||||
}
|
||||
|
||||
static void _log_writeln(FILE * stream, int codepage, const char * prefix, const char *format, va_list args)
|
||||
{
|
||||
static void log_stdio(void *data, int level, const char *module, const char *format, va_list args) {
|
||||
FILE *out = (FILE *)data;
|
||||
int codepage = (out == stderr || out == stdout) ? stdio_codepage : 0;
|
||||
const char *prefix = log_prefix(level);
|
||||
size_t len = strlen(format);
|
||||
_log_write(stream, codepage, prefix, format, args);
|
||||
|
||||
fprintf(out, "%s: ", prefix);
|
||||
|
||||
_log_write(out, codepage, format, args);
|
||||
if (format[len - 1] != '\n') {
|
||||
fputc('\n', stream);
|
||||
}
|
||||
}
|
||||
void log_debug(const char *format, ...)
|
||||
{
|
||||
const char * prefix = "DEBUG";
|
||||
const int mask = LOG_CPDEBUG;
|
||||
|
||||
/* write to the logfile, always */
|
||||
if (logfile && (log_flags & mask)) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
_log_writeln(logfile, 0, prefix, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/* write to stderr, if that's not the logfile already */
|
||||
if (logfile != stderr && (log_stderr & mask)) {
|
||||
int dupe = check_dupe(format, prefix);
|
||||
if (!dupe) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
_log_writeln(stderr, stdio_codepage, prefix, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
}
|
||||
if (log_flags & LOG_FLUSH) {
|
||||
log_flush();
|
||||
fputc('\n', out);
|
||||
}
|
||||
}
|
||||
|
||||
void log_warning(const char *format, ...)
|
||||
{
|
||||
const char * prefix = "WARNING";
|
||||
const int mask = LOG_CPWARNING;
|
||||
void log_to_file(int flags, FILE *out) {
|
||||
log_create(flags, out, log_stdio);
|
||||
}
|
||||
|
||||
/* write to the logfile, always */
|
||||
if (logfile && (log_flags & mask)) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
_log_writeln(logfile, 0, prefix, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/* write to stderr, if that's not the logfile already */
|
||||
if (logfile != stderr && (log_stderr & mask)) {
|
||||
int dupe = check_dupe(format, prefix);
|
||||
if (!dupe) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
_log_writeln(stderr, stdio_codepage, prefix, format, args);
|
||||
va_end(args);
|
||||
static void log_write(int flags, const char *module, const char *format, va_list args) {
|
||||
logger *lg;
|
||||
for (lg = loggers; lg; lg = lg->next) {
|
||||
int level = flags & LOG_LEVELS;
|
||||
if (lg->flags & level) {
|
||||
int dupe = 0;
|
||||
if (lg->flags & LOG_BRIEF) {
|
||||
dupe = check_dupe(format, level);
|
||||
}
|
||||
if (dupe == 0) {
|
||||
lg->log(lg->data, level, NULL, format, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (log_flags & LOG_FLUSH) {
|
||||
log_flush();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void log_fatal(const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
log_write(LOG_CPERROR, NULL, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void log_error(const char *format, ...)
|
||||
{
|
||||
const char * prefix = "ERROR";
|
||||
const int mask = LOG_CPERROR;
|
||||
|
||||
/* write to the logfile, always */
|
||||
if (logfile && (log_flags & mask)) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
_log_writeln(logfile, 0, prefix, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/* write to stderr, if that's not the logfile already */
|
||||
if (logfile != stderr && (log_stderr & mask)) {
|
||||
int dupe = check_dupe(format, prefix);
|
||||
if (!dupe) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
_log_writeln(stderr, stdio_codepage, prefix, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
}
|
||||
if (log_flags & LOG_FLUSH) {
|
||||
log_flush();
|
||||
}
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
log_write(LOG_CPERROR, NULL, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void log_fatal(const char *format, ...)
|
||||
void log_warning(const char *format, ...)
|
||||
{
|
||||
const char * prefix = "ERROR";
|
||||
const int mask = LOG_CPERROR;
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
log_write(LOG_CPWARNING, NULL, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/* write to the logfile, always */
|
||||
if (logfile && (log_flags & mask)) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
_log_writeln(logfile, 0, prefix, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/* write to stderr, if that's not the logfile already */
|
||||
if (logfile != stderr) {
|
||||
int dupe = check_dupe(format, prefix);
|
||||
if (!dupe) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
_log_writeln(stderr, stdio_codepage, prefix, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
}
|
||||
if (log_flags & LOG_FLUSH) {
|
||||
log_flush();
|
||||
}
|
||||
void log_debug(const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
log_write(LOG_CPDEBUG, NULL, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void log_info(const char *format, ...)
|
||||
{
|
||||
const char * prefix = "INFO";
|
||||
const int mask = LOG_CPINFO;
|
||||
|
||||
/* write to the logfile, always */
|
||||
if (logfile && (log_flags & mask)) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
_log_writeln(logfile, 0, prefix, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/* write to stderr, if that's not the logfile already */
|
||||
if (logfile != stderr && (log_stderr & mask)) {
|
||||
int dupe = check_dupe(format, prefix);
|
||||
if (!dupe) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
_log_writeln(stderr, stdio_codepage, prefix, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
}
|
||||
if (log_flags & LOG_FLUSH) {
|
||||
log_flush();
|
||||
}
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
log_write(LOG_CPINFO, NULL, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void log_printf(FILE * io, const char *format, ...)
|
||||
{
|
||||
const char * prefix = "INFO";
|
||||
const int mask = LOG_CPINFO;
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
log_write(LOG_CPINFO, NULL, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/* write to the logfile, always */
|
||||
if (logfile && (log_flags & mask)) {
|
||||
int codepage = (logfile == stderr || logfile == stdout) ? stdio_codepage : 0;
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
_log_write(logfile, codepage, prefix, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
static FILE *logfile;
|
||||
|
||||
/* write to io, if that's not the logfile already */
|
||||
if (logfile != io && (log_stderr & mask)) {
|
||||
int dupe = check_dupe(format, prefix);
|
||||
if (!dupe) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
_log_write(io, stdio_codepage, prefix, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
void log_close(void)
|
||||
{
|
||||
while (loggers) {
|
||||
logger *lgr = loggers;
|
||||
loggers = lgr->next;
|
||||
free(lgr);
|
||||
}
|
||||
if (log_flags & LOG_FLUSH) {
|
||||
log_flush();
|
||||
if (logfile) {
|
||||
time_t ltime;
|
||||
time(<ime);
|
||||
fprintf(logfile, "===\n=== Logfile closed at %s===\n\n", ctime(<ime));
|
||||
fclose(logfile);
|
||||
}
|
||||
logfile = 0;
|
||||
}
|
||||
|
||||
void log_open(const char *filename)
|
||||
{
|
||||
log_rotate(filename, LOG_MAXBACKUPS);
|
||||
logfile = fopen(filename, "a");
|
||||
if (logfile) {
|
||||
/* Get UNIX-style time and display as number and string. */
|
||||
time_t ltime;
|
||||
time(<ime);
|
||||
fprintf(logfile, "===\n=== Logfile started at %s===\n", ctime(<ime));
|
||||
log_create(log_flags, logfile, log_stdio);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,9 +15,10 @@ without prior permission by the authors of Eressea.
|
|||
extern "C" {
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
extern void log_open(const char *filename);
|
||||
extern void log_close(void);
|
||||
extern void log_flush(void);
|
||||
|
||||
/* use macros above instead of these: */
|
||||
extern void log_fatal(const char *format, ...);
|
||||
|
@ -27,11 +28,18 @@ extern "C" {
|
|||
extern void log_info(const char *format, ...);
|
||||
extern void log_printf(FILE * ios, const char *format, ...);
|
||||
|
||||
#define LOG_FLUSH 0x01
|
||||
#define LOG_CPERROR 0x01
|
||||
#define LOG_CPWARNING 0x02
|
||||
#define LOG_CPERROR 0x04
|
||||
#define LOG_CPINFO 0x08
|
||||
#define LOG_CPDEBUG 0x10
|
||||
#define LOG_CPINFO 0x04
|
||||
#define LOG_CPDEBUG 0x08
|
||||
#define LOG_LEVELS 0x0F
|
||||
#define LOG_FLUSH 0x10
|
||||
#define LOG_BRIEF 0x20
|
||||
|
||||
typedef void(*log_fun)(void *data, int level, const char *module, const char *format, va_list args);
|
||||
|
||||
void log_create(int flags, void *data, log_fun call);
|
||||
void log_to_file(int flags, FILE *out);
|
||||
|
||||
extern int log_flags;
|
||||
extern int log_stderr;
|
||||
|
|
2
storage
2
storage
|
@ -1 +1 @@
|
|||
Subproject commit 89f3c1b01e41f2675fcbfd51fd8494894dc22d44
|
||||
Subproject commit 18cc3bb8f8906237915eb31c9899f95340318087
|
Loading…
Reference in a new issue