2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) 2010-2011 - DIGITEO - Allan CORNET
5 * Copyright (C) 2012 - 2016 - Scilab Enterprises
7 * This file is hereby licensed under the terms of the GNU GPL v2.0,
8 * pursuant to article 5.3.4 of the CeCILL v.2.1.
9 * This file was originally licensed under the terms of the CeCILL v2.1,
10 * and continues to be available under such terms.
11 * For more information, see the COPYING file which you should have received
12 * along with this program.
21 #include "stringToComplex.h"
22 #include "stringToDouble.h"
23 #include "sci_malloc.h"
24 #include "os_string.h"
27 /* ========================================================================== */
29 #define PlusCharW L'+'
31 #define LessCharW L'-'
32 #define ComplexCharI 'i'
33 #define ComplexCharIW L'i'
34 #define ComplexCharJ 'j'
35 #define ComplexCharJW L'j'
36 #define ComplexScilab "%i"
37 #define ComplexScilabW L"%i"
39 #define ComplexIW L"i"
40 /* ========================================================================== */
43 #define strnicmp strncasecmp
46 #define stricmp _stricmp
50 #define strnicmp _strnicmp
52 /* ========================================================================== */
53 static int ParseNumber(const char* tx);
54 static int ParseNumberW(const wchar_t* tx);
55 static stringToComplexError ParseComplexValue(const char *tx, BOOL bConvertByNAN, double *real, double *imag);
56 static stringToComplexError ParseComplexValueW(const wchar_t *tx, BOOL bConvertByNAN, double *real, double *imag);
57 static char* midstring(const char *tx, size_t pos, int nb);
58 static wchar_t* midstringW(const wchar_t *tx, size_t pos, int nb);
59 static char *leftstring(const char *tx, size_t pos);
60 static wchar_t* leftstringW(const wchar_t* tx, size_t pos);
61 static BOOL is_unit_imaginary (const char *src, double *im);
62 static BOOL is_unit_imaginaryW (const wchar_t* src, double *im);
63 static double returnNAN(void);
64 /* ========================================================================== */
65 complexArray *stringsToComplexArray(const char **pSTRs, int nbElements,
68 stringToComplexError *ierr)
70 complexArray *pComplexArray = NULL;
72 *ierr = STRINGTOCOMPLEX_ERROR;
80 *ierr = STRINGTOCOMPLEX_MEMORY_ALLOCATION;
84 pComplexArray = createComplexArrayEmpty(nbElements);
88 for (i = 0; i < nbElements; i++)
90 doublecomplex dComplexValue = stringToComplex(pSTRs[i], decimal, bConvertByNAN, ierr);
91 if (*ierr != STRINGTOCOMPLEX_NO_ERROR)
93 freeComplexArray(pComplexArray);
98 pComplexArray->realPart[i] = dComplexValue.r;
99 pComplexArray->imagPart[i] = dComplexValue.i;
102 cleanImagPartComplexArray(pComplexArray);
106 *ierr = STRINGTOCOMPLEX_MEMORY_ALLOCATION;
109 return pComplexArray;
111 /* ========================================================================== */
112 doublecomplex stringToComplex(const char *pSTR, const char *decimal, BOOL bConvertByNAN, stringToComplexError *ierr)
114 doublecomplex dComplexValue;
115 *ierr = STRINGTOCOMPLEX_ERROR;
117 dComplexValue.r = 0.;
118 dComplexValue.i = 0.;
124 char *pStrTemp = strsub((char*)pSTR, " ", "");
128 char *pStrFormatted = strsub(pStrTemp, decimal, ".");
133 int lenStrFormatted = (int) strlen(pStrFormatted);
135 /* case .4 replaced by 0.4 */
136 if (pStrFormatted[0] == '.')
138 /* case .4 replaced by 0.4 */
139 char *pstStrTemp = (char*)MALLOC(sizeof(char) * (lenStrFormatted + strlen("0") + 1));
140 strcpy(pstStrTemp, "0");
141 strcat(pstStrTemp, pStrFormatted);
143 pStrFormatted = pstStrTemp;
146 if (lenStrFormatted > 1)
148 if (((pStrFormatted[0] == '+') || (pStrFormatted[0] == '-')) &&
149 (pStrFormatted[1] == '.'))
151 /* case +.4 replaced by +0.4 */
152 char *pstStrTemp = strsub(pStrFormatted, "+.", "+0.");
155 /* case -.4 replaced by -0.4 */
156 pStrFormatted = strsub(pstStrTemp, "-.", "-0.");
161 /* Case: "i", "+i", "-i", and with "j" */
162 if (is_unit_imaginary (pStrFormatted, &imag))
164 *ierr = STRINGTOCOMPLEX_NO_ERROR;
165 dComplexValue.r = 0.;
166 dComplexValue.i = imag;
170 *ierr = ParseComplexValue(pStrFormatted, bConvertByNAN, &real, &imag);
175 dComplexValue.r = real;
176 dComplexValue.i = imag;
178 return dComplexValue;
180 /* ========================================================================== */
181 doublecomplex stringToComplexW(const wchar_t *pSTR, const wchar_t *decimal, BOOL bConvertByNAN, stringToComplexError *ierr)
183 doublecomplex dComplexValue;
184 *ierr = STRINGTOCOMPLEX_ERROR;
186 dComplexValue.r = 0.;
187 dComplexValue.i = 0.;
193 wchar_t *pStrTemp = wcssub(pSTR, L" ", L"");
197 wchar_t *pStrFormatted = wcssub(pStrTemp, decimal, L".");
202 int lenStrFormatted = (int) wcslen(pStrFormatted);
204 /* case .4 replaced by 0.4 */
205 if (pStrFormatted[0] == '.')
207 /* case .4 replaced by 0.4 */
208 wchar_t *pstStrTemp = (wchar_t*)MALLOC(sizeof(wchar_t) * (lenStrFormatted + wcslen(L"0") + 1));
209 wcscpy(pstStrTemp, L"0");
210 wcscat(pstStrTemp, pStrFormatted);
212 pStrFormatted = pstStrTemp;
215 if (lenStrFormatted > 1)
217 if (((pStrFormatted[0] == '+') || (pStrFormatted[0] == '-')) &&
218 (pStrFormatted[1] == '.'))
220 /* case +.4 replaced by +0.4 */
221 wchar_t *pstStrTemp = wcssub(pStrFormatted, L"+.", L"+0.");
224 /* case -.4 replaced by -0.4 */
225 pStrFormatted = wcssub(pstStrTemp, L"-.", L"-0.");
230 /* Case: "i", "+i", "-i", and with "j" */
231 if (is_unit_imaginaryW(pStrFormatted, &imag))
233 *ierr = STRINGTOCOMPLEX_NO_ERROR;
234 dComplexValue.r = 0.;
235 dComplexValue.i = imag;
239 *ierr = ParseComplexValueW(pStrFormatted, bConvertByNAN, &real, &imag);
244 dComplexValue.r = real;
245 dComplexValue.i = imag;
247 return dComplexValue;
249 /* ========================================================================== */
251 static int ParseNumber(const char* tx)
265 // Special cases: constants
266 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))
270 else if (strlen(tx) >= 4 && (strncmp(tx, "%eps", 4) == 0 || strncmp(tx, "+%pi", 4) == 0 || strncmp(tx, "-%pi", 4) == 0 ||
271 strncmp(tx, "+Inf", 4) == 0 || strncmp(tx, "-Inf", 4) == 0 || strncmp(tx, "+Nan", 4) == 0 ||
272 strncmp(tx, "-Nan", 4) == 0 || strncmp(tx, "%nan", 4) == 0 || strncmp(tx, "%inf", 4) == 0 ))
276 else if (strlen(tx) >= 3 && (strncmp(tx, "+%e", 3) == 0 || strncmp(tx, "-%e", 3) == 0 || strncmp(tx, "%pi", 3) == 0 ||
277 strncmp(tx, "Nan", 3) == 0 || strncmp(tx, "Inf", 3) == 0 || strncmp(tx, "%pi", 3) == 0))
281 else if (strlen(tx) >= 2 && strncmp(tx, "%e", 2) == 0)
286 if ((tx[len] == '+') || (tx[len] == '-'))
291 while (isdigit(tx[len]))
297 if (tx[lookahead] == '.')
301 while (isdigit(tx[len + lookahead]))
308 if ((tx[lookahead] == 'E') || (tx[lookahead] == 'e') ||
309 (tx[lookahead] == 'D') || (tx[lookahead] == 'd'))
313 if ((tx[lookahead] == '+') || (tx[lookahead] == '-'))
319 while (isdigit(tx[len + lookahead]))
328 /* ========================================================================== */
329 static int ParseNumberW(const wchar_t* tx)
343 if ((tx[len] == L'+') || (tx[len] == L'-'))
348 while (iswdigit(tx[len]))
354 if (tx[lookahead] == L'.')
358 while (iswdigit(tx[len + lookahead]))
365 if ((tx[lookahead] == L'E') || (tx[lookahead] == L'e') ||
366 (tx[lookahead] == L'D') || (tx[lookahead] == L'd'))
370 if ((tx[lookahead] == L'+') || (tx[lookahead] == L'-'))
376 while (iswdigit(tx[len + lookahead]))
385 /* ========================================================================== */
386 static stringToComplexError ParseComplexValue(const char *tx, BOOL bConvertByNAN, double *real, double *imag)
388 stringToDoubleError ierrDouble = STRINGTODOUBLE_NO_ERROR;
389 stringToComplexError ierr = STRINGTOCOMPLEX_NO_ERROR;
390 char *rnum_string = NULL;
391 char *inum_string = NULL;
393 BOOL haveImagI = FALSE;
394 char *modifiedTxt = NULL;
397 *real = stringToDouble(tx, FALSE, &ierrDouble);
400 /* test on strlen(tx) > 1 to remove case 'e' */
401 if ((int)strlen(tx) < 2)
403 if (ierrDouble == STRINGTODOUBLE_NO_ERROR)
405 ierr = (stringToComplexError) ierrDouble;
411 ierrDouble = STRINGTODOUBLE_NOT_A_NUMBER;
419 ierr = (stringToComplexError) ierrDouble;
423 else if (ierrDouble != STRINGTODOUBLE_NO_ERROR)
425 modifiedTxt = strsub((char*)tx, ComplexScilab, ComplexI);
426 lnum = ParseNumber(modifiedTxt);
429 /* manages special cases nan + nani, ... */
430 if (strnicmp(modifiedTxt, NanString, strlen(NanString)) == 0)
432 lnum = strlen(NanString);
434 else if (strnicmp(modifiedTxt, InfString, strlen(InfString)) == 0)
436 lnum = strlen(InfString);
438 else if (strnicmp(modifiedTxt, NegInfString, strlen(NegInfString)) == 0)
440 lnum = strlen(NegInfString);
442 else if (strnicmp(modifiedTxt, PosInfString, strlen(PosInfString)) == 0)
444 lnum = strlen(PosInfString);
446 else if (strnicmp(modifiedTxt, NegNanString, strlen(NegNanString)) == 0)
448 lnum = strlen(NegNanString);
450 else if (strnicmp(modifiedTxt, PosNanString, strlen(PosNanString)) == 0)
452 lnum = strlen(PosNanString);
455 inum_string = midstring(modifiedTxt, lnum, -1);
457 if ((inum_string[strlen(inum_string) - 1] == 'i') ||
458 (inum_string[strlen(inum_string) - 1] == 'j')) // The imaginary part looks like "a*%i"
460 inum_string[strlen(inum_string) - 1] = 0;
461 if (inum_string[strlen(inum_string) - 1] == '*')
463 inum_string[strlen(inum_string) - 1] = 0;
466 if (strcmp(inum_string, "+") == 0)
469 inum_string = os_strdup("+1");
472 if (strcmp(inum_string, "-") == 0)
475 inum_string = os_strdup("-1");
479 else if (inum_string[1] == 'i' || inum_string[1] == 'j') // The imaginary part looks like "%i*a". For instance if string() has been used
481 int len_inum_string = strlen(inum_string);
482 for (i = 1; i < len_inum_string; ++i)
484 inum_string[i] = inum_string[i + 1]; // Removing the "i"
486 if (inum_string[1] == '*')
488 for (i = 1; i < len_inum_string; ++i)
490 inum_string[i] = inum_string[i + 1]; // Removing the "*"
494 if (strcmp(inum_string, "+") == 0)
497 inum_string = strdup("+1");
500 if (strcmp(inum_string, "-") == 0)
503 inum_string = strdup("-1");
511 rnum_string = leftstring(modifiedTxt, lnum);
513 if (strcmp(inum_string, "") == 0)
515 *imag = stringToDouble(rnum_string, bConvertByNAN, &ierrDouble);
516 ierr = (stringToComplexError)(ierrDouble);
524 stringToDoubleError ierrReal = STRINGTODOUBLE_NO_ERROR;
525 stringToDoubleError ierrImag = STRINGTODOUBLE_NO_ERROR;
526 dReal = stringToDouble(rnum_string, FALSE, &ierrReal);
527 dImag = stringToDouble(inum_string, FALSE, &ierrImag);
529 if ((ierrReal == STRINGTODOUBLE_NO_ERROR) && (ierrImag == STRINGTODOUBLE_NO_ERROR))
535 ierr = STRINGTOCOMPLEX_NO_ERROR;
541 ierr = STRINGTOCOMPLEX_ERROR;
546 ierr = STRINGTOCOMPLEX_NO_ERROR;
555 ierr = STRINGTOCOMPLEX_NO_ERROR;
561 ierr = STRINGTOCOMPLEX_ERROR;
572 /* ========================================================================== */
573 static stringToComplexError ParseComplexValueW(const wchar_t *tx, BOOL bConvertByNAN, double *real, double *imag)
575 stringToDoubleError ierrDouble = STRINGTODOUBLE_NO_ERROR;
576 stringToComplexError ierr = STRINGTOCOMPLEX_NO_ERROR;
577 wchar_t *rnum_string = NULL;
578 wchar_t *inum_string = NULL;
580 BOOL haveImagI = FALSE;
581 wchar_t *modifiedTxt = NULL;
583 *real = stringToDoubleW(tx, FALSE, &ierrDouble);
586 /* test on strlen(tx) > 1 to remove case 'e' */
587 if ((int)wcslen(tx) < 2)
589 if (ierrDouble == STRINGTODOUBLE_NO_ERROR)
591 ierr = (stringToComplexError) ierrDouble;
597 ierrDouble = STRINGTODOUBLE_NOT_A_NUMBER;
605 ierr = (stringToComplexError) ierrDouble;
609 else if (ierrDouble != STRINGTODOUBLE_NO_ERROR)
611 modifiedTxt = wcssub(tx, ComplexScilabW, ComplexIW);
612 lnum = ParseNumberW(modifiedTxt);
615 /* manages special cases nan + nani, ... */
616 if (wcsnicmp(modifiedTxt, NanStringW, wcslen(NanStringW)) == 0)
618 lnum = wcslen(NanStringW);
620 else if (wcsnicmp(modifiedTxt, InfStringW, wcslen(InfStringW)) == 0)
622 lnum = wcslen(InfStringW);
624 else if (wcsnicmp(modifiedTxt, NegInfStringW, wcslen(NegInfStringW)) == 0)
626 lnum = wcslen(NegInfStringW);
628 else if (wcsnicmp(modifiedTxt, PosInfStringW, wcslen(PosInfStringW)) == 0)
630 lnum = wcslen(PosInfStringW);
632 else if (wcsnicmp(modifiedTxt, NegNanStringW, wcslen(NegNanStringW)) == 0)
634 lnum = wcslen(NegNanStringW);
636 else if (wcsnicmp(modifiedTxt, PosNanStringW, wcslen(PosNanStringW)) == 0)
638 lnum = wcslen(PosNanStringW);
640 else if (wcsnicmp(modifiedTxt, ScilabEpsStringW, wcslen(ScilabEpsStringW)) == 0)
642 lnum = wcslen(ScilabEpsStringW);
644 else if (wcsnicmp(modifiedTxt, ScilabPosEpsStringW, wcslen(ScilabPosEpsStringW)) == 0)
646 lnum = wcslen(ScilabPosEpsStringW);
648 else if (wcsnicmp(modifiedTxt, ScilabNegEpsStringW, wcslen(ScilabNegEpsStringW)) == 0)
650 lnum = wcslen(ScilabNegEpsStringW);
652 else if (wcsnicmp(modifiedTxt, ScilabPiStringW, wcslen(ScilabPiStringW)) == 0)
654 lnum = wcslen(ScilabPiStringW);
656 else if (wcsnicmp(modifiedTxt, ScilabNegPiStringW, wcslen(ScilabNegPiStringW)) == 0)
658 lnum = wcslen(ScilabNegPiStringW);
660 else if (wcsnicmp(modifiedTxt, ScilabPosPiStringW, wcslen(ScilabPosPiStringW)) == 0)
662 lnum = wcslen(ScilabPosPiStringW);
664 else if (wcsnicmp(modifiedTxt, ScilabEStringW, wcslen(ScilabEStringW)) == 0)
666 lnum = wcslen(ScilabEStringW);
668 else if (wcsnicmp(modifiedTxt, ScilabPosEStringW, wcslen(ScilabPosEStringW)) == 0)
670 lnum = wcslen(ScilabPosEStringW);
672 else if (wcsnicmp(modifiedTxt, ScilabNegEStringW, wcslen(ScilabNegEStringW)) == 0)
674 lnum = wcslen(ScilabNegEStringW);
677 inum_string = midstringW(modifiedTxt, lnum, -1);
679 if ((inum_string[wcslen(inum_string) - 1] == L'i') ||
680 (inum_string[wcslen(inum_string) - 1] == L'j'))
682 inum_string[wcslen(inum_string) - 1] = 0;
683 if (inum_string[wcslen(inum_string) - 1] == L'*')
685 inum_string[wcslen(inum_string) - 1] = 0;
688 if (wcscmp(inum_string, L"+") == 0)
691 inum_string = os_wcsdup(L"+1");
694 if (wcscmp(inum_string, L"-") == 0)
697 inum_string = os_wcsdup(L"-1");
701 else if ((inum_string[1] == L'i') ||
702 (inum_string[1] == L'j'))
704 if (inum_string[2] == L'*')
707 for (i = 1; (i + 2) < wcslen(inum_string); i++)
709 inum_string[i] = inum_string[i + 2];
711 inum_string[wcslen(inum_string) - 1] = 0;
712 inum_string[wcslen(inum_string) - 1] = 0;
715 if (wcscmp(inum_string, L"+") == 0)
718 inum_string = os_wcsdup(L"+1");
721 if (wcscmp(inum_string, L"-") == 0)
724 inum_string = os_wcsdup(L"-1");
732 rnum_string = leftstringW(modifiedTxt, lnum);
734 if (wcscmp(inum_string, L"") == 0)
736 *imag = stringToDoubleW(rnum_string, bConvertByNAN, &ierrDouble);
737 ierr = (stringToComplexError)(ierrDouble);
745 stringToDoubleError ierrReal = STRINGTODOUBLE_NO_ERROR;
746 stringToDoubleError ierrImag = STRINGTODOUBLE_NO_ERROR;
747 dReal = stringToDoubleW(rnum_string, FALSE, &ierrReal);
748 dImag = stringToDoubleW(inum_string, FALSE, &ierrImag);
750 if ((ierrReal == STRINGTODOUBLE_NO_ERROR) && (ierrImag == STRINGTODOUBLE_NO_ERROR))
756 ierr = STRINGTOCOMPLEX_NO_ERROR;
762 ierr = STRINGTOCOMPLEX_ERROR;
767 ierr = STRINGTOCOMPLEX_NO_ERROR;
776 ierr = STRINGTOCOMPLEX_NO_ERROR;
782 ierr = STRINGTOCOMPLEX_ERROR;
799 /* ========================================================================== */
800 static char *midstring(const char *tx, size_t pos, int nb)
802 char *returnString = NULL;
805 int lenTx = (int) strlen(tx);
820 returnString = (char*)MALLOC(sizeof(char) * newLen);
821 strncpy(returnString, &tx[pos], posEnd);
822 returnString[posEnd] = 0;
827 /* ========================================================================== */
828 static wchar_t* midstringW(const wchar_t* tx, size_t pos, int nb)
830 wchar_t *returnString = NULL;
833 int lenTx = (int) wcslen(tx);
848 returnString = (wchar_t*)MALLOC(sizeof(wchar_t) * newLen);
849 wcsncpy(returnString, &tx[pos], posEnd);
850 returnString[posEnd] = 0;
855 /* ========================================================================== */
856 static char *leftstring(const char *tx, size_t pos)
858 char *returnString = NULL;
861 int lenTx = (int) strlen(tx);
862 returnString = os_strdup(tx);
869 returnString[pos] = 0;
874 /* ========================================================================== */
875 static wchar_t *leftstringW(const wchar_t *tx, size_t pos)
877 wchar_t *returnString = NULL;
880 int lenTx = (int) wcslen(tx);
881 returnString = os_wcsdup(tx);
888 returnString[pos] = 0;
893 /* ========================================================================== */
894 static BOOL is_unit_imaginary (const char *src, double *im)
896 char *modifiedSrc = strsub((char*)src, ComplexScilab, ComplexI);
897 char *nextChar = NULL;
898 BOOL isUnitImag = FALSE;
900 if (modifiedSrc == NULL)
905 if (modifiedSrc[0] == LessChar)
908 nextChar = modifiedSrc + 1;
913 if (modifiedSrc[0] == PlusChar)
915 nextChar = modifiedSrc + 1;
919 nextChar = modifiedSrc;
925 if ((nextChar[0] == ComplexCharI || nextChar[0] == ComplexCharJ) && nextChar[1] == 0)
938 /* ========================================================================== */
939 static BOOL is_unit_imaginaryW(const wchar_t *src, double *im)
941 wchar_t *modifiedSrc = wcssub(src, ComplexScilabW, ComplexIW);
942 wchar_t *nextChar = NULL;
943 BOOL isUnitImag = FALSE;
945 if (modifiedSrc == NULL)
950 if (modifiedSrc[0] == LessChar)
953 nextChar = modifiedSrc + 1;
958 if (modifiedSrc[0] == PlusChar)
960 nextChar = modifiedSrc + 1;
964 nextChar = modifiedSrc;
970 if ((nextChar[0] == ComplexCharI || nextChar[0] == ComplexCharJ) && nextChar[1] == 0)
983 /* ========================================================================== */
984 static double returnNAN(void)
986 static int first = 1;
987 static double nan = 1.0;
991 nan = (nan - (double) first) / (nan - (double) first);
996 // =============================================================================