Include a printf implementation supporting C99 snprintf and SUS
[platform/upstream/glib.git] / glib / gmessages.c
index f3b664c..0fb2358 100644 (file)
@@ -44,6 +44,7 @@
 #include <locale.h>
 #include <errno.h>
 #include "gdebug.h"
+#include "gprintfint.h"
 
 #ifdef G_OS_WIN32
 typedef FILE* GFileDescriptor;
@@ -71,14 +72,6 @@ struct _GLogHandler
 };
 
 
-/* --- 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;
@@ -409,10 +402,6 @@ g_logv (const gchar   *log_domain,
   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;
@@ -420,21 +409,7 @@ g_logv (const gchar   *log_domain,
   /* 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))
     {
@@ -548,7 +523,7 @@ strdup_convert (const gchar *string,
          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);
          
@@ -909,333 +884,12 @@ g_printerr (const gchar *format,
   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