Patch from Sven Neumann to make the include order consistent. (#71704)
[platform/upstream/glib.git] / glib / gmessages.c
index eb8aed7..820c3ee 100644 (file)
@@ -2,53 +2,54 @@
  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
  *
  * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
+ * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
  * version 2 of the License, or (at your option) any later version.
  *
  * This library is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
  *
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the
  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  * Boston, MA 02111-1307, USA.
  */
 
+/*
+ * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GLib Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
 /* 
  * 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 <signal.h>
+#include <locale.h>
+#include <errno.h>
 
-#ifdef NATIVE_WIN32
-/* 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)
-{
-  fwrite (buf, len, 1, fd);
-
-  return len;
-}
-#endif /* NATIVE_WIN32 */
+#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;
@@ -71,44 +72,129 @@ struct _GLogHandler
 
 
 /* --- 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 --- */
-static inline GLogDomain*
-g_log_find_domain (const gchar   *log_domain)
+#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
+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);
+  
+      if (handle == INVALID_HANDLE_VALUE)
+       {
+         AllocConsole ();
+         alloc_console_called = TRUE;
+         freopen ("CONOUT$", "w", stdout);
+       }
+    }
+}
+#else
+#define ensure_stdout_valid()  /* Define as empty */
+#endif
+
+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;
 
@@ -117,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)
@@ -135,7 +219,6 @@ g_log_domain_check_free (GLogDomain *domain)
       
       last = NULL;  
 
-      g_mutex_lock (g_messages_lock);
       work = g_log_domains;
       while (work)
        {
@@ -149,16 +232,16 @@ g_log_domain_check_free (GLogDomain *domain)
              g_free (domain);
              break;
            }
-         work = work->next;
+         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)
     {
@@ -183,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;
@@ -199,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;
@@ -213,53 +298,60 @@ 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;
 }
 
 void
-g_log_remove_handler (const gchar    *log_domain,
-                     guint           handler_id)
+g_log_remove_handler (const gchar *log_domain,
+                     guint        handler_id)
 {
   register GLogDomain *domain;
   
@@ -268,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;
@@ -283,28 +376,31 @@ 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;
            }
-         work = work->next;
+         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
-g_logv (const gchar    *log_domain,
-       GLogLevelFlags  log_level,
-       const gchar    *format,
-       va_list         args1)
+g_logv (const gchar   *log_domain,
+       GLogLevelFlags log_level,
+       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;
@@ -312,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 (g_printf_string_upper_bound (format, 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))
     {
@@ -338,29 +420,67 @@ 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)
-           abort ();
+           {
+#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))
+               G_BREAKPOINT ();
+             else
+               abort ();
+#else /* !G_ENABLE_DEBUG || !(SIGTRAP || G_OS_WIN32) */
+             abort ();
+#endif /* !G_ENABLE_DEBUG || !(SIGTRAP || G_OS_WIN32) */
+           }
          
          depth--;
          g_private_set (g_log_depth, GUINT_TO_POINTER (depth));
@@ -369,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;
@@ -381,211 +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 NATIVE_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;
-
-  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 (!g_utf8_validate (string, -1, NULL))
+    return g_strconcat ("[Invalid UTF-8] ", string, NULL);
+  else
+    {
+      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;
+    }
   
-  if (!message)
-    message = "g_log_default_handler(): (NULL) message";
+  if (!num)
+    {
+      *buf++ = '0';
+      *buf = '\000';
+      return;
+    } 
   
-#ifdef NATIVE_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 (radix == 16)
+    {
+      *buf++ = '0';
+      *buf++ = 'x';
+    }
+  else if (radix == 8)
+    {
+      *buf++ = '0';
+    }
+       
+  n = 0;
+  tmp = num;
+  while (tmp)
+    {
+      tmp /= radix;
+      n++;
+    }
+
+  i = n;
+
+  /* Again we can't use g_assert; actually this check should _never_ fail. */
+  if (n > FORMAT_UNSIGNED_BUFSIZE - 3)
+    {
+      *buf = '\000';
+      return;
+    }
+
+  while (num)
+    {
+      i--;
+      c = (num % radix);
+      if (c < 10)
+       buf[i] = c + '0';
+      else
+       buf[i] = c + 'a' - 10;
+      num /= radix;
+    }
   
-  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);
+  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)
+  switch (log_level & G_LOG_LEVEL_MASK)
     {
     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 */
-      if (log_domain)
-       {
-         write (fd, "\n", 1);
-         write (fd, log_domain, strlen (log_domain));
-         write (fd, "-", 1);
-       }
-      else
-       write (fd, "\n** ", 4);
-      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);
-      else
-       write (fd, "\n", 1);
+      strcpy (level_prefix, "ERROR");
+      to_stdout = FALSE;
       break;
     case G_LOG_LEVEL_CRITICAL:
-      if (log_domain)
-       {
-         write (fd, "\n", 1);
-         write (fd, log_domain, strlen (log_domain));
-         write (fd, "-", 1);
-       }
-      else
-       write (fd, "\n** ", 4);
-      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;
-       }
-      if (log_domain)
-       {
-         write (fd, "\n", 1);
-         write (fd, log_domain, strlen (log_domain));
-         write (fd, "-", 1);
-       }
-      else
-       write (fd, "\n** ", 4);
-      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;
-       }
-      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:
-      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:
-      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.
-       */
-      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
@@ -618,12 +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
     {
-      fputs (string, stdout);
+      const gchar *charset;
+
+      ensure_stdout_valid ();
+      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);
@@ -659,62 +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)
-{
-  GPrintFunc old_message_func;
-  
-  g_mutex_lock (g_messages_lock);
-  old_message_func = glib_message_func;
-  glib_message_func = func;
-  g_mutex_unlock (g_messages_lock);
-  
-  return old_message_func;
-}
+gboolean _g_debug_initialized = FALSE;
+guint _g_debug_flags = 0;
 
 void
-g_messages_init (void)
+_g_debug_init (void) 
 {
-  g_messages_lock = g_mutex_new();
-  g_log_depth = g_private_new(NULL);
+  const gchar *val;
+  
+  _g_debug_initialized = TRUE;
+  
+  val = g_getenv ("G_DEBUG");
+  if (val != 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);
+    }
 }