mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-02-08 03:45:49 +01:00
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.
This commit is contained in:
parent
b0facb3863
commit
3c39c8fcd0
15
ChangeLog
15
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>
|
2001-10-23 Tor Lillqvist <tml@iki.fi>
|
||||||
|
|
||||||
* config.h.win32.in: Typo: GLIB_MICRO_VERSION and
|
* config.h.win32.in: Typo: GLIB_MICRO_VERSION and
|
||||||
|
@ -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>
|
2001-10-23 Tor Lillqvist <tml@iki.fi>
|
||||||
|
|
||||||
* config.h.win32.in: Typo: GLIB_MICRO_VERSION and
|
* config.h.win32.in: Typo: GLIB_MICRO_VERSION and
|
||||||
|
@ -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>
|
2001-10-23 Tor Lillqvist <tml@iki.fi>
|
||||||
|
|
||||||
* config.h.win32.in: Typo: GLIB_MICRO_VERSION and
|
* config.h.win32.in: Typo: GLIB_MICRO_VERSION and
|
||||||
|
@ -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>
|
2001-10-23 Tor Lillqvist <tml@iki.fi>
|
||||||
|
|
||||||
* config.h.win32.in: Typo: GLIB_MICRO_VERSION and
|
* config.h.win32.in: Typo: GLIB_MICRO_VERSION and
|
||||||
|
@ -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>
|
2001-10-23 Tor Lillqvist <tml@iki.fi>
|
||||||
|
|
||||||
* config.h.win32.in: Typo: GLIB_MICRO_VERSION and
|
* config.h.win32.in: Typo: GLIB_MICRO_VERSION and
|
||||||
|
@ -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>
|
2001-10-23 Tor Lillqvist <tml@iki.fi>
|
||||||
|
|
||||||
* config.h.win32.in: Typo: GLIB_MICRO_VERSION and
|
* config.h.win32.in: Typo: GLIB_MICRO_VERSION and
|
||||||
|
@ -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>
|
2001-10-23 Tor Lillqvist <tml@iki.fi>
|
||||||
|
|
||||||
* config.h.win32.in: Typo: GLIB_MICRO_VERSION and
|
* config.h.win32.in: Typo: GLIB_MICRO_VERSION and
|
||||||
|
@ -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>
|
2001-10-23 Tor Lillqvist <tml@iki.fi>
|
||||||
|
|
||||||
* config.h.win32.in: Typo: GLIB_MICRO_VERSION and
|
* config.h.win32.in: Typo: GLIB_MICRO_VERSION and
|
||||||
|
@ -922,6 +922,12 @@ g_strncasecmp
|
|||||||
|
|
||||||
<SUBSECTION>
|
<SUBSECTION>
|
||||||
g_strreverse
|
g_strreverse
|
||||||
|
|
||||||
|
<SUBSECTION>
|
||||||
|
G_ASCII_DTOSTR_BUF_SIZE
|
||||||
|
g_ascii_strtod
|
||||||
|
g_ascii_dtostr
|
||||||
|
g_ascii_formatd
|
||||||
g_strtod
|
g_strtod
|
||||||
|
|
||||||
<SUBSECTION>
|
<SUBSECTION>
|
||||||
|
@ -562,19 +562,68 @@ For example, g_strreverse ("abcdef") will result in "fedcba".
|
|||||||
@Returns: the same pointer passed in as @string.
|
@Returns: the same pointer passed in as @string.
|
||||||
|
|
||||||
|
|
||||||
<!-- ##### FUNCTION g_strtod ##### -->
|
<!-- ##### MACRO G_ASCII_DTOSTR_BUF_SIZE ##### -->
|
||||||
<para>
|
<para>
|
||||||
Converts a string to a gdouble value.
|
A good size for a buffer to be passed into <function>g_ascii_dtostr</function>.
|
||||||
It calls the standard <function>strtod()</function> function
|
It is guaranteed to be enough for all output of that function on systems with
|
||||||
to handle the conversion, but if the string is not completely converted
|
64bit IEEE compatible doubles.
|
||||||
it attempts the conversion again in the "C" locale, and returns the best
|
</para>
|
||||||
match.
|
<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>
|
</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.
|
<!-- ##### FUNCTION g_ascii_strtod ##### -->
|
||||||
@Returns: the gdouble value.
|
<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>
|
||||||
|
|
||||||
|
</para>
|
||||||
|
|
||||||
|
@nptr:
|
||||||
|
@endptr:
|
||||||
|
@Returns:
|
||||||
|
|
||||||
|
|
||||||
<!-- ##### FUNCTION g_strchug ##### -->
|
<!-- ##### FUNCTION g_strchug ##### -->
|
||||||
|
305
glib/gstrfuncs.c
305
glib/gstrfuncs.c
@ -39,6 +39,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <ctype.h> /* For tolower() */
|
#include <ctype.h> /* For tolower() */
|
||||||
#if !defined (HAVE_STRSIGNAL) || !defined(NO_SYS_SIGLIST_DECL)
|
#if !defined (HAVE_STRSIGNAL) || !defined(NO_SYS_SIGLIST_DECL)
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
@ -253,9 +254,29 @@ g_strconcat (const gchar *string1, ...)
|
|||||||
return concat;
|
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
|
gdouble
|
||||||
g_strtod (const gchar *nptr,
|
g_strtod (const gchar *nptr,
|
||||||
gchar **endptr)
|
gchar **endptr)
|
||||||
{
|
{
|
||||||
gchar *fail_pos_1;
|
gchar *fail_pos_1;
|
||||||
gchar *fail_pos_2;
|
gchar *fail_pos_2;
|
||||||
@ -270,15 +291,7 @@ g_strtod (const gchar *nptr,
|
|||||||
val_1 = strtod (nptr, &fail_pos_1);
|
val_1 = strtod (nptr, &fail_pos_1);
|
||||||
|
|
||||||
if (fail_pos_1 && fail_pos_1[0] != 0)
|
if (fail_pos_1 && fail_pos_1[0] != 0)
|
||||||
{
|
val_2 = g_ascii_strtod (nptr, &fail_pos_2);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!fail_pos_1 || fail_pos_1[0] == 0 || fail_pos_1 >= 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_CONST_RETURN gchar*
|
||||||
g_strerror (gint errnum)
|
g_strerror (gint errnum)
|
||||||
{
|
{
|
||||||
|
@ -93,13 +93,11 @@ gint g_ascii_xdigit_value (gchar c) G_GNUC_CONST;
|
|||||||
*/
|
*/
|
||||||
#define G_STR_DELIMITERS "_-|> <."
|
#define G_STR_DELIMITERS "_-|> <."
|
||||||
gchar* g_strdelimit (gchar *string,
|
gchar* g_strdelimit (gchar *string,
|
||||||
const gchar *delimiters,
|
const gchar *delimiters,
|
||||||
gchar new_delimiter);
|
gchar new_delimiter);
|
||||||
gchar* g_strcanon (gchar *string,
|
gchar* g_strcanon (gchar *string,
|
||||||
const gchar *valid_chars,
|
const gchar *valid_chars,
|
||||||
gchar substitutor);
|
gchar substitutor);
|
||||||
gdouble g_strtod (const gchar *nptr,
|
|
||||||
gchar **endptr);
|
|
||||||
G_CONST_RETURN gchar* g_strerror (gint errnum) G_GNUC_CONST;
|
G_CONST_RETURN gchar* g_strerror (gint errnum) G_GNUC_CONST;
|
||||||
G_CONST_RETURN gchar* g_strsignal (gint signum) G_GNUC_CONST;
|
G_CONST_RETURN gchar* g_strsignal (gint signum) G_GNUC_CONST;
|
||||||
gchar* g_strreverse (gchar *string);
|
gchar* g_strreverse (gchar *string);
|
||||||
@ -118,6 +116,24 @@ gchar * g_strrstr_len (const gchar *haystack,
|
|||||||
gssize haystack_len,
|
gssize haystack_len,
|
||||||
const gchar *needle);
|
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 */
|
/* removes leading spaces */
|
||||||
gchar* g_strchug (gchar *string);
|
gchar* g_strchug (gchar *string);
|
||||||
/* removes trailing spaces */
|
/* removes trailing spaces */
|
||||||
|
@ -72,6 +72,7 @@ test_programs = \
|
|||||||
spawn-test \
|
spawn-test \
|
||||||
strfunc-test \
|
strfunc-test \
|
||||||
string-test \
|
string-test \
|
||||||
|
strtod-test \
|
||||||
thread-test \
|
thread-test \
|
||||||
threadpool-test \
|
threadpool-test \
|
||||||
tree-test \
|
tree-test \
|
||||||
@ -114,6 +115,7 @@ slist_test_LDADD = $(progs_LDADD)
|
|||||||
spawn_test_LDADD = $(progs_LDADD)
|
spawn_test_LDADD = $(progs_LDADD)
|
||||||
strfunc_test_LDADD = $(progs_LDADD)
|
strfunc_test_LDADD = $(progs_LDADD)
|
||||||
string_test_LDADD = $(progs_LDADD)
|
string_test_LDADD = $(progs_LDADD)
|
||||||
|
strtod_test_LDADD = $(progs_LDADD) -lm
|
||||||
thread_test_LDADD = $(thread_LDADD)
|
thread_test_LDADD = $(thread_LDADD)
|
||||||
threadpool_test_LDADD = $(thread_LDADD)
|
threadpool_test_LDADD = $(thread_LDADD)
|
||||||
tree_test_LDADD = $(progs_LDADD)
|
tree_test_LDADD = $(progs_LDADD)
|
||||||
|
53
tests/strtod-test.c
Normal file
53
tests/strtod-test.c
Normal file
@ -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;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user