35
35
36
36
/* Convert strings to bc numbers. Base 10 only.*/
37
37
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 )
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 = str ;
43
+ char * fractional_ptr = NULL ;
44
+ char * fractional_end = NULL ;
44
45
bool zero_int = false;
45
46
46
47
/* Prepare num. */
47
48
bc_free_num (num );
48
49
49
50
/* Check for valid number and count digits. */
50
- ptr = str ;
51
-
52
51
if ((* ptr == '+' ) || (* ptr == '-' )) {
53
52
/* Skip Sign */
54
53
ptr ++ ;
@@ -57,77 +56,102 @@ bool bc_str2num(bc_num *num, char *str, size_t scale)
57
56
while (* ptr == '0' ) {
58
57
ptr ++ ;
59
58
}
59
+ const char * integer_ptr = ptr ;
60
60
/* digits before the decimal point */
61
61
while (* ptr >= '0' && * ptr <= '9' ) {
62
62
ptr ++ ;
63
63
digits ++ ;
64
64
}
65
65
/* decimal point */
66
- if (* ptr == '.' ) {
67
- ptr ++ ;
66
+ char * decimal_point = (* ptr == '.' ) ? ptr : NULL ;
67
+
68
+ /* If a non-digit and non-decimal-point indicator is in the string, i.e. an invalid character */
69
+ if (!decimal_point && * ptr != '\0' ) {
70
+ goto fail ;
68
71
}
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 ;
72
+
73
+ /* search and validate fractional end if exists */
74
+ if (decimal_point ) {
75
+ /* search */
76
+ fractional_ptr = fractional_end = decimal_point + 1 ;
77
+ if (* fractional_ptr == '\0' ) {
78
+ goto after_fractional ;
75
79
}
76
- ptr ++ ;
77
- strscale ++ ;
78
- }
79
80
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 ;
81
+ /* validate */
82
+ while (* fractional_ptr >= '0' && * fractional_ptr <= '9' ) {
83
+ fractional_end = * fractional_ptr != '0' ? fractional_ptr + 1 : fractional_end ;
84
+ fractional_ptr ++ ;
85
+ }
86
+ if (* fractional_ptr != '\0' ) {
87
+ /* invalid num */
88
+ goto fail ;
89
+ }
90
+ /* Move the pointer to the beginning of the fraction. */
91
+ fractional_ptr = decimal_point + 1 ;
92
+
93
+ /* Calculate the length of the fraction excluding trailing zero. */
94
+ str_scale = fractional_end - fractional_ptr ;
95
+
96
+ /*
97
+ * If set the scale manually and it is smaller than the automatically calculated scale,
98
+ * adjust it to match the manual setting.
99
+ */
100
+ if (str_scale > scale && !auto_scale ) {
101
+ fractional_end -= str_scale - scale ;
102
+ str_scale = scale ;
103
+ }
83
104
}
84
- if ((* ptr != '\0' ) || (digits + strscale == 0 )) {
85
- * num = bc_copy_num (BCG (_zero_ ));
86
- return * ptr == '\0' ;
105
+
106
+ after_fractional :
107
+
108
+ if (digits + str_scale == 0 ) {
109
+ goto zero ;
87
110
}
88
111
89
112
/* Adjust numbers and allocate storage and initialize fields. */
90
- strscale = MIN (strscale , scale );
91
113
if (digits == 0 ) {
92
114
zero_int = true;
93
115
digits = 1 ;
94
116
}
95
- * num = bc_new_num (digits , strscale );
117
+ * num = bc_new_num (digits , str_scale );
118
+ (* num )-> n_sign = * str == '-' ? MINUS : PLUS ;
119
+ char * nptr = (* num )-> n_value ;
96
120
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
- }
110
- nptr = (* num )-> n_value ;
111
121
if (zero_int ) {
112
- * nptr ++ = 0 ;
113
- digits = 0 ;
114
- }
115
- for (; digits > 0 ; digits -- ) {
116
- * nptr ++ = CH_VAL (* ptr ++ );
117
- }
118
-
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 ++ );
122
+ nptr ++ ;
123
+ /*
124
+ * If zero_int is true and the str_scale is 0, there is an early return,
125
+ * so here str_scale is always greater than 0.
126
+ */
127
+ while (fractional_ptr < fractional_end ) {
128
+ * nptr = CH_VAL (* fractional_ptr );
129
+ nptr ++ ;
130
+ fractional_ptr ++ ;
131
+ }
132
+ } else {
133
+ const char * integer_end = integer_ptr + digits ;
134
+ while (integer_ptr < integer_end ) {
135
+ * nptr = CH_VAL (* integer_ptr );
136
+ nptr ++ ;
137
+ integer_ptr ++ ;
138
+ }
139
+ if (str_scale > 0 ) {
140
+ while (fractional_ptr < fractional_end ) {
141
+ * nptr = CH_VAL (* fractional_ptr );
142
+ nptr ++ ;
143
+ fractional_ptr ++ ;
144
+ }
125
145
}
126
146
}
127
147
128
- if (bc_is_zero (* num )) {
129
- (* num )-> n_sign = PLUS ;
130
- }
148
+ return true;
131
149
150
+ zero :
151
+ * num = bc_copy_num (BCG (_zero_ ));
132
152
return true;
153
+
154
+ fail :
155
+ * num = bc_copy_num (BCG (_zero_ ));
156
+ return false;
133
157
}
0 commit comments