g_ascii_strtoll

This commit is contained in:
Matthias Clasen 2006-05-16 05:49:46 +00:00
parent 503db3a1fa
commit 49ab402f5a
9 changed files with 214 additions and 40 deletions

View File

@ -1,3 +1,18 @@
2006-05-16 Matthias Clasen <mclasen@redhat.com>
* tests/Makefile.am:
* tests/strtoll-test.c: Add tests for g_ascii_strtoll()
and g_ascii_strtoull().
* glib/glib.symbols:
* glib/gstrfuncs.h:
* glib/gstrfuncs.c (g_ascii_strtoll): New function to
parse signed 64bit integers like strtoll does.
* glib/goption.c (parse_int64): Use g_ascii_strtoll(),
since strtoll() is C99 and not available on some
systems. (#341826, Kazuki Iwamoto)
2006-05-15 Matthias Clasen <mclasen@redhat.com>
* configure.in: Bump version

View File

@ -1,3 +1,18 @@
2006-05-16 Matthias Clasen <mclasen@redhat.com>
* tests/Makefile.am:
* tests/strtoll-test.c: Add tests for g_ascii_strtoll()
and g_ascii_strtoull().
* glib/glib.symbols:
* glib/gstrfuncs.h:
* glib/gstrfuncs.c (g_ascii_strtoll): New function to
parse signed 64bit integers like strtoll does.
* glib/goption.c (parse_int64): Use g_ascii_strtoll(),
since strtoll() is C99 and not available on some
systems. (#341826, Kazuki Iwamoto)
2006-05-15 Matthias Clasen <mclasen@redhat.com>
* configure.in: Bump version

View File

@ -1,3 +1,7 @@
2006-05-16 Matthias Clasen <mclasen@redhat.com>
* glib/glib-sections.txt: Add g_ascii_strtoll
2006-05-15 Matthias Clasen <mclasen@redhat.com>
* === Released 2.11.1 ===

View File

@ -1119,6 +1119,7 @@ g_strncasecmp
g_strreverse
<SUBSECTION>
g_ascii_strtoll
g_ascii_strtoull
G_ASCII_DTOSTR_BUF_SIZE
g_ascii_strtod

View File

@ -1012,6 +1012,7 @@ g_ascii_formatd
g_ascii_strdown G_GNUC_MALLOC
g_ascii_strtod
g_ascii_strtoull
g_ascii_strtoll
g_ascii_strup G_GNUC_MALLOC
g_ascii_tolower G_GNUC_CONST
g_ascii_toupper G_GNUC_CONST

View File

@ -591,38 +591,11 @@ g_ascii_formatd (gchar *buffer,
return buffer;
}
/**
* g_ascii_strtoull:
* @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.
* @base: to be used for the conversion, 2..36 or 0
*
* Converts a string to a #guint64 value.
* This function behaves like the standard strtoull() 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 independent.
* To handle input from the user you should normally use the
* locale-sensitive system strtoull() function.
*
* If the correct value would cause overflow, %G_MAXUINT64
* is returned, and %ERANGE is stored in %errno. If the base is
* outside the valid range, zero is returned, and %EINVAL is stored
* in %errno. If the string conversion fails, zero is returned, and
* @endptr returns @nptr (if @endptr is non-%NULL).
*
* Return value: the #guint64 value or zero on error.
*
* Since: 2.2
**/
guint64
g_ascii_strtoull (const gchar *nptr,
gchar **endptr,
guint base)
static guint64
g_parse_long_long (const gchar *nptr,
gchar **endptr,
guint base,
gboolean *negative)
{
/* this code is based on on the strtol(3) code from GNU libc released under
* the GNU Lesser General Public License.
@ -637,7 +610,7 @@ g_ascii_strtoull (const gchar *nptr,
#define ISALPHA(c) (ISUPPER (c) || ISLOWER (c))
#define TOUPPER(c) (ISLOWER (c) ? (c) - 'a' + 'A' : (c))
#define TOLOWER(c) (ISUPPER (c) ? (c) - 'A' + 'a' : (c))
gboolean negative, overflow;
gboolean overflow;
guint64 cutoff;
guint64 cutlim;
guint64 ui64;
@ -657,14 +630,15 @@ g_ascii_strtoull (const gchar *nptr,
/* Skip white space. */
while (ISSPACE (*s))
++s;
if (!*s)
if (G_UNLIKELY (!*s))
goto noconv;
/* Check for a sign. */
negative = FALSE;
*negative = FALSE;
if (*s == '-')
{
negative = TRUE;
*negative = TRUE;
++s;
}
else if (*s == '+')
@ -721,14 +695,13 @@ g_ascii_strtoull (const gchar *nptr,
if (endptr)
*endptr = (gchar*) s;
if (overflow)
if (G_UNLIKELY (overflow))
{
errno = ERANGE;
return G_MAXUINT64;
}
/* Return the result of the appropriate sign. */
return negative ? -ui64 : ui64;
return ui64;
noconv:
/* We must handle a special case here: the base is 0 or 16 and the
@ -747,6 +720,99 @@ g_ascii_strtoull (const gchar *nptr,
return 0;
}
/**
* g_ascii_strtoull:
* @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.
* @base: to be used for the conversion, 2..36 or 0
*
* Converts a string to a #guint64 value.
* This function behaves like the standard strtoull() 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 independent.
* To handle input from the user you should normally use the
* locale-sensitive system strtoull() function.
*
* If the correct value would cause overflow, %G_MAXUINT64
* is returned, and %ERANGE is stored in %errno. If the base is
* outside the valid range, zero is returned, and %EINVAL is stored
* in %errno. If the string conversion fails, zero is returned, and
* @endptr returns @nptr (if @endptr is non-%NULL).
*
* Return value: the #guint64 value or zero on error.
*
* Since: 2.2
**/
guint64
g_ascii_strtoull (const gchar *nptr,
gchar **endptr,
guint base)
{
gboolean negative;
guint64 result;
result = g_parse_long_long (nptr, endptr, base, &negative);
/* Return the result of the appropriate sign. */
return negative ? -result : result;
}
/**
* g_ascii_strtoll:
* @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.
* @base: to be used for the conversion, 2..36 or 0
*
* Converts a string to a #gint64 value.
* This function behaves like the standard strtoll() 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 independent.
* To handle input from the user you should normally use the
* locale-sensitive system strtoll() function.
*
* If the correct value would cause overflow, %G_MAXINT64 or %G_MININT64
* is returned, and %ERANGE is stored in %errno. If the base is
* outside the valid range, zero is returned, and %EINVAL is stored
* in %errno. If the string conversion fails, zero is returned, and
* @endptr returns @nptr (if @endptr is non-%NULL).
*
* Return value: the #gint64 value or zero on error.
*
* Since: 2.12
**/
gint64
g_ascii_strtoll (const gchar *nptr,
gchar **endptr,
guint base)
{
gboolean negative;
guint64 result;
result = g_parse_long_long (nptr, endptr, base, &negative);
if (negative && result > (guint64) G_MININT64)
{
errno = ERANGE;
return G_MININT64;
}
else if (!negative && result > (guint64) G_MAXINT64)
{
errno = ERANGE;
return G_MAXINT64;
}
else
return (gint64) result;
}
G_CONST_RETURN gchar*
g_strerror (gint errnum)

View File

@ -130,6 +130,9 @@ gdouble g_ascii_strtod (const gchar *nptr,
guint64 g_ascii_strtoull (const gchar *nptr,
gchar **endptr,
guint base);
gint64 g_ascii_strtoll (const gchar *nptr,
gchar **endptr,
guint base);
/* 29 bytes should enough for all possible values that
* g_ascii_dtostr can produce.
* Then add 10 for good measure */

View File

@ -100,6 +100,7 @@ test_programs = \
strfunc-test \
string-test \
strtod-test \
strtoll-test \
thread-test \
threadpool-test \
tree-test \
@ -166,6 +167,7 @@ spawn_test_LDADD = $(progs_ldadd)
strfunc_test_LDADD = $(progs_ldadd)
string_test_LDADD = $(progs_ldadd)
strtod_test_LDADD = $(progs_ldadd) -lm
strtoll_test_LDADD = $(progs_ldadd) -lm
thread_test_LDADD = $(thread_ldadd)
threadpool_test_LDADD = $(thread_ldadd)
tree_test_LDADD = $(progs_ldadd)

67
tests/strtoll-test.c Normal file
View File

@ -0,0 +1,67 @@
#undef G_DISABLE_ASSERT
#undef G_LOG_DOMAIN
#include <errno.h>
#include <string.h>
#include <glib.h>
static void
test_uint64 (const gchar *str,
const gchar *end,
gint base,
guint64 result,
gint error)
{
guint64 actual;
gchar *endptr = NULL;
gint err;
errno = 0;
actual = g_ascii_strtoull (str, &endptr, base);
err = errno;
g_assert (actual == result);
g_assert (strcmp (end, endptr) == 0);
g_assert (err == error);
}
static void
test_int64 (const gchar *str,
const gchar *end,
gint base,
gint64 result,
gint error)
{
gint64 actual;
gchar *endptr = NULL;
gint err;
errno = 0;
actual = g_ascii_strtoll (str, &endptr, base);
err = errno;
g_assert (actual == result);
g_assert (strcmp (end, endptr) == 0);
g_assert (err == error);
}
int
main (int argc, char *argv[])
{
test_uint64 ("0", "", 10, 0, 0);
test_uint64 ("+0", "", 10, 0, 0);
test_uint64 ("-0", "", 10, 0, 0);
test_uint64 ("18446744073709551615", "", 10, G_MAXUINT64, 0);
test_uint64 ("18446744073709551616", "", 10, G_MAXUINT64, ERANGE);
test_uint64 ("20xyz", "xyz", 10, 20, 0);
test_uint64 ("-1", "", 10, G_MAXUINT64, 0);
test_int64 ("0", "", 10, 0, 0);
test_int64 ("9223372036854775807", "", 10, G_MAXINT64, 0);
test_int64 ("9223372036854775808", "", 10, G_MAXINT64, ERANGE);
test_int64 ("-9223372036854775808", "", 10, G_MININT64, 0);
test_int64 ("-9223372036854775809", "", 10, G_MININT64, ERANGE);
return 0;
}