bug 13272: fixed csvRead when looking for comments on a csv file without comments
[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     int iErrEmpty = 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     int header = 0;
54
55     char **toreplace = NULL;
56     int nbElementsToReplace = 0;
57
58     char *regexp = NULL;
59     int haveRegexp = 0;
60
61     csvResult *result = NULL;
62
63     double *dRealValues = NULL;
64
65     sciErr.iErr = 0;
66
67     CheckRhs(1, 8);
68     CheckLhs(1, 2);
69
70     if (Rhs == 8)
71     {
72         header = (int) csv_getArgumentAsScalarDouble(pvApiCtx, 8, fname, &iErr);
73         if (iErr)
74         {
75             freeVar(&filename, &separator, &decimal, &conversion, &iRange, &toreplace, 0, &regexp);
76             return 0;
77         }
78     }
79
80     if (Rhs == 7)
81     {
82         int m7 = 0, n7 = 0;
83
84         iRange = csv_getArgumentAsMatrixofIntFromDouble(pvApiCtx, 7, fname, &m7, &n7, &iErr);
85         if (iErr)
86         {
87             freeVar(&filename, &separator, &decimal, &conversion, &iRange, &toreplace, 0, &regexp);
88             return 0;
89         }
90
91         if ((m7 * n7 != SIZE_RANGE_SUPPORTED) )
92         {
93             freeVar(&filename, &separator, &decimal, &conversion, &iRange, &toreplace, 0, &regexp);
94             Scierror(999, _("%s: Wrong size for input argument #%d: Four entries expected.\n"), fname, 7);
95             return 0;
96         }
97
98         if ((m7 != 1) && (n7 != 1))
99         {
100             freeVar(&filename, &separator, &decimal, &conversion, &iRange, &toreplace, 0, &regexp);
101             Scierror(999, _("%s: Wrong size for input argument #%d: A column or row vector expected.\n"), fname, 7);
102             return 0;
103         }
104
105         if (isValidRange(iRange, m7 * n7))
106         {
107             haveRange = 1;
108         }
109         else
110         {
111             freeVar(&filename, &separator, &decimal, &conversion, &iRange, &toreplace, 0, &regexp);
112             Scierror(999, _("%s: Wrong value for input argument #%d: Inconsistent range.\n"), fname, 7);
113             return 0;
114         }
115     }
116
117
118     if (Rhs >= 6)
119     {
120         regexp = csv_getArgumentAsStringWithEmptyManagement(pvApiCtx, 6, fname, getCsvDefaultCommentsRegExp(), &iErr);
121         if (regexp)
122         {
123             if (strcmp(regexp, "") == 0)
124             {
125                 FREE(regexp);
126                 regexp = NULL;
127             }
128             else
129             {
130                 haveRegexp = 1;
131             }
132         }
133
134         if (iErr)
135         {
136             freeVar(&filename, &separator, &decimal, &conversion, &iRange, &toreplace, 0, &regexp);
137             return 0;
138         }
139     }
140     else
141     {
142         regexp = strdup(getCsvDefaultCommentsRegExp());
143         if (regexp)
144         {
145             if (strcmp(regexp, "") == 0)
146             {
147                 FREE(regexp);
148                 regexp = NULL;
149             }
150         }
151     }
152
153     if (Rhs >= 5)
154     {
155         if (csv_isEmpty(pvApiCtx, 5))
156         {
157             toreplace = NULL;
158             nbElementsToReplace = 0;
159         }
160         else
161         {
162             int m5 = 0, n5 = 0;
163             toreplace = csv_getArgumentAsMatrixOfString(pvApiCtx, 5, fname, &m5, &n5, &iErr);
164             if (iErr)
165             {
166                 freeVar(&filename, &separator, &decimal, &conversion, &iRange, &toreplace, m5 * n5, &regexp);
167                 return 0;
168             }
169
170             if (n5 != 2)
171             {
172                 freeVar(&filename, &separator, &decimal, &conversion, &iRange, &toreplace, m5 * n5, &regexp);
173                 Scierror(999, _("%s: Wrong size for input argument #%d.\n"), fname, 5);
174                 return 0;
175             }
176             nbElementsToReplace = m5;
177         }
178     }
179     else
180     {
181         toreplace = NULL;
182         nbElementsToReplace = 0;
183     }
184
185     if (Rhs >= 4)
186     {
187         int iErr = 0;
188         conversion = csv_getArgumentAsStringWithEmptyManagement(pvApiCtx, 4, fname, getCsvDefaultConversion(), &iErr);
189         if (iErr)
190         {
191             freeVar(&filename, &separator, &decimal, &conversion, &iRange, &toreplace, nbElementsToReplace, &regexp);
192             return 0;
193         }
194
195         if (!((strcmp(conversion, CONVTOSTR) == 0) || (strcmp(conversion, CONVTODOUBLE) == 0)))
196         {
197             freeVar(&filename, &separator, &decimal, &conversion, &iRange, &toreplace, nbElementsToReplace, &regexp);
198             Scierror(999, _("%s: Wrong value for input argument #%d: '%s' or '%s' string expected.\n"), fname, 4, "double", "string");
199             return 0;
200         }
201     }
202     else
203     {
204         /* read_csv is using a 'string' conversion while csvRead is doing
205            a 'double' conversion */
206         if (strcmp(fname, "read_csv") == 0)
207         {
208             conversion = (char*)MALLOC((strlen("string") + 1) * sizeof(char));
209             strcpy(conversion, "string");
210         }
211         else
212         {
213             conversion = strdup(getCsvDefaultConversion());
214         }
215     }
216
217     if (Rhs >= 3)
218     {
219         int iErr = 0;
220         decimal = csv_getArgumentAsStringWithEmptyManagement(pvApiCtx, 3, fname, getCsvDefaultDecimal(), &iErr);
221         if (iErr)
222         {
223             freeVar(&filename, &separator, &decimal, &conversion, &iRange, &toreplace, nbElementsToReplace, &regexp);
224             return 0;
225         }
226     }
227     else
228     {
229         decimal = strdup(getCsvDefaultDecimal());
230     }
231
232     if (Rhs >= 2)
233     {
234         int iErr = 0;
235         separator = csv_getArgumentAsStringWithEmptyManagement(pvApiCtx, 2, fname, getCsvDefaultSeparator(), &iErr);
236         if (iErr)
237         {
238             freeVar(&filename, &separator, &decimal, &conversion, &iRange, &toreplace, nbElementsToReplace, &regexp);
239             return 0;
240         }
241     }
242     else
243     {
244         separator = strdup(getCsvDefaultSeparator());
245     }
246
247     if (strcmp(separator, "\\t") == 0)
248     {
249         /* In Scilab, if the user is providing \t as separator, transform it to a real
250            tab. Example: read_csv(filename,"\t");
251         */
252         strcpy(separator, "\t");
253     }
254
255
256     filename = csv_getArgumentAsString(pvApiCtx, 1, fname, &iErr);
257     if (iErr)
258     {
259         freeVar(&filename, &separator, &decimal, &conversion, &iRange, &toreplace, nbElementsToReplace, &regexp);
260         return 0;
261     }
262
263     result = csvRead(filename, separator, decimal, (const char**)toreplace, nbElementsToReplace * 2, regexp, header);
264     freeVar(NULL, &separator, &decimal, NULL, NULL, &toreplace, nbElementsToReplace, &regexp);
265
266     if (result)
267     {
268         switch (result->err)
269         {
270             case CSV_READ_REGEXP_ERROR:
271             {
272                 Scierror(999, _("%s: Wrong value for input argument #%d.\n"), fname, 6);
273             }
274             break;
275
276             case CSV_READ_SEPARATOR_DECIMAL_EQUAL:
277             {
278                 Scierror(999, _("%s: separator and decimal must have different values.\n"), fname);
279             }
280             break;
281
282             case CSV_READ_NO_ERROR:
283             {
284                 if (strcmp(conversion, CONVTOSTR) == 0)
285                 {
286                     if (haveRange)
287                     {
288                         int newM = 0;
289                         int newN = 0;
290
291                         char **pStrRange = getRangeAsString((const char**)result->pstrValues, result->m, result->n, iRange, &newM, &newN);
292                         if (pStrRange)
293                         {
294                             sciErr = createMatrixOfString(pvApiCtx, Rhs + 1, newM, newN, pStrRange);
295                             freeArrayOfString(pStrRange, newM * newN);
296                         }
297                         else
298                         {
299                             if ((newM == 0) || (newN == 0))
300                             {
301                                 Scierror(999, _("%s: Range row or/and column left indice(s) out of bounds.\n"), fname);
302                             }
303                             else
304                             {
305                                 Scierror(999, _("%s: Memory allocation error.\n"), fname);
306                             }
307
308                             freeCsvResult(result);
309                             freeVar(&filename, &separator, &decimal, &conversion, &iRange, &toreplace, nbElementsToReplace, &regexp);
310                             return 0;
311                         }
312                     }
313                     else
314                     {
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 }