Merge branch 'feature/issue-462-log-test-errors' of https://github.com/ennorehling/eressea into ennorehling-feature/issue-462-log-test-errors

Conflicts:
	src/magic.test.c
This commit is contained in:
Enno Rehling 2016-01-31 21:58:16 +01:00
commit 09ae3d8993
15 changed files with 212 additions and 243 deletions

View file

@ -640,9 +640,43 @@ int check_param(const struct param *p, const char *key, const char *searchvalue)
return result; return result;
} }
const char * relpath(char *buf, size_t sz, const char *path) { static const char *g_basedir;
strlcpy(buf, basepath(), sz); const char *basepath(void)
strlcat(buf, path, sz); {
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; return buf;
} }
@ -652,7 +686,7 @@ const char *datapath(void)
static char zText[MAX_PATH]; // FIXME: static return value static char zText[MAX_PATH]; // FIXME: static return value
if (g_datadir) if (g_datadir)
return g_datadir; return g_datadir;
return relpath(zText, sizeof(zText), "/data"); return relpath(zText, sizeof(zText), "data");
} }
void set_datapath(const char *path) void set_datapath(const char *path)
@ -666,7 +700,7 @@ const char *reportpath(void)
static char zText[MAX_PATH]; // FIXME: static return value static char zText[MAX_PATH]; // FIXME: static return value
if (g_reportdir) if (g_reportdir)
return g_reportdir; return g_reportdir;
return relpath(zText, sizeof(zText), "/reports"); return relpath(zText, sizeof(zText), "reports");
} }
void set_reportpath(const char *path) void set_reportpath(const char *path)
@ -674,19 +708,6 @@ void set_reportpath(const char *path)
g_reportdir = 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) double get_param_flt(const struct param *p, const char *key, double def)
{ {
const char *str = get_param(p, key); const char *str = get_param(p, key);

View file

@ -185,6 +185,7 @@ struct param;
double config_get_flt(const char *key, double def); double config_get_flt(const char *key, double def);
bool config_token(const char *key, const char *tok); 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); bool ExpensiveMigrants(void);
int NMRTimeout(void); int NMRTimeout(void);
int LongHunger(const struct unit *u); int LongHunger(const struct unit *u);

View file

@ -90,7 +90,7 @@ struct message *msg_feedback(const struct unit *u, struct order *ord,
ord = u->thisorder; ord = u->thisorder;
if (!mtype) { 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")) { if (!mt_find("missing_feedback")) {
mt_register(mt_new_va("missing_feedback", "unit:unit", "region:region", "command:order", "name:string", 0)); mt_register(mt_new_va("missing_feedback", "unit:unit", "region:region", "command:order", "name:string", 0));
} }

View file

@ -32,6 +32,7 @@ static void test_readwrite_unit(CuTest * tc)
struct region *r; struct region *r;
struct faction *f; struct faction *f;
int fno; int fno;
/* FIXME: at some point during this test, errno is set to 17 (File exists), why? */
test_cleanup(); test_cleanup();
r = test_create_region(0, 0, 0); r = test_create_region(0, 0, 0);
@ -39,7 +40,7 @@ static void test_readwrite_unit(CuTest * tc)
fno = f->no; fno = f->no;
u = test_create_unit(f, r); u = test_create_unit(f, r);
_mkdir(datapath()); _mkdir(datapath());
sprintf(path, "%s/%s", datapath(), filename); join_path(datapath(), filename, path, sizeof(path));
data = gamedata_open(path, "wb"); data = gamedata_open(path, "wb");
CuAssertPtrNotNull(tc, data); // TODO: intermittent test CuAssertPtrNotNull(tc, data); // TODO: intermittent test

View file

@ -2,6 +2,7 @@
#include <quicklist.h> #include <quicklist.h>
#include <kernel/spell.h> #include <kernel/spell.h>
#include <util/log.h>
#include <CuTest.h> #include <CuTest.h>
#include <tests.h> #include <tests.h>
@ -24,6 +25,7 @@ static void test_create_a_spell(CuTest * tc)
static void test_create_duplicate_spell(CuTest * tc) static void test_create_duplicate_spell(CuTest * tc)
{ {
spell *sp; spell *sp;
/* FIXME: this test emits ERROR messages (duplicate spells), inject a logger to verify that */
test_cleanup(); test_cleanup();
CuAssertPtrEquals(tc, 0, find_spell("testspell")); 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) static void test_create_spell_with_id(CuTest * tc)
{ {
spell *sp; spell *sp;
/* FIXME: this test emits ERROR messages (duplicate spells), inject a logger to verify that */
test_cleanup(); test_cleanup();
CuAssertPtrEquals(tc, 0, find_spellbyid(42)); CuAssertPtrEquals(tc, 0, find_spellbyid(42));

View file

@ -1229,6 +1229,8 @@ static void test_show_without_item(CuTest *tc)
test_cleanup(); test_cleanup();
loc = get_or_create_locale("de"); 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)); r = test_create_region(0, 0, test_create_terrain("testregion", LAND_REGION));
f = test_create_faction(test_create_race("human")); f = test_create_faction(test_create_race("human"));

View file

@ -3,6 +3,7 @@
#include "magic.h" #include "magic.h"
#include "teleport.h" #include "teleport.h"
#include <kernel/config.h>
#include <kernel/race.h> #include <kernel/race.h>
#include <kernel/faction.h> #include <kernel/faction.h>
#include <kernel/order.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 = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
u->faction->locale = lang = get_or_create_locale("de"); 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"); locale_setstring(lang, mkname("spell", sp->sname), "Feuerball");
CuAssertStrEquals(tc, "Feuerball", spell_name(sp, lang)); CuAssertStrEquals(tc, "Feuerball", spell_name(sp, lang));
set_level(u, SK_MAGIC, 10); set_level(u, SK_MAGIC, 10);

View file

@ -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) static int parse_args(int argc, char **argv, int *exitcode)
{ {
int i; int i, log_stderr = 0;
for (i = 1; i != argc; ++i) { for (i = 1; i != argc; ++i) {
char *argi = argv[i]; char *argi = argv[i];
@ -210,6 +210,10 @@ static int parse_args(int argc, char **argv, int *exitcode)
break; break;
} }
if (log_stderr) {
log_to_file(log_stderr, stderr);
}
return 0; return 0;
} }
@ -284,10 +288,6 @@ int main(int argc, char **argv)
int err = 0; int err = 0;
lua_State *L; lua_State *L;
setup_signal_handler(); 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*/ /* ini file sets defaults for arguments*/
parse_config(inifile); parse_config(inifile);
if (!global.inifile) { if (!global.inifile) {

View file

@ -253,6 +253,7 @@ static void test_write_unit(CuTest *tc) {
race *rc; race *rc;
struct locale *lang; struct locale *lang;
char buffer[1024]; char buffer[1024];
/* FIXME: test emits ERROR: no translation for combat status status_aggressive in locale de */
test_cleanup(); test_cleanup();
rc = rc_get_or_create("human"); rc = rc_get_or_create("human");

View file

@ -100,7 +100,7 @@ static void test_sabotage_self(CuTest *tc) {
order *ord; order *ord;
setup_sabotage(); setup_sabotage();
r = test_create_region(0, 0, NULL); r = findregion(0, 0);
assert(r); assert(r);
u = test_create_unit(test_create_faction(NULL), r); u = test_create_unit(test_create_faction(NULL), r);
assert(u && u->faction && u->region == r); assert(u && u->faction && u->region == r);
@ -122,7 +122,7 @@ static void test_sabotage_other_fail(CuTest *tc) {
message *msg; message *msg;
setup_sabotage(); setup_sabotage();
r = test_create_region(0, 0, NULL); r = findregion(0, 0);
assert(r); assert(r);
u = test_create_unit(test_create_faction(NULL), r); u = test_create_unit(test_create_faction(NULL), r);
u2 = 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; order *ord;
setup_sabotage(); setup_sabotage();
r = test_create_region(0, 0, NULL); r = findregion(0, 0);
assert(r); assert(r);
u = test_create_unit(test_create_faction(NULL), r); u = test_create_unit(test_create_faction(NULL), r);
u2 = test_create_unit(test_create_faction(NULL), r); u2 = test_create_unit(test_create_faction(NULL), r);

View file

@ -6,6 +6,7 @@
#include <kernel/unit.h> #include <kernel/unit.h>
#include <kernel/faction.h> #include <kernel/faction.h>
#include <kernel/order.h> #include <kernel/order.h>
#include <kernel/region.h>
#include <util/message.h> #include <util/message.h>
#include <util/language.h> #include <util/language.h>
#include <util/base36.h> #include <util/base36.h>
@ -29,7 +30,7 @@ static void setup_study(study_fixture *fix, skill_t sk) {
test_cleanup(); test_cleanup();
config_set("study.random_progress", "0"); config_set("study.random_progress", "0");
test_create_world(); test_create_world();
r = test_create_region(0, 0, 0); r = findregion(0, 0);
f = test_create_faction(0); f = test_create_faction(0);
lang = get_or_create_locale(locale_name(f->locale)); lang = get_or_create_locale(locale_name(f->locale));
locale_setstring(lang, mkname("skill", skillnames[sk]), skillnames[sk]); locale_setstring(lang, mkname("skill", skillnames[sk]), skillnames[sk]);

View file

@ -156,7 +156,7 @@ int RunAllTests(int argc, char *argv[])
} }
int main(int argc, char ** argv) { int main(int argc, char ** argv) {
log_stderr = 0; log_to_file(LOG_CPERROR, stderr);
++argv; ++argv;
--argc; --argc;
if (argc > 0 && strcmp("--list", argv[0]) == 0) { if (argc > 0 && strcmp("--list", argv[0]) == 0) {

View file

@ -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) 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) { if (!terrain) {
terrain_type *t = get_or_create_terrain("plain"); terrain_type *t = get_or_create_terrain("plain");
t->size = 1000; t->size = 1000;
fset(t, LAND_REGION|CAVALRY_REGION|FOREST_REGION); fset(t, LAND_REGION|CAVALRY_REGION|FOREST_REGION);
terraform_region(r, t); terraform_region(r, t);
} else }
else {
terraform_region(r, terrain); terraform_region(r, terrain);
}
rsettrees(r, 0, 0); rsettrees(r, 0, 0);
rsettrees(r, 1, 0); rsettrees(r, 1, 0);
rsettrees(r, 2, 0); rsettrees(r, 2, 0);
@ -103,7 +108,7 @@ void test_cleanup(void)
if (errno) { if (errno) {
int error = errno; int error = errno;
errno = 0; errno = 0;
log_error("errno: %d", error); log_error("errno: %d (%s)", error, strerror(error));
} }
random_source_reset(); random_source_reset();
@ -255,6 +260,11 @@ void test_create_world(void)
struct locale * loc; struct locale * loc;
loc = get_or_create_locale("de"); 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, keyword(K_RESERVE), "RESERVIEREN");
locale_setstring(loc, "money", "SILBER"); locale_setstring(loc, "money", "SILBER");
init_resources(); init_resources();
@ -270,6 +280,7 @@ void test_create_world(void)
test_create_itemtype("iron"); test_create_itemtype("iron");
test_create_itemtype("stone"); test_create_itemtype("stone");
t_plain = test_create_terrain("plain", LAND_REGION | FOREST_REGION | WALK_INTO | CAVALRY_REGION | SAIL_INTO | FLY_INTO); t_plain = test_create_terrain("plain", LAND_REGION | FOREST_REGION | WALK_INTO | CAVALRY_REGION | SAIL_INTO | FLY_INTO);
t_plain->size = 1000; t_plain->size = 1000;
t_plain->max_road = 100; t_plain->max_road = 100;

View file

@ -24,29 +24,33 @@ without prior permission by the authors of Eressea.
/* TODO: set from external function */ /* TODO: set from external function */
int log_flags = LOG_FLUSH | LOG_CPERROR | LOG_CPWARNING | LOG_CPDEBUG; int log_flags = LOG_FLUSH | LOG_CPERROR | LOG_CPWARNING | LOG_CPDEBUG;
int log_stderr = LOG_FLUSH | LOG_CPERROR | LOG_CPWARNING;
#ifdef STDIO_CP #ifdef STDIO_CP
static int stdio_codepage = STDIO_CP; static int stdio_codepage = STDIO_CP;
#else #else
static int stdio_codepage = 0; static int stdio_codepage = 0;
#endif #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 MAXLENGTH 4096 /* because I am lazy, CP437 output is limited to this many chars */
#define LOG_MAXBACKUPS 5 #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 static int
cp_convert(const char *format, char *buffer, size_t length, int codepage) 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) static const char *log_prefix(int level) {
{ const char * prefix = "ERROR";
if (logfile) { if (level == LOG_CPWARNING) prefix = "WARNING";
log_close(); else if (level == LOG_CPDEBUG) prefix = "DEBUG";
} else if (level == LOG_CPINFO) prefix = "INFO";
log_rotate(filename, LOG_MAXBACKUPS); return prefix;
logfile = fopen(filename, "a");
if (logfile) {
/* Get UNIX-style time and display as number and string. */
time_t ltime;
time(&ltime);
fprintf(logfile, "===\n=== Logfile started at %s===\n", ctime(&ltime));
}
} }
void log_close(void) static int check_dupe(const char *format, int type)
{ {
if (!logfile || logfile == stderr || logfile == stdout) static int last_type; /* STATIC_XCALL: used across calls */
return;
if (logfile) {
/* Get UNIX-style time and display as number and string. */
time_t ltime;
time(&ltime);
fprintf(logfile, "===\n=== Logfile closed at %s===\n\n", ctime(&ltime));
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 char last_message[32]; /* STATIC_XCALL: used across calls */ static char last_message[32]; /* STATIC_XCALL: used across calls */
static int dupes = 0; /* STATIC_XCALL: used across calls */ static int dupes = 0; /* STATIC_XCALL: used across calls */
if (strncmp(last_message, format, sizeof(last_message)) == 0) { 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 (dupes) {
if (log_flags & LOG_CPERROR) { 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 + 1);
} }
dupes = 0; dupes = 0;
@ -150,202 +133,136 @@ static int check_dupe(const char *format, const char *type)
return 0; 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) { if (codepage) {
fprintf(stream, "%s: ", prefix); char buffer[MAXLENGTH];
if (codepage) { char converted[MAXLENGTH];
char buffer[MAXLENGTH];
char converted[MAXLENGTH];
vsnprintf(buffer, sizeof(buffer), format, args); vsnprintf(buffer, sizeof(buffer), format, args);
if (cp_convert(buffer, converted, MAXLENGTH, codepage) == 0) { if (cp_convert(buffer, converted, MAXLENGTH, codepage) == 0) {
fputs(converted, stream); fputs(converted, stream);
}
else {
/* fall back to non-converted output */
vfprintf(stream, format, args);
}
} }
else { else {
/* fall back to non-converted output */
vfprintf(stream, format, args); 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); 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') { if (format[len - 1] != '\n') {
fputc('\n', stream); fputc('\n', out);
}
}
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();
} }
} }
void log_warning(const char *format, ...) void log_to_file(int flags, FILE *out) {
{ log_create(flags, out, log_stdio);
const char * prefix = "WARNING"; }
const int mask = LOG_CPWARNING;
/* write to the logfile, always */ static void log_write(int flags, const char *module, const char *format, va_list args) {
if (logfile && (log_flags & mask)) { logger *lg;
va_list args; for (lg = loggers; lg; lg = lg->next) {
va_start(args, format); int level = flags & LOG_LEVELS;
_log_writeln(logfile, 0, prefix, format, args); if (lg->flags & level) {
va_end(args); int dupe = 0;
} if (lg->flags & LOG_BRIEF) {
dupe = check_dupe(format, level);
/* write to stderr, if that's not the logfile already */ }
if (logfile != stderr && (log_stderr & mask)) { if (dupe == 0) {
int dupe = check_dupe(format, prefix); lg->log(lg->data, level, NULL, format, args);
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_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, ...) void log_error(const char *format, ...)
{ {
const char * prefix = "ERROR"; va_list args;
const int mask = LOG_CPERROR; va_start(args, format);
log_write(LOG_CPERROR, NULL, format, args);
/* write to the logfile, always */ va_end(args);
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();
}
} }
void log_fatal(const char *format, ...) void log_warning(const char *format, ...)
{ {
const char * prefix = "ERROR"; va_list args;
const int mask = LOG_CPERROR; va_start(args, format);
log_write(LOG_CPWARNING, NULL, format, args);
va_end(args);
}
/* write to the logfile, always */ void log_debug(const char *format, ...)
if (logfile && (log_flags & mask)) { {
va_list args; va_list args;
va_start(args, format); va_start(args, format);
_log_writeln(logfile, 0, prefix, format, args); log_write(LOG_CPDEBUG, NULL, format, args);
va_end(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_info(const char *format, ...) void log_info(const char *format, ...)
{ {
const char * prefix = "INFO"; va_list args;
const int mask = LOG_CPINFO; va_start(args, format);
log_write(LOG_CPINFO, NULL, format, args);
/* write to the logfile, always */ va_end(args);
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();
}
} }
void log_printf(FILE * io, const char *format, ...) void log_printf(FILE * io, const char *format, ...)
{ {
const char * prefix = "INFO"; va_list args;
const int mask = LOG_CPINFO; va_start(args, format);
log_write(LOG_CPINFO, NULL, format, args);
va_end(args);
}
/* write to the logfile, always */ static FILE *logfile;
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);
}
/* write to io, if that's not the logfile already */ void log_close(void)
if (logfile != io && (log_stderr & mask)) { {
int dupe = check_dupe(format, prefix); while (loggers) {
if (!dupe) { logger *lgr = loggers;
va_list args; loggers = lgr->next;
va_start(args, format); free(lgr);
_log_write(io, stdio_codepage, prefix, format, args);
va_end(args);
}
} }
if (log_flags & LOG_FLUSH) { if (logfile) {
log_flush(); time_t ltime;
time(&ltime);
fprintf(logfile, "===\n=== Logfile closed at %s===\n\n", ctime(&ltime));
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(&ltime);
fprintf(logfile, "===\n=== Logfile started at %s===\n", ctime(&ltime));
log_create(log_flags, logfile, log_stdio);
} }
} }

View file

@ -15,9 +15,10 @@ without prior permission by the authors of Eressea.
extern "C" { extern "C" {
#endif #endif
#include <stdio.h> #include <stdio.h>
#include <stdarg.h>
extern void log_open(const char *filename); extern void log_open(const char *filename);
extern void log_close(void); extern void log_close(void);
extern void log_flush(void);
/* use macros above instead of these: */ /* use macros above instead of these: */
extern void log_fatal(const char *format, ...); extern void log_fatal(const char *format, ...);
@ -27,11 +28,18 @@ extern "C" {
extern void log_info(const char *format, ...); extern void log_info(const char *format, ...);
extern void log_printf(FILE * ios, 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_CPWARNING 0x02
#define LOG_CPERROR 0x04 #define LOG_CPINFO 0x04
#define LOG_CPINFO 0x08 #define LOG_CPDEBUG 0x08
#define LOG_CPDEBUG 0x10 #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_flags;
extern int log_stderr; extern int log_stderr;