From 49ab402f5ad82de53fcb71f61a855f1a83940a29 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Tue, 16 May 2006 05:49:46 +0000 Subject: [PATCH] g_ascii_strtoll --- ChangeLog | 15 +++ ChangeLog.pre-2-12 | 15 +++ docs/reference/ChangeLog | 4 + docs/reference/glib/glib-sections.txt | 1 + glib/glib.symbols | 1 + glib/gstrfuncs.c | 146 +++++++++++++++++++------- glib/gstrfuncs.h | 3 + tests/Makefile.am | 2 + tests/strtoll-test.c | 67 ++++++++++++ 9 files changed, 214 insertions(+), 40 deletions(-) create mode 100644 tests/strtoll-test.c diff --git a/ChangeLog b/ChangeLog index ef00354c9..d8652f5ec 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2006-05-16 Matthias Clasen + + * 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 * configure.in: Bump version diff --git a/ChangeLog.pre-2-12 b/ChangeLog.pre-2-12 index ef00354c9..d8652f5ec 100644 --- a/ChangeLog.pre-2-12 +++ b/ChangeLog.pre-2-12 @@ -1,3 +1,18 @@ +2006-05-16 Matthias Clasen + + * 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 * configure.in: Bump version diff --git a/docs/reference/ChangeLog b/docs/reference/ChangeLog index 11e766fef..b8b1f6f6b 100644 --- a/docs/reference/ChangeLog +++ b/docs/reference/ChangeLog @@ -1,3 +1,7 @@ +2006-05-16 Matthias Clasen + + * glib/glib-sections.txt: Add g_ascii_strtoll + 2006-05-15 Matthias Clasen * === Released 2.11.1 === diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt index 687847b34..aa6459125 100644 --- a/docs/reference/glib/glib-sections.txt +++ b/docs/reference/glib/glib-sections.txt @@ -1119,6 +1119,7 @@ g_strncasecmp g_strreverse +g_ascii_strtoll g_ascii_strtoull G_ASCII_DTOSTR_BUF_SIZE g_ascii_strtod diff --git a/glib/glib.symbols b/glib/glib.symbols index 61f33e45d..62e2a1065 100644 --- a/glib/glib.symbols +++ b/glib/glib.symbols @@ -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 diff --git a/glib/gstrfuncs.c b/glib/gstrfuncs.c index d7db60002..260853ab4 100644 --- a/glib/gstrfuncs.c +++ b/glib/gstrfuncs.c @@ -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) diff --git a/glib/gstrfuncs.h b/glib/gstrfuncs.h index 9c41dcad0..15803beda 100644 --- a/glib/gstrfuncs.h +++ b/glib/gstrfuncs.h @@ -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 */ diff --git a/tests/Makefile.am b/tests/Makefile.am index a4d5e74a3..b731affeb 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -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) diff --git a/tests/strtoll-test.c b/tests/strtoll-test.c new file mode 100644 index 000000000..6c1de3fb6 --- /dev/null +++ b/tests/strtoll-test.c @@ -0,0 +1,67 @@ +#undef G_DISABLE_ASSERT +#undef G_LOG_DOMAIN + +#include +#include +#include + + +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; +}