nuclear@1: #include nuclear@1: #include nuclear@1: #include nuclear@1: #include nuclear@1: #include nuclear@1: #include "logger.h" nuclear@1: nuclear@1: struct LogTarget { nuclear@1: enum LogTargetType { LOG_TYPE_STREAM, LOG_TYPE_CALLBACK } type; nuclear@1: FILE *fp; nuclear@1: void (*func)(const char*, void*); nuclear@1: void *func_cls; nuclear@1: }; nuclear@1: nuclear@1: static void logmsg(LogTarget &out, const char *msg); nuclear@1: nuclear@1: static LogTarget def_log_target = { LogTarget::LOG_TYPE_STREAM, stderr, 0, 0 }; nuclear@1: static std::list targets; nuclear@1: nuclear@1: void set_log_file(FILE *fp) nuclear@1: { nuclear@1: LogTarget targ; nuclear@1: memset(&targ, 0, sizeof targ); nuclear@1: targ.type = LogTarget::LOG_TYPE_STREAM; nuclear@1: targ.fp = fp; nuclear@1: targets.push_back(targ); nuclear@1: } nuclear@1: nuclear@1: void set_log_callback(void (*cb)(const char*, void*), void *cls) nuclear@1: { nuclear@1: LogTarget targ; nuclear@1: memset(&targ, 0, sizeof targ); nuclear@1: targ.type = LogTarget::LOG_TYPE_CALLBACK; nuclear@1: targ.func = cb; nuclear@1: targ.func_cls = cls; nuclear@1: targets.push_back(targ); nuclear@1: } nuclear@1: nuclear@1: void log_message(const char *fmt, ...) nuclear@1: { nuclear@1: static char buf[512]; nuclear@1: nuclear@1: va_list ap; nuclear@1: va_start(ap, fmt); nuclear@1: vsnprintf(buf, sizeof buf, fmt, ap); nuclear@1: va_end(ap); nuclear@1: nuclear@1: if(targets.empty()) { nuclear@1: logmsg(def_log_target, buf); nuclear@1: } else { nuclear@1: std::list::iterator it = targets.begin(); nuclear@1: while(it != targets.end()) { nuclear@1: logmsg(*it++, buf); nuclear@1: } nuclear@1: } nuclear@1: } nuclear@1: nuclear@1: nuclear@1: static void logmsg(LogTarget &out, const char *msg) nuclear@1: { nuclear@1: switch(out.type) { nuclear@1: case LogTarget::LOG_TYPE_STREAM: nuclear@1: fputs(msg, out.fp); nuclear@1: fflush(out.fp); nuclear@1: break; nuclear@1: nuclear@1: case LogTarget::LOG_TYPE_CALLBACK: nuclear@1: out.func(msg, out.func_cls); nuclear@1: break; nuclear@1: nuclear@1: default: nuclear@1: break; nuclear@1: } nuclear@1: }