diff --git a/src/kernel/config.c b/src/kernel/config.c index bd9a30d81..6cc31c3b0 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,19 +708,6 @@ 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; -} - double get_param_flt(const struct param *p, const char *key, double def) { const char *str = get_param(p, key); diff --git a/src/kernel/config.h b/src/kernel/config.h index 257de940d..30aa25549 100644 --- a/src/kernel/config.h +++ b/src/kernel/config.h @@ -185,6 +185,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/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.test.c b/src/kernel/save.test.c index 35e07325b..1492750ab 100644 --- a/src/kernel/save.test.c +++ b/src/kernel/save.test.c @@ -32,6 +32,7 @@ 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? */ test_cleanup(); r = test_create_region(0, 0, 0); @@ -39,7 +40,7 @@ static void test_readwrite_unit(CuTest * tc) 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"); CuAssertPtrNotNull(tc, data); // TODO: intermittent test 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.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..efcbc6203 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, 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.test.c b/src/reports.test.c index 0955e8a6f..103dc28ff 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"); 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..0511919c3 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,11 @@ 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, keyword(K_RESERVE), "RESERVIEREN"); locale_setstring(loc, "money", "SILBER"); init_resources(); @@ -270,6 +280,7 @@ void test_create_world(void) test_create_itemtype("iron"); test_create_itemtype("stone"); + t_plain = test_create_terrain("plain", LAND_REGION | FOREST_REGION | WALK_INTO | CAVALRY_REGION | SAIL_INTO | FLY_INTO); t_plain->size = 1000; t_plain->max_road = 100; 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;