This has two main advantages:
- it parses the number with C locale explicitly
- it behaves the same on Windows as on Linux and BSD
both of which are wanted behaviours.
Signed-off-by: Martin Kletzander <mkletzan(a)redhat.com>
---
src/util/virstring.c | 54 +++++++++++++++++++++++++++-----------------
1 file changed, 33 insertions(+), 21 deletions(-)
diff --git a/src/util/virstring.c b/src/util/virstring.c
index 635685eed4a4..6b728ff04759 100644
--- a/src/util/virstring.c
+++ b/src/util/virstring.c
@@ -35,7 +35,7 @@
VIR_LOG_INIT("util.string");
-/* Like strtol, but produce an "int" result, and check more carefully.
+/* Like strtol with C locale, but produce an "int" result, and check more
carefully.
Return 0 upon success; return -1 to indicate failure.
When END_PTR is NULL, the byte after the final valid digit must be NUL.
Otherwise, it's like strtol and lets the caller check any suffix for
@@ -44,12 +44,12 @@ VIR_LOG_INIT("util.string");
int
virStrToLong_i(char const *s, char **end_ptr, int base, int *result)
{
- long int val;
+ long long val;
char *p;
int err;
errno = 0;
- val = strtol(s, &p, base); /* exempt from syntax-check */
+ val = g_ascii_strtoll(s, &p, base);
err = (errno || (!end_ptr && *p) || p == s || (int) val != val);
if (end_ptr)
*end_ptr = p;
@@ -65,22 +65,22 @@ virStrToLong_i(char const *s, char **end_ptr, int base, int *result)
int
virStrToLong_ui(char const *s, char **end_ptr, int base, unsigned int *result)
{
- unsigned long int val;
+ unsigned long long val;
char *p;
bool err = false;
errno = 0;
- val = strtoul(s, &p, base); /* exempt from syntax-check */
+ val = g_ascii_strtoull(s, &p, base);
/* This one's tricky. We _want_ to allow "-1" as shorthand for
* UINT_MAX regardless of whether long is 32-bit or 64-bit. But
- * strtoul treats "-1" as ULONG_MAX, and going from ulong back
- * to uint differs depending on the size of long. */
- if (sizeof(long) > sizeof(int) && memchr(s, '-', p - s)) {
+ * g_ascii_strtoull treats "-1" as ULLONG_MAX, and going from ullong back
+ * to uint differs depending on the size of uint. */
+ if (memchr(s, '-', p - s)) {
if (-val > UINT_MAX)
err = true;
else
- val &= 0xffffffff;
+ val &= UINT_MAX;
}
err |= (errno || (!end_ptr && *p) || p == s || (unsigned int) val != val);
@@ -97,12 +97,12 @@ virStrToLong_ui(char const *s, char **end_ptr, int base, unsigned int
*result)
int
virStrToLong_uip(char const *s, char **end_ptr, int base, unsigned int *result)
{
- unsigned long int val;
+ unsigned long long val;
char *p;
bool err = false;
errno = 0;
- val = strtoul(s, &p, base); /* exempt from syntax-check */
+ val = g_ascii_strtoull(s, &p, base);
err = (memchr(s, '-', p - s) ||
errno || (!end_ptr && *p) || p == s || (unsigned int) val != val);
if (end_ptr)
@@ -121,13 +121,25 @@ virStrToLong_uip(char const *s, char **end_ptr, int base, unsigned
int *result)
int
virStrToLong_ul(char const *s, char **end_ptr, int base, unsigned long *result)
{
- unsigned long int val;
+ unsigned long long val;
char *p;
- int err;
+ bool err = false;
errno = 0;
- val = strtoul(s, &p, base); /* exempt from syntax-check */
- err = (errno || (!end_ptr && *p) || p == s);
+ val = g_ascii_strtoull(s, &p, base);
+
+ /* This one's tricky. We _want_ to allow "-1" as shorthand for
+ * ULONG_MAX regardless of whether long is 32-bit or 64-bit. But
+ * g_ascii_strtoull treats "-1" as ULLONG_MAX, and going from ullong back
+ * to ulong differs depending on the size of ulong. */
+ if (memchr(s, '-', p - s)) {
+ if (-val > ULONG_MAX)
+ err = true;
+ else
+ val &= ULONG_MAX;
+ }
+
+ err |= (errno || (!end_ptr && *p) || p == s || (unsigned long) val != val);
if (end_ptr)
*end_ptr = p;
if (err)
@@ -142,14 +154,14 @@ int
virStrToLong_ulp(char const *s, char **end_ptr, int base,
unsigned long *result)
{
- unsigned long int val;
+ unsigned long long val;
char *p;
int err;
errno = 0;
- val = strtoul(s, &p, base); /* exempt from syntax-check */
+ val = g_ascii_strtoull(s, &p, base);
err = (memchr(s, '-', p - s) ||
- errno || (!end_ptr && *p) || p == s);
+ errno || (!end_ptr && *p) || p == s || (unsigned long) val != val);
if (end_ptr)
*end_ptr = p;
if (err)
@@ -167,7 +179,7 @@ virStrToLong_ll(char const *s, char **end_ptr, int base, long long
*result)
int err;
errno = 0;
- val = strtoll(s, &p, base); /* exempt from syntax-check */
+ val = g_ascii_strtoll(s, &p, base);
err = (errno || (!end_ptr && *p) || p == s);
if (end_ptr)
*end_ptr = p;
@@ -189,7 +201,7 @@ virStrToLong_ull(char const *s, char **end_ptr, int base,
int err;
errno = 0;
- val = strtoull(s, &p, base); /* exempt from syntax-check */
+ val = g_ascii_strtoull(s, &p, base);
err = (errno || (!end_ptr && *p) || p == s);
if (end_ptr)
*end_ptr = p;
@@ -210,7 +222,7 @@ virStrToLong_ullp(char const *s, char **end_ptr, int base,
int err;
errno = 0;
- val = strtoull(s, &p, base); /* exempt from syntax-check */
+ val = g_ascii_strtoull(s, &p, base);
err = (memchr(s, '-', p - s) ||
errno || (!end_ptr && *p) || p == s);
if (end_ptr)
--
2.41.0