diff --git a/src/bind_storage.c b/src/bind_storage.c index ca83f199a..aaeb84128 100644 --- a/src/bind_storage.c +++ b/src/bind_storage.c @@ -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); diff --git a/src/kernel/config.c b/src/kernel/config.c index bd9a30d81..08b7f53c9 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -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) diff --git a/src/kernel/config.h b/src/kernel/config.h index 257de940d..dda7873aa 100644 --- a/src/kernel/config.h +++ b/src/kernel/config.h @@ -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); diff --git a/src/kernel/group.test.c b/src/kernel/group.test.c index 46d794d2d..35b25aad5 100644 --- a/src/kernel/group.test.c +++ b/src/kernel/group.test.c @@ -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; diff --git a/src/kernel/jsonconf.c b/src/kernel/jsonconf.c index fc2d9dd20..099b7a228 100644 --- a/src/kernel/jsonconf.c +++ b/src/kernel/jsonconf.c @@ -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) { diff --git a/src/kernel/messages.c b/src/kernel/messages.c index 779354498..330c2feeb 100644 --- a/src/kernel/messages.c +++ b/src/kernel/messages.c @@ -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)); } diff --git a/src/kernel/save.c b/src/kernel/save.c index 2d37c6822..25ae2d858 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -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; diff --git a/src/kernel/save.test.c b/src/kernel/save.test.c index 35e07325b..e7f85ad7e 100644 --- a/src/kernel/save.test.c +++ b/src/kernel/save.test.c @@ -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); diff --git a/src/kernel/spell.test.c b/src/kernel/spell.test.c index 23e227ebe..0c0beb6ce 100644 --- a/src/kernel/spell.test.c +++ b/src/kernel/spell.test.c @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -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)); diff --git a/src/laws.c b/src/laws.c index 8b2f781c3..eb079b8ac 100755 --- a/src/laws.c +++ b/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); } } diff --git a/src/laws.test.c b/src/laws.test.c index 5d21250cd..5be4c7143 100644 --- a/src/laws.test.c +++ b/src/laws.test.c @@ -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")); diff --git a/src/magic.test.c b/src/magic.test.c index 1f0995bc6..ad698625a 100644 --- a/src/magic.test.c +++ b/src/magic.test.c @@ -3,6 +3,7 @@ #include "magic.h" #include "teleport.h" +#include #include #include #include @@ -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); diff --git a/src/main.c b/src/main.c index 6eac28470..305d4a901 100644 --- a/src/main.c +++ b/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) { diff --git a/src/reports.c b/src/reports.c index 99b9f755c..b33f5f1cb 100644 --- a/src/reports.c +++ b/src/reports.c @@ -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); diff --git a/src/reports.test.c b/src/reports.test.c index 0955e8a6f..dd2c544eb 100644 --- a/src/reports.test.c +++ b/src/reports.test.c @@ -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"); diff --git a/src/spy.test.c b/src/spy.test.c index 00a1767d0..a4e2f1151 100644 --- a/src/spy.test.c +++ b/src/spy.test.c @@ -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); diff --git a/src/study.test.c b/src/study.test.c index 6b9d97787..bdbfb9a01 100644 --- a/src/study.test.c +++ b/src/study.test.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -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]); diff --git a/src/test_eressea.c b/src/test_eressea.c index 1053306c6..a9b9b941c 100644 --- a/src/test_eressea.c +++ b/src/test_eressea.c @@ -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) { diff --git a/src/tests.c b/src/tests.c index 6fef425d0..b8508b4cc 100644 --- a/src/tests.c +++ b/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(); diff --git a/src/util/log.c b/src/util/log.c index 3b7ec50a0..958e26e2f 100644 --- a/src/util/log.c +++ b/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); } } diff --git a/src/util/log.h b/src/util/log.h index 40a667de4..8fd8f2a95 100644 --- a/src/util/log.h +++ b/src/util/log.h @@ -15,9 +15,10 @@ without prior permission by the authors of Eressea. extern "C" { #endif #include +#include + 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; diff --git a/storage b/storage index 89f3c1b01..18cc3bb8f 160000 --- a/storage +++ b/storage @@ -1 +1 @@ -Subproject commit 89f3c1b01e41f2675fcbfd51fd8494894dc22d44 +Subproject commit 18cc3bb8f8906237915eb31c9899f95340318087