Skip to content

Commit ff77807

Browse files
committed
refactor bc_str2num
1 parent 7f7df8f commit ff77807

File tree

1 file changed

+66
-56
lines changed

1 file changed

+66
-56
lines changed

ext/bcmath/libbcmath/src/str2num.c

Lines changed: 66 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,8 @@
3838
bool bc_str2num(bc_num *num, char *str, size_t 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, *nptr, *integer_ptr, *integer_end, *fractional_ptr = NULL, *fractional_end = NULL, *decimal_point;
4443
bool zero_int = false;
4544

4645
/* Prepare num. */
@@ -49,85 +48,96 @@ bool bc_str2num(bc_num *num, char *str, size_t scale)
4948
/* Check for valid number and count digits. */
5049
ptr = str;
5150

52-
if ((*ptr == '+') || (*ptr == '-')) {
53-
/* Skip Sign */
54-
ptr++;
55-
}
51+
ptr += (*ptr == '-' || *ptr == '+');
52+
5653
/* Skip leading zeros. */
5754
while (*ptr == '0') {
5855
ptr++;
5956
}
60-
/* digits before the decimal point */
57+
integer_ptr = ptr;
58+
59+
/* Count digits. */
6160
while (*ptr >= '0' && *ptr <= '9') {
6261
ptr++;
6362
digits++;
6463
}
6564
/* decimal point */
66-
if (*ptr == '.') {
67-
ptr++;
65+
decimal_point = (*ptr == '.') ? ptr : NULL;
66+
67+
/* If a string other than numbers exists */
68+
if (!decimal_point && *ptr != '\0') {
69+
goto fail;
6870
}
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;
71+
72+
/* search and validate fractional end if exists */
73+
if (decimal_point) {
74+
/* search */
75+
fractional_ptr = decimal_point + 1;
76+
fractional_end = fractional_ptr + strlen(fractional_ptr) - 1;
77+
while (*fractional_end == '0' && fractional_end >= decimal_point) {
78+
fractional_end--;
79+
}
80+
fractional_end++;
81+
str_scale = fractional_end - fractional_ptr;
82+
83+
/* validate */
84+
if (strspn(fractional_ptr, "0123456789") < str_scale) {
85+
/* invalid num */
86+
goto fail;
7587
}
76-
ptr++;
77-
strscale++;
78-
}
7988

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;
89+
while (str_scale > scale) {
90+
fractional_end--;
91+
str_scale--;
92+
}
8393
}
84-
if ((*ptr != '\0') || (digits + strscale == 0)) {
85-
*num = bc_copy_num(BCG(_zero_));
86-
return *ptr == '\0';
94+
95+
if (digits + str_scale == 0) {
96+
goto zero;
8797
}
8898

8999
/* Adjust numbers and allocate storage and initialize fields. */
90-
strscale = MIN(strscale, scale);
91100
if (digits == 0) {
92101
zero_int = true;
93102
digits = 1;
94103
}
95-
*num = bc_new_num (digits, strscale);
96104

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-
}
105+
*num = bc_new_num(digits, str_scale);
106+
(*num)->n_sign = *str == '-' ? MINUS : PLUS;
110107
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-
}
118108

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++);
109+
if (zero_int) {
110+
nptr++;
111+
if (str_scale > 0) {
112+
while (fractional_ptr < fractional_end) {
113+
*nptr = CH_VAL(*fractional_ptr);
114+
nptr++;
115+
fractional_ptr++;
116+
}
117+
}
118+
} else {
119+
integer_end = integer_ptr + digits - 1;
120+
while (integer_ptr <= integer_end) {
121+
*nptr = CH_VAL(*integer_ptr);
122+
nptr++;
123+
integer_ptr++;
124+
}
125+
if (str_scale > 0) {
126+
while (fractional_ptr < fractional_end) {
127+
*nptr = CH_VAL(*fractional_ptr);
128+
nptr++;
129+
fractional_ptr++;
130+
}
125131
}
126132
}
127133

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

136+
zero:
137+
*num = bc_copy_num(BCG(_zero_));
132138
return true;
139+
140+
fail:
141+
*num = bc_copy_num(BCG(_zero_));
142+
return false;
133143
}

0 commit comments

Comments
 (0)