|
|
3a204fb |
From e82a1473dac1c7068f5d30f34bc07360ab70881d Mon Sep 17 00:00:00 2001
|
|
|
3a204fb |
From: Jakub Filak <jfilak@redhat.com>
|
|
|
3a204fb |
Date: Thu, 4 Jun 2015 16:53:18 +0200
|
|
|
3a204fb |
Subject: [PATCH] lib: add utility functions parsing numbers
|
|
|
3a204fb |
|
|
|
3a204fb |
The x* variants dies on errors but we do not want to do that in some
|
|
|
3a204fb |
cases.
|
|
|
3a204fb |
|
|
|
3a204fb |
Signed-off-by: Jakub Filak <jfilak@redhat.com>
|
|
|
3a204fb |
---
|
|
|
3a204fb |
src/include/internal_libreport.h | 6 +++
|
|
|
3a204fb |
src/lib/xatonum.c | 95 ++++++++++++++++++++++++++-------
|
|
|
3a204fb |
tests/xfuncs.at | 110 +++++++++++++++++++++++++++++++++++++++
|
|
|
3a204fb |
3 files changed, 192 insertions(+), 19 deletions(-)
|
|
|
3a204fb |
|
|
|
3a204fb |
diff --git a/src/include/internal_libreport.h b/src/include/internal_libreport.h
|
|
|
3a204fb |
index 25af681..4f8ea26 100644
|
|
|
3a204fb |
--- a/src/include/internal_libreport.h
|
|
|
3a204fb |
+++ b/src/include/internal_libreport.h
|
|
|
3a204fb |
@@ -241,8 +241,12 @@ const uint8_t *str_to_sha1(uint8_t result[SHA1_RESULT_LEN], const char *str);
|
|
|
3a204fb |
const char *str_to_sha1str(char result[SHA1_RESULT_LEN*2 + 1], const char *str);
|
|
|
3a204fb |
|
|
|
3a204fb |
|
|
|
3a204fb |
+#define try_atou libreport_try_atou
|
|
|
3a204fb |
+int try_atou(const char *numstr, unsigned *value);
|
|
|
3a204fb |
#define xatou libreport_xatou
|
|
|
3a204fb |
unsigned xatou(const char *numstr);
|
|
|
3a204fb |
+#define try_atoi libreport_try_atoi
|
|
|
3a204fb |
+int try_atoi(const char *numstr, int *value);
|
|
|
3a204fb |
#define xatoi libreport_xatoi
|
|
|
3a204fb |
int xatoi(const char *numstr);
|
|
|
3a204fb |
/* Using xatoi() instead of naive atoi() is not always convenient -
|
|
|
3a204fb |
@@ -252,6 +256,8 @@ int xatoi(const char *numstr);
|
|
|
3a204fb |
* It should really be named xatoi_nonnegative (since it allows 0),
|
|
|
3a204fb |
* but that would be too long.
|
|
|
3a204fb |
*/
|
|
|
3a204fb |
+#define try_atoi_positive libreport_try_atoi_positive
|
|
|
3a204fb |
+int try_atoi_positive(const char *numstr, int *value);
|
|
|
3a204fb |
#define xatoi_positive libreport_xatoi_positive
|
|
|
3a204fb |
int xatoi_positive(const char *numstr);
|
|
|
3a204fb |
|
|
|
3a204fb |
diff --git a/src/lib/xatonum.c b/src/lib/xatonum.c
|
|
|
3a204fb |
index 71b0247..510d766 100644
|
|
|
3a204fb |
--- a/src/lib/xatonum.c
|
|
|
3a204fb |
+++ b/src/lib/xatonum.c
|
|
|
3a204fb |
@@ -22,44 +22,101 @@
|
|
|
3a204fb |
*/
|
|
|
3a204fb |
#include "internal_libreport.h"
|
|
|
3a204fb |
|
|
|
3a204fb |
-unsigned xatou(const char *numstr)
|
|
|
3a204fb |
+int try_atou(const char *numstr, unsigned *value)
|
|
|
3a204fb |
{
|
|
|
3a204fb |
+ int ret = 0;
|
|
|
3a204fb |
unsigned long r;
|
|
|
3a204fb |
int old_errno;
|
|
|
3a204fb |
char *e;
|
|
|
3a204fb |
|
|
|
3a204fb |
+ old_errno = errno;
|
|
|
3a204fb |
if (*numstr < '0' || *numstr > '9')
|
|
|
3a204fb |
- goto inval;
|
|
|
3a204fb |
+ {
|
|
|
3a204fb |
+ ret = -EINVAL;
|
|
|
3a204fb |
+ goto finito;
|
|
|
3a204fb |
+ }
|
|
|
3a204fb |
|
|
|
3a204fb |
- old_errno = errno;
|
|
|
3a204fb |
errno = 0;
|
|
|
3a204fb |
r = strtoul(numstr, &e, 10);
|
|
|
3a204fb |
- if (errno || numstr == e || *e != '\0' || r > UINT_MAX)
|
|
|
3a204fb |
- goto inval; /* error / no digits / illegal trailing chars */
|
|
|
3a204fb |
+ if (errno || numstr == e || *e != '\0')
|
|
|
3a204fb |
+ {
|
|
|
3a204fb |
+ ret = errno != 0 ? -errno : -EINVAL; /* error / no digits / illegal trailing chars */
|
|
|
3a204fb |
+ goto finito;
|
|
|
3a204fb |
+ }
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ /* check range */
|
|
|
3a204fb |
+ if (r > UINT_MAX)
|
|
|
3a204fb |
+ {
|
|
|
3a204fb |
+ /* In this case errno is probably 0, because UINT_MAX < ULONG_MAX, thus
|
|
|
3a204fb |
+ * strtoul should not return an error */
|
|
|
3a204fb |
+ ret = -ERANGE;
|
|
|
3a204fb |
+ goto finito;
|
|
|
3a204fb |
+ }
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ *value = r;
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+finito:
|
|
|
3a204fb |
errno = old_errno; /* Ok. So restore errno. */
|
|
|
3a204fb |
- return r;
|
|
|
3a204fb |
+ return ret;
|
|
|
3a204fb |
+}
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+unsigned xatou(const char *numstr)
|
|
|
3a204fb |
+{
|
|
|
3a204fb |
+ unsigned value = (unsigned)-1;
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ if (try_atou(numstr, &value) != 0)
|
|
|
3a204fb |
+ error_msg_and_die("expected number in range <0, %d>: '%s'", UINT_MAX, numstr);
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ return value;
|
|
|
3a204fb |
+}
|
|
|
3a204fb |
|
|
|
3a204fb |
-inval:
|
|
|
3a204fb |
- error_msg_and_die("invalid number '%s'", numstr);
|
|
|
3a204fb |
+int try_atoi_positive(const char *numstr, int *value)
|
|
|
3a204fb |
+{
|
|
|
3a204fb |
+ unsigned tmp;
|
|
|
3a204fb |
+ int r = try_atou(numstr, &tmp);
|
|
|
3a204fb |
+ if (r != 0)
|
|
|
3a204fb |
+ return r;
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ if (tmp > (unsigned)INT_MAX)
|
|
|
3a204fb |
+ return -ERANGE;
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ *value = (int)tmp;
|
|
|
3a204fb |
+ return 0;
|
|
|
3a204fb |
}
|
|
|
3a204fb |
|
|
|
3a204fb |
int xatoi_positive(const char *numstr)
|
|
|
3a204fb |
{
|
|
|
3a204fb |
- unsigned r = xatou(numstr);
|
|
|
3a204fb |
- if (r > (unsigned)INT_MAX)
|
|
|
3a204fb |
- error_msg_and_die("invalid number '%s'", numstr);
|
|
|
3a204fb |
- return r;
|
|
|
3a204fb |
+ int value = INT_MIN;
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ if (try_atoi_positive(numstr, &value) != 0)
|
|
|
3a204fb |
+ error_msg_and_die("expected number in range <0, %d>: '%s'", INT_MAX, numstr);
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ return value;
|
|
|
3a204fb |
+}
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+int try_atoi(const char *numstr, int *value)
|
|
|
3a204fb |
+{
|
|
|
3a204fb |
+ if (*numstr != '-')
|
|
|
3a204fb |
+ return try_atoi_positive(numstr, value);
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ unsigned tmp;
|
|
|
3a204fb |
+ int r = try_atou(numstr + 1, &tmp);
|
|
|
3a204fb |
+ if (r < 0)
|
|
|
3a204fb |
+ return r;
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ if (tmp > (unsigned)INT_MAX + 1)
|
|
|
3a204fb |
+ return -ERANGE;
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ *value = - (int)tmp;
|
|
|
3a204fb |
+ return 0;
|
|
|
3a204fb |
}
|
|
|
3a204fb |
|
|
|
3a204fb |
int xatoi(const char *numstr)
|
|
|
3a204fb |
{
|
|
|
3a204fb |
- unsigned r;
|
|
|
3a204fb |
+ int value = INT_MIN;
|
|
|
3a204fb |
|
|
|
3a204fb |
- if (*numstr != '-')
|
|
|
3a204fb |
- return xatoi_positive(numstr);
|
|
|
3a204fb |
+ if (try_atoi(numstr, &value))
|
|
|
3a204fb |
+ error_msg_and_die("expected number in range <%d, %d>: '%s'", INT_MIN, INT_MAX, numstr);
|
|
|
3a204fb |
|
|
|
3a204fb |
- r = xatou(numstr + 1);
|
|
|
3a204fb |
- if (r > (unsigned)INT_MAX + 1)
|
|
|
3a204fb |
- error_msg_and_die("invalid number '%s'", numstr);
|
|
|
3a204fb |
- return - (int)r;
|
|
|
3a204fb |
+ return (int)value;
|
|
|
3a204fb |
}
|
|
|
3a204fb |
diff --git a/tests/xfuncs.at b/tests/xfuncs.at
|
|
|
3a204fb |
index d7e947a..dbcc602 100644
|
|
|
3a204fb |
--- a/tests/xfuncs.at
|
|
|
3a204fb |
+++ b/tests/xfuncs.at
|
|
|
3a204fb |
@@ -54,3 +54,113 @@ int main(void)
|
|
|
3a204fb |
}
|
|
|
3a204fb |
|
|
|
3a204fb |
]])
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+## ------------- ##
|
|
|
3a204fb |
+## parse_numbers ##
|
|
|
3a204fb |
+## ------------- ##
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+AT_TESTFUN([parse_numbers],
|
|
|
3a204fb |
+[[#include "internal_libreport.h"
|
|
|
3a204fb |
+#include <assert.h>
|
|
|
3a204fb |
+#include <string.h>
|
|
|
3a204fb |
+#include <stdio.h>
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+int main(void)
|
|
|
3a204fb |
+{
|
|
|
3a204fb |
+ g_verbose=3;
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ /* 1. not a number - ERROR
|
|
|
3a204fb |
+ * 2. a number with an alpha suffix - ERROR
|
|
|
3a204fb |
+ * 3. out of range number - ERROR
|
|
|
3a204fb |
+ * a. max + 1 - ERROR
|
|
|
3a204fb |
+ * b. min - 1 - ERROR
|
|
|
3a204fb |
+ * c. max - OK
|
|
|
3a204fb |
+ * d. min - OK
|
|
|
3a204fb |
+ */
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ {
|
|
|
3a204fb |
+ unsigned uint_value = 12345;
|
|
|
3a204fb |
+ assert(try_atou("foo", &uint_value) != 0);
|
|
|
3a204fb |
+ assert(uint_value == 12345);
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ assert(try_atou("foo54321", &uint_value) != 0);
|
|
|
3a204fb |
+ assert(uint_value == 12345);
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ char buf[sizeof(unsigned long) * 3 + 1];
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ snprintf(buf, sizeof(buf), "%lu", 1LU + UINT_MAX);
|
|
|
3a204fb |
+ assert(try_atou(buf, &uint_value) != 0 || !"Above UINT_MAX");
|
|
|
3a204fb |
+ assert(uint_value == 12345);
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ assert(try_atou("-1", &uint_value) != 0);
|
|
|
3a204fb |
+ assert(uint_value == 12345);
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ snprintf(buf, sizeof(buf), "%lu", (long unsigned)UINT_MAX);
|
|
|
3a204fb |
+ assert(try_atou(buf, &uint_value) == 0);
|
|
|
3a204fb |
+ assert(uint_value == UINT_MAX);
|
|
|
3a204fb |
+ assert(xatou(buf) == UINT_MAX);
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ assert(try_atou("0", &uint_value) == 0);
|
|
|
3a204fb |
+ assert(uint_value == 0);
|
|
|
3a204fb |
+ assert(xatou("0") == 0);
|
|
|
3a204fb |
+ }
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ {
|
|
|
3a204fb |
+ int int_value = 12345;
|
|
|
3a204fb |
+ assert(try_atoi("foo", &int_value) != 0);
|
|
|
3a204fb |
+ assert(int_value == 12345);
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ assert(try_atoi("foo54321", &int_value) != 0);
|
|
|
3a204fb |
+ assert(int_value == 12345);
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ char buf[sizeof(long) * 3 + 1];
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ snprintf(buf, sizeof(buf), "%ld", 1L + INT_MAX);
|
|
|
3a204fb |
+ assert(try_atoi(buf, &int_value) != 0 || !"Parse INT_MAX+1");
|
|
|
3a204fb |
+ assert(int_value == 12345 || !"Above INT_MAX");
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ snprintf(buf, sizeof(buf), "%ld", -1L + INT_MIN);
|
|
|
3a204fb |
+ assert(try_atoi(buf, &int_value) != 0 || !"Parse INT_MIN-1");
|
|
|
3a204fb |
+ assert(int_value == 12345 || !"Belove INT_MIN");
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ snprintf(buf, sizeof(buf), "%ld", (long unsigned)INT_MAX);
|
|
|
3a204fb |
+ assert(try_atoi(buf, &int_value) == 0 || !"Parse INT_MAX");
|
|
|
3a204fb |
+ assert(int_value == INT_MAX);
|
|
|
3a204fb |
+ assert(xatoi(buf) == INT_MAX);
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ snprintf(buf, sizeof(buf), "%ld", (long unsigned)INT_MIN);
|
|
|
3a204fb |
+ assert(try_atoi(buf, &int_value) == 0 || !"Parse INT_MIN");
|
|
|
3a204fb |
+ assert(int_value == INT_MIN);
|
|
|
3a204fb |
+ assert(xatoi(buf) == INT_MIN);
|
|
|
3a204fb |
+ }
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ {
|
|
|
3a204fb |
+ int positive_value = 12345;
|
|
|
3a204fb |
+ assert(try_atoi_positive("foo", &positive_value) != 0);
|
|
|
3a204fb |
+ assert(positive_value == 12345);
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ assert(try_atoi_positive("foo54321", &positive_value) != 0);
|
|
|
3a204fb |
+ assert(positive_value == 12345);
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ char buf[sizeof(long) * 3 + 1];
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ snprintf(buf, sizeof(buf), "%ld", 1L + INT_MAX);
|
|
|
3a204fb |
+ assert(try_atoi_positive(buf, &positive_value) != 0);
|
|
|
3a204fb |
+ assert(positive_value == 12345 || !"Above INT_MAX");
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ assert(try_atoi_positive("-1", &positive_value) != 0);
|
|
|
3a204fb |
+ assert(positive_value == 12345 || !"After -1");
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ snprintf(buf, sizeof(buf), "%ld", (long unsigned)INT_MAX);
|
|
|
3a204fb |
+ assert(try_atoi_positive(buf, &positive_value) == 0 || !"Parse INT_MAX");
|
|
|
3a204fb |
+ assert(positive_value == INT_MAX);
|
|
|
3a204fb |
+ assert(xatoi_positive(buf) == INT_MAX);
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ assert(try_atoi_positive("0", &positive_value) == 0);
|
|
|
3a204fb |
+ assert(positive_value == 0);
|
|
|
3a204fb |
+ assert(xatoi_positive("0") == 0);
|
|
|
3a204fb |
+ }
|
|
|
3a204fb |
+
|
|
|
3a204fb |
+ return 0;
|
|
|
3a204fb |
+}
|
|
|
3a204fb |
+]])
|
|
|
3a204fb |
--
|
|
|
3a204fb |
2.1.0
|
|
|
3a204fb |
|