core: refactor nm_utils_ascii_str_to_int64()

No need to allocate a dynamic buffer in most of the cases.

And extended test cases to test with/without white space
and leading zeros.

Signed-off-by: Thomas Haller <thaller@redhat.com>
This commit is contained in:
Thomas Haller
2014-03-18 11:42:31 +01:00
parent cbee213781
commit 80d2d0ebe1
2 changed files with 151 additions and 41 deletions

View File

@@ -878,11 +878,11 @@ gint64
nm_utils_ascii_str_to_int64 (const char *str, guint base, gint64 min, gint64 max, gint64 fallback) nm_utils_ascii_str_to_int64 (const char *str, guint base, gint64 min, gint64 max, gint64 fallback)
{ {
gint64 v; gint64 v;
char *end; size_t len;
char *str_free = NULL; char buf[64], *s, *str_free = NULL;
if (str) { if (str) {
while (str[0] && g_ascii_isspace (str[0])) while (g_ascii_isspace (str[0]))
str++; str++;
} }
if (!str || !str[0]) { if (!str || !str[0]) {
@@ -890,32 +890,48 @@ nm_utils_ascii_str_to_int64 (const char *str, guint base, gint64 min, gint64 max
return fallback; return fallback;
} }
if (g_ascii_isspace (str[strlen (str) - 1])) { len = strlen (str);
str_free = g_strdup (str); if (g_ascii_isspace (str[--len])) {
g_strstrip (str_free); /* backward search the first non-ws character.
str = str_free; * We already know that str[0] is non-ws. */
while (g_ascii_isspace (str[--len]))
;
/* str[len] is now the last non-ws character... */
len++;
if (len >= sizeof (buf))
s = str_free = g_malloc (len + 1);
else
s = buf;
memcpy (s, str, len);
s[len] = 0;
/*
g_assert (len > 0 && len < strlen (str) && len == strlen (s));
g_assert (!g_ascii_isspace (str[len-1]) && g_ascii_isspace (str[len]));
g_assert (strncmp (str, s, len) == 0);
*/
str = s;
} }
errno = 0; errno = 0;
v = g_ascii_strtoll (str, &end, base); v = g_ascii_strtoll (str, &s, base);
if (errno != 0) { if (errno != 0)
g_free (str_free); v = fallback;
return fallback; else if (s[0] != 0) {
}
if (end[0] != 0) {
g_free (str_free);
errno = EINVAL; errno = EINVAL;
return fallback; v = fallback;
} } else if (v > max || v < min) {
g_free (str_free);
if (v > max || v < min) {
errno = ERANGE; errno = ERANGE;
return fallback; v = fallback;
} }
if (G_UNLIKELY (str_free))
g_free (str_free);
return v; return v;
} }

View File

@@ -27,38 +27,132 @@
static void static void
test_nm_utils_ascii_str_to_int64_do (const char *str, guint base, gint64 min, test_nm_utils_ascii_str_to_int64_check (const char *str, guint base, gint64 min,
gint64 max, gint64 fallback, int exp_errno, gint64 max, gint64 fallback, int exp_errno,
gint64 exp_val) gint64 exp_val)
{ {
gint64 v; gint64 v;
errno = 0; errno = 1;
v = nm_utils_ascii_str_to_int64 (str, base, min, max, fallback); v = nm_utils_ascii_str_to_int64 (str, base, min, max, fallback);
g_assert_cmpint (errno, ==, exp_errno); g_assert_cmpint (errno, ==, exp_errno);
g_assert_cmpint (v, ==, exp_val); g_assert_cmpint (v, ==, exp_val);
} }
static void
test_nm_utils_ascii_str_to_int64_do (const char *str, guint base, gint64 min,
gint64 max, gint64 fallback, int exp_errno,
gint64 exp_val)
{
const char *sign = "";
const char *val;
static const char *whitespaces[] = {
"",
" ",
"\r\n\t",
" \r\n\t ",
" \r\n\t \t\r\n\t",
NULL,
};
static const char *nulls[] = {
"",
"0",
"00",
"0000",
"0000000000000000",
"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
NULL,
};
const char **ws_pre, **ws_post, **null;
int i;
if (str == NULL || exp_errno != 0) {
test_nm_utils_ascii_str_to_int64_check (str, base, min, max, fallback, exp_errno, exp_val);
return;
}
if (strncmp (str, "-", 1) == 0)
sign = "-";
val = str + strlen (sign);
for (ws_pre = whitespaces; *ws_pre; ws_pre++) {
for (ws_post = whitespaces; *ws_post; ws_post++) {
for (null = nulls; *null; null++) {
for (i = 0; ; i++) {
char *s;
const char *str_base = "";
if (base == 16) {
if (i == 1)
str_base = "0x";
else if (i > 1)
break;
} else if (base == 8) {
if (i == 1)
str_base = "0";
else if (i > 1)
break;
} else if (base == 0) {
if (i > 0)
break;
/* with base==0, a leading zero would be interpreted as octal. Only test without *null */
if ((*null)[0])
break;
} else {
if (i > 0)
break;
}
s = g_strdup_printf ("%s%s%s%s%s%s", *ws_pre, sign, str_base, *null, val, *ws_post);
test_nm_utils_ascii_str_to_int64_check (s, base, min, max, fallback, exp_errno, exp_val);
g_free (s);
}
}
}
}
}
static void static void
test_nm_utils_ascii_str_to_int64 (void) test_nm_utils_ascii_str_to_int64 (void)
{ {
test_nm_utils_ascii_str_to_int64_do ("4711", 10, 0, 10000, -1, 0, 4711);
test_nm_utils_ascii_str_to_int64_do ("", 10, 0, 10000, -1, EINVAL, -1);
test_nm_utils_ascii_str_to_int64_do (NULL, 10, 0, 10000, -1, EINVAL, -1); test_nm_utils_ascii_str_to_int64_do (NULL, 10, 0, 10000, -1, EINVAL, -1);
test_nm_utils_ascii_str_to_int64_do ("", 10, 0, 10000, -1, EINVAL, -1);
test_nm_utils_ascii_str_to_int64_do ("1x", 10, 0, 10000, -1, EINVAL, -1); test_nm_utils_ascii_str_to_int64_do ("1x", 10, 0, 10000, -1, EINVAL, -1);
test_nm_utils_ascii_str_to_int64_do ("4711", 10, 0, 10000, -1, 0, 4711);
test_nm_utils_ascii_str_to_int64_do ("10000", 10, 0, 10000, -1, 0, 10000); test_nm_utils_ascii_str_to_int64_do ("10000", 10, 0, 10000, -1, 0, 10000);
test_nm_utils_ascii_str_to_int64_do ("10001", 10, 0, 10000, -1, ERANGE, -1); test_nm_utils_ascii_str_to_int64_do ("10001", 10, 0, 10000, -1, ERANGE, -1);
test_nm_utils_ascii_str_to_int64_do (" 0xFF ", 16, 0, 10000, -1, 0, 255);
test_nm_utils_ascii_str_to_int64_do ("FF", 16, 0, 10000, -1, 0, 255); test_nm_utils_ascii_str_to_int64_do ("FF", 16, 0, 10000, -1, 0, 255);
test_nm_utils_ascii_str_to_int64_do ("FF", 10, 0, 10000, -2, EINVAL, -2); test_nm_utils_ascii_str_to_int64_do ("FF", 10, 0, 10000, -2, EINVAL, -2);
test_nm_utils_ascii_str_to_int64_do ("9223372036854775807", 10, 0, G_MAXINT64, -2, 0, G_MAXINT64); test_nm_utils_ascii_str_to_int64_do ("9223372036854775807", 10, 0, G_MAXINT64, -2, 0, G_MAXINT64);
test_nm_utils_ascii_str_to_int64_do (" 0x7FFFFFFFFFFFFFFF ", 16, 0, G_MAXINT64, -2, 0, G_MAXINT64);
test_nm_utils_ascii_str_to_int64_do ("7FFFFFFFFFFFFFFF", 16, 0, G_MAXINT64, -2, 0, G_MAXINT64); test_nm_utils_ascii_str_to_int64_do ("7FFFFFFFFFFFFFFF", 16, 0, G_MAXINT64, -2, 0, G_MAXINT64);
test_nm_utils_ascii_str_to_int64_do ("9223372036854775808", 10, 0, G_MAXINT64, -2, ERANGE, -2); test_nm_utils_ascii_str_to_int64_do ("9223372036854775808", 10, 0, G_MAXINT64, -2, ERANGE, -2);
test_nm_utils_ascii_str_to_int64_do ("-9223372036854775808", 10, G_MININT64, 0, -2, 0, G_MININT64); test_nm_utils_ascii_str_to_int64_do ("-9223372036854775808", 10, G_MININT64, 0, -2, 0, G_MININT64);
test_nm_utils_ascii_str_to_int64_do ("-9223372036854775808", 10, G_MININT64+1, 0, -2, ERANGE, -2); test_nm_utils_ascii_str_to_int64_do ("-9223372036854775808", 10, G_MININT64+1, 0, -2, ERANGE, -2);
test_nm_utils_ascii_str_to_int64_do ("-9223372036854775809", 10, G_MININT64, 0, -2, ERANGE, -2); test_nm_utils_ascii_str_to_int64_do ("-9223372036854775809", 10, G_MININT64, 0, -2, ERANGE, -2);
test_nm_utils_ascii_str_to_int64_do ("\r\n\t10000\t\n\t\n", 10, 0, 10000, -1, 0, 10000); test_nm_utils_ascii_str_to_int64_do ("1.0", 10, 1, 1, -1, EINVAL, -1);
test_nm_utils_ascii_str_to_int64_do ("1x0", 16, -10, 10, -100, EINVAL, -100);
test_nm_utils_ascii_str_to_int64_do ("0", 16, -10, 10, -100, 0, 0);
test_nm_utils_ascii_str_to_int64_do ("10001111", 2, -1000, 1000, -100000, 0, 0x8F);
test_nm_utils_ascii_str_to_int64_do ("-10001111", 2, -1000, 1000, -100000, 0, -0x8F);
test_nm_utils_ascii_str_to_int64_do ("1111111", 2, G_MININT64, G_MAXINT64, -1, 0, 0x7F);
test_nm_utils_ascii_str_to_int64_do ("111111111111111", 2, G_MININT64, G_MAXINT64, -1, 0, 0x7FFF);
test_nm_utils_ascii_str_to_int64_do ("11111111111111111111111111111111111111111111111", 2, G_MININT64, G_MAXINT64, -1, 0, 0x7FFFFFFFFFFF);
test_nm_utils_ascii_str_to_int64_do ("111111111111111111111111111111111111111111111111111111111111111", 2, G_MININT64, G_MAXINT64, -1, 0, 0x7FFFFFFFFFFFFFFF);
test_nm_utils_ascii_str_to_int64_do ("100000000000000000000000000000000000000000000000000000000000000", 2, G_MININT64, G_MAXINT64, -1, 0, 0x4000000000000000);
test_nm_utils_ascii_str_to_int64_do ("1000000000000000000000000000000000000000000000000000000000000000", 2, G_MININT64, G_MAXINT64, -1, ERANGE, -1);
test_nm_utils_ascii_str_to_int64_do ("-100000000000000000000000000000000000000000000000000000000000000", 2, G_MININT64, G_MAXINT64, -1, 0, -0x4000000000000000);
test_nm_utils_ascii_str_to_int64_do ("111111111111111111111111111111111111111111111111111111111111111", 2, G_MININT64, G_MAXINT64, -1, 0, 0x7FFFFFFFFFFFFFFF);
test_nm_utils_ascii_str_to_int64_do ("-100000000000000000000000000000000000000000000000000000000000000", 2, G_MININT64, G_MAXINT64, -1, 0, -0x4000000000000000);
test_nm_utils_ascii_str_to_int64_do ("0x70", 10, G_MININT64, G_MAXINT64, -1, EINVAL, -1);
test_nm_utils_ascii_str_to_int64_do ("4711", 0, G_MININT64, G_MAXINT64, -1, 0, 4711);
test_nm_utils_ascii_str_to_int64_do ("04711", 0, G_MININT64, G_MAXINT64, -1, 0, 04711);
test_nm_utils_ascii_str_to_int64_do ("0x4711", 0, G_MININT64, G_MAXINT64, -1, 0, 0x4711);
test_nm_utils_ascii_str_to_int64_do ("080", 0, G_MININT64, G_MAXINT64, -1, EINVAL, -1);
test_nm_utils_ascii_str_to_int64_do ("070", 0, G_MININT64, G_MAXINT64, -1, 0, 7*8);
test_nm_utils_ascii_str_to_int64_do ("0x70", 0, G_MININT64, G_MAXINT64, -1, 0, 0x70);
} }
/* Reference implementation for nm_utils_ip6_address_clear_host_address. /* Reference implementation for nm_utils_ip6_address_clear_host_address.