* 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>
#include <string.h>
-#include <unistd.h>
#include "glib.h"
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <signal.h>
+#include <locale.h>
+#include <errno.h>
/* --- structures --- */
};
+/* --- 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;
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;
}
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;
}
{
register GLogDomain *last, *work;
- last = NULL;
+ last = NULL;
+
+ g_mutex_lock (g_messages_lock);
work = g_log_domains;
while (work)
{
g_free (domain);
break;
}
- work = work->next;
- }
+ last = work;
+ work = last->next;
+ }
+ g_mutex_unlock (g_messages_lock);
}
}
/* 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;
}
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;
}
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;
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\"",
}
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];
* 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
{
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));
}
}
}
const gchar *message,
gpointer unused_data)
{
+#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 ());
- fd = (log_level >= G_LOG_LEVEL_MESSAGE) ? 1 : 2;
+#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;
+#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));
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));
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));
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
/* 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));
}
else
write (fd, "): ", 3);
- write (fd, message, strlen(message));
+ write (fd, message, strlen (message));
if (is_fatal)
write (fd, "\naborting...\n", 13);
else
{
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;
}
{
va_list args;
gchar *string;
+ GPrintFunc local_glib_print_func;
g_return_if_fail (format != NULL);
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);
}
{
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;
}
{
va_list args;
gchar *string;
+ GPrintFunc local_glib_printerr_func;
g_return_if_fail (format != NULL);
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);
{
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;
}
{
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;
}
{
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);
+}