- rename log functions to stop conflicts under win32 (wingdi)
[fw/openocd] / src / helper / log.c
index cdd7b7bfe512d2f82efd4860871fca1adebfa5bf..d0f0e3ddb4ba615727a72c82c0bb34d450850af0 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "log.h"
 #include "configuration.h"
+#include "time_support.h"
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -35,7 +36,7 @@ int debug_level = -1;
 static FILE* log_output;
 static log_callback_t *log_callbacks = NULL;
 
-static time_t start;
+static long long start;
 
 static char *log_strings[5] =
 {
@@ -60,9 +61,7 @@ static int count = 0;
  */
 static void log_puts(enum log_levels level, const char *file, int line, const char *function, const char *string)
 {
-       log_callback_t *cb;
-
-       if (level == LOG_OUTPUT)
+       if (level == LOG_LVL_OUTPUT)
        {
                /* do not prepend any headers, just print out what we were given and return */
                fputs(string, log_output);
@@ -76,10 +75,10 @@ static void log_puts(enum log_levels level, const char *file, int line, const ch
 
        if (strchr(string, '\n')!=NULL)
        {
-               if (debug_level >= LOG_DEBUG)
+               if (debug_level >= LOG_LVL_DEBUG)
                {
                        /* print with count and time information */
-                       int t=(int)(time(NULL)-start);
+                       int t=(int)(timeval_ms()-start);
                        fprintf(log_output, "%s %d %d %s:%d %s(): %s", log_strings[level+1], count, t, file, line, function, string);
                }
                else
@@ -95,13 +94,17 @@ static void log_puts(enum log_levels level, const char *file, int line, const ch
 
        fflush(log_output);
        
-       /* Never forward LOG_DEBUG, too verbose and they can be found in the log if need be */
-       if (level <= LOG_INFO)
+       /* Never forward LOG_LVL_DEBUG, too verbose and they can be found in the log if need be */
+       if (level <= LOG_LVL_INFO)
        {
-               log_callback_t *cb;
-               for (cb = log_callbacks; cb; cb = cb->next)
+               log_callback_t *cb, *next;
+               cb = log_callbacks;
+               /* DANGER!!!! the log callback can remove itself!!!! */
+               while (cb)
                {
+                       next=cb->next;
                        cb->fn(cb->priv, file, line, function, string);
+                       cb=next;
                }
        }
 }
@@ -117,7 +120,7 @@ void log_printf(enum log_levels level, const char *file, int line, const char *f
        va_list ap;
        va_start(ap, format);
 
-       string = alloc_printf(format, ap);
+       string = alloc_vprintf(format, ap);
        if (string != NULL)
        {
                log_puts(level, file, line, function, string);
@@ -138,10 +141,10 @@ void log_printf_lf(enum log_levels level, const char *file, int line, const char
        va_list ap;
        va_start(ap, format);
        
-       string = alloc_printf(format, ap);
+       string = alloc_vprintf(format, ap);
        if (string != NULL)
        {
-               strcat(string, "\n"); /* alloc_printf guaranteed the buffer to be at least one char longer */
+               strcat(string, "\n"); /* alloc_vprintf guaranteed the buffer to be at least one char longer */
                log_puts(level, file, line, function, string);
                free(string);
        }
@@ -189,7 +192,7 @@ int handle_log_output_command(struct command_context_s *cmd_ctx, char *cmd, char
 
 int log_register_commands(struct command_context_s *cmd_ctx)
 {
-       start = time(NULL);
+       start = timeval_ms();
        register_command(cmd_ctx, NULL, "log_output", handle_log_output_command,
                COMMAND_ANY, "redirect logging to <file> (default: stderr)");
        register_command(cmd_ctx, NULL, "debug_level", handle_debug_level_command,
@@ -202,7 +205,7 @@ int log_init(struct command_context_s *cmd_ctx)
 {
        /* set defaults for daemon configuration, if not set by cmdline or cfgfile */
        if (debug_level == -1)
-               debug_level = LOG_INFO;
+               debug_level = LOG_LVL_INFO;
        
        if (log_output == NULL)
        {
@@ -262,36 +265,48 @@ int log_remove_callback(log_callback_fn fn, void *priv)
 }
 
 /* return allocated string w/printf() result */
-char *alloc_printf(const char *fmt, va_list ap)
+char *alloc_vprintf(const char *fmt, va_list ap)
 {
        /* no buffer at the beginning, force realloc to do the job */
        char *string = NULL;
        
-       /* start with minimal length to exercise all the code paths */
-       int size = 1;
+       /* start with buffer size suitable for typical messages */
+       int size = 128;
 
        for (;;)
        {
-               size *= 2; /* double the buffer size */
+               char *t = string;
+               string = realloc(string, size);
+               if (string == NULL)
+               {
+                       if (t != NULL)
+                               free(t);
+                       return NULL;
+               }
+
+               va_list ap_copy;
+               va_copy(ap_copy, ap);
 
-                       char *t = string;
-                       string = realloc(string, size);
-                       if (string == NULL)
-                       {
-                               if (t != NULL)
-                                       free(t);
-                               return NULL;
-                       }
-       
                int ret;
-               ret = vsnprintf(string, size, fmt, ap);
+               ret = vsnprintf(string, size, fmt, ap_copy);
                /* NB! The result of the vsnprintf() might be an *EMPTY* string! */
                if ((ret >= 0) && ((ret + 1) < size))
                        break;
 
                /* there was just enough or not enough space, allocate more in the next round */
+               size *= 2; /* double the buffer size */
        }
        
        /* the returned buffer is by principle guaranteed to be at least one character longer */
        return string;
 }
+
+char *alloc_printf(const char *format, ...)
+{
+       char *string;
+       va_list ap;
+       va_start(ap, format);
+       string = alloc_vprintf(format, ap);
+       va_end(ap);
+       return string;
+}