diff options
author | Thomas Haller <thaller@redhat.com> | 2014-03-18 11:42:31 +0100 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2014-04-10 16:32:20 +0200 |
commit | 80d2d0ebe1adca2439829e3637d0f58808251a05 (patch) | |
tree | 0775d5ad8de2ee727130b2f8900fbbea101b8f35 | |
parent | cbee213781a1e17651ae97b1ff3f8566aa708a84 (diff) |
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>
-rw-r--r-- | src/NetworkManagerUtils.c | 58 | ||||
-rw-r--r-- | src/tests/test-general.c | 134 |
2 files changed, 151 insertions, 41 deletions
diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c index 0fc35c2d96..17116ee6cb 100644 --- a/src/NetworkManagerUtils.c +++ b/src/NetworkManagerUtils.c @@ -878,11 +878,11 @@ gint64 nm_utils_ascii_str_to_int64 (const char *str, guint base, gint64 min, gint64 max, gint64 fallback) { gint64 v; - char *end; - char *str_free = NULL; + size_t len; + char buf[64], *s, *str_free = NULL; if (str) { - while (str[0] && g_ascii_isspace (str[0])) + while (g_ascii_isspace (str[0])) str++; } 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; } - if (g_ascii_isspace (str[strlen (str) - 1])) { - str_free = g_strdup (str); - g_strstrip (str_free); - str = str_free; - } + len = strlen (str); + if (g_ascii_isspace (str[--len])) { + /* backward search the first non-ws character. + * We already know that str[0] is non-ws. */ + while (g_ascii_isspace (str[--len])) + ; - errno = 0; - v = g_ascii_strtoll (str, &end, base); + /* str[len] is now the last non-ws character... */ + len++; - if (errno != 0) { - g_free (str_free); - return fallback; - } + if (len >= sizeof (buf)) + s = str_free = g_malloc (len + 1); + else + s = buf; - if (end[0] != 0) { - g_free (str_free); - errno = EINVAL; - return fallback; + 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; } - g_free (str_free); - if (v > max || v < min) { + errno = 0; + v = g_ascii_strtoll (str, &s, base); + + if (errno != 0) + v = fallback; + else if (s[0] != 0) { + errno = EINVAL; + v = fallback; + } else if (v > max || v < min) { errno = ERANGE; - return fallback; + v = fallback; } + if (G_UNLIKELY (str_free)) + g_free (str_free); return v; } diff --git a/src/tests/test-general.c b/src/tests/test-general.c index 4711bc5f30..ecbda9a72b 100644 --- a/src/tests/test-general.c +++ b/src/tests/test-general.c @@ -27,38 +27,132 @@ 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) +test_nm_utils_ascii_str_to_int64_check (const char *str, guint base, gint64 min, + gint64 max, gint64 fallback, int exp_errno, + gint64 exp_val) { gint64 v; - errno = 0; + errno = 1; v = nm_utils_ascii_str_to_int64 (str, base, min, max, fallback); g_assert_cmpint (errno, ==, exp_errno); 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 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 (" 1x ", 10, 0, 10000, -1, EINVAL, -1); - 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 (" 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 ", 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 (" 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 (" 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+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 ("\r\n\t10000\t\n\t\n", 10, 0, 10000, -1, 0, 10000); + 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 ("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 ("10001", 10, 0, 10000, -1, ERANGE, -1); + 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 ("9223372036854775807", 10, 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, 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 ("-9223372036854775809", 10, G_MININT64, 0, -2, ERANGE, -2); + 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. |