diff options
author | Christopher James Lahey <clahey@ximian.com> | 2001-10-06 22:23:10 +0800 |
---|---|---|
committer | Chris Lahey <clahey@src.gnome.org> | 2001-10-06 22:23:10 +0800 |
commit | 8c8bf81c61d4da00bfd529f92a394f59a1b1f5b7 (patch) | |
tree | 1649c82449d745844f044061c8137e88e100d6d1 | |
parent | 9e805a243e4cbee3dedf0275c69528717e0e3aeb (diff) | |
download | gsoc2013-evolution-8c8bf81c61d4da00bfd529f92a394f59a1b1f5b7.tar.gz gsoc2013-evolution-8c8bf81c61d4da00bfd529f92a394f59a1b1f5b7.tar.zst gsoc2013-evolution-8c8bf81c61d4da00bfd529f92a394f59a1b1f5b7.zip |
New function that parses a string as a double either in the C locale or
2001-10-06 Christopher James Lahey <clahey@ximian.com>
* gal/util/e-util.c, gal/util/e-util.h (e_flexible_strtod): New
function that parses a string as a double either in the C locale
or the current locale.
(e_ascii_dtostr): New function that saves a double as a string as
it would be saved in the C locale.
* gal/util/e-xml-utils.c
(e_xml_get_double_prop_by_name_with_default): Use
e_flexible_strtod here.
(e_xml_set_double_prop_by_name): Use e_ascii_dtostr here.
svn path=/trunk/; revision=13479
-rw-r--r-- | e-util/e-util.c | 224 | ||||
-rw-r--r-- | e-util/e-util.h | 262 | ||||
-rw-r--r-- | e-util/e-xml-utils.c | 12 |
3 files changed, 368 insertions, 130 deletions
diff --git a/e-util/e-util.c b/e-util/e-util.c index d3479a6661..345fd39bf4 100644 --- a/e-util/e-util.c +++ b/e-util/e-util.c @@ -1178,3 +1178,227 @@ size_t e_strftime_fix_am_pm(char *s, size_t max, const char *fmt, const struct t return(ret); } +/** + * e_flexible_strtod: + * @nptr: the string to convert to a numeric value. + * @endptr: if non-NULL, it returns the character after + * the last character used in the conversion. + * + * Converts a string to a gdouble value. This function detects + * strings either in the standard C locale or in the current locale. + * + * This function is typically used when reading configuration files or + * other non-user input that should not be locale dependent, but may + * have been in the past. To handle input from the user you should + * normally use the locale-sensitive system strtod function. + * + * To convert from a double to a string in a locale-insensitive way, use + * @g_ascii_dtostr. + * + * Return value: the gdouble value. + **/ +gdouble +e_flexible_strtod (const gchar *nptr, + gchar **endptr) +{ + gchar *fail_pos; + gdouble val; + struct lconv *locale_data; + const char *decimal_point; + int decimal_point_len; + const char *p, *decimal_point_pos; + const char *end = NULL; /* Silence gcc */ + char *copy, *c; + + g_return_val_if_fail (nptr != NULL, 0); + + fail_pos = NULL; + + locale_data = localeconv (); + decimal_point = locale_data->decimal_point; + decimal_point_len = strlen (decimal_point); + + g_assert (decimal_point_len != 0); + + decimal_point_pos = NULL; + if (!strcmp (decimal_point, ".")) + return strtod (nptr, endptr); + + p = nptr; + + /* Skip leading space */ + while (isspace ((guchar)*p)) + p++; + + /* Skip leading optional sign */ + if (*p == '+' || *p == '-') + p++; + + if (p[0] == '0' && + (p[1] == 'x' || p[1] == 'X')) { + p += 2; + /* HEX - find the (optional) decimal point */ + + while (isxdigit ((guchar)*p)) + p++; + + if (*p == '.') { + decimal_point_pos = p++; + + while (isxdigit ((guchar)*p)) + p++; + + if (*p == 'p' || *p == 'P') + p++; + if (*p == '+' || *p == '-') + p++; + while (isdigit ((guchar)*p)) + p++; + end = p; + } else if (strncmp (p, decimal_point, decimal_point_len) == 0) { + return strtod (nptr, endptr); + } + } else { + while (isdigit ((guchar)*p)) + p++; + + if (*p == '.') { + decimal_point_pos = p++; + + while (isdigit ((guchar)*p)) + p++; + + if (*p == 'e' || *p == 'E') + p++; + if (*p == '+' || *p == '-') + p++; + while (isdigit ((guchar)*p)) + p++; + end = p; + } else if (strncmp (p, decimal_point, decimal_point_len) == 0) { + return strtod (nptr, endptr); + } + } + /* For the other cases, we need not convert the decimal point */ + + if (!decimal_point_pos) + return strtod (nptr, endptr); + + /* We need to convert the '.' to the locale specific decimal point */ + copy = g_malloc (end - nptr + 1 + decimal_point_len); + + c = copy; + memcpy (c, nptr, decimal_point_pos - nptr); + c += decimal_point_pos - nptr; + memcpy (c, decimal_point, decimal_point_len); + c += decimal_point_len; + memcpy (c, decimal_point_pos + 1, end - (decimal_point_pos + 1)); + c += end - (decimal_point_pos + 1); + *c = 0; + + val = strtod (copy, &fail_pos); + + if (fail_pos) { + if (fail_pos > decimal_point_pos) + fail_pos = (char *)nptr + (fail_pos - copy) - (decimal_point_len - 1); + else + fail_pos = (char *)nptr + (fail_pos - copy); + } + + g_free (copy); + + if (endptr) + *endptr = fail_pos; + + return val; +} + +/** + * e_ascii_dtostr: + * @buffer: A buffer to place the resulting string in + * @buf_len: The length of the buffer. + * @format: The printf-style format to use for the + * code to use for converting. + * @d: The double to convert + * + * Converts a double to a string, using the '.' as + * decimal_point. To format the number you pass in + * a printf-style formating string. Allowed conversion + * specifiers are eEfFgG. + * + * If you want to generates enough precision that converting + * the string back using @g_strtod gives the same machine-number + * (on machines with IEEE compatible 64bit doubles) use the format + * string "%.17g". If you do this it is guaranteed that the size + * of the resulting string will never be larger than + * @G_ASCII_DTOSTR_BUF_SIZE bytes. + * + * Return value: The pointer to the buffer with the converted string. + **/ +gchar * +e_ascii_dtostr (gchar *buffer, + gint buf_len, + const gchar *format, + gdouble d) +{ + struct lconv *locale_data; + const char *decimal_point; + int decimal_point_len; + gchar *p; + int rest_len; + gchar format_char; + + g_return_val_if_fail (buffer != NULL, NULL); + g_return_val_if_fail (format[0] == '%', NULL); + g_return_val_if_fail (strpbrk (format + 1, "'l%") == NULL, NULL); + + format_char = format[strlen (format) - 1]; + + g_return_val_if_fail (format_char == 'e' || format_char == 'E' || + format_char == 'f' || format_char == 'F' || + format_char == 'g' || format_char == 'G', + NULL); + + if (format[0] != '%') + return NULL; + + if (strpbrk (format + 1, "'l%")) + return NULL; + + if (!(format_char == 'e' || format_char == 'E' || + format_char == 'f' || format_char == 'F' || + format_char == 'g' || format_char == 'G')) + return NULL; + + + g_snprintf (buffer, buf_len, format, d); + + locale_data = localeconv (); + decimal_point = locale_data->decimal_point; + decimal_point_len = strlen (decimal_point); + + g_assert (decimal_point_len != 0); + + if (strcmp (decimal_point, ".")) { + p = buffer; + + if (*p == '+' || *p == '-') + p++; + + while (isdigit ((guchar)*p)) + p++; + + if (strncmp (p, decimal_point, decimal_point_len) == 0) { + *p = '.'; + p++; + if (decimal_point_len > 1) { + rest_len = strlen (p + (decimal_point_len-1)); + memmove (p, p + (decimal_point_len-1), + rest_len); + p[rest_len] = 0; + } + } + } + + return buffer; +} diff --git a/e-util/e-util.h b/e-util/e-util.h index 179a2c2788..e9eb07ffa8 100644 --- a/e-util/e-util.h +++ b/e-util/e-util.h @@ -68,155 +68,169 @@ typedef enum { E_FOCUS_START, E_FOCUS_END } EFocus; -int g_str_compare (const void *x, - const void *y); -int g_int_compare (const void *x, - const void *y); -char *e_strdup_strip (const char *string); - -void e_free_object_list (GList *list); -void e_free_object_slist (GSList *list); -void e_free_string_list (GList *list); -void e_free_string_slist (GSList *list); - -char *e_read_file (const char *filename); -int e_write_file (const char *filename, - const char *data, - int flags); -int e_mkdir_hier (const char *path, - mode_t mode); +int g_str_compare (const void *x, + const void *y); +int g_int_compare (const void *x, + const void *y); +char *e_strdup_strip (const char *string); +void e_free_object_list (GList *list); +void e_free_object_slist (GSList *list); +void e_free_string_list (GList *list); +void e_free_string_slist (GSList *list); +char *e_read_file (const char *filename); +int e_write_file (const char *filename, + const char *data, + int flags); +int e_mkdir_hier (const char *path, + mode_t mode); gchar **e_strsplit (const gchar *string, const gchar *delimiter, gint max_tokens); -gchar *e_strstrcase (const gchar *haystack, - const gchar *needle); -void e_filename_make_safe (gchar *string); -gchar *e_format_number (gint number); -gchar *e_format_number_float (gfloat number); -gboolean e_create_directory (gchar *directory); +gchar *e_strstrcase (const gchar *haystack, + const gchar *needle); +void e_filename_make_safe (gchar *string); +gchar *e_format_number (gint number); +gchar *e_format_number_float (gfloat number); +gboolean e_create_directory (gchar *directory); typedef int (*ESortCompareFunc) (const void *first, const void *second, gpointer closure); -void e_sort (void *base, - size_t nmemb, - size_t size, - ESortCompareFunc compare, - gpointer closure); -void e_bsearch (const void *key, - const void *base, - size_t nmemb, - size_t size, - ESortCompareFunc compare, - gpointer closure, - size_t *start, - size_t *end); -size_t e_strftime_fix_am_pm (char *s, - size_t max, - const char *fmt, - const struct tm *tm); -void e_marshal_INT__INT_INT_POINTER (GtkObject *object, - GtkSignalFunc func, - gpointer func_data, - GtkArg *args); -void e_marshal_INT__INT_POINTER_INT_POINTER (GtkObject *object, - GtkSignalFunc func, - gpointer func_data, - GtkArg *args); -void e_marshal_NONE__OBJECT_DOUBLE_DOUBLE_BOOL (GtkObject *object, - GtkSignalFunc func, - gpointer func_data, - GtkArg *args); -void e_marshal_DOUBLE__OBJECT_DOUBLE_DOUBLE_BOOL (GtkObject *object, - GtkSignalFunc func, - gpointer func_data, - GtkArg *args); -void e_marshal_BOOL__OBJECT_DOUBLE_DOUBLE_BOOL (GtkObject *object, - GtkSignalFunc func, - gpointer func_data, - GtkArg *args); +void e_sort (void *base, + size_t nmemb, + size_t size, + ESortCompareFunc compare, + gpointer closure); +void e_bsearch (const void *key, + const void *base, + size_t nmemb, + size_t size, + ESortCompareFunc compare, + gpointer closure, + size_t *start, + size_t *end); +size_t e_strftime_fix_am_pm (char *s, + size_t max, + const char *fmt, + const struct tm *tm); + + +/* String to/from double conversion functions */ +gdouble e_flexible_strtod (const gchar *nptr, + gchar **endptr); +/* 29 bytes should enough for all possible values that + * g_ascii_dtostr can produce with the %.17g format. + * Then add 10 for good measure */ +#define E_ASCII_DTOSTR_BUF_SIZE (29 + 10) +gchar *e_ascii_dtostr (gchar *buffer, + gint buf_len, + const gchar *format, + gdouble d); + + +/* Marshallers */ +void e_marshal_INT__INT_INT_POINTER (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); +void e_marshal_INT__INT_POINTER_INT_POINTER (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); +void e_marshal_NONE__OBJECT_DOUBLE_DOUBLE_BOOL (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); +void e_marshal_DOUBLE__OBJECT_DOUBLE_DOUBLE_BOOL (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); +void e_marshal_BOOL__OBJECT_DOUBLE_DOUBLE_BOOL (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); #define e_marshal_NONE__INT_INT_POINTER_POINTER_UINT_UINT e_marshal_NONE__INT_INT_POINTER_POINTER_INT_INT -void e_marshal_NONE__INT_INT_POINTER_POINTER_INT_INT (GtkObject *object, - GtkSignalFunc func, - gpointer func_data, - GtkArg *args); +void e_marshal_NONE__INT_INT_POINTER_POINTER_INT_INT (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); #define e_marshal_NONE__INT_POINTER_INT_POINTER_POINTER_UINT_UINT e_marshal_NONE__INT_POINTER_INT_POINTER_POINTER_INT_INT -void e_marshal_NONE__INT_POINTER_INT_POINTER_POINTER_INT_INT (GtkObject *object, - GtkSignalFunc func, - gpointer func_data, - GtkArg *args); +void e_marshal_NONE__INT_POINTER_INT_POINTER_POINTER_INT_INT (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); #define e_marshal_NONE__INT_INT_POINTER_UINT e_marshal_NONE__INT_INT_POINTER_INT -void e_marshal_NONE__INT_INT_POINTER_INT (GtkObject *object, - GtkSignalFunc func, - gpointer func_data, - GtkArg *args); +void e_marshal_NONE__INT_INT_POINTER_INT (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); #define e_marshal_NONE__INT_POINTER_INT_POINTER_UINT e_marshal_NONE__INT_POINTER_INT_POINTER_INT -void e_marshal_NONE__INT_POINTER_INT_POINTER_INT (GtkObject *object, - GtkSignalFunc func, - gpointer func_data, - GtkArg *args); +void e_marshal_NONE__INT_POINTER_INT_POINTER_INT (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); #define e_marshal_BOOL__INT_INT_POINTER_INT_INT_UINT e_marshal_BOOL__INT_INT_POINTER_INT_INT_INT -void e_marshal_BOOL__INT_INT_POINTER_INT_INT_INT (GtkObject *object, - GtkSignalFunc func, - gpointer func_data, - GtkArg *args); +void e_marshal_BOOL__INT_INT_POINTER_INT_INT_INT (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); #define e_marshal_BOOL__INT_POINTER_INT_POINTER_INT_INT_UINT e_marshal_BOOL__INT_POINTER_INT_POINTER_INT_INT_INT -void e_marshal_BOOL__INT_POINTER_INT_POINTER_INT_INT_INT (GtkObject *object, - GtkSignalFunc func, - gpointer func_data, - GtkArg *args); +void e_marshal_BOOL__INT_POINTER_INT_POINTER_INT_INT_INT (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); #define e_marshal_NONE__INT_INT_POINTER_INT_INT_POINTER_UINT_UINT e_marshal_NONE__INT_INT_POINTER_INT_INT_POINTER_INT_INT -void e_marshal_NONE__INT_INT_POINTER_INT_INT_POINTER_INT_INT (GtkObject *object, - GtkSignalFunc func, - gpointer func_data, - GtkArg *args); +void e_marshal_NONE__INT_INT_POINTER_INT_INT_POINTER_INT_INT (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); #define e_marshal_NONE__INT_POINTER_INT_POINTER_INT_INT_POINTER_UINT_UINT e_marshal_NONE__INT_POINTER_INT_POINTER_INT_INT_POINTER_INT_INT -void e_marshal_NONE__INT_POINTER_INT_POINTER_INT_INT_POINTER_INT_INT (GtkObject *object, - GtkSignalFunc func, - gpointer func_data, - GtkArg *args); -void e_marshal_NONE__POINTER_POINTER_INT (GtkObject *object, - GtkSignalFunc func, - gpointer func_data, - GtkArg *args); -void e_marshal_NONE__INT_POINTER_INT_POINTER (GtkObject *object, - GtkSignalFunc func, - gpointer func_data, - GtkArg *args); -void e_marshal_INT__POINTER_POINTER (GtkObject *object, - GtkSignalFunc func, - gpointer func_data, - GtkArg *args); -void e_marshal_INT__POINTER_POINTER_POINTER (GtkObject *object, - GtkSignalFunc func, - gpointer func_data, - GtkArg *args); -void e_marshal_INT__POINTER_POINTER_POINTER_POINTER (GtkObject *object, - GtkSignalFunc func, - gpointer func_data, - GtkArg *args); -void e_marshal_INT__POINTER_POINTER_POINTER_POINTER_POINTER (GtkObject *object, - GtkSignalFunc func, - gpointer func_data, - GtkArg *args); -void e_marshal_NONE__POINTER_INT_INT_INT (GtkObject *object, - GtkSignalFunc func, - gpointer func_data, - GtkArg *args); -void e_marshal_INT__OBJECT_POINTER (GtkObject *object, - GtkSignalFunc func, - gpointer func_data, - GtkArg *args); +void e_marshal_NONE__INT_POINTER_INT_POINTER_INT_INT_POINTER_INT_INT (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); +void e_marshal_NONE__POINTER_POINTER_INT (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); +void e_marshal_NONE__INT_POINTER_INT_POINTER (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); +void e_marshal_INT__POINTER_POINTER (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); +void e_marshal_INT__POINTER_POINTER_POINTER (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); +void e_marshal_INT__POINTER_POINTER_POINTER_POINTER (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); +void e_marshal_INT__POINTER_POINTER_POINTER_POINTER_POINTER (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); +void e_marshal_NONE__POINTER_INT_INT_INT (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); +void e_marshal_INT__OBJECT_POINTER (GtkObject *object, + GtkSignalFunc func, + gpointer func_data, + GtkArg *args); #ifdef __cplusplus diff --git a/e-util/e-xml-utils.c b/e-util/e-xml-utils.c index 1285b5ce75..6ff68c5904 100644 --- a/e-util/e-xml-utils.c +++ b/e-util/e-xml-utils.c @@ -30,6 +30,7 @@ #include <gnome-xml/parser.h> #include <gnome-xml/xmlmemory.h> #include "gal/util/e-i18n.h" +#include "gal/util/e-util.h" xmlNode * e_xml_get_child_by_name (const xmlNode *parent, const xmlChar *child_name) @@ -329,7 +330,7 @@ e_xml_get_double_prop_by_name_with_default (const xmlNode *parent, const xmlChar prop = xmlGetProp ((xmlNode *) parent, prop_name); if (prop != NULL) { - (void) sscanf (prop, "%lf", &ret_val); + ret_val = e_flexible_strtod (prop, NULL); xmlFree (prop); } return ret_val; @@ -338,18 +339,17 @@ e_xml_get_double_prop_by_name_with_default (const xmlNode *parent, const xmlChar void e_xml_set_double_prop_by_name(xmlNode *parent, const xmlChar *prop_name, gdouble value) { - gchar *valuestr; + char buffer[E_ASCII_DTOSTR_BUF_SIZE]; g_return_if_fail (parent != NULL); g_return_if_fail (prop_name != NULL); if (fabs (value) < 1e9 && fabs (value) > 1e-5) { - valuestr = g_strdup_printf ("%f", value); + e_ascii_dtostr (buffer, sizeof (buffer), "%.17f", value); } else { - valuestr = g_strdup_printf ("%.*g", DBL_DIG, value); + e_ascii_dtostr (buffer, sizeof (buffer), "%.17g", value); } - xmlSetProp (parent, prop_name, valuestr); - g_free (valuestr); + xmlSetProp (parent, prop_name, buffer); } gchar * |