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