Skip to content

Commit 8528ec5

Browse files
committed
refactor bc_str2num
1 parent 7f7df8f commit 8528ec5

File tree

1 file changed

+68
-51
lines changed

1 file changed

+68
-51
lines changed

ext/bcmath/libbcmath/src/str2num.c

Lines changed: 68 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -39,51 +39,71 @@ bool bc_str2num(bc_num *num, char *str, size_t scale)
3939
{
4040
size_t digits = 0;
4141
size_t strscale = 0;
42-
char *ptr, *nptr;
43-
size_t trailing_zeros = 0;
42+
char *ptr, *nptr, *integer_ptr, *integer_end, *fractional_ptr = NULL, *fractional_end = NULL, *decimal_point;
4443
bool zero_int = false;
44+
size_t len = strlen(str);
45+
sign num_sign = PLUS;
4546

4647
/* Prepare num. */
4748
bc_free_num (num);
4849

4950
/* Check for valid number and count digits. */
5051
ptr = str;
5152

52-
if ((*ptr == '+') || (*ptr == '-')) {
53+
if (*ptr == '+') {
5354
/* Skip Sign */
5455
ptr++;
56+
} else if (*ptr == '-') {
57+
/* Skip Sign */
58+
num_sign = MINUS;
59+
ptr++;
5560
}
61+
5662
/* Skip leading zeros. */
5763
while (*ptr == '0') {
5864
ptr++;
5965
}
60-
/* digits before the decimal point */
66+
integer_ptr = ptr;
67+
68+
/* Count digits. */
6169
while (*ptr >= '0' && *ptr <= '9') {
6270
ptr++;
6371
digits++;
6472
}
6573
/* decimal point */
66-
if (*ptr == '.') {
67-
ptr++;
74+
decimal_point = (*ptr == '.') ? ptr : NULL;
75+
76+
/* If a string other than numbers exists */
77+
if (!decimal_point && *ptr != '\0') {
78+
goto fail;
6879
}
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;
80+
81+
/* search and validate fractional end if exists */
82+
if (decimal_point) {
83+
/* search */
84+
fractional_ptr = decimal_point + 1;
85+
fractional_end = str + len - 1;
86+
bool has_trailing_zero = false;
87+
while (*fractional_end == '0' && fractional_end >= fractional_ptr) {
88+
fractional_end--;
89+
has_trailing_zero = true;
90+
}
91+
if (has_trailing_zero) {
92+
fractional_end++;
7593
}
76-
ptr++;
77-
strscale++;
78-
}
7994

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;
95+
/* validate */
96+
strscale = fractional_end - fractional_ptr;
97+
if (strspn(fractional_ptr, "0123456789") < strscale) {
98+
/* invalid num */
99+
*num = bc_copy_num(BCG(_zero_));
100+
return false;
101+
}
83102
}
84-
if ((*ptr != '\0') || (digits + strscale == 0)) {
103+
104+
if (digits + strscale == 0) {
85105
*num = bc_copy_num(BCG(_zero_));
86-
return *ptr == '\0';
106+
return true;
87107
}
88108

89109
/* Adjust numbers and allocate storage and initialize fields. */
@@ -92,42 +112,39 @@ bool bc_str2num(bc_num *num, char *str, size_t scale)
92112
zero_int = true;
93113
digits = 1;
94114
}
95-
*num = bc_new_num (digits, strscale);
96115

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-
}
116+
*num = bc_new_num(digits, strscale);
117+
(*num)->n_sign = num_sign;
110118
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-
}
118119

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++);
120+
if (zero_int) {
121+
nptr++;
122+
if (decimal_point) {
123+
while (fractional_ptr <= fractional_end) {
124+
*nptr = CH_VAL(*fractional_ptr);
125+
nptr++;
126+
fractional_ptr++;
127+
}
128+
}
129+
} else {
130+
integer_end = integer_ptr + digits - 1;
131+
while (integer_ptr <= integer_end) {
132+
*nptr = CH_VAL(*integer_ptr);
133+
nptr++;
134+
integer_ptr++;
135+
}
136+
if (decimal_point) {
137+
while (fractional_ptr <= fractional_end) {
138+
*nptr = CH_VAL(*fractional_ptr);
139+
nptr++;
140+
fractional_ptr++;
141+
}
125142
}
126-
}
127-
128-
if (bc_is_zero(*num)) {
129-
(*num)->n_sign = PLUS;
130143
}
131144

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

0 commit comments

Comments
 (0)