[bug_14020] mscanf fixed about empty data.
[scilab.git] / scilab / modules / fileio / sci_gateway / cpp / sci_mscanf.cpp
1 /*
2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) 2006 - INRIA - Allan CORNET
4 * Copyright (C) 2009 - DIGITEO - Allan CORNET
5 * Copyright (C) 2010 - DIGITEO - Antoine ELIAS
6 * Copyright (C) 2011 - DIGITEO - Cedric DELAMARRE
7 *
8 * This file must be used under the terms of the CeCILL.
9 * This source file is licensed as described in the file COPYING, which
10 * you should have received as part of this distribution.  The terms
11 * are also available at
12 * http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
13 *
14 */
15 /*--------------------------------------------------------------------------*/
16 #include "fileio_gw.hxx"
17 #include "string.hxx"
18 #include "scilabWrite.hxx"
19 #include "cell.hxx"
20 #include "function.hxx"
21 #include "double.hxx"
22
23 extern "C"
24 {
25 #include "sci_malloc.h"
26 #include "localization.h"
27 #include "Scierror.h"
28 #include "do_xxscanf.h"
29 #include "scanf_functions.h"
30 #include "scilabRead.h"
31 }
32
33 types::Function::ReturnValue sci_mscanf(types::typed_list &in, int _iRetCount, types::typed_list &out)
34 {
35     int size                    = (int)in.size();
36     int iNiter                  = 1;
37     wchar_t* wcsFormat          = NULL;
38     wchar_t* wcsRead            = NULL;
39     int dimsArray[2]            = {1, 1};
40     std::vector<types::InternalType*>* pIT = new std::vector<types::InternalType*>();
41
42     int args        = 0;
43     int nrow        = 0;
44     int ncol        = 0;
45     int retval      = 0;
46     int retval_s    = 0;
47     int rowcount    = -1;
48     rec_entry buf[MAXSCAN];
49     entry *data;
50     sfdir type[MAXSCAN], type_s[MAXSCAN];
51
52     if (size < 1 || size > 2)
53     {
54         Scierror(77, _("%s: Wrong number of input argument(s): %d to %d expected.\n"), "mscanf", 1, 2);
55         return types::Function::Error;
56     }
57
58     if (size == 2)
59     {
60         if (in[0]->isDouble() == false || in[0]->getAs<types::Double>()->isScalar() == false || in[0]->getAs<types::Double>()->isComplex())
61         {
62             Scierror(999, _("%s: Wrong type for input argument #%d: A Real expected.\n"), "mscanf", 1);
63             return types::Function::Error;
64         }
65         iNiter = static_cast<int>(in[0]->getAs<types::Double>()->get(0));
66         if (iNiter < 0)
67         {
68             iNiter = 1;
69         }
70     }
71
72     if (in[size - 1]->isString() == false || in[size - 1]->getAs<types::String>()->isScalar() == false)
73     {
74         Scierror(999, _("%s: Wrong type for input argument #%d: A String expected.\n"), "mscanf", size);
75         return types::Function::Error;
76     }
77
78     wcsFormat = in[size - 1]->getAs<types::String>()->get(0);
79     nrow = iNiter;
80     while (++rowcount < iNiter)
81     {
82         if ((iNiter >= 0) && (rowcount >= iNiter))
83         {
84             break;
85         }
86         // get data
87         wcsRead = to_wide_string(scilabRead());
88         int err = do_xxscanf(L"sscanf", (FILE *)0, wcsFormat, &args, wcsRead, &retval, buf, type);
89         if (err < 0)
90         {
91             return types::Function::Error;
92         }
93         err = Store_Scan(&nrow, &ncol, type_s, type, &retval, &retval_s, buf, &data, rowcount, args);
94         if (err < 0)
95         {
96             switch (err)
97             {
98                 case DO_XXPRINTF_MISMATCH:
99                     if (iNiter >= 0)
100                     {
101                         Free_Scan(rowcount, ncol, type_s, &data);
102                         Scierror(999, _("%s: Data mismatch.\n"), "mscanf");
103                         return types::Function::Error;
104                     }
105                     break;
106
107                 case DO_XXPRINTF_MEM_LACK:
108                     Free_Scan(rowcount, ncol, type_s, &data);
109                     Scierror(999, _("%s: No more memory.\n"), "mscanf");
110                     return types::Function::Error;
111                     break;
112             }
113             if (err == DO_XXPRINTF_MISMATCH)
114             {
115                 break;
116             }
117         }
118         FREE(wcsRead);
119     }
120
121     unsigned int uiFormatUsed = 0;
122     for (int i = 0; i < ncol; i++)
123     {
124         switch ( type_s[i] )
125         {
126             case SF_C:
127             case SF_S:
128             {
129                 types::String* ps = new types::String(iNiter, 1);
130                 for (int j = 0; j < iNiter; j++)
131                 {
132                     ps->set(j, data[i + ncol * j].s);
133                 }
134                 pIT->push_back(ps);
135                 uiFormatUsed |= (1 << 1);
136             }
137             break;
138             case SF_LUI:
139             case SF_SUI:
140             case SF_UI:
141             case SF_LI:
142             case SF_SI:
143             case SF_I:
144             case SF_LF:
145             case SF_F:
146             {
147                 types::Double* p = new types::Double(iNiter, 1);
148                 for (int j = 0; j < iNiter; j++)
149                 {
150                     p->set(j, data[i + ncol * j].d);
151                 }
152                 pIT->push_back(p);
153                 uiFormatUsed |= (1 << 2);
154             }
155             break;
156         }
157     }
158
159     int sizeOfVector = (int)pIT->size();
160     if (_iRetCount > 1)
161     {
162         types::Double* pDouble = new types::Double(2, dimsArray);
163         pDouble->set(0, retval);
164         out.push_back(pDouble);
165
166         for (int i = 0; i < sizeOfVector; i++)
167         {
168             out.push_back((*pIT)[i]);
169         }
170         for (int i = sizeOfVector + 1; i < _iRetCount; i++)
171         {
172             out.push_back(types::Double::Empty());
173         }
174     }
175     else
176     {
177         if (sizeOfVector == 0)
178         {
179             out.push_back(new types::String(L""));
180             return types::Function::OK;
181         }
182
183         switch (uiFormatUsed)
184         {
185             case (1 << 1) :
186             {
187                 int sizeOfString = (*pIT)[0]->getAs<types::String>()->getRows();
188                 int dimsArrayOfRes[2] = {sizeOfString, sizeOfVector};
189                 types::String* pString = new types::String(2, dimsArrayOfRes);
190                 for (int i = 0; i < sizeOfVector; i++)
191                 {
192                     for (int j = 0; j < sizeOfString; j++)
193                     {
194                         pString->set(i * sizeOfString + j, (*pIT)[i]->getAs<types::String>()->get(j));
195                     }
196                 }
197                 out.push_back(pString);
198             }
199             break;
200             case (1 << 2) :
201             {
202                 int sizeOfDouble = (*pIT)[0]->getAs<types::Double>()->getRows();
203                 int dimsArrayOfRes[2] = {sizeOfDouble, sizeOfVector};
204                 types::Double* pDouble = new types::Double(2, dimsArrayOfRes);
205                 for (int i = 0; i < sizeOfVector; i++)
206                 {
207                     for (int j = 0; j < sizeOfDouble; j++)
208                     {
209                         pDouble->set(i * sizeOfDouble + j, (*pIT)[i]->getAs<types::Double>()->get(j));
210                     }
211                 }
212                 out.push_back(pDouble);
213             }
214             break;
215             default :
216             {
217                 std::vector<types::InternalType*>* pITTemp = new std::vector<types::InternalType*>();
218                 pITTemp->push_back((*pIT)[0]);
219
220                 // sizeOfVector always > 1
221                 for (int i = 1; i < sizeOfVector; i++) // concatenates the Cells. ex : [String 4x1] [String 4x1] = [String 4x2]
222                 {
223                     if (pITTemp->back()->getType() == (*pIT)[i]->getType())
224                     {
225                         switch (pITTemp->back()->getType())
226                         {
227                             case types::InternalType::ScilabString :
228                             {
229                                 int iRows               = pITTemp->back()->getAs<types::String>()->getRows();
230                                 int iCols               = pITTemp->back()->getAs<types::String>()->getCols();
231                                 int arrayOfType[2]      = {iRows, iCols + 1};
232                                 types::String* pType    = new types::String(2, arrayOfType);
233
234                                 for (int k = 0; k < pITTemp->back()->getAs<types::String>()->getSize(); k++)
235                                 {
236                                     pType->set(k, pITTemp->back()->getAs<types::String>()->get(k));
237                                 }
238                                 for (int k = 0; k < (*pIT)[i]->getAs<types::String>()->getSize(); k++)
239                                 {
240                                     pType->set(iRows * iCols + k, (*pIT)[i]->getAs<types::String>()->get(k));
241                                 }
242                                 pITTemp->pop_back();
243                                 pITTemp->push_back(pType);
244                             }
245                             break;
246                             case types::InternalType::ScilabDouble :
247                             {
248                                 int iRows               = pITTemp->back()->getAs<types::Double>()->getRows();
249                                 int iCols               = pITTemp->back()->getAs<types::Double>()->getCols();
250                                 int arrayOfType[2]      = {iRows, iCols + 1};
251                                 types::Double* pType    = new types::Double(2, arrayOfType);
252
253                                 pType->set(pITTemp->back()->getAs<types::Double>()->get());
254                                 for (int k = 0; k < (*pIT)[i]->getAs<types::Double>()->getSize(); k++)
255                                 {
256                                     pType->set(iRows * iCols + k, (*pIT)[i]->getAs<types::Double>()->get(k));
257                                 }
258                                 pITTemp->pop_back();
259                                 pITTemp->push_back(pType);
260                             }
261                             break;
262                             default :
263                                 return types::Function::Error;
264                         }
265                     }
266                     else
267                     {
268                         pITTemp->push_back((*pIT)[i]);
269                     }
270                 }
271
272                 int dimsArrayOfCell[2] = {1, (int)pITTemp->size()};
273                 types::Cell* pCell = new types::Cell(2, dimsArrayOfCell);
274                 for (int i = 0; i < dimsArrayOfCell[1]; i++)
275                 {
276                     pCell->set(i, (*pITTemp)[i]);
277                 }
278                 out.push_back(pCell);
279             }
280         }
281     }
282     Free_Scan(rowcount, ncol, type_s, &data);
283     return types::Function::OK;
284 }
285 /*--------------------------------------------------------------------------*/