* Bug 4401 fixed - String: fix for isnum
[scilab.git] / scilab / modules / string / 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.1-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 "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 complexArray *stringsToComplexArray(const char **pSTRs, int nbElements,
53                                     const char *decimal,
54                                     BOOL bConvertByNAN,
55                                     stringToComplexError *ierr)
56 {
57     complexArray *pComplexArray = 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         pComplexArray = createComplexArrayEmpty(nbElements);
72         if (pComplexArray)
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                     freeComplexArray(pComplexArray);
81                     return NULL;
82                 }
83                 else
84                 {
85                     pComplexArray->realPart[i] = dComplexValue.r;
86                     pComplexArray->imagPart[i] = dComplexValue.i;
87                 }
88             }
89             cleanImagPartComplexArray(pComplexArray);
90         }
91         else
92         {
93             *ierr = STRINGTOCOMPLEX_MEMORY_ALLOCATION;
94         }
95     }
96     return pComplexArray;
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 = strsub((char*)pSTR, " ", "");
112
113         if (pStrTemp)
114         {
115             char *pStrFormatted = strsub(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 = strsub(pStrFormatted, "+.", "+0.");
140                         FREE(pStrFormatted);
141
142                         /* case -.4 replaced by -0.4 */
143                         pStrFormatted = strsub(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     // Special cases: constants
183     if (strlen(tx) >= 5 && strncmp(tx, "+%eps", 5) == 0 || strncmp(tx, "-%eps", 5) == 0 || strncmp(tx, "+%nan", 5) == 0 ||
184             strncmp(tx, "-%nan", 5) == 0 || strncmp(tx, "+%inf", 5) == 0 || strncmp(tx, "-%inf", 5) == 0)
185     {
186         return 5;
187     }
188     else if (strlen(tx) >= 4 && strncmp(tx, "%eps", 4) == 0 || strncmp(tx, "+%pi", 4) == 0 || strncmp(tx, "-%pi", 4) == 0 ||
189              strncmp(tx, "+Inf", 4) == 0 || strncmp(tx, "-Inf", 4) == 0 || strncmp(tx, "+Nan", 4) == 0 ||
190              strncmp(tx, "-Nan", 4) == 0 || strncmp(tx, "%nan", 4) == 0 || strncmp(tx, "%inf", 4) == 0 )
191     {
192         return 4;
193     }
194     else if (strlen(tx) >= 3 && strncmp(tx, "+%e", 3) == 0 || strncmp(tx, "-%e", 3) == 0 || strncmp(tx, "%pi", 3) == 0 ||
195              strncmp(tx, "Nan", 3) == 0 || strncmp(tx, "Inf", 3) == 0 || strncmp(tx, "%pi", 3) == 0)
196     {
197         return 3;
198     }
199     else if (strlen(tx) >= 2 && strncmp(tx, "%e", 2) == 0)
200     {
201         return 2;
202     }
203
204     if ((tx[len] == '+') || (tx[len] == '-'))
205     {
206         len++;
207     }
208
209     while (isdigit(tx[len]))
210     {
211         len++;
212     }
213     lookahead = len;
214
215     if (tx[lookahead] == '.')
216     {
217         lookahead++;
218         len = 0;
219         while (isdigit(tx[len + lookahead]))
220         {
221             len++;
222         }
223         lookahead += len;
224     }
225
226     if ((tx[lookahead] == 'E') || (tx[lookahead] == 'e') ||
227             (tx[lookahead] == 'D') || (tx[lookahead] == 'd'))
228     {
229
230         lookahead++;
231         if ((tx[lookahead] == '+') || (tx[lookahead] == '-'))
232         {
233             lookahead++;
234         }
235
236         len = 0;
237         while (isdigit(tx[len + lookahead]))
238         {
239             len++;
240         }
241
242         lookahead += len;
243     }
244     return lookahead;
245 }
246 /* ========================================================================== */
247 static stringToComplexError ParseComplexValue(const char *tx, BOOL bConvertByNAN, double *real, double *imag)
248 {
249     stringToDoubleError ierrDouble = STRINGTODOUBLE_NO_ERROR;
250     stringToComplexError ierr = STRINGTOCOMPLEX_NO_ERROR;
251     char *rnum_string = NULL;
252     char *inum_string = NULL;
253     size_t lnum = 0;
254     BOOL haveImagI = FALSE;
255     char *modifiedTxt = NULL;
256     int i = 0;
257
258     *real = stringToDouble(tx, FALSE, &ierrDouble);
259     *imag = 0;
260
261     /* test on strlen(tx) > 1 to remove case 'e' */
262     if ((int)strlen(tx) < 2)
263     {
264         if (ierrDouble == STRINGTODOUBLE_NO_ERROR)
265         {
266             ierr = (stringToComplexError) ierrDouble;
267         }
268         else
269         {
270             if (bConvertByNAN)
271             {
272                 ierrDouble = STRINGTODOUBLE_NOT_A_NUMBER;
273                 *real = returnNAN();
274                 *imag = 0;
275             }
276             else
277             {
278                 *real = 0;
279                 *imag = 0;
280                 ierr = (stringToComplexError) ierrDouble;
281             }
282         }
283     }
284     else if (ierrDouble != STRINGTODOUBLE_NO_ERROR)
285     {
286         modifiedTxt = strsub((char*)tx, ComplexScilab, ComplexI);
287         lnum = ParseNumber(modifiedTxt);
288         if (lnum <= 1)
289         {
290             /* manages special cases nan + nani, ... */
291             if (strnicmp(modifiedTxt, NanString, strlen(NanString)) == 0)
292             {
293                 lnum = strlen(NanString);
294             }
295             else if (strnicmp(modifiedTxt, InfString, strlen(InfString)) == 0)
296             {
297                 lnum = strlen(InfString);
298             }
299             else if (strnicmp(modifiedTxt, NegInfString, strlen(NegInfString)) == 0)
300             {
301                 lnum = strlen(NegInfString);
302             }
303             else if (strnicmp(modifiedTxt, PosInfString, strlen(PosInfString)) == 0)
304             {
305                 lnum = strlen(PosInfString);
306             }
307             else if (strnicmp(modifiedTxt, NegNanString, strlen(NegNanString)) == 0)
308             {
309                 lnum = strlen(NegNanString);
310             }
311             else if (strnicmp(modifiedTxt, PosNanString, strlen(PosNanString)) == 0)
312             {
313                 lnum = strlen(PosNanString);
314             }
315         }
316         inum_string = midstring(modifiedTxt, lnum, -1);
317
318         if ((inum_string[strlen(inum_string) - 1] == 'i') ||
319                 (inum_string[strlen(inum_string) - 1] == 'j')) // The imaginary part looks like "a*%i"
320         {
321             inum_string[strlen(inum_string) - 1] = 0;
322             if (inum_string[strlen(inum_string) - 1] == '*')
323             {
324                 inum_string[strlen(inum_string) - 1] = 0;
325             }
326
327             if (strcmp(inum_string, "+") == 0)
328             {
329                 FREE(inum_string);
330                 inum_string = strdup("+1");
331             }
332
333             if (strcmp(inum_string, "-") == 0)
334             {
335                 FREE(inum_string);
336                 inum_string = strdup("-1");
337             }
338             haveImagI = TRUE;
339         }
340         else if (inum_string[1] == 'i' || inum_string[1] == 'j') // The imaginary part looks like "%i*a". For instance if string() has been used
341         {
342             for (i = 1; i < strlen(inum_string); ++i)
343             {
344                 inum_string[i] = inum_string[i + 1];    // Removing the "i"
345             }
346             if (inum_string[1] == '*')
347             {
348                 for (i = 1; i < strlen(inum_string); ++i)
349                 {
350                     inum_string[i] = inum_string[i + 1];    // Removing the "*"
351                 }
352             }
353
354             if (strcmp(inum_string, "+") == 0)
355             {
356                 FREE(inum_string);
357                 inum_string = strdup("+1");
358             }
359
360             if (strcmp(inum_string, "-") == 0)
361             {
362                 FREE(inum_string);
363                 inum_string = strdup("-1");
364             }
365             haveImagI = TRUE;
366         }
367         else
368         {
369             haveImagI = FALSE;
370         }
371         rnum_string = leftstring(modifiedTxt, lnum);
372
373         if (strcmp(inum_string, "") == 0)
374         {
375             *imag = stringToDouble(rnum_string, bConvertByNAN, &ierrDouble);
376             ierr = (stringToComplexError)(ierrDouble);
377             *real = 0.;
378         }
379         else
380         {
381             double dReal = 0.;
382             double dImag = 0.;
383
384             stringToDoubleError ierrReal = STRINGTODOUBLE_NO_ERROR;
385             stringToDoubleError ierrImag = STRINGTODOUBLE_NO_ERROR;
386             dReal = stringToDouble(rnum_string, FALSE, &ierrReal);
387             dImag = stringToDouble(inum_string, FALSE, &ierrImag);
388
389             if ((ierrReal == STRINGTODOUBLE_NO_ERROR) && (ierrImag == STRINGTODOUBLE_NO_ERROR))
390             {
391                 if (!haveImagI)
392                 {
393                     if (bConvertByNAN)
394                     {
395                         ierr = STRINGTOCOMPLEX_NO_ERROR;
396                         *real = returnNAN();
397                         *imag = 0.;
398                     }
399                     else
400                     {
401                         ierr = STRINGTOCOMPLEX_ERROR;
402                     }
403                 }
404                 else
405                 {
406                     ierr = STRINGTOCOMPLEX_NO_ERROR;
407                     *real = dReal;
408                     *imag = dImag;
409                 }
410             }
411             else
412             {
413                 if (bConvertByNAN)
414                 {
415                     ierr = STRINGTOCOMPLEX_NO_ERROR;
416                     *real = returnNAN();
417                     *imag = 0.;
418                 }
419                 else
420                 {
421                     ierr = STRINGTOCOMPLEX_ERROR;
422                 }
423             }
424         }
425
426         FREE(rnum_string);
427         FREE(inum_string);
428         FREE(modifiedTxt);
429     }
430     return ierr;
431 }
432 /* ========================================================================== */
433 static char *midstring(const char *tx, size_t pos, int nb)
434 {
435     char *returnString = NULL;
436     if (tx)
437     {
438         int lenTx = (int) strlen(tx);
439         int posEnd = 0;
440         int newLen = 0;
441
442         if (nb < 0)
443         {
444             posEnd = lenTx;
445         }
446         else
447         {
448             posEnd = nb;
449         }
450         newLen = posEnd + 1;
451         if (newLen > 0)
452         {
453             returnString = (char*)MALLOC(sizeof(char) * newLen);
454             strncpy(returnString, &tx[pos], posEnd);
455             returnString[posEnd] = 0;
456         }
457     }
458     return returnString;
459 }
460 /* ========================================================================== */
461 static char *leftstring(const char *tx, size_t pos)
462 {
463     char *returnString = NULL;
464     if (tx)
465     {
466         int lenTx = (int) strlen(tx);
467         returnString = strdup(tx);
468         if ((pos > lenTx))
469         {
470             return returnString;
471         }
472         else
473         {
474             returnString[pos] = 0;
475         }
476     }
477     return returnString;
478 }
479 /* ========================================================================== */
480 static BOOL is_unit_imaginary (const char *src, double *im)
481 {
482     char *modifiedSrc = strsub((char*)src, ComplexScilab, ComplexI);
483     char *nextChar = NULL;
484     BOOL isUnitImag = FALSE;
485
486     if (modifiedSrc == NULL)
487     {
488         return isUnitImag;
489     }
490
491     if (modifiedSrc[0] == LessChar)
492     {
493         *im = -1.0;
494         nextChar = modifiedSrc + 1;
495     }
496     else
497     {
498         *im = +1.0;
499         if (modifiedSrc[0] == PlusChar)
500         {
501             nextChar = modifiedSrc + 1;
502         }
503         else
504         {
505             nextChar = modifiedSrc;
506         }
507     }
508
509     if (nextChar)
510     {
511         if ((nextChar[0] == ComplexCharI || nextChar[0] == ComplexCharJ) && nextChar[1] == 0)
512         {
513             isUnitImag = TRUE;
514         }
515     }
516
517     if (modifiedSrc)
518     {
519         FREE(modifiedSrc);
520         modifiedSrc = NULL;
521     }
522     return isUnitImag;
523 }
524 /* ========================================================================== */
525 static double returnNAN(void)
526 {
527     static int first = 1;
528     static double nan = 1.0;
529
530     if ( first )
531     {
532         nan = (nan - (double) first) / (nan - (double) first);
533         first = 0;
534     }
535     return (nan);
536 }
537 // =============================================================================