From a44d5145ea2dc66d5170caea925c31702b98b4ab Mon Sep 17 00:00:00 2001 From: "CST 2001 Shawn T. Amundson" Date: Tue, 27 Feb 2001 04:46:00 +0000 Subject: [PATCH] Backport implementation of g_printf_string_upper_bound from 1.3. Bug Mon Feb 26 21:06:17 CST 2001 Shawn T. Amundson * gstrfuncs.c: Backport implementation of g_printf_string_upper_bound from 1.3. Bug #50217. * gmain.c: Cast RHS of an assignment to a GSourceFunc variable. Fourth param of g_source_add() is a gpointer, so add a cast to that param. From Richard K. Lloyd. A portion of bug #50793. --- ChangeLog | 10 + ChangeLog.pre-2-0 | 10 + ChangeLog.pre-2-10 | 10 + ChangeLog.pre-2-12 | 10 + ChangeLog.pre-2-2 | 10 + ChangeLog.pre-2-4 | 10 + ChangeLog.pre-2-6 | 10 + ChangeLog.pre-2-8 | 10 + glib/gmain.c | 4 +- glib/gstrfuncs.c | 445 ++++++++++++++++++++++++++++++++------------- gmain.c | 4 +- gstrfuncs.c | 445 ++++++++++++++++++++++++++++++++------------- 12 files changed, 726 insertions(+), 252 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0e667b989..e8ed132ce 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ + +Mon Feb 26 21:06:17 CST 2001 Shawn T. Amundson + + * gstrfuncs.c: Backport implementation of + g_printf_string_upper_bound from 1.3. Bug #50217. + + * gmain.c: Cast RHS of an assignment to a GSourceFunc variable. + Fourth param of g_source_add() is a gpointer, so add a cast to that + param. From Richard K. Lloyd. A portion of bug #50793. + Mon Feb 26 23:06:54 2001 Owen Taylor * README: Fix information about reporting bugs to diff --git a/ChangeLog.pre-2-0 b/ChangeLog.pre-2-0 index 0e667b989..e8ed132ce 100644 --- a/ChangeLog.pre-2-0 +++ b/ChangeLog.pre-2-0 @@ -1,3 +1,13 @@ + +Mon Feb 26 21:06:17 CST 2001 Shawn T. Amundson + + * gstrfuncs.c: Backport implementation of + g_printf_string_upper_bound from 1.3. Bug #50217. + + * gmain.c: Cast RHS of an assignment to a GSourceFunc variable. + Fourth param of g_source_add() is a gpointer, so add a cast to that + param. From Richard K. Lloyd. A portion of bug #50793. + Mon Feb 26 23:06:54 2001 Owen Taylor * README: Fix information about reporting bugs to diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index 0e667b989..e8ed132ce 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,13 @@ + +Mon Feb 26 21:06:17 CST 2001 Shawn T. Amundson + + * gstrfuncs.c: Backport implementation of + g_printf_string_upper_bound from 1.3. Bug #50217. + + * gmain.c: Cast RHS of an assignment to a GSourceFunc variable. + Fourth param of g_source_add() is a gpointer, so add a cast to that + param. From Richard K. Lloyd. A portion of bug #50793. + Mon Feb 26 23:06:54 2001 Owen Taylor * README: Fix information about reporting bugs to diff --git a/ChangeLog.pre-2-12 b/ChangeLog.pre-2-12 index 0e667b989..e8ed132ce 100644 --- a/ChangeLog.pre-2-12 +++ b/ChangeLog.pre-2-12 @@ -1,3 +1,13 @@ + +Mon Feb 26 21:06:17 CST 2001 Shawn T. Amundson + + * gstrfuncs.c: Backport implementation of + g_printf_string_upper_bound from 1.3. Bug #50217. + + * gmain.c: Cast RHS of an assignment to a GSourceFunc variable. + Fourth param of g_source_add() is a gpointer, so add a cast to that + param. From Richard K. Lloyd. A portion of bug #50793. + Mon Feb 26 23:06:54 2001 Owen Taylor * README: Fix information about reporting bugs to diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2 index 0e667b989..e8ed132ce 100644 --- a/ChangeLog.pre-2-2 +++ b/ChangeLog.pre-2-2 @@ -1,3 +1,13 @@ + +Mon Feb 26 21:06:17 CST 2001 Shawn T. Amundson + + * gstrfuncs.c: Backport implementation of + g_printf_string_upper_bound from 1.3. Bug #50217. + + * gmain.c: Cast RHS of an assignment to a GSourceFunc variable. + Fourth param of g_source_add() is a gpointer, so add a cast to that + param. From Richard K. Lloyd. A portion of bug #50793. + Mon Feb 26 23:06:54 2001 Owen Taylor * README: Fix information about reporting bugs to diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4 index 0e667b989..e8ed132ce 100644 --- a/ChangeLog.pre-2-4 +++ b/ChangeLog.pre-2-4 @@ -1,3 +1,13 @@ + +Mon Feb 26 21:06:17 CST 2001 Shawn T. Amundson + + * gstrfuncs.c: Backport implementation of + g_printf_string_upper_bound from 1.3. Bug #50217. + + * gmain.c: Cast RHS of an assignment to a GSourceFunc variable. + Fourth param of g_source_add() is a gpointer, so add a cast to that + param. From Richard K. Lloyd. A portion of bug #50793. + Mon Feb 26 23:06:54 2001 Owen Taylor * README: Fix information about reporting bugs to diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index 0e667b989..e8ed132ce 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -1,3 +1,13 @@ + +Mon Feb 26 21:06:17 CST 2001 Shawn T. Amundson + + * gstrfuncs.c: Backport implementation of + g_printf_string_upper_bound from 1.3. Bug #50217. + + * gmain.c: Cast RHS of an assignment to a GSourceFunc variable. + Fourth param of g_source_add() is a gpointer, so add a cast to that + param. From Richard K. Lloyd. A portion of bug #50793. + Mon Feb 26 23:06:54 2001 Owen Taylor * README: Fix information about reporting bugs to diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index 0e667b989..e8ed132ce 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,13 @@ + +Mon Feb 26 21:06:17 CST 2001 Shawn T. Amundson + + * gstrfuncs.c: Backport implementation of + g_printf_string_upper_bound from 1.3. Bug #50217. + + * gmain.c: Cast RHS of an assignment to a GSourceFunc variable. + Fourth param of g_source_add() is a gpointer, so add a cast to that + param. From Richard K. Lloyd. A portion of bug #50793. + Mon Feb 26 23:06:54 2001 Owen Taylor * README: Fix information about reporting bugs to diff --git a/glib/gmain.c b/glib/gmain.c index bf4fdfe29..8ead8a017 100644 --- a/glib/gmain.c +++ b/glib/gmain.c @@ -1362,7 +1362,7 @@ g_idle_dispatch (gpointer source_data, GTimeVal *dispatch_time, gpointer user_data) { - GSourceFunc func = source_data; + GSourceFunc func = (GSourceFunc) source_data; return func (user_data); } @@ -1375,7 +1375,7 @@ g_idle_add_full (gint priority, { g_return_val_if_fail (function != NULL, 0); - return g_source_add (priority, FALSE, &idle_funcs, function, data, notify); + return g_source_add (priority, FALSE, &idle_funcs, (gpointer) function, data, notify); } guint diff --git a/glib/gstrfuncs.c b/glib/gstrfuncs.c index bdf0f8649..feb457275 100644 --- a/glib/gstrfuncs.c +++ b/glib/gstrfuncs.c @@ -37,6 +37,7 @@ #include #include #include +#include #include /* For tolower() */ #if !defined (HAVE_STRSIGNAL) || !defined(NO_SYS_SIGLIST_DECL) #include @@ -46,6 +47,36 @@ * inteferes with g_strsignal() on some OSes */ +typedef union _GDoubleIEEE754 GDoubleIEEE754; +#define G_IEEE754_DOUBLE_BIAS (1023) +/* multiply with base2 exponent to get base10 exponent (nomal numbers) */ +#define G_LOG_2_BASE_10 (0.30102999566398119521) +#if G_BYTE_ORDER == G_LITTLE_ENDIAN +union _GDoubleIEEE754 +{ + gdouble v_double; + struct { + guint mantissa_low : 32; + guint mantissa_high : 20; + guint biased_exponent : 11; + guint sign : 1; + } mpn; +}; +#elif G_BYTE_ORDER == G_BIG_ENDIAN +union _GDoubleIEEE754 +{ + gdouble v_double; + struct { + guint sign : 1; + guint biased_exponent : 11; + guint mantissa_high : 20; + guint mantissa_low : 32; + } mpn; +}; +#else /* !G_LITTLE_ENDIAN && !G_BIG_ENDIAN */ +#error unknown ENDIAN type +#endif /* !G_LITTLE_ENDIAN && !G_BIG_ENDIAN */ + gchar* g_strdup (const gchar *str) { @@ -791,143 +822,309 @@ g_strsignal (gint signum) return msg; } +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; + guint g_printf_string_upper_bound (const gchar* format, va_list args) { + static const gboolean honour_longs = SIZEOF_LONG > 4 || SIZEOF_VOID_P > 4; guint len = 1; + if (!format) + return len; + while (*format) { - gboolean long_int = FALSE; - gboolean extra_long = FALSE; - gchar c; + register gchar c = *format++; - 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; - if (c == '%') - { - gboolean done = FALSE; + do + { + c = *format++; + switch (c) + { + GDoubleIEEE754 u_double; + guint v_uint; + gint v_int; + const gchar *v_string; - while (*format && !done) - { - switch (*format++) - { - gchar *string_arg; + /* beware of positional parameters + */ + case '$': + g_warning (G_GNUC_PRETTY_FUNCTION + "(): unable to handle positional parameters (%%n$)"); + len += 1024; /* try adding some safety padding */ + break; - case '*': - len += va_arg (args, int); - break; - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - /* add specified format length, since it might exceed the - * size we assume it to have. - */ - format -= 1; - len += strtol (format, (char**) &format, 10); - break; - case 'h': - /* ignore short int flag, since all args have at least the - * same size as an int - */ - break; - case 'l': - if (long_int) - extra_long = TRUE; /* linux specific */ - else - long_int = TRUE; - break; - case 'q': - case 'L': - long_int = TRUE; - extra_long = TRUE; - break; - case '\'': - len += 64; - break; - case 's': - string_arg = va_arg (args, char *); - if (string_arg) - len += strlen (string_arg); - else - { - /* add enough padding to hold "(null)" identifier */ - len += 16; - } - done = TRUE; - break; - case 'd': - case 'i': - case 'o': - case 'u': - case 'x': - case 'X': -#ifdef G_HAVE_GINT64 - if (extra_long) - (void) va_arg (args, gint64); - else -#endif /* G_HAVE_GINT64 */ - { - if (long_int) - (void) va_arg (args, long); - else - (void) va_arg (args, int); - } - len += extra_long ? 64 : 32; - done = TRUE; - break; - case 'D': - case 'O': - case 'U': - (void) va_arg (args, long); - len += 32; - done = TRUE; - break; - case 'e': - case 'E': - case 'f': - case 'g': - case 'G': + /* 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 (spec.mod_extra_long) + g_warning (G_GNUC_PRETTY_FUNCTION + "(): unable to handle long double, collecting double only"); #ifdef HAVE_LONG_DOUBLE - if (extra_long) - (void) va_arg (args, long double); - else -#endif /* HAVE_LONG_DOUBLE */ - (void) va_arg (args, double); - len += extra_long ? 128 : 64; - done = TRUE; - break; - case 'c': - (void) va_arg (args, int); - len += 1; - done = TRUE; - break; - case 'p': - case 'n': - (void) va_arg (args, void*); - len += 32; - done = TRUE; - break; - case '%': - len += 1; - done = TRUE; - break; - default: - /* ignore unknow/invalid flags */ - break; - } - } - } - else - len += 1; - } +#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) + { + 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: + 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; } diff --git a/gmain.c b/gmain.c index bf4fdfe29..8ead8a017 100644 --- a/gmain.c +++ b/gmain.c @@ -1362,7 +1362,7 @@ g_idle_dispatch (gpointer source_data, GTimeVal *dispatch_time, gpointer user_data) { - GSourceFunc func = source_data; + GSourceFunc func = (GSourceFunc) source_data; return func (user_data); } @@ -1375,7 +1375,7 @@ g_idle_add_full (gint priority, { g_return_val_if_fail (function != NULL, 0); - return g_source_add (priority, FALSE, &idle_funcs, function, data, notify); + return g_source_add (priority, FALSE, &idle_funcs, (gpointer) function, data, notify); } guint diff --git a/gstrfuncs.c b/gstrfuncs.c index bdf0f8649..feb457275 100644 --- a/gstrfuncs.c +++ b/gstrfuncs.c @@ -37,6 +37,7 @@ #include #include #include +#include #include /* For tolower() */ #if !defined (HAVE_STRSIGNAL) || !defined(NO_SYS_SIGLIST_DECL) #include @@ -46,6 +47,36 @@ * inteferes with g_strsignal() on some OSes */ +typedef union _GDoubleIEEE754 GDoubleIEEE754; +#define G_IEEE754_DOUBLE_BIAS (1023) +/* multiply with base2 exponent to get base10 exponent (nomal numbers) */ +#define G_LOG_2_BASE_10 (0.30102999566398119521) +#if G_BYTE_ORDER == G_LITTLE_ENDIAN +union _GDoubleIEEE754 +{ + gdouble v_double; + struct { + guint mantissa_low : 32; + guint mantissa_high : 20; + guint biased_exponent : 11; + guint sign : 1; + } mpn; +}; +#elif G_BYTE_ORDER == G_BIG_ENDIAN +union _GDoubleIEEE754 +{ + gdouble v_double; + struct { + guint sign : 1; + guint biased_exponent : 11; + guint mantissa_high : 20; + guint mantissa_low : 32; + } mpn; +}; +#else /* !G_LITTLE_ENDIAN && !G_BIG_ENDIAN */ +#error unknown ENDIAN type +#endif /* !G_LITTLE_ENDIAN && !G_BIG_ENDIAN */ + gchar* g_strdup (const gchar *str) { @@ -791,143 +822,309 @@ g_strsignal (gint signum) return msg; } +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; + guint g_printf_string_upper_bound (const gchar* format, va_list args) { + static const gboolean honour_longs = SIZEOF_LONG > 4 || SIZEOF_VOID_P > 4; guint len = 1; + if (!format) + return len; + while (*format) { - gboolean long_int = FALSE; - gboolean extra_long = FALSE; - gchar c; + register gchar c = *format++; - 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; - if (c == '%') - { - gboolean done = FALSE; + do + { + c = *format++; + switch (c) + { + GDoubleIEEE754 u_double; + guint v_uint; + gint v_int; + const gchar *v_string; - while (*format && !done) - { - switch (*format++) - { - gchar *string_arg; + /* beware of positional parameters + */ + case '$': + g_warning (G_GNUC_PRETTY_FUNCTION + "(): unable to handle positional parameters (%%n$)"); + len += 1024; /* try adding some safety padding */ + break; - case '*': - len += va_arg (args, int); - break; - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - /* add specified format length, since it might exceed the - * size we assume it to have. - */ - format -= 1; - len += strtol (format, (char**) &format, 10); - break; - case 'h': - /* ignore short int flag, since all args have at least the - * same size as an int - */ - break; - case 'l': - if (long_int) - extra_long = TRUE; /* linux specific */ - else - long_int = TRUE; - break; - case 'q': - case 'L': - long_int = TRUE; - extra_long = TRUE; - break; - case '\'': - len += 64; - break; - case 's': - string_arg = va_arg (args, char *); - if (string_arg) - len += strlen (string_arg); - else - { - /* add enough padding to hold "(null)" identifier */ - len += 16; - } - done = TRUE; - break; - case 'd': - case 'i': - case 'o': - case 'u': - case 'x': - case 'X': -#ifdef G_HAVE_GINT64 - if (extra_long) - (void) va_arg (args, gint64); - else -#endif /* G_HAVE_GINT64 */ - { - if (long_int) - (void) va_arg (args, long); - else - (void) va_arg (args, int); - } - len += extra_long ? 64 : 32; - done = TRUE; - break; - case 'D': - case 'O': - case 'U': - (void) va_arg (args, long); - len += 32; - done = TRUE; - break; - case 'e': - case 'E': - case 'f': - case 'g': - case 'G': + /* 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 (spec.mod_extra_long) + g_warning (G_GNUC_PRETTY_FUNCTION + "(): unable to handle long double, collecting double only"); #ifdef HAVE_LONG_DOUBLE - if (extra_long) - (void) va_arg (args, long double); - else -#endif /* HAVE_LONG_DOUBLE */ - (void) va_arg (args, double); - len += extra_long ? 128 : 64; - done = TRUE; - break; - case 'c': - (void) va_arg (args, int); - len += 1; - done = TRUE; - break; - case 'p': - case 'n': - (void) va_arg (args, void*); - len += 32; - done = TRUE; - break; - case '%': - len += 1; - done = TRUE; - break; - default: - /* ignore unknow/invalid flags */ - break; - } - } - } - else - len += 1; - } +#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) + { + 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: + 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; }