#include <locale.h>
#include <errno.h>
#include "gdebug.h"
+#include "gprintfint.h"
#ifdef G_OS_WIN32
typedef FILE* GFileDescriptor;
};
-/* --- prototypes --- */
-#ifndef HAVE_C99_VSNPRINTF
-static gsize printf_string_upper_bound (const gchar *format,
- gboolean may_warn,
- va_list args);
-#endif /* !HAVE_C99_VSNPRINTF */
-
-
/* --- variables --- */
static GMutex *g_messages_lock = NULL;
static GLogDomain *g_log_domains = NULL;
gboolean was_recursion = (log_level & G_LOG_FLAG_RECURSION) != 0;
gint i;
-#ifndef HAVE_VSNPRINTF
- va_list args2;
-#endif /* HAVE_VSNPRINTF */
-
log_level &= G_LOG_LEVEL_MASK;
if (!log_level)
return;
/* we use a stack buffer of fixed size, because we might get called
* recursively.
*/
-#ifdef HAVE_VSNPRINTF
- vsnprintf (buffer, 1024, format, args1);
-#else /* !HAVE_VSNPRINTF */
- 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(). */
- /* we are out of luck here */
- strncpy (buffer, format, 1024);
- buffer[1024] = 0;
- }
- va_end (args2);
-#endif /* !HAVE_VSNPRINTF */
+ _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))
{
if (!warned)
{
warned = TRUE;
- fprintf (stderr, "GLib: Cannot convert message: %s\n", err->message);
+ _g_fprintf (stderr, "GLib: Cannot convert message: %s\n", err->message);
}
g_error_free (err);
g_free (string);
}
-#ifndef MB_LEN_MAX
-# define MB_LEN_MAX 8
-#endif
-
-#ifndef HAVE_C99_VSNPRINTF
-
-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 gsize
-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;
- gsize 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;
- gsize conv_len = 0;
- const gchar *spec_start = format;
-
- do
- {
- c = *format++;
- switch (c)
- {
- GDoubleIEEE754 u_double;
- guint v_uint;
- gint v_int;
- const 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 */
- conv_done = TRUE;
- 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)
- {
- (void) va_arg (args, 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 += ABS (exp); /* exp can be <0 */
- }
- /* 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;
-}
-
-#endif /* !HAVE_C99_VSNPRINTF */
-
-
gsize
g_printf_string_upper_bound (const gchar *format,
va_list args)
{
-#if HAVE_C99_VSNPRINTF
gchar c;
- return vsnprintf (&c, 1, format, args) + 1;
-#else
- return printf_string_upper_bound (format, TRUE, args);
-#endif
+ return _g_vsnprintf (&c, 1, format, args) + 1;
}
void