@@ -56,6 +56,47 @@ fix_error copy_fix_tag_as_string(const fix_group* const group, unsigned tag, cha
5656 return FE_OK ;
5757}
5858
59+ // ascii digits to long converters
60+ static
61+ const char * convert_significant_digits (const char * s , long * const result )
62+ {
63+ long res = 0 ;
64+ unsigned c = CHAR_TO_INT (* s ) - '0' ;
65+
66+ if (c == 0 )
67+ return NULL ;
68+
69+ if (c <= 9 )
70+ {
71+ res = c ;
72+
73+ for (c = CHAR_TO_INT (* ++ s ) - '0' ; c <= 9 ; c = CHAR_TO_INT (* ++ s ) - '0' )
74+ {
75+ const long t = res * 10 + c ;
76+
77+ if (t < res ) // overflow
78+ return NULL ;
79+
80+ res = t ;
81+ }
82+ }
83+
84+ // done
85+ * result = res ;
86+ return s ;
87+ }
88+
89+ static
90+ const char * convert_digits (const char * s , long * const result )
91+ {
92+ // skip leading zeroes
93+ while (* s == '0' )
94+ ++ s ;
95+
96+ // convert digits
97+ return convert_significant_digits (s , result );
98+ }
99+
59100// tag as long integer
60101fix_error get_fix_tag_as_long (const fix_group * const group , unsigned tag , long * const result )
61102{
@@ -70,31 +111,33 @@ fix_error get_fix_tag_as_long(const fix_group* const group, unsigned tag, long*
70111 if (err != FE_OK )
71112 return err ;
72113
73- // conversion
74- long val = 0 ;
75- const char * s = value .begin ;
76- const int negative = (* s == '-' ) ? (++ s , 1 ) : 0 ;
114+ if (fix_string_length (value ) > 20 ) // ???
115+ RETURN ( FE_INVALID_VALUE );
77116
78- // quickly skip leading zeroes
79- while (* s == '0' )
80- ++ s ;
117+ // sign
118+ bool neg = false;
81119
82- // convert all significant digits
83- while (* s >= '0' && * s <= '9' )
120+ if (* value .begin == '-' )
84121 {
85- const long new_val = val * 10L + * s ++ - '0' ;
122+ ++ value .begin ;
123+ neg = true;
124+ }
86125
87- if ( new_val < val ) // overflow
88- RETURN ( FE_INVALID_VALUE ) ;
126+ // conversion
127+ long val ;
89128
90- val = new_val ;
91- }
129+ value .begin = convert_digits (value .begin , & val );
92130
93- if (* s != SOH || s == value .begin + negative ) // no SOH terminator or the sign only
131+ // validation
132+ if (!value .begin || (neg && val == 0 )) // overflow or '-0'
133+ RETURN ( FE_INVALID_VALUE );
134+
135+ if (value .begin < value .end ) // unprocessed bytes
94136 RETURN ( FE_INCORRECT_VALUE_FORMAT );
95137
138+ // all clear
96139 if (result )
97- * result = negative ? - val : val ;
140+ * result = neg ? - val : val ;
98141
99142 return FE_OK ;
100143}
@@ -118,62 +161,70 @@ fix_error get_fix_tag_as_double(const fix_group* const group, unsigned tag, doub
118161 if (err != FE_OK )
119162 return err ;
120163
121- // conversion
122- long val = 0 , frac = 0 ;
123- unsigned ndig = 0 ; // number of significant digits
124- const char * s = value .begin ;
125- const double sign = (* s == '-' ) ? (++ s , -1. ) : 1. ;
126- const char * mark = s ;
164+ // sign
165+ bool neg = false;
166+
167+ if (* value .begin == '-' )
168+ {
169+ ++ value .begin ;
170+ neg = true;
171+ }
127172
128173 // skip leading zeroes
129- while (* s == '0' )
130- ++ s ;
174+ while (* value . begin == '0' )
175+ ++ value . begin ;
131176
132177 // integer part
133- while (* s >= '0' && * s <= '9' )
134- {
135- if (++ ndig > 15 )
136- RETURN ( FE_INVALID_VALUE );
178+ long int_part ;
179+ const char * s = convert_significant_digits (value .begin , & int_part );
137180
138- val = val * 10L + * s ++ - '0' ;
139- }
181+ if (! s )
182+ RETURN ( FE_INVALID_VALUE );
140183
141- if (s == mark ) // cannot have empty integer part
142- RETURN ( FE_INCORRECT_VALUE_FORMAT );
184+ unsigned nsig = s - value .begin ; // significant digits counter
143185
144- // fractional part
186+ if (nsig > 15 )
187+ RETURN ( FE_INVALID_VALUE );
188+
189+ long frac_part = 0 ;
145190 unsigned nfrac = 0 ;
146191
147- if (* s == '.' )
192+ if (* s == '.' && * ++ s != SOH )
148193 {
149- mark = ++ s ;
194+ // fractional part
195+ value .begin = s ;
196+ s = convert_digits (s , & frac_part );
150197
151- if (ndig == 0 )
152- while (* s == '0' ) // skip leading zeroes
153- ++ s ;
198+ if (!s )
199+ RETURN ( FE_INCORRECT_VALUE_FORMAT );
154200
155- while (* s >= '0' && * s <= '9' )
156- {
157- if (++ ndig > 15 )
158- RETURN ( FE_INVALID_VALUE );
201+ nfrac = s - value .begin ;
159202
160- frac = frac * 10L + * s ++ - '0' ;
161- }
162-
163- nfrac = s - mark ;
203+ if (nsig + nfrac > 15 ) // counting trailing zeros as significant, contrary to the definition
204+ RETURN ( FE_INCORRECT_VALUE_FORMAT );
164205 }
165206
166- if (* s != SOH )
207+ // final checks
208+ if (s < value .end ) // unprocessed bytes
167209 RETURN ( FE_INCORRECT_VALUE_FORMAT );
168210
169- static const double mult [] = { 0. , 1e-1 , 1e-2 , 1e-3 , 1e-4 , 1e-5 , 1e-6 , 1e-7 , 1e-8 , 1e-9 , 1e-10 , 1e-11 , 1e-12 , 1e-13 , 1e-14 , 1e-15 };
211+ if (neg && int_part == 0 && frac_part == 0 ) // -0.0
212+ RETURN ( FE_INVALID_VALUE );
213+
214+ // compose result
215+ static const double factor [] = { 0. , 1e-1 , 1e-2 , 1e-3 , 1e-4 , 1e-5 , 1e-6 , 1e-7 , 1e-8 , 1e-9 , 1e-10 , 1e-11 , 1e-12 , 1e-13 , 1e-14 , 1e-15 };
216+
217+ double res = (double )int_part ;
218+
219+ if (frac_part != 0 )
220+ res += (double )frac_part * factor [nfrac ];
221+
222+ if (neg )
223+ res = - res ;
170224
225+ // all done
171226 if (result )
172- #ifdef FP_FAST_FMA
173- * result = copysign (fma ((double )frac , mult [nfrac ], (double )val ), sign );
174- #else
175- * result = copysign (frac * mult [nfrac ] + val , sign );
176- #endif
227+ * result = res ;
177228
178229 return FE_OK ;
179230}
@@ -228,14 +279,14 @@ fix_error get_fix_tag_as_boolean(const fix_group* const group, unsigned tag, boo
228279
229280// matchers (unsafe macros!)
230281#define READ_FIRST_DIGIT (s , r ) \
231- switch(CHAR_TO_INT( *(s) )) { \
282+ switch(*(s)) { \
232283 case '0' ... '9': (r) = *(s) - '0'; break; \
233284 default: RETURN( FE_INCORRECT_VALUE_FORMAT ); \
234285 } \
235286 ++(s)
236287
237288#define READ_DIGIT (s , r ) \
238- switch(CHAR_TO_INT( *(s) )) { \
289+ switch(*(s)) { \
239290 case '0' ... '9': (r) = (r) * 10 + *(s) - '0'; break; \
240291 default: RETURN( FE_INCORRECT_VALUE_FORMAT ); \
241292 } \
@@ -309,7 +360,7 @@ fix_error read_time_part(const fix_group* const group, fix_string* const ps, utc
309360static
310361fix_error read_time_ms_part (const fix_group * const group , fix_string * const ps , utc_timestamp * const ts )
311362{
312- fix_error err = read_time_part (group , ps , ts );
363+ const fix_error err = read_time_part (group , ps , ts );
313364
314365 if (err != FE_OK )
315366 return err ;
@@ -470,7 +521,7 @@ fix_error get_fix_tag_as_LocalMktDate(const fix_group* const group, unsigned tag
470521 // FUNCTION EXPECTS A STRING IN THE "YYYY-MM-DD" FORMAT.
471522
472523 fix_string value ;
473- fix_error err = get_fix_tag_as_string (group , tag , & value );
524+ const fix_error err = get_fix_tag_as_string (group , tag , & value );
474525
475526 if (err != FE_OK )
476527 return err ;
0 commit comments