boot: Add parse_number8/16
This commit is contained in:
@@ -239,6 +239,38 @@ bool efi_fnmatch(const char16_t *pattern, const char16_t *haystack) {
|
||||
return efi_fnmatch_internal(pattern, haystack, 32);
|
||||
}
|
||||
|
||||
#define DEFINE_PARSE_NUMBER(type, name) \
|
||||
bool name(const type *s, uint64_t *ret_u, const type **ret_tail) { \
|
||||
assert(ret_u); \
|
||||
\
|
||||
if (!s) \
|
||||
return false; \
|
||||
\
|
||||
/* Need at least one digit. */ \
|
||||
if (*s < '0' || *s > '9') \
|
||||
return false; \
|
||||
\
|
||||
uint64_t u = 0; \
|
||||
while (*s >= '0' && *s <= '9') { \
|
||||
if (__builtin_mul_overflow(u, 10, &u)) \
|
||||
return false; \
|
||||
if (__builtin_add_overflow(u, *s - '0', &u)) \
|
||||
return false; \
|
||||
s++; \
|
||||
} \
|
||||
\
|
||||
if (!ret_tail && *s != '\0') \
|
||||
return false; \
|
||||
\
|
||||
*ret_u = u; \
|
||||
if (ret_tail) \
|
||||
*ret_tail = s; \
|
||||
return true; \
|
||||
}
|
||||
|
||||
DEFINE_PARSE_NUMBER(char, parse_number8);
|
||||
DEFINE_PARSE_NUMBER(char16_t, parse_number16);
|
||||
|
||||
int efi_memcmp(const void *p1, const void *p2, size_t n) {
|
||||
const uint8_t *up1 = p1, *up2 = p2;
|
||||
int r;
|
||||
|
||||
@@ -101,6 +101,9 @@ static inline char16_t *xstrdup16(const char16_t *s) {
|
||||
|
||||
bool efi_fnmatch(const char16_t *pattern, const char16_t *haystack);
|
||||
|
||||
bool parse_number8(const char *s, uint64_t *ret_u, const char **ret_tail);
|
||||
bool parse_number16(const char16_t *s, uint64_t *ret_u, const char16_t **ret_tail);
|
||||
|
||||
#ifdef SD_BOOT
|
||||
/* The compiler normally has knowledge about standard functions such as memcmp, but this is not the case when
|
||||
* compiling with -ffreestanding. By referring to builtins, the compiler can check arguments and do
|
||||
|
||||
@@ -371,6 +371,60 @@ TEST(efi_fnmatch) {
|
||||
TEST_FNMATCH_ONE("?a*b[.-0]c", "/a/b/c", true);
|
||||
}
|
||||
|
||||
TEST(parse_number8) {
|
||||
uint64_t u;
|
||||
const char *tail;
|
||||
|
||||
assert_se(!parse_number8(NULL, &u, NULL));
|
||||
assert_se(!parse_number8("", &u, NULL));
|
||||
assert_se(!parse_number8("a1", &u, NULL));
|
||||
assert_se(!parse_number8("1a", &u, NULL));
|
||||
assert_se(!parse_number8("-42", &u, NULL));
|
||||
assert_se(!parse_number8("18446744073709551616", &u, NULL));
|
||||
|
||||
assert_se(parse_number8("0", &u, NULL));
|
||||
assert_se(u == 0);
|
||||
assert_se(parse_number8("1", &u, NULL));
|
||||
assert_se(u == 1);
|
||||
assert_se(parse_number8("999", &u, NULL));
|
||||
assert_se(u == 999);
|
||||
assert_se(parse_number8("18446744073709551615", &u, NULL));
|
||||
assert_se(u == UINT64_MAX);
|
||||
assert_se(parse_number8("42", &u, &tail));
|
||||
assert_se(u == 42);
|
||||
assert_se(streq8(tail, ""));
|
||||
assert_se(parse_number8("54321rest", &u, &tail));
|
||||
assert_se(u == 54321);
|
||||
assert_se(streq8(tail, "rest"));
|
||||
}
|
||||
|
||||
TEST(parse_number16) {
|
||||
uint64_t u;
|
||||
const char16_t *tail;
|
||||
|
||||
assert_se(!parse_number16(NULL, &u, NULL));
|
||||
assert_se(!parse_number16(u"", &u, NULL));
|
||||
assert_se(!parse_number16(u"a1", &u, NULL));
|
||||
assert_se(!parse_number16(u"1a", &u, NULL));
|
||||
assert_se(!parse_number16(u"-42", &u, NULL));
|
||||
assert_se(!parse_number16(u"18446744073709551616", &u, NULL));
|
||||
|
||||
assert_se(parse_number16(u"0", &u, NULL));
|
||||
assert_se(u == 0);
|
||||
assert_se(parse_number16(u"1", &u, NULL));
|
||||
assert_se(u == 1);
|
||||
assert_se(parse_number16(u"999", &u, NULL));
|
||||
assert_se(u == 999);
|
||||
assert_se(parse_number16(u"18446744073709551615", &u, NULL));
|
||||
assert_se(u == UINT64_MAX);
|
||||
assert_se(parse_number16(u"42", &u, &tail));
|
||||
assert_se(u == 42);
|
||||
assert_se(streq16(tail, u""));
|
||||
assert_se(parse_number16(u"54321rest", &u, &tail));
|
||||
assert_se(u == 54321);
|
||||
assert_se(streq16(tail, u"rest"));
|
||||
}
|
||||
|
||||
TEST(efi_memcmp) {
|
||||
assert_se(efi_memcmp(NULL, NULL, 0) == 0);
|
||||
assert_se(efi_memcmp(NULL, NULL, 1) == 0);
|
||||
|
||||
Reference in New Issue
Block a user