diff --git a/include/cc_bstring.h b/include/cc_bstring.h index 18cfda558..86c1aadb7 100644 --- a/include/cc_bstring.h +++ b/include/cc_bstring.h @@ -170,6 +170,7 @@ void bstring_free(struct bstring **bstring); /* bstring to uint conversion */ rstatus_i bstring_atou64(uint64_t *u64, struct bstring *str); +rstatus_i bstring_atoi64(int64_t *i64, struct bstring *str); #ifdef __cplusplus } diff --git a/src/cc_bstring.c b/src/cc_bstring.c index efa51949f..68374423c 100644 --- a/src/cc_bstring.c +++ b/src/cc_bstring.c @@ -113,6 +113,46 @@ bstring_compare(const struct bstring *s1, const struct bstring *s2) return cc_bcmp(s1->data, s2->data, s1->len); } +rstatus_i +bstring_atoi64(int64_t *i64, struct bstring *str) +{ + uint32_t offset = 0; + uint8_t c; + int64_t sign = 1; + + if (str->len == 0 || str->len >= CC_INT64_MAXLEN) { + return CC_ERROR; + } + + if (*str->data == '-') { + offset = 1; + sign = -1; + } + + for (*i64 = 0LL; offset < str->len; offset++) { + c = *(str->data + offset); + if (c < '0' || c > '9') { + return CC_ERROR; + } + + // overflow check + if (offset == CC_INT64_MAXLEN - 2) { + if (sign < 0 && *i64 == INT64_MIN / 10 && + c - '0' > (uint64_t)(-INT64_MIN) % 10) { + return CC_ERROR; + } + if (sign > 0 && *i64 == INT64_MAX / 10 && + c - '0' > INT64_MAX % 10) { + return CC_ERROR; + } + } + + *i64 = *i64 * 10LL + sign * (int64_t)(c - '0'); + } + + return CC_OK; +} + rstatus_i bstring_atou64(uint64_t *u64, struct bstring *str) { diff --git a/test/bstring/check_bstring.c b/test/bstring/check_bstring.c index 313e7196b..e35fa61aa 100644 --- a/test/bstring/check_bstring.c +++ b/test/bstring/check_bstring.c @@ -119,6 +119,37 @@ START_TEST(test_strcmp) END_TEST +START_TEST(test_atoi64) +{ + int64_t val; + struct bstring bstr; + char int64[CC_INT64_MAXLEN]; + + test_reset(); + + ck_assert_int_eq(bstring_atoi64(&val, &str2bstr("foo")), CC_ERROR); + + ck_assert_int_eq(bstring_atoi64(&val, &str2bstr("123")), CC_OK); + ck_assert_uint_eq(val, 123); + ck_assert_int_eq(bstring_atoi64(&val, &str2bstr("-123")), CC_OK); + ck_assert_uint_eq(val, -123); + + sprintf(int64, "%"PRIi64, INT64_MAX); + bstring_init(&bstr); + ck_assert_int_eq(bstring_copy(&bstr, int64, strlen(int64)), CC_OK); + ck_assert_int_eq(bstring_atoi64(&val, &bstr), CC_OK); + ck_assert_int_eq(val, INT64_MAX); + bstring_deinit(&bstr); + + sprintf(int64, "%"PRIi64, INT64_MIN); + bstring_init(&bstr); + ck_assert_int_eq(bstring_copy(&bstr, int64, strlen(int64)), CC_OK); + ck_assert_int_eq(bstring_atoi64(&val, &bstr), CC_OK); + ck_assert_int_eq(val, INT64_MIN); + bstring_deinit(&bstr); +} +END_TEST + START_TEST(test_atou64) { uint64_t val; @@ -189,6 +220,7 @@ bstring_suite(void) tcase_add_test(tc_bstring, test_copy); tcase_add_test(tc_bstring, test_compare); tcase_add_test(tc_bstring, test_strcmp); + tcase_add_test(tc_bstring, test_atoi64); tcase_add_test(tc_bstring, test_atou64); tcase_add_test(tc_bstring, test_bstring_alloc_and_free);