summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCST 2001 Shawn T. Amundson <amundson@gtk.org>2001-02-27 04:46:00 +0000
committerShawn Amundson <amundson@src.gnome.org>2001-02-27 04:46:00 +0000
commita44d5145ea2dc66d5170caea925c31702b98b4ab (patch)
treee70e1760c5b39d3094498f4aae7da3c5bbb045c9
parent80af2274580ca63231b2045074bd0e221a153489 (diff)
downloadglib-a44d5145ea2dc66d5170caea925c31702b98b4ab.tar.gz
Backport implementation of g_printf_string_upper_bound from 1.3. Bug
Mon Feb 26 21:06:17 CST 2001 Shawn T. Amundson <amundson@gtk.org> * 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.
-rw-r--r--ChangeLog10
-rw-r--r--ChangeLog.pre-2-010
-rw-r--r--ChangeLog.pre-2-1010
-rw-r--r--ChangeLog.pre-2-1210
-rw-r--r--ChangeLog.pre-2-210
-rw-r--r--ChangeLog.pre-2-410
-rw-r--r--ChangeLog.pre-2-610
-rw-r--r--ChangeLog.pre-2-810
-rw-r--r--glib/gmain.c4
-rw-r--r--glib/gstrfuncs.c453
-rw-r--r--gmain.c4
-rw-r--r--gstrfuncs.c453
12 files changed, 734 insertions, 260 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 <amundson@gtk.org>
+
+ * 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 <otaylor@redhat.com>
* 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 <amundson@gtk.org>
+
+ * 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 <otaylor@redhat.com>
* 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 <amundson@gtk.org>
+
+ * 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 <otaylor@redhat.com>
* 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 <amundson@gtk.org>
+
+ * 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 <otaylor@redhat.com>
* 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 <amundson@gtk.org>
+
+ * 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 <otaylor@redhat.com>
* 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 <amundson@gtk.org>
+
+ * 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 <otaylor@redhat.com>
* 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 <amundson@gtk.org>
+
+ * 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 <otaylor@redhat.com>
* 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 <amundson@gtk.org>
+
+ * 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 <otaylor@redhat.com>
* 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 <stdlib.h>
#include <string.h>
#include <locale.h>
+#include <errno.h>
#include <ctype.h> /* For tolower() */
#if !defined (HAVE_STRSIGNAL) || !defined(NO_SYS_SIGLIST_DECL)
#include <signal.h>
@@ -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;
-
- c = *format++;
-
- if (c == '%')
- {
- gboolean done = FALSE;
-
- while (*format && !done)
- {
- switch (*format++)
- {
- gchar *string_arg;
-
- 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':
+ 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;
+ const gchar *v_string;
+
+ /* 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;
+
+ /* 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 <stdlib.h>
#include <string.h>
#include <locale.h>
+#include <errno.h>
#include <ctype.h> /* For tolower() */
#if !defined (HAVE_STRSIGNAL) || !defined(NO_SYS_SIGLIST_DECL)
#include <signal.h>
@@ -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;
-
- c = *format++;
-
- if (c == '%')
- {
- gboolean done = FALSE;
-
- while (*format && !done)
- {
- switch (*format++)
- {
- gchar *string_arg;
-
- 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':
+ 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;
+ const gchar *v_string;
+
+ /* 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;
+
+ /* 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;
}