Patch from Sven Neumann to make the include order consistent. (#71704)
[platform/upstream/glib.git] / glib / gmessages.c
index 32b63e1..820c3ee 100644 (file)
  * MT safe
  */
 
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
+#include "config.h"
 
 #include <stdlib.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <string.h>
-#include "glib.h"
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
 #include <locale.h>
 #include <errno.h>
 
+#include "glib.h"
+#include "gdebug.h"
+#include "gprintfint.h"
+
+#ifdef G_OS_WIN32
+typedef FILE* GFileDescriptor;
+#else
+typedef gint GFileDescriptor;
+#endif
 
 /* --- structures --- */
 typedef struct _GLogDomain     GLogDomain;
@@ -65,53 +71,62 @@ struct _GLogHandler
 };
 
 
-/* --- prototypes --- */
-static inline guint printf_string_upper_bound (const gchar *format,
-                                              gboolean     may_warn,
-                                              va_list      args);
-
-
 /* --- variables --- */
-
-static GMutex* g_messages_lock = NULL;
-
-const gchar         *g_log_domain_glib = "GLib";
+static GMutex        *g_messages_lock = NULL;
 static GLogDomain    *g_log_domains = NULL;
 static GLogLevelFlags g_log_always_fatal = G_LOG_FATAL_MASK;
 static GPrintFunc     glib_print_func = NULL;
 static GPrintFunc     glib_printerr_func = NULL;
-static GErrorFunc     glib_error_func = NULL;
-static GWarningFunc   glib_warning_func = NULL;
-static GPrintFunc     glib_message_func = NULL;
-
-static GPrivate* g_log_depth = NULL;
+static GPrivate             *g_log_depth = NULL;
+static GLogLevelFlags g_log_msg_prefix = G_LOG_LEVEL_ERROR | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_DEBUG;
 
 
 /* --- functions --- */
 #ifdef G_OS_WIN32
 #  define STRICT
 #  include <windows.h>
+#  undef STRICT
 #  include <process.h>          /* For _getpid() */
-
 static gboolean alloc_console_called = FALSE;
+static gboolean win32_keep_fatal_message = FALSE;
+
+/* This default message will usually be overwritten. */
+/* Yes, a fixed size buffer is bad. So sue me. But g_error is never
+ * with huge strings, is it?
+ */
+static gchar  fatal_msg_buf[1000] = "Unspecified fatal error encountered, aborting.";
+static gchar *fatal_msg_ptr = fatal_msg_buf;
 
 /* Just use stdio. If we're out of memory, we're hosed anyway. */
 #undef write
 static inline int
-write (FILE       *fd,
-       const char *buf,
-       int         len)
+dowrite (GFileDescriptor fd,
+        const void  *buf,
+        unsigned int len)
 {
+  if (win32_keep_fatal_message)
+    {
+      memcpy (fatal_msg_ptr, buf, len);
+      fatal_msg_ptr += len;
+      *fatal_msg_ptr = 0;
+      return len;
+    }
+
   fwrite (buf, len, 1, fd);
   fflush (fd);
 
   return len;
 }
+#define write(fd, buf, len) dowrite(fd, buf, len)
+
 static void
 ensure_stdout_valid (void)
 {
   HANDLE handle;
 
+  if (win32_keep_fatal_message)
+    return;
+
   if (!alloc_console_called)
     {
       handle = GetStdHandle (STD_OUTPUT_HANDLE);
@@ -127,29 +142,59 @@ ensure_stdout_valid (void)
 #else
 #define ensure_stdout_valid()  /* Define as empty */
 #endif
-       
-static inline GLogDomain*
-g_log_find_domain (const gchar *log_domain)
+
+static void
+write_string (GFileDescriptor fd,
+             const gchar    *string)
+{
+  write (fd, string, strlen (string));
+}
+
+static void
+g_messages_prefixed_init (void)
+{
+  static gboolean initialized = FALSE;
+
+  if (!initialized)
+    {
+      const gchar *val;
+
+      initialized = TRUE;
+      val = g_getenv ("G_MESSAGES_PREFIXED");
+      
+      if (val)
+       {
+         static const GDebugKey keys[] = {
+           { "error", G_LOG_LEVEL_ERROR },
+           { "critical", G_LOG_LEVEL_CRITICAL },
+           { "warning", G_LOG_LEVEL_WARNING },
+           { "message", G_LOG_LEVEL_MESSAGE },
+           { "info", G_LOG_LEVEL_INFO },
+           { "debug", G_LOG_LEVEL_DEBUG }
+         };
+         
+         g_log_msg_prefix = g_parse_debug_string (val, keys, G_N_ELEMENTS (keys));
+       }
+    }
+}
+
+static GLogDomain*
+g_log_find_domain_L (const gchar *log_domain)
 {
   register GLogDomain *domain;
   
-  g_mutex_lock (g_messages_lock);
   domain = g_log_domains;
   while (domain)
     {
       if (strcmp (domain->log_domain, log_domain) == 0)
-       {
-         g_mutex_unlock (g_messages_lock);
-         return domain;
-       }
+       return domain;
       domain = domain->next;
     }
-  g_mutex_unlock (g_messages_lock);
   return NULL;
 }
 
-static inline GLogDomain*
-g_log_domain_new (const gchar *log_domain)
+static GLogDomain*
+g_log_domain_new_L (const gchar *log_domain)
 {
   register GLogDomain *domain;
 
@@ -158,16 +203,14 @@ g_log_domain_new (const gchar *log_domain)
   domain->fatal_mask = G_LOG_FATAL_MASK;
   domain->handlers = NULL;
   
-  g_mutex_lock (g_messages_lock);
   domain->next = g_log_domains;
   g_log_domains = domain;
-  g_mutex_unlock (g_messages_lock);
   
   return domain;
 }
 
-static inline void
-g_log_domain_check_free (GLogDomain *domain)
+static void
+g_log_domain_check_free_L (GLogDomain *domain)
 {
   if (domain->fatal_mask == G_LOG_FATAL_MASK &&
       domain->handlers == NULL)
@@ -176,7 +219,6 @@ g_log_domain_check_free (GLogDomain *domain)
       
       last = NULL;  
 
-      g_mutex_lock (g_messages_lock);
       work = g_log_domains;
       while (work)
        {
@@ -193,14 +235,13 @@ g_log_domain_check_free (GLogDomain *domain)
          last = work;
          work = last->next;
        }  
-      g_mutex_unlock (g_messages_lock);
     }
 }
 
-static inline GLogFunc
-g_log_domain_get_handler (GLogDomain   *domain,
-                         GLogLevelFlags log_level,
-                         gpointer      *data)
+static GLogFunc
+g_log_domain_get_handler_L (GLogDomain *domain,
+                           GLogLevelFlags log_level,
+                           gpointer    *data)
 {
   if (domain && log_level)
     {
@@ -225,7 +266,9 @@ g_log_set_always_fatal (GLogLevelFlags fatal_mask)
 {
   GLogLevelFlags old_mask;
 
-  /* restrict the global mask to levels that are known to glib */
+  /* restrict the global mask to levels that are known to glib
+   * since this setting applies to all domains
+   */
   fatal_mask &= (1 << G_LOG_LEVEL_USER_SHIFT) - 1;
   /* force errors to be fatal */
   fatal_mask |= G_LOG_LEVEL_ERROR;
@@ -241,8 +284,8 @@ g_log_set_always_fatal (GLogLevelFlags fatal_mask)
 }
 
 GLogLevelFlags
-g_log_set_fatal_mask (const gchar    *log_domain,
-                     GLogLevelFlags  fatal_mask)
+g_log_set_fatal_mask (const gchar   *log_domain,
+                     GLogLevelFlags fatal_mask)
 {
   GLogLevelFlags old_flags;
   register GLogDomain *domain;
@@ -255,46 +298,53 @@ g_log_set_fatal_mask (const gchar    *log_domain,
   /* remove bogus flag */
   fatal_mask &= ~G_LOG_FLAG_FATAL;
   
-  domain = g_log_find_domain (log_domain);
+  g_mutex_lock (g_messages_lock);
+
+  domain = g_log_find_domain_L (log_domain);
   if (!domain)
-    domain = g_log_domain_new (log_domain);
+    domain = g_log_domain_new_L (log_domain);
   old_flags = domain->fatal_mask;
   
   domain->fatal_mask = fatal_mask;
-  g_log_domain_check_free (domain);
-  
+  g_log_domain_check_free_L (domain);
+
+  g_mutex_unlock (g_messages_lock);
+
   return old_flags;
 }
 
 guint
-g_log_set_handler (const gchar   *log_domain,
-                  GLogLevelFlags  log_levels,
-                  GLogFunc        log_func,
-                  gpointer        user_data)
+g_log_set_handler (const gchar  *log_domain,
+                  GLogLevelFlags log_levels,
+                  GLogFunc       log_func,
+                  gpointer       user_data)
 {
-  register GLogDomain *domain;
-  register GLogHandler *handler;
   static guint handler_id = 0;
+  GLogDomain *domain;
+  GLogHandler *handler;
   
   g_return_val_if_fail ((log_levels & G_LOG_LEVEL_MASK) != 0, 0);
   g_return_val_if_fail (log_func != NULL, 0);
   
   if (!log_domain)
     log_domain = "";
-  
-  domain = g_log_find_domain (log_domain);
-  if (!domain)
-    domain = g_log_domain_new (log_domain);
-  
+
   handler = g_new (GLogHandler, 1);
+
   g_mutex_lock (g_messages_lock);
+
+  domain = g_log_find_domain_L (log_domain);
+  if (!domain)
+    domain = g_log_domain_new_L (log_domain);
+  
   handler->id = ++handler_id;
-  g_mutex_unlock (g_messages_lock);
   handler->log_level = log_levels;
   handler->log_func = log_func;
   handler->data = user_data;
   handler->next = domain->handlers;
   domain->handlers = handler;
+
+  g_mutex_unlock (g_messages_lock);
   
   return handler_id;
 }
@@ -310,10 +360,11 @@ g_log_remove_handler (const gchar *log_domain,
   if (!log_domain)
     log_domain = "";
   
-  domain = g_log_find_domain (log_domain);
+  g_mutex_lock (g_messages_lock);
+  domain = g_log_find_domain_L (log_domain);
   if (domain)
     {
-      register GLogHandler *work, *last;
+      GLogHandler *work, *last;
       
       last = NULL;
       work = domain->handlers;
@@ -325,17 +376,18 @@ g_log_remove_handler (const gchar *log_domain,
                last->next = work->next;
              else
                domain->handlers = work->next;
+             g_log_domain_check_free_L (domain); 
+             g_mutex_unlock (g_messages_lock);
              g_free (work);
-             g_log_domain_check_free (domain);
              return;
            }
          last = work;
          work = last->next;
        }
-    }
-  g_warning ("g_log_remove_handler(): could not find handler with id `%d' for domain \"%s\"",
-            handler_id,
-            log_domain);
+    } 
+  g_mutex_unlock (g_messages_lock);
+  g_warning ("%s: could not find handler with id `%d' for domain \"%s\"",
+            G_STRLOC, handler_id, log_domain);
 }
 
 void
@@ -344,10 +396,11 @@ g_logv (const gchar   *log_domain,
        const gchar   *format,
        va_list        args1)
 {
-  va_list args2;
   gchar buffer[1025];
-  register gint i;
-  
+  gboolean was_fatal = (log_level & G_LOG_FLAG_FATAL) != 0;
+  gboolean was_recursion = (log_level & G_LOG_FLAG_RECURSION) != 0;
+  gint i;
+
   log_level &= G_LOG_LEVEL_MASK;
   if (!log_level)
     return;
@@ -355,21 +408,7 @@ g_logv (const gchar   *log_domain,
   /* we use a stack buffer of fixed size, because we might get called
    * recursively.
    */
-  G_VA_COPY (args2, args1);
-  if (printf_string_upper_bound (format, FALSE, args1) < 1024)
-    vsprintf (buffer, format, args2);
-  else
-    {
-      /* since we might be out of memory, we can't use g_vsnprintf(). */
-#ifdef  HAVE_VSNPRINTF
-      vsnprintf (buffer, 1024, format, args2);
-#else  /* !HAVE_VSNPRINTF */
-      /* we are out of luck here */
-      strncpy (buffer, format, 1024);
-#endif /* !HAVE_VSNPRINTF */
-      buffer[1024] = 0;
-    }
-  va_end (args2);
+  _g_vsnprintf (buffer, 1024, format, args1);
   
   for (i = g_bit_nth_msf (log_level, -1); i >= 0; i = g_bit_nth_msf (log_level, i))
     {
@@ -381,37 +420,66 @@ g_logv (const gchar   *log_domain,
          guint depth = GPOINTER_TO_UINT (g_private_get (g_log_depth));
          GLogDomain *domain;
          GLogFunc log_func;
+         guint domain_fatal_mask;
          gpointer data = NULL;
-         
-         domain = g_log_find_domain (log_domain ? log_domain : "");
-         
+
+         if (was_fatal)
+           test_level |= G_LOG_FLAG_FATAL;
+         if (was_recursion)
+           test_level |= G_LOG_FLAG_RECURSION;
+
+         /* check recursion and lookup handler */
+         g_mutex_lock (g_messages_lock);
+         domain = g_log_find_domain_L (log_domain ? log_domain : "");
          if (depth)
            test_level |= G_LOG_FLAG_RECURSION;
-         
          depth++;
+         domain_fatal_mask = domain ? domain->fatal_mask : G_LOG_FATAL_MASK;
+         if ((domain_fatal_mask | g_log_always_fatal) & test_level)
+           test_level |= G_LOG_FLAG_FATAL;
+         if (test_level & G_LOG_FLAG_RECURSION)
+           log_func = _g_log_fallback_handler;
+         else
+           log_func = g_log_domain_get_handler_L (domain, test_level, &data);
+         domain = NULL;
+         g_mutex_unlock (g_messages_lock);
+
          g_private_set (g_log_depth, GUINT_TO_POINTER (depth));
 
-         g_mutex_lock (g_messages_lock);
-         if ((((domain ? domain->fatal_mask : G_LOG_FATAL_MASK) | 
-               g_log_always_fatal) & test_level) != 0)
-           test_level |= G_LOG_FLAG_FATAL;  
-         g_mutex_unlock (g_messages_lock);
+         /* had to defer debug initialization until we can keep track of recursion */
+         if (!(test_level & G_LOG_FLAG_RECURSION) && !_g_debug_initialized)
+           {
+             guint orig_test_level = test_level;
+
+             _g_debug_init ();
+             if ((domain_fatal_mask | g_log_always_fatal) & test_level)
+               test_level |= G_LOG_FLAG_FATAL;
+             if (test_level != orig_test_level)
+               {
+                 /* need a relookup, not nice, but not too bad either */
+                 g_mutex_lock (g_messages_lock);
+                 domain = g_log_find_domain_L (log_domain ? log_domain : "");
+                 log_func = g_log_domain_get_handler_L (domain, test_level, &data);
+                 domain = NULL;
+                 g_mutex_unlock (g_messages_lock);
+               }
+           }
 
-         log_func = g_log_domain_get_handler (domain, test_level, &data);
          log_func (log_domain, test_level, buffer, data);
-         
-         /* *domain can be cluttered now */
-         
+
          if (test_level & G_LOG_FLAG_FATAL)
            {
-#if defined (G_ENABLE_DEBUG) && defined (SIGTRAP)
+#ifdef G_OS_WIN32
+             MessageBox (NULL, fatal_msg_buf, NULL, MB_OK);
+#endif
+#if defined (G_ENABLE_DEBUG) && (defined (SIGTRAP) || defined (G_OS_WIN32))
              if (!(test_level & G_LOG_FLAG_RECURSION))
-               raise (SIGTRAP);
+               G_BREAKPOINT ();
              else
                abort ();
-#else /* !G_ENABLE_DEBUG || !SIGTRAP */
+#else /* !G_ENABLE_DEBUG || !(SIGTRAP || G_OS_WIN32) */
              abort ();
-#endif /* !G_ENABLE_DEBUG || !SIGTRAP */
+#endif /* !G_ENABLE_DEBUG || !(SIGTRAP || G_OS_WIN32) */
            }
          
          depth--;
@@ -421,9 +489,9 @@ g_logv (const gchar   *log_domain,
 }
 
 void
-g_log (const gchar    *log_domain,
-       GLogLevelFlags  log_level,
-       const gchar    *format,
+g_log (const gchar   *log_domain,
+       GLogLevelFlags log_level,
+       const gchar   *format,
        ...)
 {
   va_list args;
@@ -433,254 +501,283 @@ g_log (const gchar    *log_domain,
   va_end (args);
 }
 
-void
-g_log_default_handler (const gchar    *log_domain,
-                      GLogLevelFlags  log_level,
-                      const gchar    *message,
-                      gpointer        unused_data)
+static gchar*
+strdup_convert (const gchar *string,
+               const gchar *charset)
 {
-#ifdef G_OS_WIN32
-  FILE *fd;
-#else
-  gint fd;
-#endif
-  gboolean in_recursion;
-  gboolean is_fatal;  
-  GErrorFunc local_glib_error_func;
-  GWarningFunc local_glib_warning_func;
-  GPrintFunc local_glib_message_func;
-  gchar prg_pid[64], *prg_name = g_get_prgname ();
-
-  in_recursion = (log_level & G_LOG_FLAG_RECURSION) != 0;
-  is_fatal = (log_level & G_LOG_FLAG_FATAL) != 0;
-  log_level &= G_LOG_LEVEL_MASK;
-  
-  if (!message)
-    message = "g_log_default_handler(): (NULL) message";
-  if (!prg_name)
+  if (!g_utf8_validate (string, -1, NULL))
+    return g_strconcat ("[Invalid UTF-8] ", string, NULL);
+  else
     {
-      prg_name = "(process";
-      sprintf (prg_pid, ":%u): ", getpid ());
+      GError *err = NULL;
+      
+      gchar *result = g_convert_with_fallback (string, -1, charset, "UTF-8", "?", NULL, NULL, &err);
+      if (result)
+       return result;
+      else
+       {
+         /* Not thread-safe, but doesn't matter if we print the warning twice
+          */
+         static gboolean warned = FALSE; 
+         if (!warned)
+           {
+             warned = TRUE;
+             _g_fprintf (stderr, "GLib: Cannot convert message: %s\n", err->message);
+           }
+         g_error_free (err);
+         
+         return g_strdup (string);
+       }
+    }
+}
+
+/* For a radix of 8 we need at most 3 output bytes for 1 input
+ * byte. Additionally we might need up to 2 output bytes for the
+ * readix prefix and 1 byte for the trailing NULL.
+ */
+#define FORMAT_UNSIGNED_BUFSIZE ((GLIB_SIZEOF_LONG * 3) + 3)
+
+static void
+format_unsigned (gchar  *buf,
+                gulong  num,
+                guint   radix)
+{
+  gulong tmp;
+  gchar c;
+  gint i, n;
+
+  /* we may not call _any_ GLib functions here (or macros like g_return_if_fail()) */
+
+  if (radix != 8 && radix != 10 && radix != 16)
+    {
+      *buf = '\000';
+      return;
     }
-  else
-    sprintf (prg_pid, " (pid:%u): ", getpid ());
   
-#ifdef G_OS_WIN32
-  /* Use just stdout as stderr is hard to get redirected from the
-   * DOS prompt.
-   */
-  fd = stdout;
-#else
-  fd = (log_level >= G_LOG_LEVEL_MESSAGE) ? 1 : 2;
-#endif
+  if (!num)
+    {
+      *buf++ = '0';
+      *buf = '\000';
+      return;
+    } 
   
-  g_mutex_lock (g_messages_lock);
-  local_glib_error_func = glib_error_func;
-  local_glib_warning_func = glib_warning_func;
-  local_glib_message_func = glib_message_func;
-  g_mutex_unlock (g_messages_lock);
+  if (radix == 16)
+    {
+      *buf++ = '0';
+      *buf++ = 'x';
+    }
+  else if (radix == 8)
+    {
+      *buf++ = '0';
+    }
+       
+  n = 0;
+  tmp = num;
+  while (tmp)
+    {
+      tmp /= radix;
+      n++;
+    }
+
+  i = n;
 
-  switch (log_level)
+  /* Again we can't use g_assert; actually this check should _never_ fail. */
+  if (n > FORMAT_UNSIGNED_BUFSIZE - 3)
     {
-    case G_LOG_LEVEL_ERROR:
-      if (!log_domain && local_glib_error_func)
-       {
-         /* compatibility code */
-         local_glib_error_func (message);  
-         return;
-       }
-      /* use write(2) for output, in case we are out of memeory */
-      ensure_stdout_valid ();
-      write (fd, "\n", 1);
-#ifdef G_ENABLE_MSG_PREFIX
-      write (fd, prg_name, strlen (prg_name));
-      write (fd, prg_pid, strlen (prg_pid));
-#endif /* G_ENABLE_MSG_PREFIX */
-      if (log_domain)
-       {
-         write (fd, log_domain, strlen (log_domain));
-         write (fd, "-", 1);
-       }
-      else
-       write (fd, "** ", 3);
-      if (in_recursion)
-       write (fd, "ERROR (recursed) **: ", 21);
-      else
-       write (fd, "ERROR **: ", 10);
-      write (fd, message, strlen (message));
-      if (is_fatal)
-       write (fd, "\naborting...\n", 13);
+      *buf = '\000';
+      return;
+    }
+
+  while (num)
+    {
+      i--;
+      c = (num % radix);
+      if (c < 10)
+       buf[i] = c + '0';
       else
-       write (fd, "\n", 1);
+       buf[i] = c + 'a' - 10;
+      num /= radix;
+    }
+  
+  buf[n] = '\000';
+}
+
+/* string size big enough to hold level prefix */
+#define        STRING_BUFFER_SIZE      (FORMAT_UNSIGNED_BUFSIZE + 32)
+
+#define        ALERT_LEVELS            (G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING)
+
+static GFileDescriptor
+mklevel_prefix (gchar level_prefix[STRING_BUFFER_SIZE],
+               guint log_level)
+{
+  gboolean to_stdout = TRUE;
+
+  /* we may not call _any_ GLib functions here */
+
+  switch (log_level & G_LOG_LEVEL_MASK)
+    {
+    case G_LOG_LEVEL_ERROR:
+      strcpy (level_prefix, "ERROR");
+      to_stdout = FALSE;
       break;
     case G_LOG_LEVEL_CRITICAL:
-      ensure_stdout_valid ();
-      write (fd, "\n", 1);
-#ifdef G_ENABLE_MSG_PREFIX
-      write (fd, prg_name, strlen (prg_name));
-      write (fd, prg_pid, strlen (prg_pid));
-#endif /* G_ENABLE_MSG_PREFIX */
-      if (log_domain)
-       {
-         write (fd, log_domain, strlen (log_domain));
-         write (fd, "-", 1);
-       }
-      else
-       write (fd, "** ", 3);
-      if (in_recursion)
-       write (fd, "CRITICAL (recursed) **: ", 24);
-      else
-       write (fd, "CRITICAL **: ", 13);
-      write (fd, message, strlen (message));
-      if (is_fatal)
-       write (fd, "\naborting...\n", 13);
-      else
-       write (fd, "\n", 1);
+      strcpy (level_prefix, "CRITICAL");
+      to_stdout = FALSE;
       break;
     case G_LOG_LEVEL_WARNING:
-      if (!log_domain && local_glib_warning_func)
-       {
-         /* compatibility code */
-         local_glib_warning_func (message);
-         return;
-       }
-      ensure_stdout_valid ();
-      write (fd, "\n", 1);
-#ifdef G_ENABLE_MSG_PREFIX
-      write (fd, prg_name, strlen (prg_name));
-      write (fd, prg_pid, strlen (prg_pid));
-#endif /* G_ENABLE_MSG_PREFIX */
-      if (log_domain)
-       {
-         write (fd, log_domain, strlen (log_domain));
-         write (fd, "-", 1);
-       }
-      else
-       write (fd, "** ", 3);
-      if (in_recursion)
-       write (fd, "WARNING (recursed) **: ", 23);
-      else
-       write (fd, "WARNING **: ", 12);
-      write (fd, message, strlen (message));
-      if (is_fatal)
-       write (fd, "\naborting...\n", 13);
-      else
-       write (fd, "\n", 1);
+      strcpy (level_prefix, "WARNING");
+      to_stdout = FALSE;
       break;
     case G_LOG_LEVEL_MESSAGE:
-      if (!log_domain && local_glib_message_func)
-       {
-         /* compatibility code */
-         local_glib_message_func (message);
-         return;
-       }
-      ensure_stdout_valid ();
-#ifdef G_ENABLE_MSG_PREFIX
-      write (fd, prg_name, strlen (prg_name));
-      write (fd, prg_pid, strlen (prg_pid));
-#endif /* G_ENABLE_MSG_PREFIX */
-      if (log_domain)
-       {
-         write (fd, log_domain, strlen (log_domain));
-         write (fd, "-", 1);
-       }
-      if (in_recursion)
-       write (fd, "Message (recursed): ", 20);
-      else
-       write (fd, "Message: ", 9);
-      write (fd, message, strlen (message));
-      if (is_fatal)
-       write (fd, "\naborting...\n", 13);
-      else
-       write (fd, "\n", 1);
+      strcpy (level_prefix, "Message");
+      to_stdout = FALSE;
       break;
     case G_LOG_LEVEL_INFO:
-      ensure_stdout_valid ();
-#ifdef G_ENABLE_MSG_PREFIX
-      write (fd, prg_name, strlen (prg_name));
-      write (fd, prg_pid, strlen (prg_pid));
-#endif /* G_ENABLE_MSG_PREFIX */
-      if (log_domain)
-       {
-         write (fd, log_domain, strlen (log_domain));
-         write (fd, "-", 1);
-       }
-      if (in_recursion)
-       write (fd, "INFO (recursed): ", 17);
-      else
-       write (fd, "INFO: ", 6);
-      write (fd, message, strlen (message));
-      if (is_fatal)
-       write (fd, "\naborting...\n", 13);
-      else
-       write (fd, "\n", 1);
+      strcpy (level_prefix, "INFO");
       break;
     case G_LOG_LEVEL_DEBUG:
-      ensure_stdout_valid ();
-#ifdef G_ENABLE_MSG_PREFIX
-      write (fd, prg_name, strlen (prg_name));
-      write (fd, prg_pid, strlen (prg_pid));
-#endif /* G_ENABLE_MSG_PREFIX */
-      if (log_domain)
-       {
-         write (fd, log_domain, strlen (log_domain));
-         write (fd, "-", 1);
-       }
-      if (in_recursion)
-       write (fd, "DEBUG (recursed): ", 18);
-      else
-       write (fd, "DEBUG: ", 7);
-      write (fd, message, strlen (message));
-      if (is_fatal)
-       write (fd, "\naborting...\n", 13);
-      else
-       write (fd, "\n", 1);
+      strcpy (level_prefix, "DEBUG");
       break;
     default:
-      /* we are used for a log level that is not defined by GLib itself,
-       * try to make the best out of it.
-       */
-      ensure_stdout_valid ();
-#ifdef G_ENABLE_MSG_PREFIX
-      write (fd, prg_name, strlen (prg_name));
-      write (fd, prg_pid, strlen (prg_pid));
-#endif /* G_ENABLE_MSG_PREFIX */
-      if (log_domain)
-       {
-         write (fd, log_domain, strlen (log_domain));
-         if (in_recursion)
-           write (fd, "-LOG (recursed:", 15);
-         else
-           write (fd, "-LOG (", 6);
-       }
-      else if (in_recursion)
-       write (fd, "LOG (recursed:", 14);
-      else
-       write (fd, "LOG (", 5);
       if (log_level)
        {
-         gchar string[] = "0x00): ";
-         gchar *p = string + 2;
-         guint i;
-         
-         i = g_bit_nth_msf (log_level, -1);
-         *p = i >> 4;
-         p++;
-         *p = '0' + (i & 0xf);
-         if (*p > '9')
-           *p += 'A' - '9' - 1;
-         
-         write (fd, string, 7);
+         strcpy (level_prefix, "LOG-");
+         format_unsigned (level_prefix + 4, log_level & G_LOG_LEVEL_MASK, 16);
        }
       else
-       write (fd, "): ", 3);
-      write (fd, message, strlen (message));
-      if (is_fatal)
-       write (fd, "\naborting...\n", 13);
-      else
-       write (fd, "\n", 1);
+       strcpy (level_prefix, "LOG");
       break;
     }
+  if (log_level & G_LOG_FLAG_RECURSION)
+    strcat (level_prefix, " (recursed)");
+  if (log_level & ALERT_LEVELS)
+    strcat (level_prefix, " **");
+
+  ensure_stdout_valid ();
+#ifdef G_OS_WIN32
+  win32_keep_fatal_message = (log_level & G_LOG_FLAG_FATAL) != 0;
+  /* Use just stdout as stderr is hard to get redirected from the DOS prompt. */
+  return stdout;
+#else
+  return to_stdout ? 1 : 2;
+#endif
+}
+
+void
+_g_log_fallback_handler (const gchar   *log_domain,
+                        GLogLevelFlags log_level,
+                        const gchar   *message,
+                        gpointer       unused_data)
+{
+  gchar level_prefix[STRING_BUFFER_SIZE], pid_string[FORMAT_UNSIGNED_BUFSIZE];
+  gboolean is_fatal = (log_level & G_LOG_FLAG_FATAL) != 0;
+  GFileDescriptor fd;
+
+  /* we can not call _any_ GLib functions in this fallback handler,
+   * which is why we skip UTF-8 conversion, etc.
+   * since we either recursed or ran out of memory, we're in a pretty
+   * pathologic situation anyways, what we can do is giving the
+   * the process ID unconditionally however.
+   */
+
+  fd = mklevel_prefix (level_prefix, log_level);
+  if (!message)
+    message = "(NULL) message";
+
+  format_unsigned (pid_string, getpid (), 10);
+
+  if (log_domain)
+    write_string (fd, "\n");
+  else
+    write_string (fd, "\n** ");
+  write_string (fd, "(process:");
+  write_string (fd, pid_string);
+  write_string (fd, "): ");
+  if (log_domain)
+    {
+      write_string (fd, log_domain);
+      write_string (fd, "-");
+    }
+  write_string (fd, level_prefix);
+  write_string (fd, ": ");
+  write_string (fd, message);
+  if (is_fatal)
+    write_string (fd, "\naborting...\n");
+  else
+    write_string (fd, "\n");
+}
+
+void
+g_log_default_handler (const gchar   *log_domain,
+                      GLogLevelFlags log_level,
+                      const gchar   *message,
+                      gpointer       unused_data)
+{
+  gboolean is_fatal = (log_level & G_LOG_FLAG_FATAL) != 0;
+  gchar level_prefix[STRING_BUFFER_SIZE], *string;
+  GString *gstring;
+  GFileDescriptor fd;
+
+  /* we can be called externally with recursion for whatever reason */
+  if (log_level & G_LOG_FLAG_RECURSION)
+    {
+      _g_log_fallback_handler (log_domain, log_level, message, unused_data);
+      return;
+    }
+
+  g_messages_prefixed_init ();
+
+  fd = mklevel_prefix (level_prefix, log_level);
+
+  gstring = g_string_new ("");
+  if (log_level & ALERT_LEVELS)
+    g_string_append (gstring, "\n");
+  if (!log_domain)
+    g_string_append (gstring, "** ");
+
+  if ((g_log_msg_prefix & log_level) == log_level)
+    {
+      const gchar *prg_name = g_get_prgname ();
+      
+      if (!prg_name)
+       g_string_append_printf (gstring, "(process:%lu): ", (gulong)getpid ());
+      else
+       g_string_append_printf (gstring, "(%s:%lu): ", prg_name, (gulong)getpid ());
+    }
+
+  if (log_domain)
+    {
+      g_string_append (gstring, log_domain);
+      g_string_append_c (gstring, '-');
+    }
+  g_string_append (gstring, level_prefix);
+
+  g_string_append (gstring, ": ");
+  if (!message)
+    g_string_append (gstring, "(NULL) message");
+  else
+    {
+      const gchar *charset;
+
+      if (g_get_charset (&charset))
+       g_string_append (gstring, message);     /* charset is UTF-8 already */
+      else
+       {
+         string = strdup_convert (message, charset);
+         g_string_append (gstring, string);
+         g_free (string);
+       }
+    }
+  if (is_fatal)
+    g_string_append (gstring, "\naborting...\n");
+  else
+    g_string_append (gstring, "\n");
+
+  string = g_string_free (gstring, FALSE);
+
+  write_string (fd, string);
+  g_free (string);
 }
 
 GPrintFunc
@@ -713,13 +810,23 @@ g_print (const gchar *format,
   g_mutex_lock (g_messages_lock);
   local_glib_print_func = glib_print_func;
   g_mutex_unlock (g_messages_lock);
-
+  
   if (local_glib_print_func)
     local_glib_print_func (string);
   else
     {
+      const gchar *charset;
+
       ensure_stdout_valid ();
-      fputs (string, stdout);
+      if (g_get_charset (&charset))
+       fputs (string, stdout); /* charset is UTF-8 already */
+      else
+       {
+         gchar *lstring = strdup_convert (string, charset);
+
+         fputs (lstring, stdout);
+         g_free (lstring);
+       }
       fflush (stdout);
     }
   g_free (string);
@@ -755,384 +862,70 @@ g_printerr (const gchar *format,
   g_mutex_lock (g_messages_lock);
   local_glib_printerr_func = glib_printerr_func;
   g_mutex_unlock (g_messages_lock);
-
+  
   if (local_glib_printerr_func)
     local_glib_printerr_func (string);
   else
     {
-      fputs (string, stderr);
+      const gchar *charset;
+
+      if (g_get_charset (&charset))
+       fputs (string, stderr); /* charset is UTF-8 already */
+      else
+       {
+         gchar *lstring = strdup_convert (string, charset);
+
+         fputs (lstring, stderr);
+         g_free (lstring);
+       }
       fflush (stderr);
     }
   g_free (string);
 }
 
-/* compatibility code */
-GErrorFunc
-g_set_error_handler (GErrorFunc func)
+gsize
+g_printf_string_upper_bound (const gchar *format,
+                            va_list      args)
 {
-  GErrorFunc old_error_func;
-  
-  g_mutex_lock (g_messages_lock);
-  old_error_func = glib_error_func;
-  glib_error_func = func;
-  g_mutex_unlock (g_messages_lock);
-  return old_error_func;
+  gchar c;
+  return _g_vsnprintf (&c, 1, format, args) + 1;
 }
 
-/* compatibility code */
-GWarningFunc
-g_set_warning_handler (GWarningFunc func)
+void
+g_messages_init (void)
 {
-  GWarningFunc old_warning_func;
-  
-  g_mutex_lock (g_messages_lock);
-  old_warning_func = glib_warning_func;
-  glib_warning_func = func;
-  g_mutex_unlock (g_messages_lock);
-  
-  return old_warning_func;
+  g_messages_lock = g_mutex_new ();
+  g_log_depth = g_private_new (NULL);
+  g_messages_prefixed_init ();
+  _g_debug_init ();
 }
 
-/* compatibility code */
-GPrintFunc
-g_set_message_handler (GPrintFunc func)
+gboolean _g_debug_initialized = FALSE;
+guint _g_debug_flags = 0;
+
+void
+_g_debug_init (void) 
 {
-  GPrintFunc old_message_func;
+  const gchar *val;
   
-  g_mutex_lock (g_messages_lock);
-  old_message_func = glib_message_func;
-  glib_message_func = func;
-  g_mutex_unlock (g_messages_lock);
+  _g_debug_initialized = TRUE;
   
-  return old_message_func;
-}
-
-#ifndef MB_LEN_MAX
-#  define MB_LEN_MAX 8
-#endif
-
-typedef struct
-{
-  guint min_width;
-  guint precision;
-  gboolean alternate_format, zero_padding, adjust_left, locale_grouping;
-  gboolean add_space, add_sign, possible_sign, seen_precision;
-  gboolean mod_half, mod_long, mod_extra_long;
-} PrintfArgSpec;
-
-static inline guint
-printf_string_upper_bound (const gchar *format,
-                          gboolean     may_warn,
-                          va_list      args)
-{
-  static const gboolean honour_longs = SIZEOF_LONG > 4 || SIZEOF_VOID_P > 4;
-  guint len = 1;
-
-  if (!format)
-    return len;
-
-  while (*format)
+  val = g_getenv ("G_DEBUG");
+  if (val != NULL)
     {
-      register gchar c = *format++;
-
-      if (c != '%')
-       len += 1;
-      else /* (c == '%') */
-       {
-         PrintfArgSpec spec = { 0, };
-         gboolean seen_l = FALSE, conv_done = FALSE;
-         guint conv_len = 0;
-         const gchar *spec_start = format;
-
-         do
-           {
-             c = *format++;
-             switch (c)
-               {
-                 GDoubleIEEE754 u_double;
-                 guint v_uint;
-                 gint v_int;
-                 gchar *v_string;
-
-                 /* beware of positional parameters
-                  */
-               case '$':
-                 if (may_warn)
-                   g_warning (G_GNUC_PRETTY_FUNCTION
-                              "(): unable to handle positional parameters (%%n$)");
-                 len += 1024; /* try adding some safety padding */
-                 break;
-
-                 /* parse flags
-                  */
-               case '#':
-                 spec.alternate_format = TRUE;
-                 break;
-               case '0':
-                 spec.zero_padding = TRUE;
-                 break;
-               case '-':
-                 spec.adjust_left = TRUE;
-                 break;
-               case ' ':
-                 spec.add_space = TRUE;
-                 break;
-               case '+':
-                 spec.add_sign = TRUE;
-                 break;
-               case '\'':
-                 spec.locale_grouping = TRUE;
-                 break;
-
-                 /* parse output size specifications
-                  */
-               case '.':
-                 spec.seen_precision = TRUE;
-                 break;
-               case '1':
-               case '2':
-               case '3':
-               case '4':
-               case '5':
-               case '6':
-               case '7':
-               case '8':
-               case '9':
-                 v_uint = c - '0';
-                 c = *format;
-                 while (c >= '0' && c <= '9')
-                   {
-                     format++;
-                     v_uint = v_uint * 10 + c - '0';
-                     c = *format;
-                   }
-                 if (spec.seen_precision)
-                   spec.precision = MAX (spec.precision, v_uint);
-                 else
-                   spec.min_width = MAX (spec.min_width, v_uint);
-                 break;
-               case '*':
-                 v_int = va_arg (args, int);
-                 if (spec.seen_precision)
-                   {
-                     /* forget about negative precision */
-                     if (v_int >= 0)
-                       spec.precision = MAX (spec.precision, v_int);
-                   }
-                 else
-                   {
-                     if (v_int < 0)
-                       {
-                         v_int = - v_int;
-                         spec.adjust_left = TRUE;
-                       }
-                     spec.min_width = MAX (spec.min_width, v_int);
-                   }
-                 break;
-
-                 /* parse type modifiers
-                  */
-               case 'h':
-                 spec.mod_half = TRUE;
-                 break;
-               case 'l':
-                 if (!seen_l)
-                   {
-                     spec.mod_long = TRUE;
-                     seen_l = TRUE;
-                     break;
-                   }
-                 /* else, fall through */
-               case 'L':
-               case 'q':
-                 spec.mod_long = TRUE;
-                 spec.mod_extra_long = TRUE;
-                 break;
-               case 'z':
-               case 'Z':
-#if GLIB_SIZEOF_SIZE_T > 4
-                 spec.mod_long = TRUE;
-                 spec.mod_extra_long = TRUE;
-#endif /* GLIB_SIZEOF_SIZE_T > 4 */
-                 break;
-               case 't':
-#if GLIB_SIZEOF_PTRDIFF_T > 4
-                 spec.mod_long = TRUE;
-                 spec.mod_extra_long = TRUE;
-#endif /* GLIB_SIZEOF_PTRDIFF_T > 4 */
-                 break;
-               case 'j':
-#if GLIB_SIZEOF_INTMAX_T > 4
-                 spec.mod_long = TRUE;
-                 spec.mod_extra_long = TRUE;
-#endif /* GLIB_SIZEOF_INTMAX_T > 4 */
-                 break;
-
-                 /* parse output conversions
-                  */
-               case '%':
-                 conv_len += 1;
-                 break;
-               case 'O':
-               case 'D':
-               case 'I':
-               case 'U':
-                 /* some C libraries feature long variants for these as well? */
-                 spec.mod_long = TRUE;
-                 /* fall through */
-               case 'o':
-                 conv_len += 2;
-                 /* fall through */
-               case 'd':
-               case 'i':
-                 conv_len += 1; /* sign */
-                 /* fall through */
-               case 'u':
-                 conv_len += 4;
-                 /* fall through */
-               case 'x':
-               case 'X':
-                 spec.possible_sign = TRUE;
-                 conv_len += 10;
-                 if (spec.mod_long && honour_longs)
-                   conv_len *= 2;
-                 if (spec.mod_extra_long)
-                   conv_len *= 2;
-                 if (spec.mod_extra_long)
-                   {
-#ifdef G_HAVE_GINT64
-                     (void) va_arg (args, gint64);
-#else /* !G_HAVE_GINT64 */
-                     (void) va_arg (args, long);
-#endif /* !G_HAVE_GINT64 */
-                   }
-                 else if (spec.mod_long)
-                   (void) va_arg (args, long);
-                 else
-                   (void) va_arg (args, int);
-                 break;
-               case 'A':
-               case 'a':
-                 /*          0x */
-                 conv_len += 2;
-                 /* fall through */
-               case 'g':
-               case 'G':
-               case 'e':
-               case 'E':
-               case 'f':
-                 spec.possible_sign = TRUE;
-                 /*          n   .   dddddddddddddddddddddddd   E   +-  eeee */
-                 conv_len += 1 + 1 + MAX (24, spec.precision) + 1 + 1 + 4;
-                  if (may_warn && spec.mod_extra_long)
-                   g_warning (G_GNUC_PRETTY_FUNCTION
-                              "(): unable to handle long double, collecting double only");
-#ifdef HAVE_LONG_DOUBLE
-#error need to implement special handling for long double
-#endif
-                 u_double.v_double = va_arg (args, double);
-                 /* %f can expand up to all significant digits before '.' (308) */
-                 if (c == 'f' &&
-                     u_double.mpn.biased_exponent > 0 && u_double.mpn.biased_exponent < 2047)
-                   {
-                     gint exp = u_double.mpn.biased_exponent;
-
-                     exp -= G_IEEE754_DOUBLE_BIAS;
-                     exp = exp * G_LOG_2_BASE_10 + 1;
-                     conv_len += exp;
-                   }
-                 /* some printf() implementations require extra padding for rounding */
-                 conv_len += 2;
-                 /* we can't really handle locale specific grouping here */
-                 if (spec.locale_grouping)
-                   conv_len *= 2;
-                 break;
-               case 'C':
-                 spec.mod_long = TRUE;
-                  /* fall through */
-               case 'c':
-                 conv_len += spec.mod_long ? MB_LEN_MAX : 1;
-                 (void) va_arg (args, int);
-                 break;
-               case 'S':
-                 spec.mod_long = TRUE;
-                 /* fall through */
-               case 's':
-                 v_string = va_arg (args, char*);
-                 if (!v_string)
-                   conv_len += 8; /* hold "(null)" */
-                 else if (spec.seen_precision)
-                   conv_len += spec.precision;
-                 else
-                   conv_len += strlen (v_string);
-                 conv_done = TRUE;
-                 if (spec.mod_long)
-                   {
-                     if (may_warn)
-                       g_warning (G_GNUC_PRETTY_FUNCTION
-                                  "(): unable to handle wide char strings");
-                     len += 1024; /* try adding some safety padding */
-                   }
-                 break;
-               case 'P': /* do we actually need this? */
-                 /* fall through */
-               case 'p':
-                 spec.alternate_format = TRUE;
-                 conv_len += 10;
-                 if (honour_longs)
-                   conv_len *= 2;
-                 /* fall through */
-               case 'n':
-                 conv_done = TRUE;
-                 (void) va_arg (args, void*);
-                 break;
-               case 'm':
-                 /* there's not much we can do to be clever */
-                 v_string = g_strerror (errno);
-                 v_uint = v_string ? strlen (v_string) : 0;
-                 conv_len += MAX (256, v_uint);
-                 break;
-
-                 /* handle invalid cases
-                  */
-               case '\000':
-                 /* no conversion specification, bad bad */
-                 conv_len += format - spec_start;
-                 break;
-               default:
-                 if (may_warn)
-                   g_warning (G_GNUC_PRETTY_FUNCTION
-                              "(): unable to handle `%c' while parsing format",
-                              c);
-                 break;
-               }
-             conv_done |= conv_len > 0;
-           }
-         while (!conv_done);
-         /* handle width specifications */
-         conv_len = MAX (conv_len, MAX (spec.precision, spec.min_width));
-         /* handle flags */
-         conv_len += spec.alternate_format ? 2 : 0;
-         conv_len += (spec.add_space || spec.add_sign || spec.possible_sign);
-         /* finally done */
-         len += conv_len;
-       } /* else (c == '%') */
-    } /* while (*format) */
-
-  return len;
-}
-
-guint
-g_printf_string_upper_bound (const gchar *format,
-                            va_list      args)
-{
-  return printf_string_upper_bound (format, TRUE, args);
-}
-
-void
-g_messages_init (void)
-{
-  g_messages_lock = g_mutex_new();
-  g_log_depth = g_private_new(NULL);
+      static const GDebugKey keys[] = {
+       {"fatal_warnings", G_DEBUG_FATAL_WARNINGS}
+      };
+      
+      _g_debug_flags = g_parse_debug_string (val, keys, G_N_ELEMENTS (keys));
+    }
+  
+  if (_g_debug_flags & G_DEBUG_FATAL_WARNINGS) 
+    {
+      GLogLevelFlags fatal_mask;
+      
+      fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
+      fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
+      g_log_set_always_fatal (fatal_mask);
+    }
 }