aboutsummaryrefslogtreecommitdiffstats
path: root/libj2_str_to_j2u.c
diff options
context:
space:
mode:
Diffstat (limited to 'libj2_str_to_j2u.c')
-rw-r--r--libj2_str_to_j2u.c266
1 files changed, 24 insertions, 242 deletions
diff --git a/libj2_str_to_j2u.c b/libj2_str_to_j2u.c
index b7a1bc0..80c22c3 100644
--- a/libj2_str_to_j2u.c
+++ b/libj2_str_to_j2u.c
@@ -5,252 +5,13 @@
/* TODO Add man page */
-
-static int
-from_generic(const unsigned char *s, size_t slen, const unsigned char **end,
- const intmax_t symbols[256], unsigned radix, struct libj2_j2u *a)
-{
- const uintmax_t high_required_at = (UINTMAX_MAX - radix + 1U) / radix;
- uintmax_t radix_pow[9];
- uintmax_t v;
- size_t i, x;
-
- for (i = 0; i < slen; i++)
- if (symbols[s[i]] < 0)
- break;
- slen = i;
- *end = &s[slen];
-
- for (;;) {
- if (!slen)
- return 0;
- a->low *= (uintmax_t)radix;
- a->low += (uintmax_t)symbols[*s++];
- slen--;
- if (a->low > high_required_at) {
- if (!slen)
- return 0;
- break;
- }
- }
-
- radix_pow[0] = 1U;
- radix_pow[1] = (uintmax_t)radix;
- radix_pow[2] = (uintmax_t)radix * radix_pow[1];
- radix_pow[3] = (uintmax_t)radix * radix_pow[2];
- radix_pow[4] = (uintmax_t)radix * radix_pow[3];
- radix_pow[5] = (uintmax_t)radix * radix_pow[4];
- radix_pow[6] = (uintmax_t)radix * radix_pow[5];
- radix_pow[7] = (uintmax_t)radix * radix_pow[6];
- radix_pow[8] = (uintmax_t)radix * radix_pow[7];
-
- x = slen & 7U;
- x = x ? x : 8U;
- slen -= x;
- if (libj2_j2u_mul_ju_overflow(a, radix_pow[x]))
- return ERANGE;
- v = 0;
- switch (x) {
- while (slen) {
- slen -= 8U;
- if (libj2_j2u_mul_ju_overflow(a, radix_pow[8]))
- return ERANGE;
- v = 0;
- /* This isn't even a case, but GCC warns fall-through here */
- /* fall-through */
- case 8:
- v += (uintmax_t)symbols[*s++] * radix_pow[7]; /* fall-through */
- case 7:
- v += (uintmax_t)symbols[*s++] * radix_pow[6]; /* fall-through */
- case 6:
- v += (uintmax_t)symbols[*s++] * radix_pow[5]; /* fall-through */
- case 5:
- v += (uintmax_t)symbols[*s++] * radix_pow[4]; /* fall-through */
- case 4:
- v += (uintmax_t)symbols[*s++] * radix_pow[3]; /* fall-through */
- case 3:
- v += (uintmax_t)symbols[*s++] * radix_pow[2]; /* fall-through */
- case 2:
- v += (uintmax_t)symbols[*s++] * radix_pow[1]; /* fall-through */
- case 1:
- v += (uintmax_t)symbols[*s++];
- if (libj2_j2u_add_ju_overflow(a, v))
- return ERANGE;
- }
- }
-
- return 0;
-}
-
-
-static int
-from_power_of_two(const unsigned char *s, size_t slen, const unsigned char **end,
- const intmax_t symbols[256], unsigned radix, struct libj2_j2u *a)
-{
- uintmax_t high_required_at;
- uintmax_t v;
- unsigned shift, u, shift_mul[9];
- size_t i, x;
-
- shift = 0;
- for (u = radix; u >>= 1;)
- shift += 1U;
-
- for (i = 0; i < slen; i++)
- if (symbols[s[i]] < 0)
- break;
- slen = i;
- *end = &s[slen];
-
- high_required_at = (uintmax_t)1 << (LIBJ2_JU_BIT - shift);
- for (;;) {
- if (!slen)
- return 0;
- a->low <<= shift;
- a->low |= (uintmax_t)symbols[*s++];
- slen--;
- if (a->low >= high_required_at) {
- if (!slen)
- return 0;
- break;
- }
- }
-
- shift_mul[0] = 0U;
- shift_mul[1] = shift_mul[0] + shift;
- shift_mul[2] = shift_mul[1] + shift;
- shift_mul[3] = shift_mul[2] + shift;
- shift_mul[4] = shift_mul[3] + shift;
- shift_mul[5] = shift_mul[4] + shift;
- shift_mul[6] = shift_mul[5] + shift;
- shift_mul[7] = shift_mul[6] + shift;
- shift_mul[8] = shift_mul[7] + shift;
-
- x = slen & 7U;
- x = x ? x : 8U;
- slen -= x;
- if (libj2_j2u_lsh_overflow(a, shift_mul[x]))
- return ERANGE;
- v = 0;
- switch (x) {
- while (slen) {
- slen -= 8U;
- if (libj2_j2u_lsh_overflow(a, shift_mul[8]))
- return ERANGE;
- v = 0;
- /* This isn't even a case, but GCC warns fall-through here */
- /* fall-through */
- case 8:
- v |= (uintmax_t)symbols[*s++] << shift_mul[7]; /* fall-through */
- case 7:
- v |= (uintmax_t)symbols[*s++] << shift_mul[6]; /* fall-through */
- case 6:
- v |= (uintmax_t)symbols[*s++] << shift_mul[5]; /* fall-through */
- case 5:
- v |= (uintmax_t)symbols[*s++] << shift_mul[4]; /* fall-through */
- case 4:
- v |= (uintmax_t)symbols[*s++] << shift_mul[3]; /* fall-through */
- case 3:
- v |= (uintmax_t)symbols[*s++] << shift_mul[2]; /* fall-through */
- case 2:
- v |= (uintmax_t)symbols[*s++] << shift_mul[1]; /* fall-through */
- case 1:
- v |= (uintmax_t)symbols[*s++];
- libj2_j2u_or_ju(a, v);
- }
- }
-
- return 0;
-}
-
-
-int
-libj2_str_to_j2u(const char *str, size_t slen, char **end, const char *digits1,
- const char *digits2, struct libj2_j2u *a)
-{
- const unsigned char *s = (const unsigned char *)str;
- intmax_t symbols[256];
- unsigned i, radix = 0;
- struct libj2_j2u a_discard;
- char *end_discard;
- int r;
-
- if (!end)
- end = &end_discard;
- if (!a)
- a = &a_discard;
- libj2_j2u_zero(a);
-
- if (!s)
- slen = 0;
- if (!digits1) {
- digits1 = "0123456789";
- if (digits2)
- goto einval;
- }
-
- for (i = 0; i < sizeof(symbols) / sizeof(*symbols); i++)
- symbols[i] = -2;
- symbols[' '] = -1;
- symbols['\r'] = -1;
- symbols['\t'] = -1;
- symbols['\f'] = -1;
- symbols['\v'] = -1;
- symbols['\n'] = -1;
- symbols['+'] = -1;
- while (digits1[radix]) {
- if (symbols[(unsigned char)digits1[radix]] >= 0)
- goto einval;
- symbols[(unsigned char)digits1[radix]] = (intmax_t)radix;
- radix++;
- }
-
- if (digits2) {
- for (i = 0; digits2[i]; i++) {
- if (symbols[(unsigned char)digits2[i]] >= 256)
- goto einval;
- symbols[(unsigned char)digits2[i]] = (intmax_t)(i | 256U);
- }
- if (i != radix)
- goto einval;
- for (i = 0; digits2[i]; i++)
- symbols[(unsigned char)digits2[i]] &= 255;
- }
-
- if (radix < 2) {
- einval:
- *(const unsigned char **)(void *)end = s;
- return EINVAL;
- }
-
- for (;; slen--, s++) {
- if (!slen)
- goto einval;
- if (symbols[*s] != -1) {
- if (symbols[*s] >= 0)
- break;
- goto einval;
- }
- }
-
- while (slen && symbols[*s] == 0) {
- s++;
- slen--;
- }
-
- if ((radix & (radix - 1U)) == 0U)
- r = from_power_of_two(s, slen, (void *)end, symbols, radix, a);
- else
- r = from_generic(s, slen, (void *)end, symbols, radix, a);
- if (r == ERANGE)
- libj2_j2u_max(a);
- return r;
-}
+extern inline int libj2_str_to_j2u(const char *str, size_t slen, char **end, const char *digits1,
+ const char *digits2, struct libj2_j2u *a);
#else
-CONST int
+int
main(void)
{
/* Primarily tested in libj2_j2u_to_str.c */
@@ -283,6 +44,13 @@ main(void)
EXPECT(!strcmp(end, "10000"));
a = (struct libj2_j2u){111, 222};
+ end = NULL;
+ EXPECT(libj2_str_to_j2u("-10000", 5, &end, NULL, NULL, &a) == EINVAL);
+ EXPECT(libj2_j2u_is_zero(&a));
+ EXPECT(end);
+ EXPECT(!strcmp(end, "-10000"));
+
+ a = (struct libj2_j2u){111, 222};
EXPECT(libj2_str_to_j2u("10000", 3, NULL, NULL, NULL, &a) == 0);
EXPECT(libj2_j2u_eq_ju(&a, 100));
@@ -417,6 +185,20 @@ main(void)
EXPECT(end);
EXPECT(*end == 'B');
+ a = (struct libj2_j2u){111, 222};
+ end = NULL;
+ EXPECT(libj2_str_to_j2u("ba", SIZE_MAX, &end, "ab", "ba", &a) == EINVAL);
+ EXPECT(libj2_j2u_is_zero(&a));
+ EXPECT(end);
+ EXPECT(*end == 'b');
+
+ a = (struct libj2_j2u){111, 222};
+ end = NULL;
+ EXPECT(libj2_str_to_j2u("ba", SIZE_MAX, &end, "ab", "bc", &a) == EINVAL);
+ EXPECT(libj2_j2u_is_zero(&a));
+ EXPECT(end);
+ EXPECT(*end == 'b');
+
sprintf(buf, "%jx%jx", UINTMAX_MAX, UINTMAX_MAX);
a = (struct libj2_j2u){111, 222};
end = NULL;