in GaiaXAndroidQuickJS/quickjs/gxquickjs/libbf.c [2878:3127]
static int bf_atof_internal(bf_t *r, slimb_t *pexponent,
const char *str, const char **pnext, int radix,
limb_t prec, bf_flags_t flags, BOOL is_dec)
{
const char *p, *p_start;
int is_neg, radix_bits, exp_is_neg, ret, digits_per_limb, shift;
limb_t cur_limb;
slimb_t pos, expn, int_len, digit_count;
BOOL has_decpt, is_bin_exp;
bf_t a_s, *a;
*pexponent = 0;
p = str;
if (!(flags & BF_ATOF_NO_NAN_INF) && radix <= 16 &&
strcasestart(p, "nan", &p)) {
bf_set_nan(r);
ret = 0;
goto done;
}
is_neg = 0;
if (p[0] == '+') {
p++;
p_start = p;
} else if (p[0] == '-') {
is_neg = 1;
p++;
p_start = p;
} else {
p_start = p;
}
if (p[0] == '0') {
if ((p[1] == 'x' || p[1] == 'X') &&
(radix == 0 || radix == 16) &&
!(flags & BF_ATOF_NO_HEX)) {
radix = 16;
p += 2;
} else if ((p[1] == 'o' || p[1] == 'O') &&
radix == 0 && (flags & BF_ATOF_BIN_OCT)) {
p += 2;
radix = 8;
} else if ((p[1] == 'b' || p[1] == 'B') &&
radix == 0 && (flags & BF_ATOF_BIN_OCT)) {
p += 2;
radix = 2;
} else {
goto no_prefix;
}
/* there must be a digit after the prefix */
if (to_digit((uint8_t)*p) >= radix) {
bf_set_nan(r);
ret = 0;
goto done;
}
no_prefix: ;
} else {
if (!(flags & BF_ATOF_NO_NAN_INF) && radix <= 16 &&
strcasestart(p, "inf", &p)) {
bf_set_inf(r, is_neg);
ret = 0;
goto done;
}
}
if (radix == 0)
radix = 10;
if (is_dec) {
assert(radix == 10);
radix_bits = 0;
a = r;
} else if ((radix & (radix - 1)) != 0) {
radix_bits = 0; /* base is not a power of two */
a = &a_s;
bf_init(r->ctx, a);
} else {
radix_bits = ceil_log2(radix);
a = r;
}
/* skip leading zeros */
/* XXX: could also skip zeros after the decimal point */
while (*p == '0')
p++;
if (radix_bits) {
shift = digits_per_limb = LIMB_BITS;
} else {
radix_bits = 0;
shift = digits_per_limb = digits_per_limb_table[radix - 2];
}
cur_limb = 0;
bf_resize(a, 1);
pos = 0;
has_decpt = FALSE;
int_len = digit_count = 0;
for(;;) {
limb_t c;
if (*p == '.' && (p > p_start || to_digit(p[1]) < radix)) {
if (has_decpt)
break;
has_decpt = TRUE;
int_len = digit_count;
p++;
}
c = to_digit(*p);
if (c >= radix)
break;
digit_count++;
p++;
if (radix_bits) {
shift -= radix_bits;
if (shift <= 0) {
cur_limb |= c >> (-shift);
if (bf_add_limb(a, &pos, cur_limb))
goto mem_error;
if (shift < 0)
cur_limb = c << (LIMB_BITS + shift);
else
cur_limb = 0;
shift += LIMB_BITS;
} else {
cur_limb |= c << shift;
}
} else {
cur_limb = cur_limb * radix + c;
shift--;
if (shift == 0) {
if (bf_add_limb(a, &pos, cur_limb))
goto mem_error;
shift = digits_per_limb;
cur_limb = 0;
}
}
}
if (!has_decpt)
int_len = digit_count;
/* add the last limb and pad with zeros */
if (shift != digits_per_limb) {
if (radix_bits == 0) {
while (shift != 0) {
cur_limb *= radix;
shift--;
}
}
if (bf_add_limb(a, &pos, cur_limb)) {
mem_error:
ret = BF_ST_MEM_ERROR;
if (!radix_bits)
bf_delete(a);
bf_set_nan(r);
goto done;
}
}
/* reset the next limbs to zero (we prefer to reallocate in the
renormalization) */
memset(a->tab, 0, (pos + 1) * sizeof(limb_t));
if (p == p_start) {
ret = 0;
if (!radix_bits)
bf_delete(a);
bf_set_nan(r);
goto done;
}
/* parse the exponent, if any */
expn = 0;
is_bin_exp = FALSE;
if (((radix == 10 && (*p == 'e' || *p == 'E')) ||
(radix != 10 && (*p == '@' ||
(radix_bits && (*p == 'p' || *p == 'P'))))) &&
p > p_start) {
is_bin_exp = (*p == 'p' || *p == 'P');
p++;
exp_is_neg = 0;
if (*p == '+') {
p++;
} else if (*p == '-') {
exp_is_neg = 1;
p++;
}
for(;;) {
int c;
c = to_digit(*p);
if (c >= 10)
break;
if (unlikely(expn > ((BF_RAW_EXP_MAX - 2 - 9) / 10))) {
/* exponent overflow */
if (exp_is_neg) {
bf_set_zero(r, is_neg);
ret = BF_ST_UNDERFLOW | BF_ST_INEXACT;
} else {
bf_set_inf(r, is_neg);
ret = BF_ST_OVERFLOW | BF_ST_INEXACT;
}
goto done;
}
p++;
expn = expn * 10 + c;
}
if (exp_is_neg)
expn = -expn;
}
if (is_dec) {
a->expn = expn + int_len;
a->sign = is_neg;
ret = bfdec_normalize_and_round((bfdec_t *)a, prec, flags);
} else if (radix_bits) {
/* XXX: may overflow */
if (!is_bin_exp)
expn *= radix_bits;
a->expn = expn + (int_len * radix_bits);
a->sign = is_neg;
ret = bf_normalize_and_round(a, prec, flags);
} else {
limb_t l;
pos++;
l = a->len - pos; /* number of limbs */
if (l == 0) {
bf_set_zero(r, is_neg);
ret = 0;
} else {
bf_t T_s, *T = &T_s;
expn -= l * digits_per_limb - int_len;
bf_init(r->ctx, T);
if (bf_integer_from_radix(T, a->tab + pos, l, radix)) {
bf_set_nan(r);
ret = BF_ST_MEM_ERROR;
} else {
T->sign = is_neg;
if (flags & BF_ATOF_EXPONENT) {
/* return the exponent */
*pexponent = expn;
ret = bf_set(r, T);
} else {
ret = bf_mul_pow_radix(r, T, radix, expn, prec, flags);
}
}
bf_delete(T);
}
bf_delete(a);
}
done:
if (pnext)
*pnext = p;
return ret;
}