summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Larsson <alexl@redhat.com>2001-10-24 18:00:11 +0000
committerAlexander Larsson <alexl@src.gnome.org>2001-10-24 18:00:11 +0000
commit3c39c8fcd01dd9929477488ac9dd713fd0311e9b (patch)
tree4bbd3634747e13473c531101a38a3ac4f0864d08
parentb0facb386351269c29cb7afaf8325668f3c3dd01 (diff)
Add g_strtod & co.
2001-10-24 Alex Larsson <alexl@redhat.com> * docs/reference/glib/glib-sections.txt: Add g_strtod & co. * docs/reference/glib/tmpl/string_utils.sgml: Add docs for G_ASCII_DTOSTR_BUF_SIZE. * glib/gstrfuncs.[ch]: Added g_ascii_strtod, g_ascii_dtostr and g_ascii_formatd. * tests/Makefile.am: * tests/strtod-test.c: Add tests for g_ascii_strtod & co.
-rw-r--r--ChangeLog15
-rw-r--r--ChangeLog.pre-2-015
-rw-r--r--ChangeLog.pre-2-1015
-rw-r--r--ChangeLog.pre-2-1215
-rw-r--r--ChangeLog.pre-2-215
-rw-r--r--ChangeLog.pre-2-415
-rw-r--r--ChangeLog.pre-2-615
-rw-r--r--ChangeLog.pre-2-815
-rw-r--r--docs/reference/glib/glib-sections.txt6
-rw-r--r--docs/reference/glib/tmpl/string_utils.sgml67
-rw-r--r--glib/gstrfuncs.c305
-rw-r--r--glib/gstrfuncs.h28
-rw-r--r--tests/Makefile.am2
-rw-r--r--tests/strtod-test.c53
14 files changed, 556 insertions, 25 deletions
diff --git a/ChangeLog b/ChangeLog
index 97a5475ef..0817d378e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+2001-10-24 Alex Larsson <alexl@redhat.com>
+
+ * docs/reference/glib/glib-sections.txt:
+ Add g_strtod & co.
+
+ * docs/reference/glib/tmpl/string_utils.sgml:
+ Add docs for G_ASCII_DTOSTR_BUF_SIZE.
+
+ * glib/gstrfuncs.[ch]:
+ Added g_ascii_strtod, g_ascii_dtostr and g_ascii_formatd.
+
+ * tests/Makefile.am:
+ * tests/strtod-test.c:
+ Add tests for g_ascii_strtod & co.
+
2001-10-23 Tor Lillqvist <tml@iki.fi>
* config.h.win32.in: Typo: GLIB_MICRO_VERSION and
diff --git a/ChangeLog.pre-2-0 b/ChangeLog.pre-2-0
index 97a5475ef..0817d378e 100644
--- a/ChangeLog.pre-2-0
+++ b/ChangeLog.pre-2-0
@@ -1,3 +1,18 @@
+2001-10-24 Alex Larsson <alexl@redhat.com>
+
+ * docs/reference/glib/glib-sections.txt:
+ Add g_strtod & co.
+
+ * docs/reference/glib/tmpl/string_utils.sgml:
+ Add docs for G_ASCII_DTOSTR_BUF_SIZE.
+
+ * glib/gstrfuncs.[ch]:
+ Added g_ascii_strtod, g_ascii_dtostr and g_ascii_formatd.
+
+ * tests/Makefile.am:
+ * tests/strtod-test.c:
+ Add tests for g_ascii_strtod & co.
+
2001-10-23 Tor Lillqvist <tml@iki.fi>
* config.h.win32.in: Typo: GLIB_MICRO_VERSION and
diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10
index 97a5475ef..0817d378e 100644
--- a/ChangeLog.pre-2-10
+++ b/ChangeLog.pre-2-10
@@ -1,3 +1,18 @@
+2001-10-24 Alex Larsson <alexl@redhat.com>
+
+ * docs/reference/glib/glib-sections.txt:
+ Add g_strtod & co.
+
+ * docs/reference/glib/tmpl/string_utils.sgml:
+ Add docs for G_ASCII_DTOSTR_BUF_SIZE.
+
+ * glib/gstrfuncs.[ch]:
+ Added g_ascii_strtod, g_ascii_dtostr and g_ascii_formatd.
+
+ * tests/Makefile.am:
+ * tests/strtod-test.c:
+ Add tests for g_ascii_strtod & co.
+
2001-10-23 Tor Lillqvist <tml@iki.fi>
* config.h.win32.in: Typo: GLIB_MICRO_VERSION and
diff --git a/ChangeLog.pre-2-12 b/ChangeLog.pre-2-12
index 97a5475ef..0817d378e 100644
--- a/ChangeLog.pre-2-12
+++ b/ChangeLog.pre-2-12
@@ -1,3 +1,18 @@
+2001-10-24 Alex Larsson <alexl@redhat.com>
+
+ * docs/reference/glib/glib-sections.txt:
+ Add g_strtod & co.
+
+ * docs/reference/glib/tmpl/string_utils.sgml:
+ Add docs for G_ASCII_DTOSTR_BUF_SIZE.
+
+ * glib/gstrfuncs.[ch]:
+ Added g_ascii_strtod, g_ascii_dtostr and g_ascii_formatd.
+
+ * tests/Makefile.am:
+ * tests/strtod-test.c:
+ Add tests for g_ascii_strtod & co.
+
2001-10-23 Tor Lillqvist <tml@iki.fi>
* config.h.win32.in: Typo: GLIB_MICRO_VERSION and
diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2
index 97a5475ef..0817d378e 100644
--- a/ChangeLog.pre-2-2
+++ b/ChangeLog.pre-2-2
@@ -1,3 +1,18 @@
+2001-10-24 Alex Larsson <alexl@redhat.com>
+
+ * docs/reference/glib/glib-sections.txt:
+ Add g_strtod & co.
+
+ * docs/reference/glib/tmpl/string_utils.sgml:
+ Add docs for G_ASCII_DTOSTR_BUF_SIZE.
+
+ * glib/gstrfuncs.[ch]:
+ Added g_ascii_strtod, g_ascii_dtostr and g_ascii_formatd.
+
+ * tests/Makefile.am:
+ * tests/strtod-test.c:
+ Add tests for g_ascii_strtod & co.
+
2001-10-23 Tor Lillqvist <tml@iki.fi>
* config.h.win32.in: Typo: GLIB_MICRO_VERSION and
diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4
index 97a5475ef..0817d378e 100644
--- a/ChangeLog.pre-2-4
+++ b/ChangeLog.pre-2-4
@@ -1,3 +1,18 @@
+2001-10-24 Alex Larsson <alexl@redhat.com>
+
+ * docs/reference/glib/glib-sections.txt:
+ Add g_strtod & co.
+
+ * docs/reference/glib/tmpl/string_utils.sgml:
+ Add docs for G_ASCII_DTOSTR_BUF_SIZE.
+
+ * glib/gstrfuncs.[ch]:
+ Added g_ascii_strtod, g_ascii_dtostr and g_ascii_formatd.
+
+ * tests/Makefile.am:
+ * tests/strtod-test.c:
+ Add tests for g_ascii_strtod & co.
+
2001-10-23 Tor Lillqvist <tml@iki.fi>
* config.h.win32.in: Typo: GLIB_MICRO_VERSION and
diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6
index 97a5475ef..0817d378e 100644
--- a/ChangeLog.pre-2-6
+++ b/ChangeLog.pre-2-6
@@ -1,3 +1,18 @@
+2001-10-24 Alex Larsson <alexl@redhat.com>
+
+ * docs/reference/glib/glib-sections.txt:
+ Add g_strtod & co.
+
+ * docs/reference/glib/tmpl/string_utils.sgml:
+ Add docs for G_ASCII_DTOSTR_BUF_SIZE.
+
+ * glib/gstrfuncs.[ch]:
+ Added g_ascii_strtod, g_ascii_dtostr and g_ascii_formatd.
+
+ * tests/Makefile.am:
+ * tests/strtod-test.c:
+ Add tests for g_ascii_strtod & co.
+
2001-10-23 Tor Lillqvist <tml@iki.fi>
* config.h.win32.in: Typo: GLIB_MICRO_VERSION and
diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8
index 97a5475ef..0817d378e 100644
--- a/ChangeLog.pre-2-8
+++ b/ChangeLog.pre-2-8
@@ -1,3 +1,18 @@
+2001-10-24 Alex Larsson <alexl@redhat.com>
+
+ * docs/reference/glib/glib-sections.txt:
+ Add g_strtod & co.
+
+ * docs/reference/glib/tmpl/string_utils.sgml:
+ Add docs for G_ASCII_DTOSTR_BUF_SIZE.
+
+ * glib/gstrfuncs.[ch]:
+ Added g_ascii_strtod, g_ascii_dtostr and g_ascii_formatd.
+
+ * tests/Makefile.am:
+ * tests/strtod-test.c:
+ Add tests for g_ascii_strtod & co.
+
2001-10-23 Tor Lillqvist <tml@iki.fi>
* config.h.win32.in: Typo: GLIB_MICRO_VERSION and
diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt
index d42467a79..34d511207 100644
--- a/docs/reference/glib/glib-sections.txt
+++ b/docs/reference/glib/glib-sections.txt
@@ -922,6 +922,12 @@ g_strncasecmp
<SUBSECTION>
g_strreverse
+
+<SUBSECTION>
+G_ASCII_DTOSTR_BUF_SIZE
+g_ascii_strtod
+g_ascii_dtostr
+g_ascii_formatd
g_strtod
<SUBSECTION>
diff --git a/docs/reference/glib/tmpl/string_utils.sgml b/docs/reference/glib/tmpl/string_utils.sgml
index 065b0b4ec..0135b3bcd 100644
--- a/docs/reference/glib/tmpl/string_utils.sgml
+++ b/docs/reference/glib/tmpl/string_utils.sgml
@@ -562,19 +562,68 @@ For example, g_strreverse ("abcdef") will result in "fedcba".
@Returns: the same pointer passed in as @string.
+<!-- ##### MACRO G_ASCII_DTOSTR_BUF_SIZE ##### -->
+<para>
+A good size for a buffer to be passed into <function>g_ascii_dtostr</function>.
+It is guaranteed to be enough for all output of that function on systems with
+ 64bit IEEE compatible doubles.
+</para>
+<para>
+The typical usage would be something like:
+</para>
+<para>
+<literal>
+ char buf[G_ASCII_DTOSTR_BUF_SIZE];
+
+ fprintf (out, "value=%s\n", g_ascii_dtostr (buf, sizeof (buf), value));
+</literal>
+</para>
+
+
+
+<!-- ##### FUNCTION g_ascii_strtod ##### -->
+<para>
+
+</para>
+
+@nptr:
+@endptr:
+@Returns:
+
+
+<!-- ##### FUNCTION g_ascii_dtostr ##### -->
+<para>
+
+</para>
+
+@buffer:
+@buf_len:
+@d:
+@Returns:
+<!-- # Unused Parameters # -->
+@format:
+
+
+<!-- ##### FUNCTION g_ascii_formatd ##### -->
+<para>
+
+</para>
+
+@buffer:
+@buf_len:
+@format:
+@d:
+@Returns:
+
+
<!-- ##### FUNCTION g_strtod ##### -->
<para>
-Converts a string to a gdouble value.
-It calls the standard <function>strtod()</function> function
-to handle the conversion, but if the string is not completely converted
-it attempts the conversion again in the "C" locale, and returns the best
-match.
+
</para>
-@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.
-@Returns: the gdouble value.
+@nptr:
+@endptr:
+@Returns:
<!-- ##### FUNCTION g_strchug ##### -->
diff --git a/glib/gstrfuncs.c b/glib/gstrfuncs.c
index d05360a9e..e53f59ded 100644
--- a/glib/gstrfuncs.c
+++ b/glib/gstrfuncs.c
@@ -39,6 +39,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>
@@ -253,9 +254,29 @@ g_strconcat (const gchar *string1, ...)
return concat;
}
+/**
+ * g_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.
+ * It calls the standard strtod() function to handle the conversion, but
+ * if the string is not completely converted it attempts the conversion
+ * again with @g_ascii_strtod, and returns the best match.
+ *
+ * This function should seldom be used. The normal situation when reading
+ * numbers not for human consumption is to use @g_ascii_strtod(). Only when
+ * you know that you must expect both locale formated and C formated numbers
+ * should you use this. Make sure that you don't pass strings such as comma
+ * separated lists of values, since the commas may be interpreted as a decimal
+ * point in some locales, causing unexpected results.
+ *
+ * Return value: the gdouble value.
+ **/
gdouble
g_strtod (const gchar *nptr,
- gchar **endptr)
+ gchar **endptr)
{
gchar *fail_pos_1;
gchar *fail_pos_2;
@@ -270,15 +291,7 @@ g_strtod (const gchar *nptr,
val_1 = strtod (nptr, &fail_pos_1);
if (fail_pos_1 && fail_pos_1[0] != 0)
- {
- gchar *old_locale;
-
- old_locale = g_strdup (setlocale (LC_NUMERIC, NULL));
- setlocale (LC_NUMERIC, "C");
- val_2 = strtod (nptr, &fail_pos_2);
- setlocale (LC_NUMERIC, old_locale);
- g_free (old_locale);
- }
+ val_2 = g_ascii_strtod (nptr, &fail_pos_2);
if (!fail_pos_1 || fail_pos_1[0] == 0 || fail_pos_1 >= fail_pos_2)
{
@@ -294,6 +307,278 @@ g_strtod (const gchar *nptr,
}
}
+/**
+ * g_ascii_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 behaves like the standard strtod() function
+ * does in the C locale. It does this without actually
+ * changing the current locale, since that would not be
+ * thread-safe.
+ *
+ * This function is typically used when reading configuration
+ * files or other non-user input that should be locale dependent.
+ * To handle input from the user you should normally use the
+ * locale-sensitive system strtod function.
+ *
+ * To convert from a string to double in a locale-insensitive
+ * way, use @g_ascii_dtostr.
+ *
+ * If the correct value would cause overflow, plus or minus HUGE_VAL
+ * is returned (according to the sign of the value), and ERANGE is
+ * stored in errno. If the correct value would cause underflow,
+ * zero is returned and ERANGE is stored in errno.
+ *
+ * This function resets errno before calling strtod() so that
+ * you can reliably detect overflow and underflow.
+ *
+ * Return value: the gdouble value.
+ **/
+gdouble
+g_ascii_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 */
+
+ 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 (decimal_point[0] != '.' ||
+ decimal_point[1] != 0)
+ {
+ 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
+ {
+ 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;
+ }
+ }
+ /* For the other cases, we need not convert the decimal point */
+ }
+
+ /* Set errno to zero, so that we can distinguish zero results
+ and underflows */
+ errno = 0;
+
+ if (decimal_point_pos)
+ {
+ char *copy, *c;
+
+ /* 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);
+
+ }
+ else
+ val = strtod (nptr, &fail_pos);
+
+ if (endptr)
+ *endptr = fail_pos;
+
+ return val;
+}
+
+/**
+ * g_ascii_dtostr:
+ * @buffer: A buffer to place the resulting string in
+ * @buf_len: The length of the buffer.
+ * @d: The double to convert
+ *
+ * Converts a double to a string, using the '.' as
+ * decimal_point.
+ *
+ * This functions generates enough precision that converting
+ * the string back using @g_strtod gives the same machine-number
+ * (on machines with IEEE compatible 64bit doubles). 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 *
+g_ascii_dtostr (gchar *buffer,
+ gint buf_len,
+ gdouble d)
+{
+ return g_ascii_formatd (buffer, buf_len, "%.17g", d);
+}
+
+/**
+ * g_ascii_formatd:
+ * @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 just want to want to serialize the value into a
+ * string, use @g_ascii_dtostr.
+ *
+ * Return value: The pointer to the buffer with the converted string.
+ **/
+gchar *
+g_ascii_formatd (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 (decimal_point[0] != '.' ||
+ decimal_point[1] != 0)
+ {
+ 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;
+}
+
+
G_CONST_RETURN gchar*
g_strerror (gint errnum)
{
diff --git a/glib/gstrfuncs.h b/glib/gstrfuncs.h
index 7aedde134..0c4f59ef0 100644
--- a/glib/gstrfuncs.h
+++ b/glib/gstrfuncs.h
@@ -93,13 +93,11 @@ gint g_ascii_xdigit_value (gchar c) G_GNUC_CONST;
*/
#define G_STR_DELIMITERS "_-|> <."
gchar* g_strdelimit (gchar *string,
- const gchar *delimiters,
+ const gchar *delimiters,
gchar new_delimiter);
-gchar* g_strcanon (gchar *string,
- const gchar *valid_chars,
- gchar substitutor);
-gdouble g_strtod (const gchar *nptr,
- gchar **endptr);
+gchar* g_strcanon (gchar *string,
+ const gchar *valid_chars,
+ gchar substitutor);
G_CONST_RETURN gchar* g_strerror (gint errnum) G_GNUC_CONST;
G_CONST_RETURN gchar* g_strsignal (gint signum) G_GNUC_CONST;
gchar* g_strreverse (gchar *string);
@@ -118,6 +116,24 @@ gchar * g_strrstr_len (const gchar *haystack,
gssize haystack_len,
const gchar *needle);
+/* String to/from double conversion functions */
+
+gdouble g_strtod (const gchar *nptr,
+ gchar **endptr);
+gdouble g_ascii_strtod (const gchar *nptr,
+ gchar **endptr);
+/* 29 bytes should enough for all possible values that
+ * g_ascii_dtostr can produce.
+ * Then add 10 for good measure */
+#define G_ASCII_DTOSTR_BUF_SIZE (29 + 10)
+gchar * g_ascii_dtostr (gchar *buffer,
+ gint buf_len,
+ gdouble d);
+gchar * g_ascii_formatd (gchar *buffer,
+ gint buf_len,
+ const gchar *format,
+ gdouble d);
+
/* removes leading spaces */
gchar* g_strchug (gchar *string);
/* removes trailing spaces */
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 5a2910d2c..5160be6e3 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -72,6 +72,7 @@ test_programs = \
spawn-test \
strfunc-test \
string-test \
+ strtod-test \
thread-test \
threadpool-test \
tree-test \
@@ -114,6 +115,7 @@ slist_test_LDADD = $(progs_LDADD)
spawn_test_LDADD = $(progs_LDADD)
strfunc_test_LDADD = $(progs_LDADD)
string_test_LDADD = $(progs_LDADD)
+strtod_test_LDADD = $(progs_LDADD) -lm
thread_test_LDADD = $(thread_LDADD)
threadpool_test_LDADD = $(thread_LDADD)
tree_test_LDADD = $(progs_LDADD)
diff --git a/tests/strtod-test.c b/tests/strtod-test.c
new file mode 100644
index 000000000..bdb7017bc
--- /dev/null
+++ b/tests/strtod-test.c
@@ -0,0 +1,53 @@
+#include <glib.h>
+#include <locale.h>
+#include <string.h>
+#include <math.h>
+
+void
+test_string (char *number, double res)
+{
+ gdouble d;
+ char *locales[] = {"sv_SE", "en_US", "fa_IR", "C"};
+ int l;
+ char *end;
+
+ for (l = 0; l < G_N_ELEMENTS (locales); l++)
+ {
+ setlocale (LC_NUMERIC, locales[l]);
+ d = g_ascii_strtod (number, &end);
+ if (d != res)
+ g_print ("g_ascii_strtod for locale %s failed\n", locales[l]);
+ if (*end != 0)
+ g_print ("g_ascii_strtod for locale %s endptr was wrong\n", locales[l]);
+ }
+}
+
+
+int
+main ()
+{
+ gdouble d;
+ char buffer[G_ASCII_DTOSTR_BUF_SIZE];
+
+ test_string ("123.123", 123.123);
+ test_string ("123.123e2", 123.123e2);
+ test_string ("123.123e-2", 123.123e-2);
+ test_string ("-123.123", -123.123);
+ test_string ("-123.123e2", -123.123e2);
+ test_string ("-123.123e-2", -123.123e-2);
+
+ d = 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.0;
+ g_assert (d == g_ascii_strtod (g_ascii_dtostr (buffer, sizeof (buffer), d), NULL));
+
+ d = -179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.0;
+ g_assert (d == g_ascii_strtod (g_ascii_dtostr (buffer, sizeof (buffer), d), NULL));
+
+ d = pow (2.0, -1024.1);
+ g_assert (d == g_ascii_strtod (g_ascii_dtostr (buffer, sizeof (buffer), d), NULL));
+
+ d = -pow (2.0, -1024.1);
+ g_assert (d == g_ascii_strtod (g_ascii_dtostr (buffer, sizeof (buffer), d), NULL));
+
+
+ return 0;
+}