Don't warn about deprecation on Win32. Code written for GLib 1.2 doesn't
[platform/upstream/glib.git] / gmessages.c
index fa52311..f637778 100644 (file)
@@ -2,20 +2,36 @@
  * 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 <stdlib.h>
 #include <stdarg.h>
 #include <stdio.h>
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
-
-#ifdef NATIVE_WIN32
-/* Just use stdio. If we're out of memroy, 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 <signal.h>
+#include <locale.h>
+#include <errno.h>
 
 
 /* --- structures --- */
@@ -61,7 +65,16 @@ 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 GLogDomain    *g_log_domains = NULL;
 static GLogLevelFlags g_log_always_fatal = G_LOG_FATAL_MASK;
@@ -71,20 +84,89 @@ static GErrorFunc     glib_error_func = NULL;
 static GWarningFunc   glib_warning_func = NULL;
 static GPrintFunc     glib_message_func = NULL;
 
+static GPrivate* g_log_depth = NULL;
+
 
 /* --- functions --- */
+#ifdef G_OS_WIN32
+#  define STRICT
+#  include <windows.h>
+#  include <process.h>          /* For _getpid() */
+
+static gboolean alloc_console_called = FALSE;
+
+static gboolean gonna_abort = 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 char fatal_msg_buf[1000] = "Unspecified fatal error encountered, aborting.";
+static char *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 (FILE        *fd,
+        const void  *buf,
+        unsigned int len)
+{
+  if (gonna_abort)
+    {
+      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 (gonna_abort)
+    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 inline GLogDomain*
-g_log_find_domain (const gchar   *log_domain)
+g_log_find_domain (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)
-       return domain;
+       {
+         g_mutex_unlock (g_messages_lock);
+         return domain;
+       }
       domain = domain->next;
     }
+  g_mutex_unlock (g_messages_lock);
   return NULL;
 }
 
@@ -97,8 +179,11 @@ g_log_domain_new (const gchar *log_domain)
   domain->log_domain = g_strdup (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;
 }
@@ -111,7 +196,9 @@ g_log_domain_check_free (GLogDomain *domain)
     {
       register GLogDomain *last, *work;
       
-      last = NULL;
+      last = NULL;  
+
+      g_mutex_lock (g_messages_lock);
       work = g_log_domains;
       while (work)
        {
@@ -125,8 +212,10 @@ 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);
     }
 }
 
@@ -165,8 +254,10 @@ g_log_set_always_fatal (GLogLevelFlags fatal_mask)
   /* remove bogus flag */
   fatal_mask &= ~G_LOG_FLAG_FATAL;
 
+  g_mutex_lock (g_messages_lock);
   old_mask = g_log_always_fatal;
   g_log_always_fatal = fatal_mask;
+  g_mutex_unlock (g_messages_lock);
 
   return old_mask;
 }
@@ -218,7 +309,9 @@ g_log_set_handler (const gchar        *log_domain,
     domain = g_log_domain_new (log_domain);
   
   handler = g_new (GLogHandler, 1);
+  g_mutex_lock (g_messages_lock);
   handler->id = ++handler_id;
+  g_mutex_unlock (g_messages_lock);
   handler->log_level = log_levels;
   handler->log_func = log_func;
   handler->data = user_data;
@@ -229,8 +322,8 @@ g_log_set_handler (const gchar        *log_domain,
 }
 
 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;
   
@@ -258,7 +351,8 @@ g_log_remove_handler (const gchar    *log_domain,
              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\"",
@@ -267,10 +361,10 @@ g_log_remove_handler (const gchar    *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];
@@ -284,7 +378,7 @@ g_logv (const gchar    *log_domain,
    * recursively.
    */
   G_VA_COPY (args2, args1);
-  if (g_printf_string_upper_bound (format, args1) < 1024)
+  if (printf_string_upper_bound (format, FALSE, args1) < 1024)
     vsprintf (buffer, format, args2);
   else
     {
@@ -306,28 +400,47 @@ g_logv (const gchar    *log_domain,
       test_level = 1 << i;
       if (log_level & test_level)
        {
-         static guint g_log_depth = 0;
+         guint depth = GPOINTER_TO_UINT (g_private_get (g_log_depth));
          GLogDomain *domain;
          GLogFunc log_func;
          gpointer data = NULL;
          
          domain = g_log_find_domain (log_domain ? log_domain : "");
          
-         if (g_log_depth++)
+         if (depth)
            test_level |= G_LOG_FLAG_RECURSION;
          
-         if ((((domain ? domain->fatal_mask : G_LOG_FATAL_MASK) | g_log_always_fatal) &
-              test_level) != 0)
-           test_level |= G_LOG_FLAG_FATAL;
+         depth++;
+         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);
+
          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 ();
+           {
+#if defined (G_ENABLE_DEBUG) && defined (SIGTRAP)
+             if (!(test_level & G_LOG_FLAG_RECURSION))
+               raise (SIGTRAP);
+             else
+               abort ();
+#else /* !G_ENABLE_DEBUG || !SIGTRAP */
+#ifdef G_OS_WIN32
+             MessageBox (NULL, fatal_msg_buf, NULL, MB_OK);
+#endif
+             abort ();
+#endif /* !G_ENABLE_DEBUG || !SIGTRAP */
+           }
          
-         g_log_depth--;
+         depth--;
+         g_private_set (g_log_depth, GUINT_TO_POINTER (depth));
        }
     }
 }
@@ -351,109 +464,147 @@ g_log_default_handler (const gchar    *log_domain,
                       const gchar    *message,
                       gpointer        unused_data)
 {
-#ifdef NATIVE_WIN32
+#ifdef G_OS_WIN32
   FILE *fd;
 #else
   gint fd;
 #endif
   gboolean in_recursion;
-  gboolean is_fatal;
-  
+  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)
+    {
+      prg_name = "(process";
+      sprintf (prg_pid, ":%u): ", getpid ());
+    }
+  else
+    sprintf (prg_pid, " (pid:%u): ", getpid ());
   
-#ifdef NATIVE_WIN32
+#ifdef G_OS_WIN32
   /* Use just stdout as stderr is hard to get redirected from the
    * DOS prompt.
    */
   fd = stdout;
+  gonna_abort = is_fatal;
 #else
-  fd = (log_level >= G_LOG_LEVEL_MESSAGE) ? 1 : 2;
+  fd = (log_level > G_LOG_LEVEL_MESSAGE) ? 1 : 2;
 #endif
   
+  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);
+
   switch (log_level)
     {
     case G_LOG_LEVEL_ERROR:
-      if (!log_domain && glib_error_func)
+      if (!log_domain && local_glib_error_func)
        {
          /* compatibility code */
-         glib_error_func (message);
+         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, "\n", 1);
          write (fd, log_domain, strlen (log_domain));
          write (fd, "-", 1);
        }
       else
-       write (fd, "\n** ", 4);
+       write (fd, "** ", 3);
       if (in_recursion)
        write (fd, "ERROR (recursed) **: ", 21);
       else
        write (fd, "ERROR **: ", 10);
-      write (fd, message, strlen(message));
+      write (fd, message, strlen (message));
       if (is_fatal)
        write (fd, "\naborting...\n", 13);
       else
        write (fd, "\n", 1);
       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, "\n", 1);
          write (fd, log_domain, strlen (log_domain));
          write (fd, "-", 1);
        }
       else
-       write (fd, "\n** ", 4);
+       write (fd, "** ", 3);
       if (in_recursion)
        write (fd, "CRITICAL (recursed) **: ", 24);
       else
        write (fd, "CRITICAL **: ", 13);
-      write (fd, message, strlen(message));
+      write (fd, message, strlen (message));
       if (is_fatal)
        write (fd, "\naborting...\n", 13);
       else
        write (fd, "\n", 1);
       break;
     case G_LOG_LEVEL_WARNING:
-      if (!log_domain && glib_warning_func)
+      if (!log_domain && local_glib_warning_func)
        {
          /* compatibility code */
-         glib_warning_func (message);
+         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, "\n", 1);
          write (fd, log_domain, strlen (log_domain));
          write (fd, "-", 1);
        }
       else
-       write (fd, "\n** ", 4);
+       write (fd, "** ", 3);
       if (in_recursion)
        write (fd, "WARNING (recursed) **: ", 23);
       else
        write (fd, "WARNING **: ", 12);
-      write (fd, message, strlen(message));
+      write (fd, message, strlen (message));
       if (is_fatal)
        write (fd, "\naborting...\n", 13);
       else
        write (fd, "\n", 1);
       break;
     case G_LOG_LEVEL_MESSAGE:
-      if (!log_domain && glib_message_func)
+      if (!log_domain && local_glib_message_func)
        {
          /* compatibility code */
-         glib_message_func (message);
+         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));
@@ -463,13 +614,18 @@ g_log_default_handler (const gchar    *log_domain,
        write (fd, "Message (recursed): ", 20);
       else
        write (fd, "Message: ", 9);
-      write (fd, message, strlen(message));
+      write (fd, message, strlen (message));
       if (is_fatal)
        write (fd, "\naborting...\n", 13);
       else
        write (fd, "\n", 1);
       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));
@@ -479,13 +635,18 @@ g_log_default_handler (const gchar    *log_domain,
        write (fd, "INFO (recursed): ", 17);
       else
        write (fd, "INFO: ", 6);
-      write (fd, message, strlen(message));
+      write (fd, message, strlen (message));
       if (is_fatal)
        write (fd, "\naborting...\n", 13);
       else
        write (fd, "\n", 1);
       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));
@@ -495,7 +656,7 @@ g_log_default_handler (const gchar    *log_domain,
        write (fd, "DEBUG (recursed): ", 18);
       else
        write (fd, "DEBUG: ", 7);
-      write (fd, message, strlen(message));
+      write (fd, message, strlen (message));
       if (is_fatal)
        write (fd, "\naborting...\n", 13);
       else
@@ -505,6 +666,11 @@ g_log_default_handler (const gchar    *log_domain,
       /* 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));
@@ -534,7 +700,7 @@ g_log_default_handler (const gchar    *log_domain,
        }
       else
        write (fd, "): ", 3);
-      write (fd, message, strlen(message));
+      write (fd, message, strlen (message));
       if (is_fatal)
        write (fd, "\naborting...\n", 13);
       else
@@ -548,8 +714,10 @@ g_set_print_handler (GPrintFunc func)
 {
   GPrintFunc old_print_func;
   
+  g_mutex_lock (g_messages_lock);
   old_print_func = glib_print_func;
   glib_print_func = func;
+  g_mutex_unlock (g_messages_lock);
   
   return old_print_func;
 }
@@ -560,6 +728,7 @@ g_print (const gchar *format,
 {
   va_list args;
   gchar *string;
+  GPrintFunc local_glib_print_func;
   
   g_return_if_fail (format != NULL);
   
@@ -567,10 +736,15 @@ g_print (const gchar *format,
   string = g_strdup_vprintf (format, args);
   va_end (args);
   
-  if (glib_print_func)
-    glib_print_func (string);
+  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
     {
+      ensure_stdout_valid ();
       fputs (string, stdout);
       fflush (stdout);
     }
@@ -582,8 +756,10 @@ g_set_printerr_handler (GPrintFunc func)
 {
   GPrintFunc old_printerr_func;
   
+  g_mutex_lock (g_messages_lock);
   old_printerr_func = glib_printerr_func;
   glib_printerr_func = func;
+  g_mutex_unlock (g_messages_lock);
   
   return old_printerr_func;
 }
@@ -594,6 +770,7 @@ g_printerr (const gchar *format,
 {
   va_list args;
   gchar *string;
+  GPrintFunc local_glib_printerr_func;
   
   g_return_if_fail (format != NULL);
   
@@ -601,8 +778,12 @@ g_printerr (const gchar *format,
   string = g_strdup_vprintf (format, args);
   va_end (args);
   
-  if (glib_printerr_func)
-    glib_printerr_func (string);
+  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);
@@ -617,9 +798,11 @@ g_set_error_handler (GErrorFunc func)
 {
   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;
 }
 
@@ -629,8 +812,10 @@ g_set_warning_handler (GWarningFunc func)
 {
   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;
 }
@@ -641,8 +826,339 @@ 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;
 }
+
+#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)
+    {
+      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);
+}