d0b4109365427c6289ebfbbe397f81c15392d5e6
[scilab.git] / scilab / modules / string / sci_gateway / cpp / sci_strtod.cpp
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) Digiteo 2011 - Cedric DELAMARRE
4  *
5  * Copyright (C) 2012 - 2016 - Scilab Enterprises
6  *
7  * This file is hereby licensed under the terms of the GNU GPL v2.0,
8  * pursuant to article 5.3.4 of the CeCILL v.2.1.
9  * This file was originally licensed under the terms of the CeCILL v2.1,
10  * and continues to be available under such terms.
11  * For more information, see the COPYING file which you should have received
12  * along with this program.
13  *
14  */
15
16
17 #include "function.hxx"
18 #include "string.hxx"
19 #include "list.hxx"
20 #include "double.hxx"
21 #include "funcmanager.hxx"
22 #include "string_gw.hxx"
23
24 extern "C"
25 {
26 #include "core_math.h"
27 #include "localization.h"
28 #include "Scierror.h"
29 #include "os_string.h"
30 #include "locale.h"
31 }
32
33
34 types::Function::ReturnValue sci_strtod(types::typed_list &in, int _iRetCount, types::typed_list &out)
35 {
36     types::Double* pOutDouble = NULL;
37     types::String* pOutString = NULL;
38     types::String* pString = NULL;
39
40     wchar_t pwstKey[] = L"1234567890";
41     wchar_t pwstSymbol[] = L"-+.";
42     wchar_t wstDecimalSep = L'.';
43
44     unsigned long long ullNan = 0x7ff8000000000000;
45     double dblNan = *( double* )&ullNan;
46
47     if (in.size() < 1 || in.size() > 2)
48     {
49         Scierror(77, _("%s: Wrong number of input argument(s): %d to %d expected.\n"), "strtod", 1, 2);
50         return types::Function::Error;
51     }
52     if (_iRetCount > 2)
53     {
54         Scierror(78, _("%s: Wrong number of output argument(s): %d to %d expected.\n"), "strtod", 1, 2);
55         return types::Function::Error;
56     }
57
58     if (in[0]->isDouble() && in[0]->getAs<types::Double>()->isEmpty())
59     {
60         out.push_back(types::Double::Empty());
61         if (_iRetCount == 2)
62         {
63             out.push_back(new types::String(L""));
64         }
65
66         return types::Function::OK;
67     }
68
69     if (in[0]->isString() == false)
70     {
71         Scierror(999, _("%s: Wrong type for input argument #%d: Matrix of strings or empty matrix expected.\n"), "strtod", 1);
72         return types::Function::Error;
73     }
74
75     pString = in[0]->getAs<types::String>();
76
77     pOutDouble = new types::Double(pString->getDims(), pString->getDimsArray());
78     if (_iRetCount == 2)
79     {
80         pOutString = new types::String(pString->getDims(), pString->getDimsArray());
81     }
82
83     if (in.size() == 2)
84     {
85         if (in[1]->isString() == false)
86         {
87             Scierror(999, _("%s: Wrong type for input argument #%d: A single string expected.\n"), "strtod", 2);
88             return types::Function::Error;
89         }
90
91         types::String* pString2 = in[1]->getAs<types::String>();
92         std::wstring pwstr(pString2->get(0));
93
94         if (pwstr != L"." && pwstr != L",")
95         {
96             Scierror(999, _("%s: Wrong value for input argument #%d: '.' or ',' expected.\n"), "strtod", 2);
97             return types::Function::Error;
98         }
99
100         wstDecimalSep = *(pwstr.c_str());
101         pwstSymbol[2] = wstDecimalSep;
102
103         if (wstDecimalSep == L',')
104         {
105 #ifdef _MSC_VER
106             setlocale(LC_NUMERIC, "French_France.1252");
107 #else
108             setlocale(LC_NUMERIC, "fr_FR.UTF-8");
109 #endif
110         }
111     }
112
113     for (int i = 0 ; i < pString->getSize() ; i++)
114     {
115         //Double part
116         bool bStop = false;
117         wchar_t *pwstStop = NULL;
118         wchar_t* pstStr = pString->get(i);
119         int iSign = (int)wcscspn(pstStr, pwstSymbol);
120         int iKey = (int)wcscspn(pstStr, pwstKey);
121
122
123         //symbol can be use only if it is before key
124         if (iSign == iKey - 1)
125         {
126             //let strtod do with symbol
127             iKey -= 1;
128         }
129
130         //special case for "-.3"
131         if (iSign == iKey - 2 && pstStr[iSign + 1] == wstDecimalSep)
132         {
133             //let strtod do with symbol
134             iKey -= 2;
135         }
136
137         //Check if there is a number in the string
138         if (iKey)
139         {
140             for (int j = 0 ; j < iKey ; j++)
141             {
142                 if ((pstStr[j] != ' ') && (pstStr[j] != '\t') && (pstStr[j] != '\r'))// spaces are accepted
143                 {
144                     pOutDouble->set(i, dblNan);
145                     bStop = true;
146                     pwstStop = pstStr;
147                     break;
148                 }
149             }
150
151             //it is still a number
152             if (bStop == false)
153             {
154                 //only spaces ?
155                 if (wcslen(pstStr) == iKey) // strtod("  ")
156                 {
157                     pOutDouble->set(i, dblNan);
158                     pwstStop = pstStr;
159                 }
160                 else // strtod("  000xxx")
161                 {
162                     pOutDouble->set(i, wcstod(pstStr + iKey, &pwstStop));
163                 }
164             }
165         }
166         else if (wcslen(pstStr) == 0) //strtod("")
167         {
168             pOutDouble->set(i, dblNan);
169         }
170         else //all characters are digits
171         {
172             pOutDouble->set(i, wcstod(pstStr, &pwstStop));
173         }
174
175         if (_iRetCount == 2)
176         {
177             if (pwstStop)
178             {
179                 pOutString->set(i, pwstStop);
180             }
181             else
182             {
183                 pOutString->set(i, L"");
184             }
185         }
186     }
187
188     if (wstDecimalSep == L',')
189     {
190         setlocale(LC_NUMERIC, "C");
191     }
192
193     out.push_back(pOutDouble);
194
195     if (_iRetCount == 2)
196     {
197         out.push_back(pOutString);
198     }
199
200     return types::Function::OK;
201 }
202