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