aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristopher James Lahey <clahey@ximian.com>2001-10-06 22:23:10 +0800
committerChris Lahey <clahey@src.gnome.org>2001-10-06 22:23:10 +0800
commit8c8bf81c61d4da00bfd529f92a394f59a1b1f5b7 (patch)
tree1649c82449d745844f044061c8137e88e100d6d1
parent9e805a243e4cbee3dedf0275c69528717e0e3aeb (diff)
downloadgsoc2013-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.c224
-rw-r--r--e-util/e-util.h262
-rw-r--r--e-util/e-xml-utils.c12
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 *