Skip to content

Commit 30e1f29

Browse files
committed
WIP
1 parent 32547f1 commit 30e1f29

File tree

1 file changed

+92
-3
lines changed

1 file changed

+92
-3
lines changed

ext/bcmath/libbcmath/src/str2num.c

Lines changed: 92 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,96 @@ static inline const char *bc_skip_zero_reverse(const char *scanner, const char *
105105
return scanner;
106106
}
107107

108+
static bool bc_scientific_notation_str2num(
109+
bc_num *num, const char *str, const char *end, const char *integer_ptr, const char *fractional_ptr, const char *exponent_ptr,
110+
size_t digits, size_t *full_scale)
111+
{
112+
const char *fractional_end = exponent_ptr;
113+
114+
/* In scientific notation, the mantissa always has one integer digit. */
115+
if (UNEXPECTED(digits != 1)) {
116+
goto fail;
117+
}
118+
119+
/* Must be 1 <= mantissa < 10 */
120+
if (UNEXPECTED(*integer_ptr == 0)) {
121+
goto fail;
122+
}
123+
124+
if (UNEXPECTED(*exponent_ptr != 'e' && *exponent_ptr != 'E')) {
125+
goto fail;
126+
}
127+
exponent_ptr++;
128+
129+
sign exponent_sign = PLUS;
130+
if (*exponent_ptr == '+') {
131+
/* Skip Sign */
132+
exponent_ptr++;
133+
} else if (*exponent_ptr == '-') {
134+
exponent_sign = MINUS;
135+
exponent_ptr++;
136+
}
137+
138+
/* Skip exponent leading zeros. This is rare, so don't do bulk processing. */
139+
while (*exponent_ptr == '0') {
140+
exponent_ptr++;
141+
}
142+
143+
const char *exponent_end = bc_count_digits(exponent_ptr, end);
144+
if (UNEXPECTED(*exponent_end != '\0')) {
145+
/* invalid num */
146+
goto fail;
147+
}
148+
149+
size_t exponent = 0;
150+
while (exponent_ptr < exponent_end) {
151+
exponent = exponent * 10 + (*exponent_ptr - '0'); /* TODO: check overflow */
152+
exponent_ptr++;
153+
}
154+
155+
size_t str_scale = fractional_end - fractional_ptr;
156+
157+
if (exponent_sign == PLUS) {
158+
digits += exponent;
159+
str_scale = str_scale > exponent ? str_scale - exponent : 0;
160+
161+
*num = bc_new_num_nonzeroed(digits, str_scale);
162+
(*num)->n_sign = *str == '-' ? MINUS : PLUS;
163+
char *nptr = (*num)->n_value;
164+
char *nend = nptr + digits + str_scale;
165+
166+
*nptr++ = *integer_ptr - '0';
167+
nptr = bc_copy_and_toggle_bcd(nptr, fractional_ptr, fractional_end);
168+
while (nptr < nend) {
169+
*nptr++ = 0;
170+
}
171+
} else {
172+
digits = 0;
173+
str_scale += exponent;
174+
175+
*num = bc_new_num_nonzeroed(1, str_scale); // 1 is for 0
176+
(*num)->n_sign = *str == '-' ? MINUS : PLUS;
177+
char *nptr = (*num)->n_value;
178+
179+
for (size_t i = 0; i < exponent; i++) {
180+
*nptr++ = 0;
181+
}
182+
183+
*nptr++ = *integer_ptr - '0';
184+
nptr = bc_copy_and_toggle_bcd(nptr, fractional_ptr, fractional_end);
185+
}
186+
187+
if (full_scale) {
188+
*full_scale = str_scale;
189+
}
190+
191+
return true;
192+
193+
fail:
194+
*num = bc_copy_num(BCG(_zero_));
195+
return false;
196+
}
197+
108198
/* Assumes `num` points to NULL, i.e. does yet not hold a number. */
109199
bool bc_str2num(bc_num *num, const char *str, const char *end, size_t scale, size_t *full_scale, bool auto_scale)
110200
{
@@ -151,9 +241,8 @@ bool bc_str2num(bc_num *num, const char *str, const char *end, size_t scale, siz
151241

152242
/* validate */
153243
fractional_end = bc_count_digits(fractional_ptr, end);
154-
if (UNEXPECTED(*fractional_end != '\0')) {
155-
/* invalid num */
156-
goto fail;
244+
if (*fractional_end != '\0') {
245+
return bc_scientific_notation_str2num(num, str, end, integer_ptr, fractional_ptr, fractional_end, digits, full_scale);
157246
}
158247

159248
if (full_scale) {

0 commit comments

Comments
 (0)