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