util: Use g_ascii_strtoll

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@redhat.com>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
This commit is contained in:
Martin Kletzander 2023-03-31 14:44:11 +02:00
parent fd340227a7
commit 2ed41d7cd9

View File

@ -35,7 +35,7 @@
VIR_LOG_INIT("util.string"); 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. Return 0 upon success; return -1 to indicate failure.
When END_PTR is NULL, the byte after the final valid digit must be NUL. 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 Otherwise, it's like strtol and lets the caller check any suffix for
@ -44,12 +44,12 @@ VIR_LOG_INIT("util.string");
int int
virStrToLong_i(char const *s, char **end_ptr, int base, int *result) virStrToLong_i(char const *s, char **end_ptr, int base, int *result)
{ {
long int val; long long val;
char *p; char *p;
int err; int err;
errno = 0; 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); err = (errno || (!end_ptr && *p) || p == s || (int) val != val);
if (end_ptr) if (end_ptr)
*end_ptr = p; *end_ptr = p;
@ -65,22 +65,22 @@ virStrToLong_i(char const *s, char **end_ptr, int base, int *result)
int int
virStrToLong_ui(char const *s, char **end_ptr, int base, unsigned int *result) virStrToLong_ui(char const *s, char **end_ptr, int base, unsigned int *result)
{ {
unsigned long int val; unsigned long long val;
char *p; char *p;
bool err = false; bool err = false;
errno = 0; 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 /* 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 * UINT_MAX regardless of whether long is 32-bit or 64-bit. But
* strtoul treats "-1" as ULONG_MAX, and going from ulong back * g_ascii_strtoull treats "-1" as ULLONG_MAX, and going from ullong back
* to uint differs depending on the size of long. */ * to uint differs depending on the size of uint. */
if (sizeof(long) > sizeof(int) && memchr(s, '-', p - s)) { if (memchr(s, '-', p - s)) {
if (-val > UINT_MAX) if (-val > UINT_MAX)
err = true; err = true;
else else
val &= 0xffffffff; val &= UINT_MAX;
} }
err |= (errno || (!end_ptr && *p) || p == s || (unsigned int) val != val); 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 int
virStrToLong_uip(char const *s, char **end_ptr, int base, unsigned int *result) virStrToLong_uip(char const *s, char **end_ptr, int base, unsigned int *result)
{ {
unsigned long int val; unsigned long long val;
char *p; char *p;
bool err = false; bool err = false;
errno = 0; errno = 0;
val = strtoul(s, &p, base); /* exempt from syntax-check */ val = g_ascii_strtoull(s, &p, base);
err = (memchr(s, '-', p - s) || err = (memchr(s, '-', p - s) ||
errno || (!end_ptr && *p) || p == s || (unsigned int) val != val); errno || (!end_ptr && *p) || p == s || (unsigned int) val != val);
if (end_ptr) if (end_ptr)
@ -121,13 +121,25 @@ virStrToLong_uip(char const *s, char **end_ptr, int base, unsigned int *result)
int int
virStrToLong_ul(char const *s, char **end_ptr, int base, unsigned long *result) virStrToLong_ul(char const *s, char **end_ptr, int base, unsigned long *result)
{ {
unsigned long int val; unsigned long long val;
char *p; char *p;
int err; bool err = false;
errno = 0; errno = 0;
val = strtoul(s, &p, base); /* exempt from syntax-check */ val = g_ascii_strtoull(s, &p, base);
err = (errno || (!end_ptr && *p) || p == s);
/* 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) if (end_ptr)
*end_ptr = p; *end_ptr = p;
if (err) if (err)
@ -142,14 +154,14 @@ int
virStrToLong_ulp(char const *s, char **end_ptr, int base, virStrToLong_ulp(char const *s, char **end_ptr, int base,
unsigned long *result) unsigned long *result)
{ {
unsigned long int val; unsigned long long val;
char *p; char *p;
int err; int err;
errno = 0; errno = 0;
val = strtoul(s, &p, base); /* exempt from syntax-check */ val = g_ascii_strtoull(s, &p, base);
err = (memchr(s, '-', p - s) || err = (memchr(s, '-', p - s) ||
errno || (!end_ptr && *p) || p == s); errno || (!end_ptr && *p) || p == s || (unsigned long) val != val);
if (end_ptr) if (end_ptr)
*end_ptr = p; *end_ptr = p;
if (err) if (err)
@ -167,7 +179,7 @@ virStrToLong_ll(char const *s, char **end_ptr, int base, long long *result)
int err; int err;
errno = 0; 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); err = (errno || (!end_ptr && *p) || p == s);
if (end_ptr) if (end_ptr)
*end_ptr = p; *end_ptr = p;
@ -189,7 +201,7 @@ virStrToLong_ull(char const *s, char **end_ptr, int base,
int err; int err;
errno = 0; 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); err = (errno || (!end_ptr && *p) || p == s);
if (end_ptr) if (end_ptr)
*end_ptr = p; *end_ptr = p;
@ -210,7 +222,7 @@ virStrToLong_ullp(char const *s, char **end_ptr, int base,
int err; int err;
errno = 0; errno = 0;
val = strtoull(s, &p, base); /* exempt from syntax-check */ val = g_ascii_strtoull(s, &p, base);
err = (memchr(s, '-', p - s) || err = (memchr(s, '-', p - s) ||
errno || (!end_ptr && *p) || p == s); errno || (!end_ptr && *p) || p == s);
if (end_ptr) if (end_ptr)