better logging and OpenGL ARB_debug_output
[laserbrain_demo] / src / logger.cc
index 015c9bd..254c20d 100644 (file)
 enum { LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_FATAL, LOG_DEBUG };
 
 static int typecolor(int type);
+static const char *typeprefix(int type);
 
 static FILE *fp = stdout;
+static FILE *logfile;
 
 static void logmsg(int type, const char *fmt, va_list ap)
 {
+       va_list ap_orig;
+
+       va_copy(ap_orig, ap);
+
 #if defined(unix) || defined(__unix__) || (defined(__APPLE__) && !defined(TARGET_IPHONE))
        if(isatty(fileno(fp)) && type != LOG_INFO) {
                int c = typecolor(type);
@@ -28,20 +34,48 @@ static void logmsg(int type, const char *fmt, va_list ap)
        } else
 #endif
        {
+               fprintf(fp, "%s", typeprefix(type));
                vfprintf(fp, fmt, ap);
        }
        if(type == LOG_ERROR || type == LOG_FATAL || type == LOG_DEBUG) {
                fflush(fp);
        }
 
+       if(logfile) {
+               va_end(ap);
+               va_copy(ap, ap_orig);
+               fprintf(logfile, "%s", typeprefix(type));
+               vfprintf(logfile, fmt, ap);
+       }
+
 #ifdef WIN32
        if(type == LOG_FATAL) {
                static char msgbuf[1024];
-               vsnprintf(msgbuf, sizeof msgbuf - 1, fmt, ap);
+               vsnprintf(msgbuf, sizeof msgbuf - 1, fmt, ap_orig);
                msgbuf[sizeof msgbuf - 1] = 0;
                MessageBox(0, msgbuf, "Fatal error", MB_OK | MB_ICONSTOP);
        }
 #endif
+
+       va_end(ap_orig);
+}
+
+static void close_logfile(void)
+{
+       if(logfile) fclose(logfile);
+}
+
+extern "C" void set_log_file(const char *fname)
+{
+       static int init_once;
+
+       close_logfile();
+       logfile = fopen(fname, "w");
+
+       if(!init_once) {
+               atexit(close_logfile);
+               init_once = 1;
+       }
 }
 
 extern "C" void info_log(const char *fmt, ...)
@@ -127,3 +161,20 @@ static int typecolor(int type)
        }
        return 37;
 }
+
+static const char *typeprefix(int type)
+{
+       switch(type) {
+       case LOG_ERROR:
+               return "E: ";
+       case LOG_FATAL:
+               return "F: ";
+       case LOG_WARNING:
+               return "W: ";
+       case LOG_DEBUG:
+               return "D: ";
+       default:
+               break;
+       }
+       return "";
+}