string: Add function to convert from string to unsigned ints

Signed-off-by: Otavio Pontes <otavio.pontes@intel.com>
This commit is contained in:
Otavio Pontes
2020-04-28 12:13:28 -07:00
parent fb43852440
commit 5f67a46354
3 changed files with 186 additions and 0 deletions
+39
View File
@@ -165,6 +165,45 @@ int str_to_int(const char *str, int *value)
return 0;
}
int str_to_uint_endptr(const char *str, char **endptr, unsigned int *value)
{
long num;
int err;
errno = 0;
num = strtol(str, endptr, 10);
err = -errno;
/* When the return value of strtol overflows the int type, don't overflow
* and return an overflow error code. */
if (num > UINT_MAX) {
num = UINT_MAX;
err = -ERANGE;
} else if (num < 0) {
num = 0;
err = -ERANGE;
}
*value = (unsigned int)num;
return err;
}
int str_to_uint(const char *str, unsigned int *value)
{
char *endptr;
int err = str_to_uint_endptr(str, &endptr, value);
if (err) {
return err;
}
if (*endptr != '\0' && !isspace(*endptr)) {
return -EINVAL;
}
return 0;
}
char *str_to_lower(const char *str)
{
char *str_lower = malloc_or_die(str_len(str) + 1);
+28
View File
@@ -103,6 +103,34 @@ int str_to_int(const char *str, int *value);
*/
int str_to_int_endptr(const char *str, char **endptr, int *value);
/**
* Safely convert string to an unsigned integer avoiding overflows
*
* The strtol function is commonly used to convert a string to a number and
* the result is frequently stored in an int type, but type casting a long to
* an int can cause overflows.
*
* This function returns negative error codes based on the errno table:
* -ERANGE is returned when the string is out of range for int value
* -EINVAL is returned when the string isn't a valid number or has any invalid
* trailing character.
*/
int str_to_uint(const char *str, unsigned int *value);
/**
* Safely convert and string to unsigned integer avoiding overflows.
*
* The strtol function is commonly used to convert a string to a number and
* the result is frequently stored in an int type, but type casting a long to
* an int can cause overflows.
*
* This function returns negative error codes based on the errno table:
* -ERANGE is returned when the string is out of range for int value
*
* endptr is set with the value of the first invalid character in the string.
*/
int str_to_uint_endptr(const char *str, char **endptr, unsigned int *value);
/**
* Creates a new string converting all characters from the original string
* to its lower case values.
+119
View File
@@ -239,6 +239,123 @@ static void test_str_to_int_endptr()
}
static void test_str_to_uint()
{
char tmp_str[100];
int err;
unsigned int value = 0;
size_t i;
// test some standard values
char *str_values[] = { "0", "-0", "123", "000123" };
unsigned int values[] = { 0, 0, 123, 123 };
for (i = 0; i < sizeof(values) / sizeof(int); i++) {
value = 0xffffff;
err = str_to_uint(str_values[i], &value);
check(err == 0);
check(value == values[i]);
}
// test limits
value = 0xffffff;
snprintf(tmp_str, sizeof(tmp_str), "%u", UINT_MAX - 1);
err = str_to_uint(tmp_str, &value);
check(err == 0);
check(value == UINT_MAX - 1);
value = 0xffffff;
snprintf(tmp_str, sizeof(tmp_str), "%u", UINT_MAX);
err = str_to_uint(tmp_str, &value);
check(err == 0);
check(value == UINT_MAX);
// test errors
value = 0xffffff;
snprintf(tmp_str, sizeof(tmp_str), "%ld", (long)UINT_MAX + 1);
err = str_to_uint(tmp_str, &value);
check(err == -ERANGE);
check(value == UINT_MAX);
value = 0xffffff;
snprintf(tmp_str, sizeof(tmp_str), "%ld", (long)UINT_MAX + 1000);
err = str_to_uint(tmp_str, &value);
check(err == -ERANGE);
check(value == UINT_MAX);
// Negative
value = 0xffffff;
snprintf(tmp_str, sizeof(tmp_str), "%d", -1);
err = str_to_uint(tmp_str, &value);
check(err == -ERANGE);
check(value == 0);
value = 0xffffff;
snprintf(tmp_str, sizeof(tmp_str), "%d", INT_MIN);
err = str_to_uint(tmp_str, &value);
check(err == -ERANGE);
check(value == 0);
// test EINVAL errors
char *einval_errors[] = { "string", "123.456", "123a", "a123a", "456b123", "0x12345", "4f"};
for (i = 0; i < sizeof(einval_errors) / sizeof(char *); i++) {
err = str_to_uint(einval_errors[i], &value);
check(err == -EINVAL);
}
}
static void test_str_to_uint_endptr()
{
char *endptr;
int err;
unsigned int value = 0;
// Test endptr trailing chars
value = 0xffffff;
endptr = NULL;
err = str_to_uint_endptr("123.456", &endptr, &value);
check(err == 0);
check(value == 123);
check(endptr != NULL);
check(*endptr == '.');
value = 0xffffff;
endptr = NULL;
err = str_to_uint_endptr("123a456", &endptr, &value);
check(err == 0);
check(value == 123);
check(endptr != NULL);
check(*endptr == 'a');
value = 0xffffff;
endptr = NULL;
err = str_to_uint_endptr("123testing456", &endptr, &value);
check(err == 0);
check(value == 123);
check(endptr != NULL);
check(*endptr == 't');
value = 0xffffff;
endptr = NULL;
err = str_to_uint_endptr("123-456", &endptr, &value);
check(err == 0);
check(value == 123);
check(endptr != NULL);
check(*endptr == '-');
value = 0xffffff;
endptr = NULL;
err = str_to_uint_endptr("-123.456", &endptr, &value);
check(err == -ERANGE);
value = 0xffffff;
endptr = NULL;
err = str_to_uint_endptr("-123a456", &endptr, &value);
check(err == -ERANGE);
}
void test_str_join()
{
struct list *str_list = NULL;
@@ -280,6 +397,8 @@ int main() {
test_str_to_int();
test_str_to_int_endptr();
test_str_join();
test_str_to_uint();
test_str_to_uint_endptr();
return 0;
}