Skip to content

Commit 4d6e4b1

Browse files
committed
refactor bc_str2num
1 parent a1d2924 commit 4d6e4b1

File tree

3 files changed

+76
-69
lines changed

3 files changed

+76
-69
lines changed

ext/bcmath/bcmath.c

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -134,17 +134,7 @@ PHP_MINFO_FUNCTION(bcmath)
134134
Convert to bc_num detecting scale */
135135
static zend_result php_str2num(bc_num *num, char *str)
136136
{
137-
char *p;
138-
139-
if (!(p = strchr(str, '.'))) {
140-
if (!bc_str2num(num, str, 0)) {
141-
return FAILURE;
142-
}
143-
144-
return SUCCESS;
145-
}
146-
147-
if (!bc_str2num(num, str, strlen(p+1))) {
137+
if (!bc_str2num(num, str, 0, true)) {
148138
return FAILURE;
149139
}
150140

@@ -624,12 +614,12 @@ PHP_FUNCTION(bccomp)
624614
bc_init_num(&first);
625615
bc_init_num(&second);
626616

627-
if (!bc_str2num(&first, ZSTR_VAL(left), scale)) {
617+
if (!bc_str2num(&first, ZSTR_VAL(left), scale, false)) {
628618
zend_argument_value_error(1, "is not well-formed");
629619
goto cleanup;
630620
}
631621

632-
if (!bc_str2num(&second, ZSTR_VAL(right), scale)) {
622+
if (!bc_str2num(&second, ZSTR_VAL(right), scale, false)) {
633623
zend_argument_value_error(2, "is not well-formed");
634624
goto cleanup;
635625
}

ext/bcmath/libbcmath/src/bcmath.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ bc_num bc_copy_num(bc_num num);
9797

9898
void bc_init_num(bc_num *num);
9999

100-
bool bc_str2num(bc_num *num, char *str, size_t scale);
100+
bool bc_str2num(bc_num *num, char *str, size_t scale, bool auto_scale);
101101

102102
zend_string *bc_num2str_ex(bc_num num, size_t scale);
103103

ext/bcmath/libbcmath/src/str2num.c

Lines changed: 72 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -35,20 +35,23 @@
3535

3636
/* Convert strings to bc numbers. Base 10 only.*/
3737

38-
bool bc_str2num(bc_num *num, char *str, size_t scale)
38+
bool bc_str2num(bc_num *num, char *str, size_t scale, bool auto_scale)
3939
{
4040
size_t digits = 0;
41-
size_t strscale = 0;
42-
char *ptr, *nptr;
43-
size_t trailing_zeros = 0;
41+
size_t str_scale = 0;
42+
char *ptr = str;
43+
char *nptr;
44+
char *integer_ptr;
45+
char *integer_end;
46+
char *fractional_ptr = NULL;
47+
char *fractional_end = NULL;
48+
char *decimal_point;
4449
bool zero_int = false;
4550

4651
/* Prepare num. */
4752
bc_free_num (num);
4853

4954
/* Check for valid number and count digits. */
50-
ptr = str;
51-
5255
if ((*ptr == '+') || (*ptr == '-')) {
5356
/* Skip Sign */
5457
ptr++;
@@ -57,77 +60,91 @@ bool bc_str2num(bc_num *num, char *str, size_t scale)
5760
while (*ptr == '0') {
5861
ptr++;
5962
}
63+
integer_ptr = ptr;
6064
/* digits before the decimal point */
6165
while (*ptr >= '0' && *ptr <= '9') {
6266
ptr++;
6367
digits++;
6468
}
6569
/* decimal point */
66-
if (*ptr == '.') {
67-
ptr++;
70+
decimal_point = (*ptr == '.') ? ptr : NULL;
71+
72+
/* If a string other than numbers exists */
73+
if (!decimal_point && *ptr != '\0') {
74+
goto fail;
6875
}
69-
/* digits after the decimal point */
70-
while (*ptr >= '0' && *ptr <= '9') {
71-
if (*ptr == '0') {
72-
trailing_zeros++;
73-
} else {
74-
trailing_zeros = 0;
76+
77+
/* search and validate fractional end if exists */
78+
if (decimal_point) {
79+
/* search */
80+
fractional_ptr = fractional_end = decimal_point + 1;
81+
if (*fractional_ptr == '\0') {
82+
goto after_fractional;
7583
}
76-
ptr++;
77-
strscale++;
78-
}
7984

80-
if (trailing_zeros > 0) {
81-
/* Trailing zeros should not take part in the computation of the overall scale, as it is pointless. */
82-
strscale = strscale - trailing_zeros;
85+
/* validate */
86+
while (*fractional_ptr >= '0' && *fractional_ptr <= '9') {
87+
fractional_end = *fractional_ptr != '0' ? fractional_ptr + 1 : fractional_end;
88+
fractional_ptr++;
89+
}
90+
if (*fractional_ptr != '\0') {
91+
/* invalid num */
92+
goto fail;
93+
}
94+
fractional_ptr = decimal_point + 1;
95+
96+
str_scale = fractional_end - fractional_ptr;
97+
if (str_scale > scale && !auto_scale) {
98+
fractional_end -= str_scale - scale;
99+
str_scale = scale;
100+
}
83101
}
84-
if ((*ptr != '\0') || (digits + strscale == 0)) {
85-
*num = bc_copy_num(BCG(_zero_));
86-
return *ptr == '\0';
102+
103+
after_fractional:
104+
105+
if (digits + str_scale == 0) {
106+
goto zero;
87107
}
88108

89109
/* Adjust numbers and allocate storage and initialize fields. */
90-
strscale = MIN(strscale, scale);
91110
if (digits == 0) {
92111
zero_int = true;
93112
digits = 1;
94113
}
95-
*num = bc_new_num (digits, strscale);
96-
97-
/* Build the whole number. */
98-
ptr = str;
99-
if (*ptr == '-') {
100-
(*num)->n_sign = MINUS;
101-
ptr++;
102-
} else {
103-
(*num)->n_sign = PLUS;
104-
if (*ptr == '+') ptr++;
105-
}
106-
/* Skip leading zeros. */
107-
while (*ptr == '0') {
108-
ptr++;
109-
}
114+
*num = bc_new_num (digits, str_scale);
115+
(*num)->n_sign = *str == '-' ? MINUS : PLUS;
110116
nptr = (*num)->n_value;
111-
if (zero_int) {
112-
*nptr++ = 0;
113-
digits = 0;
114-
}
115-
for (; digits > 0; digits--) {
116-
*nptr++ = CH_VAL(*ptr++);
117-
}
118117

119-
/* Build the fractional part. */
120-
if (strscale > 0) {
121-
/* skip the decimal point! */
122-
ptr++;
123-
for (; strscale > 0; strscale--) {
124-
*nptr++ = CH_VAL(*ptr++);
118+
if (zero_int) {
119+
nptr++;
120+
while (fractional_ptr < fractional_end) {
121+
*nptr = CH_VAL(*fractional_ptr);
122+
nptr++;
123+
fractional_ptr++;
124+
}
125+
} else {
126+
integer_end = integer_ptr + digits;
127+
while (integer_ptr < integer_end) {
128+
*nptr = CH_VAL(*integer_ptr);
129+
nptr++;
130+
integer_ptr++;
131+
}
132+
if (str_scale > 0) {
133+
while (fractional_ptr < fractional_end) {
134+
*nptr = CH_VAL(*fractional_ptr);
135+
nptr++;
136+
fractional_ptr++;
137+
}
125138
}
126139
}
127140

128-
if (bc_is_zero(*num)) {
129-
(*num)->n_sign = PLUS;
130-
}
141+
return true;
131142

143+
zero:
144+
*num = bc_copy_num(BCG(_zero_));
132145
return true;
146+
147+
fail:
148+
*num = bc_copy_num(BCG(_zero_));
149+
return false;
133150
}

0 commit comments

Comments
 (0)