mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-02-23 18:52:09 +01:00
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.
This commit is contained in:
parent
80af227458
commit
a44d5145ea
10
ChangeLog
10
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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
359
glib/gstrfuncs.c
359
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,32 +822,81 @@ 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++;
|
||||
|
||||
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++;
|
||||
|
||||
if (c == '%')
|
||||
switch (c)
|
||||
{
|
||||
gboolean done = FALSE;
|
||||
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);
|
||||
/* 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':
|
||||
@ -827,107 +907,224 @@ g_printf_string_upper_bound (const gchar* format,
|
||||
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);
|
||||
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 'h':
|
||||
/* ignore short int flag, since all args have at least the
|
||||
* same size as an int
|
||||
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 (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
|
||||
if (!seen_l)
|
||||
{
|
||||
/* add enough padding to hold "(null)" identifier */
|
||||
len += 16;
|
||||
}
|
||||
done = TRUE;
|
||||
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':
|
||||
case 'o':
|
||||
conv_len += 1; /* sign */
|
||||
/* fall through */
|
||||
case 'u':
|
||||
conv_len += 4;
|
||||
/* fall through */
|
||||
case 'x':
|
||||
case 'X':
|
||||
#ifdef G_HAVE_GINT64
|
||||
if (extra_long)
|
||||
(void) va_arg (args, gint64);
|
||||
else
|
||||
#endif /* G_HAVE_GINT64 */
|
||||
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)
|
||||
{
|
||||
if (long_int)
|
||||
#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);
|
||||
}
|
||||
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 'A':
|
||||
case 'a':
|
||||
/* 0x */
|
||||
conv_len += 2;
|
||||
/* fall through */
|
||||
case 'g':
|
||||
case 'G':
|
||||
case 'e':
|
||||
case 'E':
|
||||
case 'f':
|
||||
case 'g':
|
||||
case 'G':
|
||||
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;
|
||||
#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);
|
||||
len += 1;
|
||||
done = TRUE;
|
||||
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*);
|
||||
len += 32;
|
||||
done = TRUE;
|
||||
break;
|
||||
case '%':
|
||||
len += 1;
|
||||
done = TRUE;
|
||||
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:
|
||||
/* ignore unknow/invalid flags */
|
||||
g_warning (G_GNUC_PRETTY_FUNCTION
|
||||
"(): unable to handle `%c' while parsing format",
|
||||
c);
|
||||
break;
|
||||
}
|
||||
conv_done |= conv_len > 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
len += 1;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
4
gmain.c
4
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
|
||||
|
359
gstrfuncs.c
359
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,32 +822,81 @@ 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++;
|
||||
|
||||
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++;
|
||||
|
||||
if (c == '%')
|
||||
switch (c)
|
||||
{
|
||||
gboolean done = FALSE;
|
||||
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);
|
||||
/* 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':
|
||||
@ -827,107 +907,224 @@ g_printf_string_upper_bound (const gchar* format,
|
||||
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);
|
||||
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 'h':
|
||||
/* ignore short int flag, since all args have at least the
|
||||
* same size as an int
|
||||
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 (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
|
||||
if (!seen_l)
|
||||
{
|
||||
/* add enough padding to hold "(null)" identifier */
|
||||
len += 16;
|
||||
}
|
||||
done = TRUE;
|
||||
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':
|
||||
case 'o':
|
||||
conv_len += 1; /* sign */
|
||||
/* fall through */
|
||||
case 'u':
|
||||
conv_len += 4;
|
||||
/* fall through */
|
||||
case 'x':
|
||||
case 'X':
|
||||
#ifdef G_HAVE_GINT64
|
||||
if (extra_long)
|
||||
(void) va_arg (args, gint64);
|
||||
else
|
||||
#endif /* G_HAVE_GINT64 */
|
||||
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)
|
||||
{
|
||||
if (long_int)
|
||||
#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);
|
||||
}
|
||||
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 'A':
|
||||
case 'a':
|
||||
/* 0x */
|
||||
conv_len += 2;
|
||||
/* fall through */
|
||||
case 'g':
|
||||
case 'G':
|
||||
case 'e':
|
||||
case 'E':
|
||||
case 'f':
|
||||
case 'g':
|
||||
case 'G':
|
||||
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;
|
||||
#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);
|
||||
len += 1;
|
||||
done = TRUE;
|
||||
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*);
|
||||
len += 32;
|
||||
done = TRUE;
|
||||
break;
|
||||
case '%':
|
||||
len += 1;
|
||||
done = TRUE;
|
||||
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:
|
||||
/* ignore unknow/invalid flags */
|
||||
g_warning (G_GNUC_PRETTY_FUNCTION
|
||||
"(): unable to handle `%c' while parsing format",
|
||||
c);
|
||||
break;
|
||||
}
|
||||
conv_done |= conv_len > 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
len += 1;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user