* isnum has been redesigned in native code. Up to 130x performance
[scilab.git] / scilab / modules / spreadsheet / src / c / csvWrite.c
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2010-2011 - DIGITEO - Allan CORNET
4  *
5  * This file must be used under the terms of the CeCILL.
6  * This source file is licensed as described in the file COPYING, which
7  * you should have received as part of this distribution.  The terms
8  * are also available at
9  * http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
10  *
11  */
12 #if defined(__linux__)
13 #define _GNU_SOURCE /* Bug 5673 fix: avoid dependency on GLIBC_2.7 */
14 #endif
15 // =============================================================================
16 #include <stdio.h>
17 #include <string.h>
18 #include "stringToDouble.h"
19 #include "csvWrite.h"
20 #include "mopen.h"
21 #include "mgetl.h"
22 #include "expandPathVariable.h"
23 #include "FileExist.h"
24 #include "mclose.h"
25 #include "MALLOC.h"
26 #include "core_math.h"
27 #ifdef _MSC_VER
28 #include "strdup_windows.h"
29 #endif
30 #include "strsubst.h"
31 #include "csvDefault.h"
32 #include "utftolatin.h"
33 // =============================================================================
34 #define DEFAULT_CSV_WRITE_STRING_FORMAT "%s"
35 #define DEFAULT_CSV_WRITE_DOUBLE_FORMAT "%.lg"
36 #define PlusStr "+"
37 #define LessStr "-"
38 #define ComplexStr "i"
39 #define EMPTY_STRING ""
40 #if _MSC_VER
41 #define MODEWFD "wt"
42 #else
43 #define MODEWFD "w"
44 #endif
45 #if _MSC_VER
46 #define snprintf _snprintf
47 #endif
48 // =============================================================================
49 #ifndef signbit
50 static int signbit(double x)
51 {
52     union
53     {
54         double d;
55         short s[4];
56         int i[2];
57     } u;
58
59     u.d = x;
60 #if SIZEOF_INT == 4
61     return u.i[1] < 0;
62 #else
63     return u.s[3] < 0;
64 #endif
65 }
66 #endif /* signbit */
67 // =============================================================================
68 static int doConvertToLatin(void)
69 {
70     const char *encoding = getCsvDefaultEncoding();
71     if (encoding)
72     {
73         return (strcmp(encoding, "iso-latin") == 0) ? 1 : 0;
74     }
75     return 0;
76 }
77 // =============================================================================
78 csvWriteError csvWrite_double(const char *filename,
79                               const double *pdValues, int m, int n,
80                               const char *separator,
81                               const char *decimal,
82                               const char *precisionFormat,
83                               const char **headersLines,
84                               int nbHeadersLines)
85 {
86     FILE  *fd = NULL;
87     int i = 0, j = 0;
88     char *expandedFilename = NULL;
89     int isIsoLatin = 0;
90
91     if (filename == NULL)
92     {
93         return CSV_WRITE_ERROR;
94     }
95     if (pdValues == NULL)
96     {
97         return CSV_WRITE_ERROR;
98     }
99     if (m < 0 || n < 0)
100     {
101         return CSV_WRITE_ERROR;
102     }
103     if (separator == NULL)
104     {
105         return CSV_WRITE_ERROR;
106     }
107     if (decimal == NULL)
108     {
109         return CSV_WRITE_ERROR;
110     }
111     if (precisionFormat == NULL)
112     {
113         return CSV_WRITE_ERROR;
114     }
115
116     if (strcmp(separator, decimal) == 0)
117     {
118         return CSV_WRITE_SEPARATOR_DECIMAL_EQUAL;
119     }
120
121     expandedFilename = expandPathVariable((char*)filename);
122     wcfopen(fd , filename, MODEWFD);
123     if (expandedFilename)
124     {
125         FREE(expandedFilename);
126         expandedFilename = NULL;
127     }
128     if ( fd == (FILE *)NULL )
129     {
130         return CSV_WRITE_FOPEN_ERROR;
131     }
132
133     isIsoLatin = doConvertToLatin();
134
135     if ((headersLines) && (nbHeadersLines > 0))
136     {
137         for (i = 0; i < nbHeadersLines; i++)
138         {
139             if (isIsoLatin)
140             {
141                 char *converted = utftolatin((char*)headersLines[i]);
142                 if (converted)
143                 {
144                     fprintf(fd, DEFAULT_CSV_WRITE_STRING_FORMAT, converted);
145                     FREE(converted);
146                 }
147                 else
148                 {
149                     fprintf(fd, DEFAULT_CSV_WRITE_STRING_FORMAT, headersLines[i]);
150                 }
151             }
152             else
153             {
154                 fprintf(fd, DEFAULT_CSV_WRITE_STRING_FORMAT, headersLines[i]);
155             }
156             fprintf(fd, "%s", getCsvDefaultEOL());
157         }
158     }
159
160     for (i = 0; i < m; i++)
161     {
162         for (j = 0; j < n; j++)
163         {
164             if (ISNAN(pdValues[i + m * j]))
165             {
166                 fprintf(fd, DEFAULT_CSV_WRITE_STRING_FORMAT, NanString);
167             }
168             else if (finite(pdValues[i + m * j]))
169             {
170                 char buffer[65535];
171                 char *result = NULL;
172                 sprintf(buffer, precisionFormat, pdValues[i + m * j]);
173                 result = strsub(buffer, getCsvDefaultDecimal(), decimal);
174                 if (result)
175                 {
176                     fprintf(fd, DEFAULT_CSV_WRITE_STRING_FORMAT, result);
177                     FREE(result);
178                     result = NULL;
179                 }
180                 else
181                 {
182                     fprintf(fd, DEFAULT_CSV_WRITE_DOUBLE_FORMAT, pdValues[i + m * j]);
183                 }
184             }
185             else
186             {
187                 if ( signbit(pdValues[i + m * j]) )
188                 {
189                     fprintf(fd, DEFAULT_CSV_WRITE_STRING_FORMAT, NegInfString);
190                 }
191                 else
192                 {
193                     fprintf(fd, DEFAULT_CSV_WRITE_STRING_FORMAT, InfString);
194                 }
195             }
196             if (j + 1 < n)
197             {
198                 fprintf(fd, "%s", separator);
199             }
200         }
201         fprintf(fd, "%s", getCsvDefaultEOL());
202     }
203
204     fclose(fd);
205     return CSV_WRITE_NO_ERROR;
206 }
207 // =============================================================================
208 csvWriteError csvWrite_complex(const char *filename,
209                                const double *pdValuesReal,
210                                const double *pdValuesImag,
211                                int m, int n,
212                                const char *separator,
213                                const char *decimal,
214                                const char *precisionFormat,
215                                const char **headersLines,
216                                int nbHeadersLines)
217 {
218     FILE  *fd = NULL;
219     int i = 0, j = 0;
220     char *expandedFilename = NULL;
221     int isIsoLatin = 0;
222
223     if (filename == NULL)
224     {
225         return CSV_WRITE_ERROR;
226     }
227     if (pdValuesReal == NULL)
228     {
229         return CSV_WRITE_ERROR;
230     }
231     if (pdValuesImag == NULL)
232     {
233         return CSV_WRITE_ERROR;
234     }
235     if (m < 0 || n < 0)
236     {
237         return CSV_WRITE_ERROR;
238     }
239     if (separator == NULL)
240     {
241         return CSV_WRITE_ERROR;
242     }
243     if (decimal == NULL)
244     {
245         return CSV_WRITE_ERROR;
246     }
247     if (precisionFormat == NULL)
248     {
249         return CSV_WRITE_ERROR;
250     }
251
252     if (strcmp(separator, decimal) == 0)
253     {
254         return CSV_WRITE_SEPARATOR_DECIMAL_EQUAL;
255     }
256
257     expandedFilename = expandPathVariable((char*)filename);
258     wcfopen(fd , filename, MODEWFD);
259     if (expandedFilename)
260     {
261         FREE(expandedFilename);
262         expandedFilename = NULL;
263     }
264     if ( fd == (FILE *)NULL )
265     {
266         return CSV_WRITE_FOPEN_ERROR;
267     }
268
269     isIsoLatin = doConvertToLatin();
270
271     if ((headersLines) && (nbHeadersLines > 0))
272     {
273         for (i = 0; i < nbHeadersLines; i++)
274         {
275             if (isIsoLatin)
276             {
277                 const char *converted = utftolatin((char*)headersLines[i]);
278                 if (converted)
279                 {
280                     fprintf(fd, DEFAULT_CSV_WRITE_STRING_FORMAT, converted);
281                     FREE((char*)converted);
282                     converted = NULL;
283                 }
284                 else
285                 {
286                     fprintf(fd, DEFAULT_CSV_WRITE_STRING_FORMAT, headersLines[i]);
287                 }
288             }
289             else
290             {
291                 fprintf(fd, DEFAULT_CSV_WRITE_STRING_FORMAT, headersLines[i]);
292             }
293             fprintf(fd, "%s", getCsvDefaultEOL());
294         }
295     }
296
297     for (i = 0; i < m; i++)
298     {
299         for (j = 0; j < n; j++)
300         {
301             char StringValue[65535];
302
303             double realValue = pdValuesReal[i + m * j];
304             double imagValue = pdValuesImag[i + m * j];
305             int hasReal = 0;
306
307             if (ISNAN(realValue))
308             {
309                 strcpy(StringValue, NanString);
310                 hasReal = 1;
311             }
312             else if (finite(realValue))
313             {
314                 if ((realValue != 0) || (finite(imagValue) && (imagValue == 0)))
315                 {
316                     char buffer[65535];
317                     char *result = NULL;
318
319                     sprintf(buffer, precisionFormat, pdValuesReal[i + m * j]);
320                     result = strsub(buffer, getCsvDefaultDecimal(), decimal);
321                     if (result)
322                     {
323                         strcpy(StringValue, result);
324                         FREE(result);
325                     }
326                     else
327                     {
328                         sprintf(StringValue, DEFAULT_CSV_WRITE_DOUBLE_FORMAT, pdValuesReal[i + m * j]);
329                     }
330                     hasReal = 1;
331                 }
332             }
333             else
334             {
335                 if (signbit(realValue))
336                 {
337                     strcpy(StringValue, NegInfString);
338                 }
339                 else
340                 {
341                     strcpy(StringValue, InfString);
342                 }
343                 hasReal = 1;
344             }
345
346             if (ISNAN(imagValue))
347             {
348                 if (hasReal)
349                 {
350                     strcat(StringValue, PlusStr);
351                     strcat(StringValue, NanString);
352                 }
353                 else
354                 {
355                     strcpy(StringValue, NanString);
356                 }
357                 strcat(StringValue, ComplexStr);
358             }
359             else if (finite(imagValue))
360             {
361                 if (imagValue != 0)
362                 {
363                     char buffer[65535];
364                     char *result = NULL;
365
366                     if (hasReal && (imagValue > 0))
367                     {
368                         strcat(StringValue, PlusStr);
369                     }
370                     else if (imagValue < 0)
371                     {
372                         if (hasReal)
373                         {
374                             strcat(StringValue, LessStr);
375                         }
376                         else
377                         {
378                             strcpy(StringValue, LessStr);
379                         }
380                     }
381
382                     sprintf(buffer, precisionFormat, fabs(imagValue));
383                     result = strsub(buffer, getCsvDefaultDecimal(), decimal);
384                     if (result)
385                     {
386                         if ((hasReal) || (imagValue < 0))
387                         {
388                             strcat(StringValue, result);
389                         }
390                         else
391                         {
392                             strcpy(StringValue, result);
393                         }
394                         FREE(result);
395                     }
396                     else
397                     {
398                         sprintf(StringValue, DEFAULT_CSV_WRITE_DOUBLE_FORMAT, imagValue);
399                     }
400                     strcat(StringValue, ComplexStr);
401                 }
402             }
403             else
404             {
405                 if (hasReal && (signbit(imagValue) == 0))
406                 {
407                     strcat(StringValue, PlusStr);
408                 }
409                 else if (signbit(realValue) > 0)
410                 {
411                     if (hasReal)
412                     {
413                         strcat(StringValue, LessStr);
414                     }
415                     else
416                     {
417                         strcpy(StringValue, LessStr);
418                     }
419                 }
420                 strcat(StringValue, InfString);
421                 strcat(StringValue, ComplexStr);
422             }
423             fprintf(fd, DEFAULT_CSV_WRITE_STRING_FORMAT, StringValue);
424             if (j + 1 < n)
425             {
426                 fprintf(fd, "%s", separator);
427             }
428         }
429         fprintf(fd, "%s", getCsvDefaultEOL());
430     }
431
432     fclose(fd);
433     return CSV_WRITE_NO_ERROR;
434 }
435 // =============================================================================
436 csvWriteError csvWrite_string(const char *filename,
437                               const char **pStrValues, int m, int n,
438                               const char *separator,
439                               const char *decimal,
440                               const char **headersLines,
441                               int nbHeadersLines)
442 {
443     FILE  *fd = NULL;
444     int i = 0, j = 0;
445     char *expandedFilename = NULL;
446     int isIsoLatin = 0;
447
448     if (filename == NULL)
449     {
450         return CSV_WRITE_ERROR;
451     }
452     if (pStrValues == NULL)
453     {
454         return CSV_WRITE_ERROR;
455     }
456     if (m < 0 || n < 0)
457     {
458         return CSV_WRITE_ERROR;
459     }
460     if (separator == NULL)
461     {
462         return CSV_WRITE_ERROR;
463     }
464
465     if (strcmp(separator, decimal) == 0)
466     {
467         return CSV_WRITE_SEPARATOR_DECIMAL_EQUAL;
468     }
469
470     expandedFilename = expandPathVariable((char*)filename);
471     wcfopen(fd , filename, MODEWFD);
472     if (expandedFilename)
473     {
474         FREE(expandedFilename);
475         expandedFilename = NULL;
476     }
477     if ( fd == (FILE *)NULL )
478     {
479         return CSV_WRITE_FOPEN_ERROR;
480     }
481
482     isIsoLatin = doConvertToLatin();
483
484     if ((headersLines) && (nbHeadersLines > 0))
485     {
486         for (i = 0; i < nbHeadersLines; i++)
487         {
488             if (isIsoLatin)
489             {
490                 const char *converted = utftolatin((char*)headersLines[i]);
491                 if (converted)
492                 {
493                     fprintf(fd, DEFAULT_CSV_WRITE_STRING_FORMAT, converted);
494                     FREE((char*)converted);
495                     converted = NULL;
496                 }
497                 else
498                 {
499                     fprintf(fd, DEFAULT_CSV_WRITE_STRING_FORMAT, headersLines[i]);
500                 }
501             }
502             else
503             {
504                 fprintf(fd, DEFAULT_CSV_WRITE_STRING_FORMAT, headersLines[i]);
505             }
506             fprintf(fd, "%s", getCsvDefaultEOL());
507         }
508     }
509
510     for (i = 0 ; i < m ; i++ )
511     {
512         for ( j = 0 ; j < n ; j++)
513         {
514             if (decimal == NULL)
515             {
516                 if (isIsoLatin)
517                 {
518                     const char *converted = utftolatin((char*)pStrValues[i + m * j]);
519                     if (converted)
520                     {
521                         fprintf(fd, DEFAULT_CSV_WRITE_STRING_FORMAT, converted);
522                         FREE((char*)converted);
523                         converted = NULL;
524                     }
525                     else
526                     {
527                         fprintf(fd, DEFAULT_CSV_WRITE_STRING_FORMAT, pStrValues[i + m * j]);
528                     }
529                 }
530                 else
531                 {
532                     fprintf(fd, DEFAULT_CSV_WRITE_STRING_FORMAT, pStrValues[i + m * j]);
533                 }
534             }
535             else
536             {
537                 char *result = NULL;
538                 result = strsub((char*)(pStrValues[i + m * j]), getCsvDefaultDecimal(), decimal);
539                 if (result)
540                 {
541                     if (isIsoLatin)
542                     {
543                         char *converted = utftolatin(result);
544                         if (converted)
545                         {
546                             fprintf(fd, DEFAULT_CSV_WRITE_STRING_FORMAT, converted);
547                             FREE(converted);
548                             converted = NULL;
549                         }
550                         else
551                         {
552                             fprintf(fd, DEFAULT_CSV_WRITE_STRING_FORMAT, result);
553                         }
554                     }
555                     else
556                     {
557                         fprintf(fd, DEFAULT_CSV_WRITE_STRING_FORMAT, result);
558                     }
559                     FREE(result);
560                     result = NULL;
561                 }
562                 else
563                 {
564                     fprintf(fd, DEFAULT_CSV_WRITE_STRING_FORMAT, pStrValues[i + m * j]);
565                 }
566             }
567             if (j + 1 < n)
568             {
569                 fprintf(fd, "%s", separator);
570             }
571         }
572         fprintf(fd, "%s", getCsvDefaultEOL());
573     }
574
575     fclose(fd);
576     return CSV_WRITE_NO_ERROR;
577 }
578 // =============================================================================
579