38
38
bool bc_str2num (bc_num * num , char * str , size_t scale )
39
39
{
40
40
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 ;
44
43
bool zero_int = false;
45
44
46
45
/* Prepare num. */
@@ -49,85 +48,96 @@ bool bc_str2num(bc_num *num, char *str, size_t scale)
49
48
/* Check for valid number and count digits. */
50
49
ptr = str ;
51
50
52
- if ((* ptr == '+' ) || (* ptr == '-' )) {
53
- /* Skip Sign */
54
- ptr ++ ;
55
- }
51
+ ptr += (* ptr == '-' || * ptr == '+' );
52
+
56
53
/* Skip leading zeros. */
57
54
while (* ptr == '0' ) {
58
55
ptr ++ ;
59
56
}
60
- /* digits before the decimal point */
57
+ integer_ptr = ptr ;
58
+
59
+ /* Count digits. */
61
60
while (* ptr >= '0' && * ptr <= '9' ) {
62
61
ptr ++ ;
63
62
digits ++ ;
64
63
}
65
64
/* 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 ;
68
70
}
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 ;
75
87
}
76
- ptr ++ ;
77
- strscale ++ ;
78
- }
79
88
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
+ }
83
93
}
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 ;
87
97
}
88
98
89
99
/* Adjust numbers and allocate storage and initialize fields. */
90
- strscale = MIN (strscale , scale );
91
100
if (digits == 0 ) {
92
101
zero_int = true;
93
102
digits = 1 ;
94
103
}
95
- * num = bc_new_num (digits , strscale );
96
104
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 ;
110
107
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
- }
118
108
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
+ }
125
131
}
126
132
}
127
133
128
- if (bc_is_zero (* num )) {
129
- (* num )-> n_sign = PLUS ;
130
- }
134
+ return true;
131
135
136
+ zero :
137
+ * num = bc_copy_num (BCG (_zero_ ));
132
138
return true;
139
+
140
+ fail :
141
+ * num = bc_copy_num (BCG (_zero_ ));
142
+ return false;
133
143
}
0 commit comments