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