* Bug #13468 fixed - Fileio: Scilab hanged when incorrect format was used for file...
[scilab.git] / scilab / modules / fileio / sci_gateway / cpp / sci_mfscanf.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  * Copyright (C) 2012 - 2016 - Scilab Enterprises
9  *
10  * This file is hereby licensed under the terms of the GNU GPL v2.0,
11  * pursuant to article 5.3.4 of the CeCILL v.2.1.
12  * This file was originally licensed under the terms of the CeCILL v2.1,
13  * and continues to be available under such terms.
14  * For more information, see the COPYING file which you should have received
15  * along with this program.
16 *
17 */
18 /*--------------------------------------------------------------------------*/
19 #include "fileio_gw.hxx"
20 #include "string.hxx"
21 #include "mlist.hxx"
22 #include "filemanager.hxx"
23 #include "double.hxx"
24 #include "function.hxx"
25
26 extern "C"
27 {
28 #include "localization.h"
29 #include "Scierror.h"
30 #include "sciprint.h"
31 #include "mgetl.h"
32 #include "do_xxscanf.h"
33 #include "scanf_functions.h"
34 #include "StringConvert.h"
35 #include "mtell.h"
36 #include "mseek.h"
37 }
38
39 types::Function::ReturnValue sci_mfscanf(types::typed_list &in, int _iRetCount, types::typed_list &out)
40 {
41     int iFile = -1; //default file : last opened file
42     int size = (int)in.size();
43     int iNiter = 1;
44     int iErr = 0;
45     wchar_t* wcsFormat = NULL;
46     std::vector<types::InternalType*> IT;
47
48     int args        = 0;
49     int nrow        = 0;
50     int ncol        = 0;
51     int retval      = 0;
52     int retval_s    = 0;
53     int rowcount    = 0;
54     rec_entry buf[MAXSCAN] = {0};
55     entry *data;
56     sfdir type[MAXSCAN] = {NONE};
57     sfdir type_s[MAXSCAN] = {NONE};
58
59     for (int i = 0; i < MAXSCAN; ++i)
60     {
61         memset(&buf[i], 0x00, sizeof(rec_entry));
62         type[i] = NONE;
63         type_s[i] = NONE;
64     }
65
66     if (size < 2 || size > 3)
67     {
68         Scierror(77, _("%s: Wrong number of input argument(s): %d to %d expected.\n"), "mfscanf", 2, 3);
69         return types::Function::Error;
70     }
71
72     if (size == 3)
73     {
74         if (in[0]->isDouble() == false || in[0]->getAs<types::Double>()->isScalar() == false || in[0]->getAs<types::Double>()->isComplex())
75         {
76             Scierror(999, _("%s: Wrong type for input argument #%d: A Real expected.\n"), "mfscanf", 1);
77             return types::Function::Error;
78         }
79         iNiter = static_cast<int>(in[0]->getAs<types::Double>()->get(0));
80     }
81
82     if (in[size - 2]->isDouble() == false || in[size - 2]->getAs<types::Double>()->isScalar() == false || in[size - 2]->getAs<types::Double>()->isComplex())
83     {
84         Scierror(999, _("%s: Wrong type for input argument #%d: A Real expected.\n"), "mfscanf", size - 1);
85         return types::Function::Error;
86     }
87
88     if (in[size - 1]->isString() == false || in[size - 1]->getAs<types::String>()->isScalar() == false)
89     {
90         Scierror(999, _("%s: Wrong type for input argument #%d: A String expected.\n"), "mfscanf", size);
91         return types::Function::Error;
92     }
93
94     iFile = static_cast<int>(in[size - 2]->getAs<types::Double>()->get(0));
95     switch (iFile)
96     {
97         case 0: // stderr
98         case 6: // stdout
99             Scierror(999, _("%s: Wrong file descriptor: %d.\n"), "mfscanf", iFile);
100             return types::Function::Error;
101         default :
102             break;
103     }
104
105     wcsFormat = in[size - 1]->getAs<types::String>()->get(0);
106     StringConvertW(wcsFormat);
107
108     types::File* pFile = FileManager::getFile(iFile);
109     if (pFile == NULL)
110     {
111         Scierror(999, _("%s: Cannot read file %d.\n"), "mfscanf", iFile);
112         return types::Function::Error;
113     }
114
115     // file opened with fortran open function
116     if (pFile->getFileType() == 1)
117     {
118         Scierror(999, _("%s: Wrong file descriptor: %d.\n"), "mfscanf", iFile);
119         return types::Function::Error;
120     }
121
122     FILE* fDesc = pFile->getFiledesc();
123     nrow = iNiter;
124     while ((iNiter == -1) || (rowcount < iNiter))
125     {
126         // get current position in file
127         int iCurrentPos = static_cast<int>(mtell(iFile));
128
129         // get data
130         int err = do_xxscanf(L"mfscanf", fDesc, wcsFormat, &args, NULL, &retval, buf, type);
131         if (err == DO_XXPRINTF_MISMATCH)
132         {
133             break;
134         }
135         if (err < 0)
136         {
137             return types::Function::Error;
138         }
139
140         err = Store_Scan(&nrow, &ncol, type_s, type, &retval, &retval_s, buf, &data, rowcount, args);
141         if (err == DO_XXPRINTF_MEM_LACK)
142         {
143             Free_Scan(rowcount, ncol, type_s, &data);
144             Scierror(999, _("%s: No more memory.\n"), "mfscanf");
145             return types::Function::Error;
146         }
147         else if (err == DO_XXPRINTF_MISMATCH)
148         {
149             // go back to the last position
150             // only if this line is not empty
151             if (args)
152             {
153                 mseek(iFile, iCurrentPos, SEEK_SET);
154             }
155
156             for (int i = 0; i < MAXSCAN; ++i)
157             {
158                 if (type[i] == NONE)
159                 {
160                     break;
161                 }
162
163                 if (type[i] == SF_S || type[i] == SF_C)
164                 {
165                     FREE(buf[i].c);
166                     buf[i].c = NULL;
167                 }
168             }
169             break;
170         }
171
172         rowcount++;
173
174         // EOF reached
175         if (retval == -1)
176         {
177             FREE(buf->c);
178             break;
179         }
180     }
181
182     unsigned int uiFormatUsed = 0;
183     for (int i = 0; i < ncol; i++)
184     {
185         switch (type_s[i])
186         {
187             case SF_C:
188             case SF_S:
189             {
190                 types::String* ps = new types::String(rowcount, 1);
191                 for (int j = 0; j < rowcount; j++)
192                 {
193                     ps->set(j, data[i + ncol * j].s);
194                 }
195
196                 IT.push_back(ps);
197                 uiFormatUsed |= (1 << 1);
198                 break;
199             }
200             case SF_LUI:
201             case SF_SUI:
202             case SF_UI:
203             case SF_LI:
204             case SF_SI:
205             case SF_I:
206             case SF_LF:
207             case SF_F:
208             {
209                 types::Double* p = new types::Double(rowcount, 1);
210                 for (int j = 0; j < rowcount; j++)
211                 {
212                     p->set(j, data[i + ncol * j].d);
213                 }
214
215                 IT.push_back(p);
216                 uiFormatUsed |= (1 << 2);
217                 break;
218             }
219             case NONE:
220                 break;
221         }
222     }
223
224     Free_Scan(rowcount, ncol, type_s, &data);
225
226     int sizeOfVector = (int)IT.size();
227     if (_iRetCount > 1)
228     {
229         out.push_back(new types::Double((double)retval_s));
230
231         for (int i = 0; i < sizeOfVector; i++)
232         {
233             out.push_back(IT[i]);
234         }
235         for (int i = sizeOfVector + 1; i < _iRetCount; i++)
236         {
237             out.push_back(types::Double::Empty());
238         }
239     }
240     else
241     {
242         if (sizeOfVector == 0)
243         {
244             out.push_back(types::Double::Empty());
245             return types::Function::OK;
246         }
247
248         switch (uiFormatUsed)
249         {
250             case (1 << 1) :
251             {
252                 int sizeOfString = IT[0]->getAs<types::String>()->getRows();
253                 int dimsArrayOfRes[2] = {sizeOfString, sizeOfVector};
254                 types::String* pString = new types::String(2, dimsArrayOfRes);
255                 for (int i = 0; i < sizeOfVector; i++)
256                 {
257                     for (int j = 0; j < sizeOfString; j++)
258                     {
259                         pString->set(i * sizeOfString + j, IT[i]->getAs<types::String>()->get(j));
260                     }
261
262                     IT[i]->killMe();
263                 }
264                 out.push_back(pString);
265                 break;
266             }
267             case (1 << 2) :
268             {
269                 int sizeOfDouble = IT[0]->getAs<types::Double>()->getRows();
270                 int dimsArrayOfRes[2] = {sizeOfDouble, sizeOfVector};
271                 types::Double* pDouble = new types::Double(2, dimsArrayOfRes);
272                 for (int i = 0; i < sizeOfVector; i++)
273                 {
274                     for (int j = 0; j < sizeOfDouble; j++)
275                     {
276                         pDouble->set(i * sizeOfDouble + j, IT[i]->getAs<types::Double>()->get(j));
277                     }
278
279                     IT[i]->killMe();
280                 }
281
282                 out.push_back(pDouble);
283                 break;
284             }
285             default:
286             {
287                 std::vector<types::InternalType*> ITTemp;
288                 ITTemp.push_back(IT[0]);
289
290                 // sizeOfVector always > 1
291                 for (int i = 1; i < sizeOfVector; i++) // concatenates the Cells. ex : [String 4x1] [String 4x1] = [String 4x2]
292                 {
293                     if (ITTemp.back()->getType() == IT[i]->getType())
294                     {
295                         switch (ITTemp.back()->getType())
296                         {
297                             case types::InternalType::ScilabString:
298                             {
299                                 int iRows = ITTemp.back()->getAs<types::String>()->getRows();
300                                 int iCols = ITTemp.back()->getAs<types::String>()->getCols();
301                                 int arrayOfType[2] = {iRows, iCols + 1};
302                                 types::String* pType = new types::String(2, arrayOfType);
303
304                                 for (int k = 0; k < ITTemp.back()->getAs<types::String>()->getSize(); k++)
305                                 {
306                                     pType->set(k, ITTemp.back()->getAs<types::String>()->get(k));
307                                 }
308
309                                 for (int k = 0; k < IT[i]->getAs<types::String>()->getSize(); k++)
310                                 {
311                                     pType->set(iRows * iCols + k, IT[i]->getAs<types::String>()->get(k));
312                                 }
313
314                                 IT[i]->killMe();
315                                 ITTemp.pop_back();
316                                 ITTemp.push_back(pType);
317                                 break;
318                             }
319                             case types::InternalType::ScilabDouble:
320                             {
321                                 int iRows = ITTemp.back()->getAs<types::Double>()->getRows();
322                                 int iCols = ITTemp.back()->getAs<types::Double>()->getCols();
323                                 int arrayOfType[2] = {iRows, iCols + 1};
324                                 types::Double* pType = new types::Double(2, arrayOfType);
325
326                                 pType->set(ITTemp.back()->getAs<types::Double>()->get());
327                                 for (int k = 0; k < IT[i]->getAs<types::Double>()->getSize(); k++)
328                                 {
329                                     pType->set(iRows * iCols + k, IT[i]->getAs<types::Double>()->get(k));
330                                 }
331
332                                 IT[i]->killMe();
333                                 ITTemp.pop_back();
334                                 ITTemp.push_back(pType);
335                                 break;
336                             }
337                             default:
338                                 return types::Function::Error;
339                         }
340                     }
341                     else
342                     {
343                         ITTemp.push_back(IT[i]);
344                     }
345                 }
346
347                 types::MList* pMList = new types::MList();
348                 pMList->append(new types::String(L"cblock"));
349                 for (int i = 0; i < ITTemp.size(); i++)
350                 {
351                     pMList->append(ITTemp[i]);
352                 }
353                 out.push_back(pMList);
354             }
355         }
356     }
357
358     return types::Function::OK;
359 }
360 /*--------------------------------------------------------------------------*/
361