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  * Copyright (C) 2012 - 2016 - Scilab Enterprises
7  *
8  * This file is hereby licensed under the terms of the GNU GPL v2.0,
9  * pursuant to article 5.3.4 of the CeCILL v.2.1.
10  * This file was originally licensed under the terms of the CeCILL v2.1,
11  * and continues to be available under such terms.
12  * For more information, see the COPYING file which you should have received
13  * along with this program.
14  *
15  * This code is also published under the GPL v3 license.
16  *
17  */
18 #include <string.h>
19 #include <stdio.h>
20 
21 #include "gw_spreadsheet.h"
22 #include "api_scilab.h"
23 #include "Scierror.h"
24 #include "sci_malloc.h"
25 #include "csvWrite.h"
26 #include "localization.h"
27 #include "freeArrayOfString.h"
28 #include "csvDefault.h"
29 #include "checkCsvWriteFormat.h"
30 #include "gw_csv_helpers.h"
31 #include "os_string.h"
32 
33 
34 static void freeVar(char** separator, char** decimal, char** filename, char** precisionFormat, char*** pHeadersLines, int sizeHeader);
35 // =============================================================================
36 // csvWrite(M, filename[, separator, decimal, precision]) */
37 // with M string or double (not complex)
38 // =============================================================================
sci_csvWrite(char * fname,void * pvApiCtx)39 int sci_csvWrite(char *fname, void* pvApiCtx)
40 {
41     SciErr sciErr;
42     int iErr = 0;
43     csvWriteError csvError = CSV_WRITE_ERROR;
44 
45     char *separator = NULL;
46     char *decimal = NULL;
47     char *filename = NULL;
48     char *precisionFormat = NULL;
49     char **pHeadersLines = NULL;
50     int nbHeadersLines = 0;
51 
52     char **pStringValues = NULL;
53     double *pDoubleValuesReal = NULL;
54     double *pDoubleValuesImag = NULL;
55     int bIsComplex = 0;
56     int mValues = 0;
57     int nValues = 0;
58 
59     int *piAddressVarTwo = NULL;
60     int m2 = 0, n2 = 0;
61     int iType2 = 0;
62 
63     int *piAddressVarOne = NULL;
64     int m1 = 0, n1 = 0;
65     int iType1 = 0;
66 
67     CheckRhs(2, 6);
68     CheckLhs(0, 1);
69 
70     if (Rhs > 5)
71     {
72         int isOnlyRowOrCol = 0;
73         int m6 = 0;
74         int n6 = 0;
75         pHeadersLines = csv_getArgumentAsMatrixOfString(pvApiCtx, 6, fname, &m6, &n6, &iErr);
76         if (iErr)
77         {
78             freeVar(&separator, &decimal, &filename, &precisionFormat, &pHeadersLines, nbHeadersLines);
79             return 0;
80         }
81         isOnlyRowOrCol = ((m6 > 1) && (n6 == 1)) || ((m6 == 1) && (n6 > 1)) || ((m6 == 1) && (n6 == 1));
82         if (!isOnlyRowOrCol)
83         {
84             freeVar(&separator, &decimal, &filename, &precisionFormat, &pHeadersLines, nbHeadersLines);
85             Scierror(999, _("%s: Wrong size for input argument #%d: A 1-by-n or m-by-1 array of strings expected.\n"), fname, 6);
86             return 0;
87         }
88         nbHeadersLines = m6 * n6;
89     }
90 
91     if (Rhs > 4)
92     {
93         if (csv_isDoubleScalar(pvApiCtx, 5))
94         {
95 #define FORMAT_FIELDVALUESTR "%%.%dlg"
96             int iFormatValue = (int) csv_getArgumentAsScalarDouble(pvApiCtx, 5, fname, &iErr);
97             if (iErr)
98             {
99                 freeVar(&separator, &decimal, &filename, &precisionFormat, &pHeadersLines, nbHeadersLines);
100                 return 0;
101             }
102 
103             if ((iFormatValue < 1) || (iFormatValue > 17))
104             {
105                 Scierror(999, _("%s: Wrong value for input argument #%d: A double (value 1 to 17) expected.\n"), fname, 5);
106                 freeVar(&separator, &decimal, &filename, &precisionFormat, &pHeadersLines, nbHeadersLines);
107                 return 0;
108             }
109 
110             precisionFormat = (char*)MALLOC(sizeof(char) * ((int)strlen(FORMAT_FIELDVALUESTR) + 1));
111             if (precisionFormat == NULL)
112             {
113                 Scierror(999, _("%s: Memory allocation error.\n"), fname);
114                 freeVar(&separator, &decimal, &filename, &precisionFormat, &pHeadersLines, nbHeadersLines);
115                 return 0;
116             }
117             sprintf(precisionFormat, FORMAT_FIELDVALUESTR, iFormatValue);
118         }
119         else
120         {
121             precisionFormat = csv_getArgumentAsStringWithEmptyManagement(pvApiCtx, 5, fname, getCsvDefaultPrecision(), &iErr);
122             if (iErr)
123             {
124                 freeVar(&separator, &decimal, &filename, &precisionFormat, &pHeadersLines, nbHeadersLines);
125                 return 0;
126             }
127 
128             if (checkCsvWriteFormat(precisionFormat))
129             {
130                 Scierror(999, _("%s: Not supported format %s.\n"), fname, precisionFormat);
131                 freeVar(&separator, &decimal, &filename, &precisionFormat, &pHeadersLines, nbHeadersLines);
132                 return 0;
133             }
134         }
135     }
136     else
137     {
138         precisionFormat = os_strdup(getCsvDefaultPrecision());
139     }
140 
141     if (Rhs > 3)
142     {
143         decimal = csv_getArgumentAsStringWithEmptyManagement(pvApiCtx, 4, fname, getCsvDefaultDecimal(), &iErr);
144         if (iErr)
145         {
146             freeVar(&separator, &decimal, &filename, &precisionFormat, &pHeadersLines, nbHeadersLines);
147             return 0;
148         }
149 
150         if (strcmp(decimal, ".") && strcmp(decimal, ","))
151         {
152             //invalid value
153             Scierror(999, _("%s: Wrong value for input argument #%d: '%s' or '%s' expected.\n"), "write_csv", 4, ".", ",");
154             freeVar(&separator, &decimal, &filename, &precisionFormat, &pHeadersLines, nbHeadersLines);
155             return 1;
156         }
157     }
158     else
159     {
160         decimal = os_strdup(getCsvDefaultDecimal());
161     }
162 
163     if (Rhs > 2)
164     {
165         separator = csv_getArgumentAsStringWithEmptyManagement(pvApiCtx, 3, fname, getCsvDefaultSeparator(), &iErr);
166         if (iErr)
167         {
168             freeVar(&separator, &decimal, &filename, &precisionFormat, &pHeadersLines, nbHeadersLines);
169             return 0;
170         }
171     }
172     else
173     {
174         separator = os_strdup(getCsvDefaultSeparator());
175     }
176 
177     filename = csv_getArgumentAsString(pvApiCtx, 2, fname, &iErr);
178     if (iErr)
179     {
180         freeVar(&separator, &decimal, &filename, &precisionFormat, &pHeadersLines, nbHeadersLines);
181         return 0;
182     }
183 
184     sciErr = getVarAddressFromPosition(pvApiCtx, 1, &piAddressVarOne);
185     if (sciErr.iErr)
186     {
187         freeVar(&separator, &decimal, &filename, &precisionFormat, &pHeadersLines, nbHeadersLines);
188         printError(&sciErr, 0);
189         return 0;
190     }
191 
192     sciErr = getVarType(pvApiCtx, piAddressVarOne, &iType1);
193     if (sciErr.iErr)
194     {
195         freeVar(&separator, &decimal, &filename, &precisionFormat, &pHeadersLines, nbHeadersLines);
196         printError(&sciErr, 0);
197         return 0;
198     }
199 
200     if (iType1 == sci_strings)
201     {
202         pStringValues = csv_getArgumentAsMatrixOfString(pvApiCtx, 1, fname, &m1, &n1, &iErr);
203         if (iErr)
204         {
205             freeVar(&separator, &decimal, &filename, &precisionFormat, &pHeadersLines, nbHeadersLines);
206             return 0;
207         }
208     }
209     else if (iType1 == sci_matrix)
210     {
211         if (isVarComplex(pvApiCtx, piAddressVarOne))
212         {
213             bIsComplex = 1;
214             sciErr = getComplexMatrixOfDouble(pvApiCtx, piAddressVarOne, &m1, &n1, &pDoubleValuesReal, &pDoubleValuesImag);
215         }
216         else
217         {
218             sciErr = getMatrixOfDouble(pvApiCtx, piAddressVarOne, &m1, &n1, &pDoubleValuesReal);
219         }
220 
221         if (sciErr.iErr)
222         {
223             freeVar(&separator, &decimal, &filename, &precisionFormat, &pHeadersLines, nbHeadersLines);
224             printError(&sciErr, 0);
225             return 0;
226         }
227     }
228     else
229     {
230         freeVar(&separator, &decimal, &filename, &precisionFormat, &pHeadersLines, nbHeadersLines);
231         Scierror(999, _("%s: Wrong type for input argument #%d: A matrix of string or a matrix of real expected.\n"), fname, 1);
232         return 0;
233     }
234 
235     if (pStringValues)
236     {
237         csvError = csvWrite_string(filename,
238                                    (const char**)pStringValues, m1, n1,
239                                    separator,
240                                    decimal,
241                                    (const char**)pHeadersLines, nbHeadersLines);
242         freeAllocatedMatrixOfString(m1, n1, pStringValues);
243     }
244     else
245     {
246         if (bIsComplex)
247         {
248             csvError = csvWrite_complex(filename,
249                                         pDoubleValuesReal,
250                                         pDoubleValuesImag,
251                                         m1, n1,
252                                         separator,
253                                         decimal,
254                                         precisionFormat,
255                                         (const char**)pHeadersLines, nbHeadersLines);
256         }
257         else
258         {
259             csvError = csvWrite_double(filename,
260                                        pDoubleValuesReal, m1, n1,
261                                        separator,
262                                        decimal,
263                                        precisionFormat,
264                                        (const char**)pHeadersLines, nbHeadersLines);
265         }
266     }
267 
268     switch (csvError)
269     {
270         case CSV_WRITE_SEPARATOR_DECIMAL_EQUAL:
271         {
272             Scierror(999, _("%s: separator and decimal must have different values.\n"), fname);
273         }
274         break;
275         case CSV_WRITE_NO_ERROR:
276         {
277             LhsVar(1) = 0;
278             PutLhsVar();
279         }
280         break;
281 
282         case CSV_WRITE_FOPEN_ERROR:
283         {
284             Scierror(999, _("%s: can not open file %s.\n"), fname, filename);
285         }
286         break;
287         default:
288         case CSV_WRITE_ERROR:
289         {
290             Scierror(999, _("%s: error.\n"), fname);
291         }
292         break;
293     }
294 
295     freeVar(&separator, &decimal, &filename, &precisionFormat, &pHeadersLines, nbHeadersLines);
296     return 0;
297 }
298 // =============================================================================
freeVar(char ** separator,char ** decimal,char ** filename,char ** precisionFormat,char *** pHeadersLines,int sizeHeader)299 static void freeVar(char** separator, char** decimal, char** filename, char** precisionFormat, char*** pHeadersLines, int sizeHeader)
300 {
301     if (separator && *separator)
302     {
303         FREE(*separator);
304         *separator = NULL;
305     }
306 
307     if (decimal && *decimal)
308     {
309         FREE(*decimal);
310         *decimal = NULL;
311     }
312 
313     if (filename && *filename)
314     {
315         FREE(*filename);
316         *filename = NULL;
317     }
318 
319     if (precisionFormat && *precisionFormat)
320     {
321         FREE(*precisionFormat);
322         *precisionFormat = NULL;
323     }
324 
325     if (pHeadersLines && *pHeadersLines)
326     {
327         freeArrayOfString(*pHeadersLines, sizeHeader);
328         *pHeadersLines = NULL;
329     }
330 
331 }
332 
333