1 /*
2 * Copyright (C) 2010-2011 - DIGITEO - Allan CORNET
3 *
4 * Copyright (C) 2012 - 2016 - Scilab Enterprises
5 *
6 * This file is hereby licensed under the terms of the GNU GPL v2.0,
7 * pursuant to article 5.3.4 of the CeCILL v.2.1.
8 * This file was originally licensed under the terms of the CeCILL v2.1,
9 * and continues to be available under such terms.
10 * For more information, see the COPYING file which you should have received
11 * along with this program.
12 *
13 */
14
15 /* ========================================================================== */
16 #if defined(__linux__)
17 #define _GNU_SOURCE /* avoid dependency on GLIBC_2.7 */
18 #endif
19 /* ========================================================================== */
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <math.h>
24 #include "stringToDouble.h"
25 #include "core_math.h"
26 #include "sci_malloc.h"
27 #include "os_string.h"
28 #include "numericconstants_interface.h"
29 #ifndef _MSC_VER
30 #ifndef stricmp
31 #define stricmp strcasecmp
32 #endif
33 #else
34 #define stricmp _stricmp
35 #endif
36 /* ========================================================================== */
37 #define DEFAULT_DOUBLE_MAX_DIGIT_FORMAT "%lg"
38 /* ========================================================================== */
39 static double returnDoubleInPlace(BOOL bConvertByNAN, wchar_t* pSTR, stringToDoubleError* ierr);
40 static double returnINF(BOOL bPositive);
41 static double returnNAN(void);
42 /* ========================================================================== */
43
replace_D_By_E(const char * _pst)44 static char* replace_D_By_E(const char* _pst)
45 {
46 //find and replace d and D by E for compatibility with strtod Linux/Mac
47 char* pstReturn = os_strdup(_pst);
48 char* pstFind = pstReturn;
49 do
50 {
51 pstFind = strchr(pstFind, 'D');
52 if (pstFind)
53 {
54 pstFind[0] = 'E';
55 }
56 }
57 while (pstFind);
58
59 pstFind = pstReturn;
60 do
61 {
62 pstFind = strchr(pstFind, 'd');
63 if (pstFind)
64 {
65 pstFind[0] = 'e';
66 }
67 }
68 while (pstFind);
69
70 return pstReturn;
71 }
72
replace_D_By_EW(const wchar_t * _pst)73 static wchar_t* replace_D_By_EW(const wchar_t* _pst)
74 {
75 //find and replace d and D by E for compatibility with strtod Linux/Mac
76 wchar_t* pstReturn = os_wcsdup(_pst);
77 wchar_t* pstFind = pstReturn;
78 do
79 {
80 pstFind = wcschr(pstFind, L'D');
81 if (pstFind)
82 {
83 pstFind[0] = L'E';
84 }
85 }
86 while (pstFind);
87
88 pstFind = pstReturn;
89 do
90 {
91 pstFind = wcschr(pstFind, L'd');
92 if (pstFind)
93 {
94 pstFind[0] = L'e';
95 }
96 }
97 while (pstFind);
98
99 return pstReturn;
100 }
101
replace_D_By_E_WInPlace(wchar_t * _pst)102 void replace_D_By_E_WInPlace(wchar_t* _pst)
103 {
104 //find and replace d and D by E for compatibility with strtod Linux/Mac
105 for (wchar_t* it = _pst; *it != '\0'; it++)
106 {
107 if (*it == L'D')
108 {
109 *it = L'E';
110 }
111 else if (*it == L'd')
112 {
113 *it = L'e';
114 }
115 }
116 }
117
stringToDouble(const char * pSTR,BOOL bConvertByNAN,stringToDoubleError * ierr)118 double stringToDouble(const char *pSTR, BOOL bConvertByNAN, stringToDoubleError *ierr)
119 {
120 double dValue = 0.0;
121 *ierr = STRINGTODOUBLE_ERROR;
122 if (pSTR)
123 {
124 if ((stricmp(pSTR, NanString) == 0) || (stricmp(pSTR, NegNanString) == 0) ||
125 (stricmp(pSTR, PosNanString) == 0) || (stricmp(pSTR, ScilabPosNanString) == 0) ||
126 (stricmp(pSTR, ScilabNanString) == 0) || (stricmp(pSTR, ScilabNegNanString) == 0))
127 {
128 dValue = nc_nan();
129 }
130 else if ((stricmp(pSTR, InfString) == 0) || (stricmp(pSTR, PosInfString) == 0) ||
131 (stricmp(pSTR, ScilabInfString) == 0) || (stricmp(pSTR, ScilabPosInfString) == 0))
132 {
133 dValue = nc_inf();
134 }
135 else if ((stricmp(pSTR, NegInfString) == 0) || (stricmp(pSTR, ScilabNegInfString) == 0))
136 {
137 dValue = nc_neginf();
138 }
139 else if ((stricmp(pSTR, ScilabPiString) == 0) || (stricmp(pSTR, ScilabPosPiString) == 0))
140 {
141 dValue = M_PI;
142 }
143 else if (stricmp(pSTR, ScilabNegPiString) == 0)
144 {
145 dValue = -M_PI;
146 }
147 else if ((stricmp(pSTR, ScilabEpsString) == 0) || (stricmp(pSTR, ScilabPosEpsString) == 0))
148 {
149 dValue = EPSILON;
150 }
151 else if (stricmp(pSTR, ScilabNegEpsString) == 0)
152 {
153 dValue = -EPSILON;
154 }
155 else if ((stricmp(pSTR, ScilabEString) == 0) || (stricmp(pSTR, ScilabPosEString) == 0))
156 {
157 dValue = exp(1);
158 }
159 else if (stricmp(pSTR, ScilabNegEString) == 0)
160 {
161 dValue = -exp(1);
162 }
163 else
164 {
165 char* pstReplaced = replace_D_By_E(pSTR);
166 char *pEnd = NULL;
167 double v = strtod(pstReplaced, &pEnd);
168 if ((v == 0) && (pEnd == pstReplaced))
169 {
170 if (bConvertByNAN)
171 {
172 dValue = nc_nan();
173 }
174 else
175 {
176 *ierr = STRINGTODOUBLE_NOT_A_NUMBER;
177 FREE(pstReplaced);
178 return (dValue = 0.0);
179 }
180 }
181 else
182 {
183 if (strcmp(pEnd, "") == 0)
184 {
185 dValue = v;
186 }
187 else
188 {
189 if (bConvertByNAN)
190 {
191 dValue = nc_nan();
192 }
193 else
194 {
195 *ierr = STRINGTODOUBLE_NOT_A_NUMBER;
196 FREE(pstReplaced);
197 return (dValue = 0.0);
198 }
199 }
200 }
201
202 FREE(pstReplaced);
203 }
204 *ierr = STRINGTODOUBLE_NO_ERROR;
205 }
206 else
207 {
208 *ierr = STRINGTODOUBLE_MEMORY_ALLOCATION;
209 }
210 return dValue;
211 }
212 // =============================================================================
stringToDoubleW(const wchar_t * pSTR,BOOL bConvertByNAN,stringToDoubleError * ierr)213 double stringToDoubleW(const wchar_t *pSTR, BOOL bConvertByNAN, stringToDoubleError *ierr)
214 {
215 double dValue = 0.0;
216 *ierr = STRINGTODOUBLE_ERROR;
217 if (pSTR)
218 {
219 if ((wcsicmp(pSTR, NanStringW) == 0) || (wcsicmp(pSTR, NegNanStringW) == 0) ||
220 (wcsicmp(pSTR, PosNanStringW) == 0) || (wcsicmp(pSTR, ScilabPosNanStringW) == 0) ||
221 (wcsicmp(pSTR, ScilabNanStringW) == 0) || (wcsicmp(pSTR, ScilabNegNanStringW) == 0))
222 {
223 dValue = nc_nan();
224 }
225 else if ((wcsicmp(pSTR, InfStringW) == 0) || (wcsicmp(pSTR, PosInfStringW) == 0) ||
226 (wcsicmp(pSTR, ScilabInfStringW) == 0) || (wcsicmp(pSTR, ScilabPosInfStringW) == 0))
227 {
228 dValue = nc_inf();
229 }
230 else if ((wcsicmp(pSTR, NegInfStringW) == 0) || (wcsicmp(pSTR, ScilabNegInfStringW) == 0))
231 {
232 dValue = nc_neginf();
233 }
234 else if ((wcsicmp(pSTR, ScilabPiStringW) == 0) || (wcsicmp(pSTR, ScilabPosPiStringW) == 0))
235 {
236 dValue = M_PI;
237 }
238 else if (wcsicmp(pSTR, ScilabNegPiStringW) == 0)
239 {
240 dValue = -M_PI;
241 }
242 else if ((wcsicmp(pSTR, ScilabPosEStringW) == 0) || (wcsicmp(pSTR, ScilabEStringW) == 0))
243 {
244 dValue = exp(1);
245 }
246 else if (wcsicmp(pSTR, ScilabNegEStringW) == 0)
247 {
248 dValue = -exp(1);
249 }
250 else if ((wcsicmp(pSTR, ScilabEpsStringW) == 0) || (wcsicmp(pSTR, ScilabPosEpsStringW) == 0))
251 {
252 dValue = EPSILON;
253 }
254 else if (wcsicmp(pSTR, ScilabNegEpsStringW) == 0)
255 {
256 dValue = -EPSILON;
257 }
258 else
259 {
260 wchar_t* pstReplaced = replace_D_By_EW(pSTR);
261 wchar_t *pEnd = NULL;
262 double v = wcstod(pstReplaced, &pEnd);
263 if ((v == 0) && (pEnd == pstReplaced))
264 {
265 if (bConvertByNAN)
266 {
267 dValue = nc_nan();
268 }
269 else
270 {
271 *ierr = STRINGTODOUBLE_NOT_A_NUMBER;
272 FREE(pstReplaced);
273 return (dValue = 0.0);
274 }
275 }
276 else
277 {
278 if (wcscmp(pEnd, L"") == 0)
279 {
280 dValue = v;
281 }
282 else
283 {
284 if (bConvertByNAN)
285 {
286 dValue = nc_nan();
287 }
288 else
289 {
290 *ierr = STRINGTODOUBLE_NOT_A_NUMBER;
291 FREE(pstReplaced);
292 return (dValue = 0.0);
293 }
294 }
295 }
296
297 FREE(pstReplaced);
298 }
299 *ierr = STRINGTODOUBLE_NO_ERROR;
300 }
301 else
302 {
303 *ierr = STRINGTODOUBLE_MEMORY_ALLOCATION;
304 }
305 return dValue;
306 }
307 // =============================================================================
stringToDoubleWInPlace(wchar_t * pSTR,BOOL bConvertByNAN,stringToDoubleError * ierr)308 double stringToDoubleWInPlace(wchar_t* pSTR, BOOL bConvertByNAN, stringToDoubleError* ierr)
309 {
310 double dValue = 0.0;
311 *ierr = STRINGTODOUBLE_ERROR;
312 if (pSTR)
313 {
314 if ('0' <= *pSTR && *pSTR <= '9')
315 {
316 // this is a regular number, convert it as fast as possible
317 dValue = returnDoubleInPlace(bConvertByNAN, pSTR, ierr);
318 }
319 else if ((wcsicmp(pSTR, NanStringW) == 0) || (wcsicmp(pSTR, NegNanStringW) == 0) ||
320 (wcsicmp(pSTR, PosNanStringW) == 0) || (wcsicmp(pSTR, ScilabPosNanStringW) == 0) ||
321 (wcsicmp(pSTR, ScilabNanStringW) == 0) || (wcsicmp(pSTR, ScilabNegNanStringW) == 0))
322 {
323 *ierr = STRINGTODOUBLE_NO_ERROR;
324 dValue = returnNAN();
325 }
326 else if ((wcsicmp(pSTR, InfStringW) == 0) || (wcsicmp(pSTR, PosInfStringW) == 0) ||
327 (wcsicmp(pSTR, ScilabInfStringW) == 0) || (wcsicmp(pSTR, ScilabPosInfStringW) == 0))
328 {
329 *ierr = STRINGTODOUBLE_NO_ERROR;
330 dValue = returnINF(TRUE);
331 }
332 else if ((wcsicmp(pSTR, NegInfStringW) == 0) || (wcsicmp(pSTR, ScilabNegInfStringW) == 0))
333 {
334 *ierr = STRINGTODOUBLE_NO_ERROR;
335 dValue = returnINF(FALSE);
336 }
337 else if ((wcsicmp(pSTR, ScilabPiStringW) == 0) || (wcsicmp(pSTR, ScilabPosPiStringW) == 0))
338 {
339 *ierr = STRINGTODOUBLE_NO_ERROR;
340 dValue = M_PI;
341 }
342 else if (wcsicmp(pSTR, ScilabNegPiStringW) == 0)
343 {
344 *ierr = STRINGTODOUBLE_NO_ERROR;
345 dValue = -M_PI;
346 }
347 else if ((wcsicmp(pSTR, ScilabEpsStringW) == 0) || (wcsicmp(pSTR, ScilabPosEpsStringW) == 0))
348 {
349 *ierr = STRINGTODOUBLE_NO_ERROR;
350 dValue = EPSILON;
351 }
352 else if (wcsicmp(pSTR, ScilabNegEpsStringW) == 0)
353 {
354 *ierr = STRINGTODOUBLE_NO_ERROR;
355 dValue = -EPSILON;
356 }
357 else if ((wcsicmp(pSTR, ScilabEStringW) == 0) || (wcsicmp(pSTR, ScilabPosEStringW) == 0))
358 {
359 *ierr = STRINGTODOUBLE_NO_ERROR;
360 dValue = exp(1);
361 }
362 else if (wcsicmp(pSTR, ScilabNegEStringW) == 0)
363 {
364 *ierr = STRINGTODOUBLE_NO_ERROR;
365 dValue = -exp(1);
366 }
367 else
368 {
369 dValue = returnDoubleInPlace(bConvertByNAN, pSTR, ierr);
370 }
371 }
372 else
373 {
374 *ierr = STRINGTODOUBLE_MEMORY_ALLOCATION;
375 }
376 return dValue;
377 }
378 // =============================================================================
returnDoubleInPlace(BOOL bConvertByNAN,wchar_t * pSTR,stringToDoubleError * ierr)379 static double returnDoubleInPlace(BOOL bConvertByNAN, wchar_t* pSTR, stringToDoubleError* ierr)
380 {
381 double dValue;
382
383 replace_D_By_E_WInPlace(pSTR);
384 wchar_t* pEnd = NULL;
385 double v = wcstod(pSTR, &pEnd);
386 if ((v == 0) && (pEnd == pSTR))
387 {
388 if (bConvertByNAN)
389 {
390 *ierr = STRINGTODOUBLE_NO_ERROR;
391 dValue = returnNAN();
392 }
393 else
394 {
395 *ierr = STRINGTODOUBLE_NOT_A_NUMBER;
396 dValue = 0.0;
397 }
398 }
399 else
400 {
401 if (*pEnd == L'\0')
402 {
403 *ierr = STRINGTODOUBLE_NO_ERROR;
404 dValue = v;
405 }
406 else
407 {
408 if (bConvertByNAN)
409 {
410 *ierr = STRINGTODOUBLE_NO_ERROR;
411 dValue = returnNAN();
412 }
413 else
414 {
415 *ierr = STRINGTODOUBLE_NOT_A_NUMBER;
416 dValue = 0.0;
417 }
418 }
419 }
420
421 return dValue;
422 }
423 // =============================================================================
returnINF(BOOL bPositive)424 static double returnINF(BOOL bPositive)
425 {
426 double dbl1 = 1.0;
427 double dbl0 = dbl1 - dbl1;
428 int iSign = bPositive == 1 ? 1 : -1;
429
430 return iSign * dbl1 / dbl0;
431 }
432 // =============================================================================
returnNAN(void)433 static double returnNAN(void)
434 {
435 static int first = 1;
436 static double nan = 1.0;
437
438 if ( first )
439 {
440 nan = (nan - (double) first) / (nan - (double) first);
441 first = 0;
442 }
443 return (nan);
444 }
445 // =============================================================================
446