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.
#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;
/* 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 == '+')
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
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)
--- /dev/null
+#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;
+}