* Bug #12527 fixed - Scilab user functions were not listed in browsevar.
[scilab.git] / scilab / modules / spreadsheet / src / c / 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 *pStrTemp = csv_strsubst(pSTR, " ", "");
112
113         if (pStrTemp)
114         {
115             char *pStrFormatted = csv_strsubst(pStrTemp, decimal, ".");
116             FREE(pStrTemp);
117
118             if (pStrFormatted)
119             {
120                 int lenStrFormatted = (int) strlen(pStrFormatted);
121
122                 /* case .4 replaced by 0.4 */
123                 if (pStrFormatted[0] == '.')
124                 {
125                     /* case .4 replaced by 0.4 */
126                     char *pstStrTemp = (char*)MALLOC(sizeof(char) * (lenStrFormatted + strlen("0") + 1));
127                     strcpy(pstStrTemp, "0");
128                     strcat(pstStrTemp, pStrFormatted);
129                     FREE(pStrFormatted);
130                     pStrFormatted = pstStrTemp;
131                 }
132
133                 if (lenStrFormatted > 1)
134                 {
135                     if (((pStrFormatted[0] == '+') || (pStrFormatted[0] == '-')) &&
136                             (pStrFormatted[1] == '.'))
137                     {
138                         /* case +.4 replaced by +0.4 */
139                         char *pstStrTemp = csv_strsubst(pStrFormatted, "+.", "+0.");
140                         FREE(pStrFormatted);
141
142                         /* case -.4 replaced by -0.4 */
143                         pStrFormatted = csv_strsubst(pstStrTemp, "-.", "-0.");
144                         FREE(pstStrTemp);
145                     }
146                 }
147
148                 /* Case: "i", "+i", "-i", and with "j"  */
149                 if (is_unit_imaginary (pStrFormatted, &imag))
150                 {
151                     *ierr = STRINGTOCOMPLEX_NO_ERROR;
152                     dComplexValue.r = 0.;
153                     dComplexValue.i = imag;
154                 }
155                 else
156                 {
157                     *ierr = ParseComplexValue(pStrFormatted, bConvertByNAN, &real, &imag);
158                 }
159                 FREE(pStrFormatted);
160             }
161         }
162         dComplexValue.r = real;
163         dComplexValue.i = imag;
164     }
165     return dComplexValue;
166 }
167 /* ========================================================================== */
168 static int ParseNumber(const char* tx)
169 {
170     int lookahead = 0;
171     int len = 0;
172
173     if (tx[len] == NULL)
174     {
175         return lookahead;
176     }
177     if (tx[len] < 0)
178     {
179         return lookahead;
180     }
181
182     if ((tx[len] == '+') || (tx[len] == '-'))
183     {
184         len++;
185     }
186
187     while (isdigit(tx[len]))
188     {
189         len++;
190     }
191     lookahead = len;
192
193     if (tx[lookahead] == '.')
194     {
195         lookahead++;
196         len = 0;
197         while (isdigit(tx[len + lookahead]))
198         {
199             len++;
200         }
201         lookahead += len;
202     }
203
204     if ((tx[lookahead] == 'E') || (tx[lookahead] == 'e') ||
205             (tx[lookahead] == 'D') || (tx[lookahead] == 'd'))
206     {
207
208         lookahead++;
209         if ((tx[lookahead] == '+') || (tx[lookahead] == '-'))
210         {
211             lookahead++;
212         }
213
214         len = 0;
215         while (isdigit(tx[len + lookahead]))
216         {
217             len++;
218         }
219
220         lookahead += len;
221     }
222     return lookahead;
223 }
224 /* ========================================================================== */
225 static stringToComplexError ParseComplexValue(const char *tx, BOOL bConvertByNAN, double *real, double *imag)
226 {
227     stringToDoubleError ierrDouble = STRINGTODOUBLE_NO_ERROR;
228     stringToComplexError ierr = STRINGTOCOMPLEX_NO_ERROR;
229     char *rnum_string = NULL;
230     char *inum_string = NULL;
231     size_t lnum = 0;
232     BOOL haveImagI = FALSE;
233     char *modifiedTxt = NULL;
234
235     *real = stringToDouble(tx, FALSE, &ierrDouble);
236     *imag = 0;
237
238     /* test on strlen(tx) > 1 to remove case 'e' */
239     if ((int)strlen(tx) < 2)
240     {
241         if (ierrDouble == STRINGTODOUBLE_NO_ERROR)
242         {
243             ierr = (stringToComplexError) ierrDouble;
244         }
245         else
246         {
247             if (bConvertByNAN)
248             {
249                 ierrDouble = STRINGTODOUBLE_NOT_A_NUMBER;
250                 *real = returnNAN();
251                 *imag = 0;
252             }
253             else
254             {
255                 *real = 0;
256                 *imag = 0;
257                 ierr = (stringToComplexError) ierrDouble;
258             }
259         }
260     }
261     else if (ierrDouble != STRINGTODOUBLE_NO_ERROR)
262     {
263         modifiedTxt = csv_strsubst(tx, ComplexScilab, ComplexI);
264         lnum = ParseNumber(modifiedTxt);
265         if (lnum <= 1)
266         {
267             /* manages special cases nan + nani, ... */
268             if (strnicmp(modifiedTxt, NanString, strlen(NanString)) == 0)
269             {
270                 lnum = strlen(NanString);
271             }
272             else if (strnicmp(modifiedTxt, InfString, strlen(InfString)) == 0)
273             {
274                 lnum = strlen(InfString);
275             }
276             else if (strnicmp(modifiedTxt, NegInfString, strlen(NegInfString)) == 0)
277             {
278                 lnum = strlen(NegInfString);
279             }
280             else if (strnicmp(modifiedTxt, PosInfString, strlen(PosInfString)) == 0)
281             {
282                 lnum = strlen(PosInfString);
283             }
284             else if (strnicmp(modifiedTxt, NegNanString, strlen(NegNanString)) == 0)
285             {
286                 lnum = strlen(NegNanString);
287             }
288             else if (strnicmp(modifiedTxt, PosNanString, strlen(PosNanString)) == 0)
289             {
290                 lnum = strlen(PosNanString);
291             }
292         }
293         inum_string = midstring(modifiedTxt, lnum, -1);
294
295         if ((inum_string[strlen(inum_string) - 1] == 'i') ||
296                 (inum_string[strlen(inum_string) - 1] == 'j'))
297         {
298             inum_string[strlen(inum_string) - 1] = 0;
299             if (inum_string[strlen(inum_string) - 1] == '*')
300             {
301                 inum_string[strlen(inum_string) - 1] = 0;
302             }
303
304             if (strcmp(inum_string, "+") == 0)
305             {
306                 FREE(inum_string);
307                 inum_string = strdup("+1");
308             }
309
310             if (strcmp(inum_string, "-") == 0)
311             {
312                 FREE(inum_string);
313                 inum_string = strdup("-1");
314             }
315             haveImagI = TRUE;
316         }
317         else
318         {
319             haveImagI = FALSE;
320         }
321         rnum_string = leftstring(modifiedTxt, lnum);
322
323         if (strcmp(inum_string, "") == 0)
324         {
325             *imag = stringToDouble(rnum_string, bConvertByNAN, &ierrDouble);
326             ierr = (stringToComplexError)(ierrDouble);
327             *real = 0.;
328         }
329         else
330         {
331             double dReal = 0.;
332             double dImag = 0.;
333
334             stringToDoubleError ierrReal = STRINGTODOUBLE_NO_ERROR;
335             stringToDoubleError ierrImag = STRINGTODOUBLE_NO_ERROR;
336             dReal = stringToDouble(rnum_string, FALSE, &ierrReal);
337             dImag = stringToDouble(inum_string, FALSE, &ierrImag);
338
339             if ((ierrReal == STRINGTODOUBLE_NO_ERROR) && (ierrImag == STRINGTODOUBLE_NO_ERROR))
340             {
341                 if (!haveImagI)
342                 {
343                     if (bConvertByNAN)
344                     {
345                         ierr = STRINGTOCOMPLEX_NO_ERROR;
346                         *real = returnNAN();
347                         *imag = 0.;
348                     }
349                     else
350                     {
351                         ierr = STRINGTOCOMPLEX_ERROR;
352                     }
353                 }
354                 else
355                 {
356                     ierr = STRINGTOCOMPLEX_NO_ERROR;
357                     *real = dReal;
358                     *imag = dImag;
359                 }
360             }
361             else
362             {
363                 if (bConvertByNAN)
364                 {
365                     ierr = STRINGTOCOMPLEX_NO_ERROR;
366                     *real = returnNAN();
367                     *imag = 0.;
368                 }
369                 else
370                 {
371                     ierr = STRINGTOCOMPLEX_ERROR;
372                 }
373             }
374         }
375
376         if (rnum_string)
377         {
378             FREE(rnum_string);
379             rnum_string = NULL;
380         }
381         if (inum_string)
382         {
383             FREE(inum_string);
384             inum_string = NULL;
385         }
386         if (modifiedTxt)
387         {
388             FREE(modifiedTxt);
389             modifiedTxt = NULL;
390         }
391     }
392     return ierr;
393 }
394 /* ========================================================================== */
395 static char *midstring(const char *tx, size_t pos, int nb)
396 {
397     char *returnString = NULL;
398     if (tx)
399     {
400         int lenTx = (int) strlen(tx);
401         int posEnd = 0;
402         int newLen = 0;
403
404         if (nb < 0)
405         {
406             posEnd = lenTx;
407         }
408         else
409         {
410             posEnd = nb;
411         }
412         newLen = posEnd + 1;
413         if (newLen > 0)
414         {
415             returnString = (char*)MALLOC(sizeof(char) * newLen);
416             strncpy(returnString, &tx[pos], posEnd);
417             returnString[posEnd] = 0;
418         }
419     }
420     return returnString;
421 }
422 /* ========================================================================== */
423 static char *leftstring(const char *tx, size_t pos)
424 {
425     char *returnString = NULL;
426     if (tx)
427     {
428         int lenTx = (int) strlen(tx);
429         returnString = strdup(tx);
430         if ((pos > lenTx) || (pos < 0))
431         {
432             return returnString;
433         }
434         else
435         {
436             returnString[pos] = 0;
437         }
438     }
439     return returnString;
440 }
441 /* ========================================================================== */
442 static BOOL is_unit_imaginary (const char *src, double *im)
443 {
444     char *modifiedSrc = csv_strsubst(src, ComplexScilab, ComplexI);
445     char *nextChar = NULL;
446     BOOL isUnitImag = FALSE;
447
448     if (modifiedSrc == NULL)
449     {
450         return isUnitImag;
451     }
452
453     if (modifiedSrc[0] == LessChar)
454     {
455         *im = -1.0;
456         nextChar = modifiedSrc + 1;
457     }
458     else
459     {
460         *im = +1.0;
461         if (modifiedSrc[0] == PlusChar)
462         {
463             nextChar = modifiedSrc + 1;
464         }
465         else
466         {
467             nextChar = modifiedSrc;
468         }
469     }
470
471     if (nextChar)
472     {
473         if ((nextChar[0] == ComplexCharI || nextChar[0] == ComplexCharJ) && nextChar[1] == 0)
474         {
475             isUnitImag = TRUE;
476         }
477     }
478
479     if (modifiedSrc)
480     {
481         FREE(modifiedSrc);
482         modifiedSrc = NULL;
483     }
484     return isUnitImag;
485 }
486 /* ========================================================================== */
487 static double returnNAN(void)
488 {
489     static int first = 1;
490     static double nan = 1.0;
491
492     if ( first )
493     {
494         nan = (nan - (double) first) / (nan - (double) first);
495         first = 0;
496     }
497     return (nan);
498 }
499 // =============================================================================