Re: g_printf_string_upper_bound (#50217)
- From: Shawn T Amundson <amundson eventloop com>
- To: gtk-devel-list gnome org
- Subject: Re: g_printf_string_upper_bound (#50217)
- Date: Mon, 26 Feb 2001 21:35:36 -0600
Ok, attached is a patch to backport from HEAD. I do make some
assumptions that Tim's new code is correct so it wouldn't hurt
if a few more critical people looked it over.
-Shawn
--
Shawn T. Amundson amundson eventloop com
Research and Development http://www.eventloop.com/
EventLoop, Inc. (651) 999-0130
"The assumption that the universe looks the same in every
direction is clearly not true in reality." - Stephen Hawking
? printf_upper_bound.patch
? printf_upper_bound.patch.1
Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/glib/ChangeLog,v
retrieving revision 1.257.2.90
diff -u -r1.257.2.90 ChangeLog
--- ChangeLog 2001/02/17 06:34:41 1.257.2.90
+++ ChangeLog 2001/02/27 03:29:02
@@ -1,3 +1,9 @@
+
+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.
+
Sat Feb 17 07:33:44 2001 Tim Janik <timj gtk org>
* configure.in (G_MODULE_BROKEN_RTLD_GLOBAL): check for systems
Index: gstrfuncs.c
===================================================================
RCS file: /cvs/gnome/glib/gstrfuncs.c,v
retrieving revision 1.26.2.9
diff -u -r1.26.2.9 gstrfuncs.c
--- gstrfuncs.c 2000/10/16 09:16:57 1.26.2.9
+++ gstrfuncs.c 2001/02/27 03:29:06
@@ -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 @@
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;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]