* read_csv has the same behavior as in the version 5.3.3
[scilab.git] / scilab / modules / spreadsheet / src / cpp / stringToComplex.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 #include <stdlib.h>
13 #include <stdio.h>
14 #include <string.h>
15 #include <math.h>
16 #include <ctype.h>
17 #include "stringToComplex.h"
18 #include "stringToDouble.h"
19 #include "MALLOC.h"
20 #ifdef  _MSC_VER
21 #include "strdup_windows.h"
22 #endif
23 #include "BOOL.h"
24 #include "csv_strsubst.h"
25 /* ========================================================================== */
26 #define PlusChar '+'
27 #define LessChar '-'
28 #define ComplexCharI 'i'
29 #define ComplexCharJ 'j'
30 #define ComplexScilab "%i"
31 #define ComplexI "i"
32 /* ========================================================================== */
33 #ifndef _MSC_VER
34 #ifndef strnicmp
35 #define strnicmp strncasecmp
36 #endif
37 #else
38 #define stricmp _stricmp
39 #endif
40 #ifdef _MSC_VER
41 #undef strnicmp
42 #define strnicmp _strnicmp
43 #endif
44 /* ========================================================================== */
45 static int ParseNumber(const char* tx);
46 static stringToComplexError ParseComplexValue(const char *tx, BOOL bConvertByNAN, double *real, double *imag);
47 static char *midstring(const char *tx, size_t pos, int nb);
48 static char *leftstring(const char *tx, size_t pos);
49 static BOOL is_unit_imaginary (const char *src, double *im);
50 static double returnNAN(void);
51 /* ========================================================================== */
52 csv_complexArray *stringsToCsvComplexArray(const char **pSTRs, int nbElements,
53         const char *decimal,
54         BOOL bConvertByNAN,
55         stringToComplexError *ierr)
56 {
57     csv_complexArray *pCsvComplexArray = NULL;
58
59     *ierr = STRINGTOCOMPLEX_ERROR;
60     if (nbElements <= 0)
61     {
62         return NULL;
63     }
64
65     if (pSTRs == NULL)
66     {
67         *ierr = STRINGTOCOMPLEX_MEMORY_ALLOCATION;
68     }
69     else
70     {
71         pCsvComplexArray = createCsvComplexArrayEmpty(nbElements);
72         if (pCsvComplexArray)
73         {
74             int i = 0;
75             for (i = 0; i < nbElements; i++)
76             {
77                 doublecomplex dComplexValue = stringToComplex(pSTRs[i], decimal, bConvertByNAN, ierr);
78                 if (*ierr != STRINGTOCOMPLEX_NO_ERROR)
79                 {
80                     freeCsvComplexArray(pCsvComplexArray);
81                     return NULL;
82                 }
83                 else
84                 {
85                     pCsvComplexArray->realPart[i] = dComplexValue.r;
86                     pCsvComplexArray->imagPart[i] = dComplexValue.i;
87                 }
88             }
89             cleanImagPartCsvComplexArray(pCsvComplexArray);
90         }
91         else
92         {
93             *ierr = STRINGTOCOMPLEX_MEMORY_ALLOCATION;
94         }
95     }
96     return pCsvComplexArray;
97 }
98 /* ========================================================================== */
99 doublecomplex stringToComplex(const char *pSTR, const char *decimal, BOOL bConvertByNAN, stringToComplexError *ierr)
100 {
101     doublecomplex dComplexValue;
102     *ierr = STRINGTOCOMPLEX_ERROR;
103
104     dComplexValue.r = 0.;
105     dComplexValue.i = 0.;
106
107     if (pSTR)
108     {
109         double real = 0.;
110         double imag = 0.;
111         char * pStrWithOutBlanks = csv_strsubst(pSTR, " ", "");
112
113         pStrWithOutBlanks = csv_strsubst(pStrWithOutBlanks, decimal, ".");
114
115         if (pStrWithOutBlanks)
116         {
117             int lenStrWithOutBlanks = (int) strlen(pStrWithOutBlanks);
118
119             /* case .4 replaced by 0.4 */
120             if (pStrWithOutBlanks[0] == '.')
121             {
122                 /* case .4 replaced by 0.4 */
123                 char *pstStrTemp = (char*)MALLOC(sizeof(char) * (lenStrWithOutBlanks + strlen("0") + 1));
124                 strcpy(pstStrTemp, "0");
125                 strcat(pstStrTemp, pStrWithOutBlanks);
126                 FREE(pStrWithOutBlanks);
127                 pStrWithOutBlanks = pstStrTemp;
128             }
129
130             if (lenStrWithOutBlanks > 1)
131             {
132                 if (((pStrWithOutBlanks[0] == '+') || (pStrWithOutBlanks[0] == '-')) &&
133                         (pStrWithOutBlanks[1] == '.'))
134                 {
135                     /* case +.4 replaced by +0.4 */
136                     char *pstStrTemp = csv_strsubst(pStrWithOutBlanks, "+.", "+0.");
137                     FREE(pStrWithOutBlanks);
138
139                     /* case -.4 replaced by -0.4 */
140                     pStrWithOutBlanks = csv_strsubst(pstStrTemp, "-.", "-0.");
141                     FREE(pstStrTemp);
142                     pstStrTemp = NULL;
143                 }
144             }
145
146             /* Case: "i", "+i", "-i", and with "j"  */
147             if (is_unit_imaginary (pStrWithOutBlanks, &imag))
148             {
149                 *ierr = STRINGTOCOMPLEX_NO_ERROR;
150                 dComplexValue.r = 0.;
151                 dComplexValue.i = imag;
152             }
153             else
154             {
155                 *ierr = ParseComplexValue(pStrWithOutBlanks, bConvertByNAN, &real, &imag);
156             }
157             FREE(pStrWithOutBlanks);
158             pStrWithOutBlanks = NULL;
159         }
160         dComplexValue.r = real;
161         dComplexValue.i = imag;
162     }
163     return dComplexValue;
164 }
165 /* ========================================================================== */
166 static int ParseNumber(const char* tx)
167 {
168     int lookahead = 0;
169     int len = 0;
170
171     if (tx[len] == NULL)
172     {
173         return lookahead;
174     }
175     if (tx[len] < 0)
176     {
177         return lookahead;
178     }
179
180     if ((tx[len] == '+') || (tx[len] == '-'))
181     {
182         len++;
183     }
184     lookahead = len;
185
186     while (isdigit(tx[len]))
187     {
188         len++;
189     }
190     lookahead = len;
191
192     if (tx[lookahead] == '.')
193     {
194         lookahead++;
195         len = 0;
196         while (isdigit(tx[len + lookahead]))
197         {
198             len++;
199         }
200         lookahead += len;
201     }
202
203     if ((tx[lookahead] == 'E') || (tx[lookahead] == 'e') ||
204             (tx[lookahead] == 'D') || (tx[lookahead] == 'd'))
205     {
206
207         lookahead++;
208         if ((tx[lookahead] == '+') || (tx[lookahead] == '-'))
209         {
210             lookahead++;
211         }
212
213         len = 0;
214         while (isdigit(tx[len + lookahead]))
215         {
216             len++;
217         }
218
219         lookahead += len;
220     }
221     return lookahead;
222 }
223 /* ========================================================================== */
224 static stringToComplexError ParseComplexValue(const char *tx, BOOL bConvertByNAN, double *real, double *imag)
225 {
226     stringToDoubleError ierrDouble = STRINGTODOUBLE_NO_ERROR;
227     stringToComplexError ierr = STRINGTOCOMPLEX_NO_ERROR;
228     char *rnum_string = NULL;
229     char *inum_string = NULL;
230     size_t lnum = 0;
231     BOOL haveImagI = FALSE;
232     char *modifiedTxt = NULL;
233
234     *real = stringToDouble(tx, FALSE, &ierrDouble);
235     *imag = 0;
236
237     /* test on strlen(tx) > 1 to remove case 'e' */
238     if ((int)strlen(tx) < 2)
239     {
240         if (ierrDouble == STRINGTODOUBLE_NO_ERROR)
241         {
242             ierr = (stringToComplexError) ierrDouble;
243         }
244         else
245         {
246             if (bConvertByNAN)
247             {
248                 ierrDouble = STRINGTODOUBLE_NOT_A_NUMBER;
249                 *real = returnNAN();
250                 *imag = 0;
251             }
252             else
253             {
254                 *real = 0;
255                 *imag = 0;
256                 ierr = (stringToComplexError) ierrDouble;
257             }
258         }
259     }
260     else if (ierrDouble != STRINGTODOUBLE_NO_ERROR)
261     {
262         modifiedTxt = csv_strsubst(tx, ComplexScilab, ComplexI);
263         lnum = ParseNumber(modifiedTxt);
264         if (lnum <= 1)
265         {
266             /* manages special cases nan + nani, ... */
267             if (strnicmp(modifiedTxt, NanString, strlen(NanString)) == 0)
268             {
269                 lnum = strlen(NanString);
270             }
271             else if (strnicmp(modifiedTxt, InfString, strlen(InfString)) == 0)
272             {
273                 lnum = strlen(InfString);
274             }
275             else if (strnicmp(modifiedTxt, NegInfString, strlen(NegInfString)) == 0)
276             {
277                 lnum = strlen(NegInfString);
278             }
279             else if (strnicmp(modifiedTxt, PosInfString, strlen(PosInfString)) == 0)
280             {
281                 lnum = strlen(PosInfString);
282             }
283             else if (strnicmp(modifiedTxt, NegNanString, strlen(NegNanString)) == 0)
284             {
285                 lnum = strlen(NegNanString);
286             }
287             else if (strnicmp(modifiedTxt, PosNanString, strlen(PosNanString)) == 0)
288             {
289                 lnum = strlen(PosNanString);
290             }
291         }
292         inum_string = midstring(modifiedTxt, lnum, -1);
293
294         if ((inum_string[strlen(inum_string) - 1] == 'i') ||
295                 (inum_string[strlen(inum_string) - 1] == 'j'))
296         {
297             inum_string[strlen(inum_string) - 1] = 0;
298             if (inum_string[strlen(inum_string) - 1] == '*')
299             {
300                 inum_string[strlen(inum_string) - 1] = 0;
301             }
302
303             if (strcmp(inum_string, "+") == 0)
304             {
305                 FREE(inum_string);
306                 inum_string = strdup("+1");
307             }
308
309             if (strcmp(inum_string, "-") == 0)
310             {
311                 FREE(inum_string);
312                 inum_string = strdup("-1");
313             }
314             haveImagI = TRUE;
315         }
316         else
317         {
318             haveImagI = FALSE;
319         }
320         rnum_string = leftstring(modifiedTxt, lnum);
321
322         if (strcmp(inum_string, "") == 0)
323         {
324             *imag = stringToDouble(rnum_string, bConvertByNAN, &ierrDouble);
325             ierr = (stringToComplexError)(ierrDouble);
326             *real = 0.;
327         }
328         else
329         {
330             double dReal = 0.;
331             double dImag = 0.;
332
333             stringToDoubleError ierrReal = STRINGTODOUBLE_NO_ERROR;
334             stringToDoubleError ierrImag = STRINGTODOUBLE_NO_ERROR;
335             dReal = stringToDouble(rnum_string, FALSE, &ierrReal);
336             dImag = stringToDouble(inum_string, FALSE, &ierrImag);
337
338             if ((ierrReal == STRINGTODOUBLE_NO_ERROR) && (ierrImag == STRINGTODOUBLE_NO_ERROR))
339             {
340                 if (!haveImagI)
341                 {
342                     if (bConvertByNAN)
343                     {
344                         ierr = STRINGTOCOMPLEX_NO_ERROR;
345                         *real = returnNAN();
346                         *imag = 0.;
347                     }
348                     else
349                     {
350                         ierr = STRINGTOCOMPLEX_ERROR;
351                     }
352                 }
353                 else
354                 {
355                     ierr = STRINGTOCOMPLEX_NO_ERROR;
356                     *real = dReal;
357                     *imag = dImag;
358                 }
359             }
360             else
361             {
362                 if (bConvertByNAN)
363                 {
364                     ierr = STRINGTOCOMPLEX_NO_ERROR;
365                     *real = returnNAN();
366                     *imag = 0.;
367                 }
368                 else
369                 {
370                     ierr = STRINGTOCOMPLEX_ERROR;
371                 }
372             }
373         }
374
375         if (rnum_string)
376         {
377             FREE(rnum_string);
378             rnum_string = NULL;
379         }
380         if (inum_string)
381         {
382             FREE(inum_string);
383             inum_string = NULL;
384         }
385         if (modifiedTxt)
386         {
387             FREE(modifiedTxt);
388             modifiedTxt = NULL;
389         }
390     }
391     return ierr;
392 }
393 /* ========================================================================== */
394 static char *midstring(const char *tx, size_t pos, int nb)
395 {
396     char *returnString = NULL;
397     if (tx)
398     {
399         int lenTx = (int) strlen(tx);
400         int posEnd = 0;
401         int newLen = 0;
402
403         if (nb < 0)
404         {
405             posEnd = lenTx;
406         }
407         else
408         {
409             posEnd = nb;
410         }
411         newLen = posEnd + 1;
412         if (newLen > 0)
413         {
414             returnString = (char*)MALLOC(sizeof(char) * newLen);
415             strncpy(returnString, &tx[pos], posEnd);
416             returnString[posEnd] = 0;
417         }
418     }
419     return returnString;
420 }
421 /* ========================================================================== */
422 static char *leftstring(const char *tx, size_t pos)
423 {
424     char *returnString = NULL;
425     if (tx)
426     {
427         int lenTx = (int) strlen(tx);
428         returnString = strdup(tx);
429         if ((pos > lenTx) || (pos < 0))
430         {
431             return returnString;
432         }
433         else
434         {
435             returnString[pos] = 0;
436         }
437     }
438     return returnString;
439 }
440 /* ========================================================================== */
441 static BOOL is_unit_imaginary (const char *src, double *im)
442 {
443     char *modifiedSrc = csv_strsubst(src, ComplexScilab, ComplexI);
444     char *nextChar = NULL;
445     BOOL isUnitImag = FALSE;
446
447     if (modifiedSrc == NULL)
448     {
449         return isUnitImag;
450     }
451
452     if (modifiedSrc[0] == LessChar)
453     {
454         *im = -1.0;
455         nextChar = modifiedSrc + 1;
456     }
457     else
458     {
459         *im = +1.0;
460         if (modifiedSrc[0] == PlusChar)
461         {
462             nextChar = modifiedSrc + 1;
463         }
464         else
465         {
466             nextChar = modifiedSrc;
467         }
468     }
469
470     if (nextChar)
471     {
472         if ((nextChar[0] == ComplexCharI || nextChar[0] == ComplexCharJ) && nextChar[1] == 0)
473         {
474             isUnitImag = TRUE;
475         }
476     }
477
478     if (modifiedSrc)
479     {
480         FREE(modifiedSrc);
481         modifiedSrc = NULL;
482     }
483     return isUnitImag;
484 }
485 /* ========================================================================== */
486 static double returnNAN(void)
487 {
488     static int first = 1;
489     static double nan = 1.0;
490
491     if ( first )
492     {
493         nan = (nan - (double) first) / (nan - (double) first);
494         first = 0;
495     }
496     return (nan);
497 }
498 // =============================================================================