* isnum has been redesigned in native code. Up to 130x performance
[scilab.git] / scilab / modules / spreadsheet / sci_gateway / c / sci_csvRead.c
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2010 - 2012 - INRIA - Allan CORNET
4  * Copyright (C) 2011 - INRIA - Michael Baudin
5  *
6  * This file must be used under the terms of the CeCILL.
7  * This source file is licensed as described in the file COPYING, which
8  * you should have received as part of this distribution.  The terms
9  * are also available at
10  * http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
11  *
12  * This code is also published under the GPL v3 license.
13  *
14  */
15
16 #include <string.h>
17 #include <stdio.h>
18 #include "gw_spreadsheet.h"
19 #include "api_scilab.h"
20 #include "Scierror.h"
21 #include "localization.h"
22 #include "freeArrayOfString.h"
23 #include "MALLOC.h"
24 #include "csvRead.h"
25 #ifdef _MSC_VER
26 #include "strdup_windows.h"
27 #endif
28 #include "stringToComplex.h"
29 #include "csvDefault.h"
30 #include "complex_array.h"
31 #include "gw_csv_helpers.h"
32 #include "getRange.h"
33
34 static void releaseObjects(csvResult *result, char *filename, char *conversion);
35
36 /* ==================================================================== */
37 #define CONVTOSTR "string"
38 #define CONVTODOUBLE "double"
39 /* ==================================================================== */
40 /* csvRead(filename, separator, decimal, conversion, substitute, range)*/
41 /* ==================================================================== */
42 int sci_csvRead(char *fname, unsigned long fname_len)
43 {
44     SciErr sciErr;
45     int iErr = 0;
46
47     char *filename = NULL;
48     char *separator = NULL;
49     char *decimal = NULL;
50     char *conversion = NULL;
51     int *iRange = NULL;
52     int haveRange = 0;
53
54     char **toreplace = NULL;
55     int nbElementsToReplace = 0;
56
57     char *regexp = NULL;
58
59     csvResult *result = NULL;
60
61     double *dRealValues = NULL;
62
63     sciErr.iErr = 0;
64
65     CheckRhs(1, 7);
66     CheckLhs(1, 2);
67
68     if (Rhs == 7)
69     {
70         int m7 = 0, n7 = 0;
71
72         iRange = csv_getArgumentAsMatrixofIntFromDouble(pvApiCtx, 7, fname, &m7, &n7, &iErr);
73         if (iErr)
74         {
75             return 0;
76         }
77
78         if ((m7 * n7 != SIZE_RANGE_SUPPORTED) )
79         {
80             if (iRange)
81             {
82                 FREE(iRange);
83                 iRange = NULL;
84             }
85             Scierror(999, _("%s: Wrong size for input argument #%d: Four entries expected.\n"), fname, 7);
86             return 0;
87         }
88
89         if ((m7 != 1) && (n7 != 1))
90         {
91             if (iRange)
92             {
93                 FREE(iRange);
94                 iRange = NULL;
95             }
96             Scierror(999, _("%s: Wrong size for input argument #%d: A column or row vector expected.\n"), fname, 7);
97             return 0;
98         }
99
100         if (isValidRange(iRange, m7 * n7))
101         {
102             haveRange = 1;
103         }
104         else
105         {
106             if (iRange)
107             {
108                 FREE(iRange);
109                 iRange = NULL;
110             }
111             Scierror(999, _("%s: Wrong value for input argument #%d: Inconsistent range.\n"), fname, 7);
112             return 0;
113         }
114     }
115
116
117     if (Rhs >= 6)
118     {
119         regexp = csv_getArgumentAsStringWithEmptyManagement(pvApiCtx, 6, fname, getCsvDefaultCommentsRegExp(), &iErr);
120         if (regexp)
121         {
122             if (strcmp(regexp, "") == 0)
123             {
124                 FREE(regexp);
125                 regexp = NULL;
126             }
127         }
128         if (iErr)
129         {
130             return 0;
131         }
132     }
133     else
134     {
135         regexp = strdup(getCsvDefaultCommentsRegExp());
136         if (regexp)
137         {
138             if (strcmp(regexp, "") == 0)
139             {
140                 FREE(regexp);
141                 regexp = NULL;
142             }
143         }
144     }
145
146     if (Rhs >= 5)
147     {
148         if (csv_isEmpty(pvApiCtx, 5))
149         {
150             toreplace = NULL;
151             nbElementsToReplace = 0;
152         }
153         else
154         {
155             int m5 = 0, n5 = 0;
156             toreplace = csv_getArgumentAsMatrixOfString(pvApiCtx, 5, fname, &m5, &n5, &iErr);
157             if (iErr)
158             {
159                 if (regexp)
160                 {
161                     FREE(regexp);
162                     regexp = NULL;
163                 }
164                 return 0;
165             }
166
167             if (n5 != 2)
168             {
169                 if (regexp)
170                 {
171                     FREE(regexp);
172                     regexp = NULL;
173                 }
174                 freeArrayOfString(toreplace, m5 * n5);
175                 toreplace = NULL;
176                 Scierror(999, _("%s: Wrong size for input argument #%d.\n"), fname, 5);
177                 return 0;
178             }
179             nbElementsToReplace = m5;
180         }
181     }
182     else
183     {
184         toreplace = NULL;
185         nbElementsToReplace = 0;
186     }
187
188     if (Rhs >= 4)
189     {
190         int iErr = 0;
191         conversion = csv_getArgumentAsStringWithEmptyManagement(pvApiCtx, 4, fname, getCsvDefaultConversion(), &iErr);
192         if (iErr)
193         {
194             FREE(regexp);
195             return 0;
196         }
197         if (!((strcmp(conversion, CONVTOSTR) == 0) || (strcmp(conversion, CONVTODOUBLE) == 0)))
198         {
199             if (regexp)
200             {
201                 FREE(regexp);
202                 regexp = NULL;
203             }
204             if (toreplace)
205             {
206                 freeArrayOfString(toreplace, nbElementsToReplace * 2);
207                 toreplace = NULL;
208             }
209             if (conversion)
210             {
211                 FREE(conversion);
212                 conversion = NULL;
213             }
214             Scierror(999, _("%s: Wrong value for input argument #%d: '%s' or '%s' string expected.\n"), fname, 4, "double", "string");
215             return 0;
216         }
217     }
218     else
219     {
220         /* read_csv is using a 'string' conversion while csvRead is doing
221            a 'double' conversion */
222         if (strcmp(fname, "read_csv") == 0)
223         {
224             conversion = (char*)MALLOC((strlen("string") + 1) * sizeof(char));
225             strcpy(conversion, "string");
226         }
227         else
228         {
229             conversion = strdup(getCsvDefaultConversion());
230         }
231     }
232
233     if (Rhs >= 3)
234     {
235         int iErr = 0;
236         decimal = csv_getArgumentAsStringWithEmptyManagement(pvApiCtx, 3, fname, getCsvDefaultDecimal(), &iErr);
237         if (iErr)
238         {
239             if (regexp)
240             {
241                 FREE(regexp);
242                 regexp = NULL;
243             }
244             if (conversion)
245             {
246                 FREE(conversion);
247                 conversion = NULL;
248             }
249             if (toreplace)
250             {
251                 freeArrayOfString(toreplace, nbElementsToReplace * 2);
252                 toreplace = NULL;
253             }
254             return 0;
255         }
256     }
257     else
258     {
259         decimal = strdup(getCsvDefaultDecimal());
260     }
261
262     if (Rhs >= 2)
263     {
264         int iErr = 0;
265         separator = csv_getArgumentAsStringWithEmptyManagement(pvApiCtx, 2, fname, getCsvDefaultSeparator(), &iErr);
266         if (iErr)
267         {
268             if (regexp)
269             {
270                 FREE(regexp);
271                 regexp = NULL;
272             }
273             if (toreplace)
274             {
275                 freeArrayOfString(toreplace, nbElementsToReplace * 2);
276                 toreplace = NULL;
277             }
278             if (conversion)
279             {
280                 FREE(conversion);
281                 conversion = NULL;
282             }
283             if (decimal)
284             {
285                 FREE(decimal);
286                 decimal = NULL;
287             }
288             return 0;
289         }
290     }
291     else
292     {
293         separator = strdup(getCsvDefaultSeparator());
294     }
295
296     if (strcmp(separator, "\\t") == 0)
297     {
298         /* In Scilab, if the user is providing \t as separator, transform it to a real
299            tab. Example: read_csv(filename,"\t");
300         */
301         strcpy(separator, "\t");
302     }
303
304
305     filename = csv_getArgumentAsString(pvApiCtx, 1, fname, &iErr);
306     if (iErr)
307     {
308         if (regexp)
309         {
310             FREE(regexp);
311             regexp = NULL;
312         }
313         if (toreplace)
314         {
315             freeArrayOfString(toreplace, nbElementsToReplace * 2);
316             toreplace = NULL;
317         }
318         if (separator)
319         {
320             FREE(separator);
321             separator = NULL;
322         }
323         if (conversion)
324         {
325             FREE(conversion);
326             conversion = NULL;
327         }
328         if (decimal)
329         {
330             FREE(decimal);
331             decimal = NULL;
332         }
333         return 0;
334     }
335
336     result = csvRead(filename, separator, decimal, (const char**)toreplace, nbElementsToReplace * 2, regexp);
337     if (regexp)
338     {
339         FREE(regexp);
340         regexp = NULL;
341     }
342     if (toreplace)
343     {
344         freeArrayOfString(toreplace, nbElementsToReplace * 2);
345         toreplace = NULL;
346     }
347     if (separator)
348     {
349         FREE(separator);
350         separator = NULL;
351     }
352     if (decimal)
353     {
354         FREE(decimal);
355         decimal = NULL;
356     }
357
358     if (result)
359     {
360         switch (result->err)
361         {
362             case CSV_READ_REGEXP_ERROR:
363             {
364                 Scierror(999, _("%s: Wrong value for input argument #%d.\n"), fname, 6);
365             }
366             break;
367
368             case CSV_READ_SEPARATOR_DECIMAL_EQUAL:
369             {
370                 Scierror(999, _("%s: separator and decimal must have different values.\n"), fname);
371             }
372             break;
373
374             case CSV_READ_NO_ERROR:
375             {
376                 if (strcmp(conversion, CONVTOSTR) == 0)
377                 {
378                     if (haveRange)
379                     {
380                         int newM = 0;
381                         int newN = 0;
382
383                         char **pStrRange = getRangeAsString((const char**)result->pstrValues, result->m, result->n, iRange, &newM, &newN);
384                         if (pStrRange)
385                         {
386                             sciErr = createMatrixOfString(pvApiCtx, Rhs + 1, newM, newN, pStrRange);
387                             freeArrayOfString(pStrRange, newM * newN);
388                         }
389                         else
390                         {
391                             if ((newM == 0) || (newN == 0))
392                             {
393                                 Scierror(999, _("%s: Range row or/and column left indice(s) out of bounds.\n"), fname);
394                             }
395                             else
396                             {
397                                 Scierror(999, _("%s: Memory allocation error.\n"), fname);
398                             }
399                             releaseObjects(result, filename, conversion);
400                             return 0;
401                         }
402                     }
403                     else
404                     {
405                         sciErr = createMatrixOfString(pvApiCtx, Rhs + 1, result->m, result->n, result->pstrValues);
406                     }
407                 }
408                 else /* to double */
409                 {
410                     stringToComplexError ierr = STRINGTOCOMPLEX_ERROR;
411                     complexArray *ptrComplexArray = stringsToComplexArray((const char**)result->pstrValues, result->m * result->n, decimal, TRUE, &ierr);
412
413                     if (ptrComplexArray == NULL)
414                     {
415                         releaseObjects(result, filename, conversion);
416                         if (ierr == STRINGTOCOMPLEX_ERROR)
417                         {
418                             Scierror(999, _("%s: can not convert data.\n"), fname);
419                         }
420                         else
421                         {
422                             Scierror(999, _("%s: Memory allocation error.\n"), fname);
423                         }
424                         return 0;
425                     }
426
427                     switch (ierr)
428                     {
429                         case STRINGTOCOMPLEX_NOT_A_NUMBER:
430                         case STRINGTOCOMPLEX_NO_ERROR:
431                         {
432                             if (haveRange)
433                             {
434                                 int newM = 0;
435                                 int newN = 0;
436                                 complexArray *complexRange = getRangeAsComplexArray(ptrComplexArray, result->m, result->n, iRange, &newM, &newN);
437                                 if (complexRange)
438                                 {
439                                     if (complexRange->isComplex)
440                                     {
441                                         sciErr = createComplexMatrixOfDouble(pvApiCtx, Rhs + 1, newM, newN, ptrComplexArray->realPart, ptrComplexArray->imagPart);
442                                     }
443                                     else
444                                     {
445                                         sciErr = createMatrixOfDouble(pvApiCtx, Rhs + 1, newM, newN, complexRange->realPart);
446                                     }
447                                     freeComplexArray(complexRange);
448                                     complexRange = NULL;
449                                 }
450                                 else
451                                 {
452                                     if ((newM == 0) || (newN == 0))
453                                     {
454                                         Scierror(999, _("%s: Range row or/and column left indice(s) out of bounds.\n"), fname);
455                                     }
456                                     else
457                                     {
458                                         Scierror(999, _("%s: Memory allocation error.\n"), fname);
459                                     }
460                                     releaseObjects(result, filename, conversion);
461                                     return 0;
462                                 }
463                             }
464                             else
465                             {
466                                 if (ptrComplexArray->isComplex)
467                                 {
468                                     sciErr = createComplexMatrixOfDouble(pvApiCtx, Rhs + 1, result->m, result->n, ptrComplexArray->realPart, ptrComplexArray->imagPart);
469                                 }
470                                 else
471                                 {
472                                     sciErr = createMatrixOfDouble(pvApiCtx, Rhs + 1, result->m, result->n, ptrComplexArray->realPart);
473                                 }
474                                 freeComplexArray(ptrComplexArray);
475                                 ptrComplexArray = NULL;
476                             }
477                         }
478                         break;
479
480                         case STRINGTOCOMPLEX_MEMORY_ALLOCATION:
481                         {
482                             Scierror(999, _("%s: Memory allocation error.\n"), fname);
483                             releaseObjects(result, filename, conversion);
484                             return 0;
485                         }
486                         default:
487                         case STRINGTOCOMPLEX_ERROR:
488                         {
489                             Scierror(999, _("%s: can not convert data.\n"), fname);
490                             releaseObjects(result, filename, conversion);
491                             return 0;
492                         }
493                     }
494                 }
495
496                 if (sciErr.iErr)
497                 {
498                     Scierror(999, _("%s: Memory allocation error.\n"), fname);
499                     releaseObjects(result, filename, conversion);
500                     return 0;
501                 }
502                 else
503                 {
504                     LhsVar(1) = Rhs + 1;
505
506                     if (Lhs == 2)
507                     {
508                         sciErr = createMatrixOfString(pvApiCtx, Rhs + 2, result->nbComments, 1, result->pstrComments);
509                         if (sciErr.iErr)
510                         {
511                             Scierror(999, _("%s: Memory allocation error.\n"), fname);
512                             releaseObjects(result, filename, conversion);
513                             return 0;
514                         }
515                         LhsVar(2) = Rhs + 2;
516                     }
517                     PutLhsVar();
518                 }
519             }
520             break;
521
522             case CSV_READ_FILE_NOT_EXIST:
523             {
524                 Scierror(999, _("%s: %s does not exist.\n"), fname, filename);
525             }
526             break;
527
528             case CSV_READ_MOPEN_ERROR:
529             {
530                 Scierror(999, _("%s: can not open file %s.\n"), fname, filename);
531             }
532             break;
533
534             case CSV_READ_MEMORY_ALLOCATION:
535             {
536                 Scierror(999, _("%s: Memory allocation error.\n"), fname);
537             }
538             break;
539
540             case CSV_READ_COLUMNS_ERROR:
541             {
542                 Scierror(999, _("%s: can not read file %s: Error in the column structure\n"), fname, filename);
543             }
544             break;
545
546             case CSV_READ_READLINES_ERROR:
547             case CSV_READ_ERROR:
548             {
549                 Scierror(999, _("%s: can not read file %s.\n"), fname, filename);
550             }
551             break;
552         }
553     }
554     else
555     {
556         Scierror(999, _("%s: Memory allocation error.\n"), fname);
557     }
558     releaseObjects(result, filename, conversion);
559
560     return 0;
561 }
562 /* ==================================================================== */
563 static void releaseObjects(csvResult *result, char* filename, char* conversion)
564 {
565     freeCsvResult(result);
566
567     FREE(filename);
568     filename = NULL;
569
570     FREE(conversion);
571     conversion = NULL;
572 }