spreadsheet: speedup by removing intermediate copies 72/20972/11
Clement DAVID [Tue, 7 May 2019 09:57:12 +0000 (11:57 +0200)]
The passed wchar_t* array should only be copied once before working on
it. During the whole processing, there should be no copy on the common
case (but extra copies might be needed for corner cases). Performance
improvement is also highly related to wchar_t* Scilab string storage.

This commit patch csvTextScan and csvRead functionnalities; please note
that using mgetl and csvTextScan will still need 2 extra copies than
csvRead (1 to store mgetl results and 1 to have mutable buffers during
scanning).

Change-Id: I51f8c4b0e0437bfe4ac69439b739a60262da1cf1

31 files changed:
scilab/CHANGES.md
scilab/modules/spreadsheet/etc/spreadsheet.quit
scilab/modules/spreadsheet/sci_gateway/c/gw_csv_helpers.c
scilab/modules/spreadsheet/sci_gateway/c/gw_csv_helpers.h
scilab/modules/spreadsheet/sci_gateway/c/sci_csvDefault.c
scilab/modules/spreadsheet/sci_gateway/c/sci_csvRead.c
scilab/modules/spreadsheet/sci_gateway/c/sci_csvTextScan.c
scilab/modules/spreadsheet/sci_gateway/cpp/sci_xls_read.cpp
scilab/modules/spreadsheet/src/c/csvDefault.c
scilab/modules/spreadsheet/src/c/csvDefault.h
scilab/modules/spreadsheet/src/c/csvRead.c
scilab/modules/spreadsheet/src/c/csvRead.h
scilab/modules/spreadsheet/src/c/splitLine.c
scilab/modules/spreadsheet/src/c/splitLine.h
scilab/modules/spreadsheet/tests/benchmarks/csvRead.tst [new file with mode: 0644]
scilab/modules/spreadsheet/tests/nonreg_tests/bug_11999.dia.ref
scilab/modules/spreadsheet/tests/nonreg_tests/bug_11999.tst
scilab/modules/spreadsheet/tests/nonreg_tests/bug_13144.dia.ref
scilab/modules/spreadsheet/tests/nonreg_tests/bug_13144.tst
scilab/modules/spreadsheet/tests/nonreg_tests/bug_8349.dia.ref
scilab/modules/spreadsheet/tests/nonreg_tests/bug_8349.tst
scilab/modules/spreadsheet/tests/nonreg_tests/ticket_194.tst
scilab/modules/spreadsheet/tests/nonreg_tests/ticket_472.dia.ref [deleted file]
scilab/modules/spreadsheet/tests/nonreg_tests/ticket_472.tst
scilab/modules/spreadsheet/tests/unit_tests/csvRead_multi_line.csv [new file with mode: 0644]
scilab/modules/spreadsheet/tests/unit_tests/csvRead_multi_line.tst [new file with mode: 0644]
scilab/modules/string/includes/stringToComplex.h
scilab/modules/string/includes/stringToDouble.h
scilab/modules/string/src/c/stringToComplex.c
scilab/modules/string/src/c/stringToDouble.c
scilab/tools/profiling/valgrind.supp

index 6db4727..9a9afbe 100644 (file)
@@ -116,7 +116,7 @@ Feature changes and additions
   - When there is no solution, [] is returned.
   - When there is an infinite number of solutions, the err flag has a specific value.
   - The output size gets the input's one.
-
+* `csvRead` and `csvTextScan` are now implemented without extra copies.
 
 Help pages:
 -----------
@@ -241,7 +241,7 @@ Bug Fixes
 * [#16227](http://bugzilla.scilab.org/show_bug.cgi?id=16227): `WSCI` was not defined as environment variable and could not be used as `%WSCI%` in commands sent with `host()` or `unix_*()`.
 * [#16242](http://bugzilla.scilab.org/show_bug.cgi?id=16242): `loadmatfile()` could not read Octave native text data files.
 * [#16257](http://bugzilla.scilab.org/show_bug.cgi?id=16257): `blockdiag()` implemented to replace `sysdiag()`, improved and extended to strings.
-* [#16260](http://bugzilla.scilab.org/show_bug.cgi?id=16260): overloading `nnz` was not possible (regression). 
+* [#16260](http://bugzilla.scilab.org/show_bug.cgi?id=16260): overloading `nnz` was not possible (regression).
 * [#16263](http://bugzilla.scilab.org/show_bug.cgi?id=16263): Polynomial insertion was broken for complex case.
 * [#16264](http://bugzilla.scilab.org/show_bug.cgi?id=16264): After empty for loop iterator was left uninitialized.
 * [#16265](http://bugzilla.scilab.org/show_bug.cgi?id=16265): The translated pages of the `warning` documentation were not up-to-date.
index 74a7fd1..a97ab6a 100644 (file)
@@ -12,3 +12,5 @@
 // along with this program.
 
 // =============================================================================
+csvDefault("reset");
+
index 27c62c3..8efa81a 100644 (file)
  *
  */
 #include <string.h>
+#include <wchar.h>
 
 #include "api_scilab.h"
 #include "sci_types.h"
 #include "Scierror.h"
 #include "sci_malloc.h"
 #include "localization.h"
+#include "charEncoding.h"
 #include "gw_csv_helpers.h"
 #include "os_string.h"
 #include "freeArrayOfString.h"
@@ -107,7 +109,144 @@ char *csv_getArgumentAsStringWithEmptyManagement(void* pvApiCtx, int _iVar, cons
     return returnedValue;
 }
 // =============================================================================
+wchar_t *csv_getArgumentAsWideStringWithEmptyManagement(void* pvApiCtx, int _iVar, const char *fname,
+        const char *defaultValue,
+        int *iErr)
+{
+    SciErr sciErr;
+    wchar_t *returnedValue = NULL;
+    int *piAddressVar = NULL;
+    int iType = 0;
+    int m = 0, n = 0;
+
+    sciErr = getVarAddressFromPosition(pvApiCtx, _iVar, &piAddressVar);
+    if (sciErr.iErr)
+    {
+        printError(&sciErr, 0);
+        *iErr = sciErr.iErr;
+        return NULL;
+    }
+
+    sciErr = getVarType(pvApiCtx, piAddressVar, &iType);
+    if (sciErr.iErr)
+    {
+        printError(&sciErr, 0);
+        *iErr = sciErr.iErr;
+        return NULL;
+    }
+
+    if (iType != sci_strings)
+    {
+        if (isEmptyMatrix(pvApiCtx, piAddressVar))
+        {
+            /* [] equals default value */
+            if (defaultValue)
+            {
+                *iErr = 0;
+                returnedValue = to_wide_string(defaultValue);
+            }
+            else
+            {
+                *iErr = 0;
+                returnedValue = NULL;
+            }
+        }
+        else
+        {
+            *iErr = API_ERROR_INVALID_TYPE;
+            Scierror(999, _("%s: Wrong type for input argument #%d: string expected.\n"), fname, _iVar);
+            return NULL;
+        }
+    }
+    else
+    {
+        *iErr = checkVarDimension(pvApiCtx, piAddressVar, 1, 1);
+
+        if (*iErr == 0 )
+        {
+            *iErr = API_ERROR_CHECK_VAR_DIMENSION;
+            Scierror(999, _("%s: Wrong size for input argument #%d: string expected.\n"), fname, _iVar);
+            return NULL;
+        }
+
+        *iErr = getAllocatedSingleWideString(pvApiCtx, piAddressVar, &returnedValue);
+        if (*iErr)
+        {
+            if (returnedValue)
+            {
+                FREE(returnedValue);
+            }
+
+            Scierror(999, _("%s: Memory allocation error.\n"), fname);
+            return NULL;
+        }
+        if (wcslen(returnedValue) == 0)
+        {
+            FREE(returnedValue);
+            returnedValue = to_wide_string(defaultValue);
+        }
+    }
+    return returnedValue;
+}
+// =============================================================================
+wchar_t *csv_getArgumentAsWideString(void* pvApiCtx, int _iVar,
+                                     const char *fname, int *iErr)
+{
+    SciErr sciErr;
+
+    int *piAddressVar = NULL;
+    int m = 0, n = 0;
+    int iType = 0;
+
+    wchar_t *returnedValue = NULL;
+
+    sciErr = getVarAddressFromPosition(pvApiCtx, _iVar, &piAddressVar);
+    if (sciErr.iErr)
+    {
+        *iErr = sciErr.iErr;
+        printError(&sciErr, 0);
+        return NULL;
+    }
 
+    sciErr = getVarType(pvApiCtx, piAddressVar, &iType);
+    if (sciErr.iErr)
+    {
+        *iErr = sciErr.iErr;
+        printError(&sciErr, 0);
+        return NULL;
+    }
+
+    if (iType != sci_strings)
+    {
+        *iErr = API_ERROR_INVALID_TYPE;
+        Scierror(999, _("%s: Wrong type for input argument #%d: string expected.\n"), fname, 1);
+        return NULL;
+    }
+
+    *iErr = checkVarDimension(pvApiCtx, piAddressVar, 1, 1);
+
+    if (*iErr == 0 )
+    {
+        *iErr = API_ERROR_CHECK_VAR_DIMENSION;
+        Scierror(999, _("%s: Wrong size for input argument #%d: string expected.\n"), fname, _iVar);
+        return NULL;
+    }
+
+    *iErr = getAllocatedSingleWideString(pvApiCtx, piAddressVar, &returnedValue);
+    if (*iErr)
+    {
+        if (returnedValue)
+        {
+            FREE(returnedValue);
+        }
+
+        Scierror(999, _("%s: Memory allocation error.\n"), fname);
+        return NULL;
+    }
+    return returnedValue;
+}
+// =============================================================================
+// =============================================================================
 char *csv_getArgumentAsString(void* pvApiCtx, int _iVar,
                               const char *fname, int *iErr)
 {
@@ -310,6 +449,61 @@ char **csv_getArgumentAsMatrixOfString(void* pvApiCtx, int _iVar,
     return pStringValues;
 }
 // =============================================================================
+wchar_t **csv_getArgumentAsMatrixOfWideString(void* pvApiCtx, int _iVar,
+        const char *fname,
+        int *m, int *n, int *iErr)
+{
+    SciErr sciErr;
+    wchar_t **pStringValues = NULL;
+    int *piAddressVar = NULL;
+    int m_ = 0, n_ = 0;
+    int iType = 0;
+    int *lengthStringValues = NULL;
+    int i = 0;
+
+    *m = 0;
+    *n = 0;
+
+    sciErr = getVarAddressFromPosition(pvApiCtx, _iVar, &piAddressVar);
+    if (sciErr.iErr)
+    {
+        *iErr = sciErr.iErr;
+        printError(&sciErr, 0);
+        return NULL;
+    }
+
+    sciErr = getVarType(pvApiCtx, piAddressVar, &iType);
+    if (sciErr.iErr)
+    {
+        *iErr = sciErr.iErr;
+        printError(&sciErr, 0);
+        return NULL;
+    }
+
+    if (iType != sci_strings)
+    {
+        *iErr =  API_ERROR_INVALID_TYPE;
+        Scierror(999, _("%s: Wrong type for input argument #%d: string expected.\n"), fname, _iVar);
+        return NULL;
+    }
+
+    *iErr = getAllocatedMatrixOfWideString(pvApiCtx, piAddressVar, &m_, &n_, &pStringValues);
+    if (*iErr != 0)
+    {
+        if (pStringValues)
+        {
+            FREE(pStringValues);
+        }
+        return NULL;
+    }
+
+    *iErr = 0;
+    *m = m_;
+    *n = n_;
+
+    return pStringValues;
+}
+// =============================================================================
 int csv_isRowVector(void* pvApiCtx, int _iVar)
 {
     SciErr sciErr;
index 90beefe..e3aff40 100644 (file)
@@ -16,6 +16,8 @@
  *
  */
 
+#include <wchar.h>
+
 #ifndef __GW_CSV_HELPERS_H__
 #define __GW_CSV_HELPERS_H__
 
@@ -23,9 +25,16 @@ char *csv_getArgumentAsStringWithEmptyManagement(void* _pvCtx, int _iVar,
         const char *fname, const char *defaultValue,
         int *iErr);
 
+wchar_t *csv_getArgumentAsWideStringWithEmptyManagement(void* _pvCtx, int _iVar,
+        const char *fname, const char *defaultValue,
+        int *iErr);
+
 char *csv_getArgumentAsString(void* _pvCtx, int _iVar,
                               const char *fname, int *iErr);
 
+wchar_t *csv_getArgumentAsWideString(void* _pvCtx, int _iVar,
+                                     const char *fname, int *iErr);
+
 int csv_getArgumentAsScalarBoolean(void* _pvCtx, int _iVar,
                                    const char *fname, int *iErr);
 
@@ -33,6 +42,10 @@ char **csv_getArgumentAsMatrixOfString(void* _pvCtx, int _iVar,
                                        const char *fname,
                                        int *m, int *n, int *iErr);
 
+wchar_t **csv_getArgumentAsMatrixOfWideString(void* _pvCtx, int _iVar,
+        const char *fname,
+        int *m, int *n, int *iErr);
+
 int *csv_getArgumentAsMatrixofIntFromDouble(void* _pvCtx, int _iVar,
         const char *fname,
         int *m, int *n, int *iErr);
index a46fe20..938062b 100644 (file)
@@ -220,7 +220,7 @@ static int sci_csvDefault_one_rhs(char *fname, void* pvApiCtx)
     {
         freeVar(&fieldname, &fieldvalue);
 
-        setCsvDefaultReset();
+        setCsvDefaultClear();
 
         createEmptyMatrix(pvApiCtx, Rhs + 1);
 
index 8f7057f..51da1fd 100644 (file)
 
 #include <string.h>
 #include <stdio.h>
+#include <wchar.h>
 #include "gw_spreadsheet.h"
 #include "api_scilab.h"
 #include "Scierror.h"
 #include "localization.h"
+#include "charEncoding.h"
 #include "freeArrayOfString.h"
 #include "sci_malloc.h"
 #include "csvRead.h"
 #include "getRange.h"
 #include "os_string.h"
 
-static void freeVar(char** filename, char** separator, char** decimal, char** conversion, int** iRange, char*** toreplace, int sizeReplace, char** regexp);
+static void freeVar(wchar_t** filename, wchar_t** separator, wchar_t** decimal, wchar_t** conversion, int** iRange, wchar_t*** toreplace, int sizeReplace, wchar_t** regexp);
 /* ==================================================================== */
-#define CONVTOSTR "string"
-#define CONVTODOUBLE "double"
+#define CONVTOSTR L"string"
+#define CONVTODOUBLE L"double"
 /* ==================================================================== */
 /* csvRead(filename, separator, decimal, conversion, substitute, range)*/
 /* ==================================================================== */
@@ -45,24 +47,21 @@ int sci_csvRead(char *fname, void* pvApiCtx)
     int iErr = 0;
     int iErrEmpty = 0;
 
-    char *filename = NULL;
-    char *separator = NULL;
-    char *decimal = NULL;
-    char *conversion = NULL;
+    wchar_t *filename = NULL;
+    wchar_t *separator = NULL;
+    wchar_t *decimal = NULL;
+    wchar_t *conversion = NULL;
     int *iRange = NULL;
     int haveRange = 0;
     int header = 0;
 
-    char **toreplace = NULL;
+    wchar_t **toreplace = NULL;
     int nbElementsToReplace = 0;
 
-    char *regexp = NULL;
+    wchar_t *regexp = NULL;
     int haveRegexp = 0;
 
     csvResult *result = NULL;
-
-    double *dRealValues = NULL;
-
     sciErr.iErr = 0;
 
     CheckRhs(1, 8);
@@ -118,10 +117,10 @@ int sci_csvRead(char *fname, void* pvApiCtx)
 
     if (Rhs >= 6)
     {
-        regexp = csv_getArgumentAsStringWithEmptyManagement(pvApiCtx, 6, fname, getCsvDefaultCommentsRegExp(), &iErr);
+        regexp = csv_getArgumentAsWideStringWithEmptyManagement(pvApiCtx, 6, fname, getCsvDefaultCommentsRegExp(), &iErr);
         if (regexp)
         {
-            if (strcmp(regexp, "") == 0)
+            if (wcscmp(regexp, L"") == 0)
             {
                 FREE(regexp);
                 regexp = NULL;
@@ -140,10 +139,10 @@ int sci_csvRead(char *fname, void* pvApiCtx)
     }
     else
     {
-        regexp = os_strdup(getCsvDefaultCommentsRegExp());
+        regexp = to_wide_string(getCsvDefaultCommentsRegExp());
         if (regexp)
         {
-            if (strcmp(regexp, "") == 0)
+            if (wcscmp(regexp, L"") == 0)
             {
                 FREE(regexp);
                 regexp = NULL;
@@ -161,7 +160,7 @@ int sci_csvRead(char *fname, void* pvApiCtx)
         else
         {
             int m5 = 0, n5 = 0;
-            toreplace = csv_getArgumentAsMatrixOfString(pvApiCtx, 5, fname, &m5, &n5, &iErr);
+            toreplace = csv_getArgumentAsMatrixOfWideString(pvApiCtx, 5, fname, &m5, &n5, &iErr);
             if (iErr)
             {
                 freeVar(&filename, &separator, &decimal, &conversion, &iRange, &toreplace, m5 * n5, &regexp);
@@ -186,16 +185,16 @@ int sci_csvRead(char *fname, void* pvApiCtx)
     if (Rhs >= 4)
     {
         int iErr = 0;
-        conversion = csv_getArgumentAsStringWithEmptyManagement(pvApiCtx, 4, fname, getCsvDefaultConversion(), &iErr);
+        conversion = csv_getArgumentAsWideStringWithEmptyManagement(pvApiCtx, 4, fname, getCsvDefaultConversion(), &iErr);
         if (iErr)
         {
-            freeVar(&filename, &separator, &decimal, &conversion, &iRange, &toreplace, nbElementsToReplace, &regexp);
+            freeVar(&filename, &separator, &decimal, &conversion, &iRange, &toreplace, nbElementsToReplace * 2, &regexp);
             return 0;
         }
 
-        if (!((strcmp(conversion, CONVTOSTR) == 0) || (strcmp(conversion, CONVTODOUBLE) == 0)))
+        if (!((wcscmp(conversion, CONVTOSTR) == 0) || (wcscmp(conversion, CONVTODOUBLE) == 0)))
         {
-            freeVar(&filename, &separator, &decimal, &conversion, &iRange, &toreplace, nbElementsToReplace, &regexp);
+            freeVar(&filename, &separator, &decimal, &conversion, &iRange, &toreplace, nbElementsToReplace * 2, &regexp);
             Scierror(999, _("%s: Wrong value for input argument #%d: '%s' or '%s' string expected.\n"), fname, 4, "double", "string");
             return 0;
         }
@@ -206,63 +205,62 @@ int sci_csvRead(char *fname, void* pvApiCtx)
            a 'double' conversion */
         if (strcmp(fname, "read_csv") == 0)
         {
-            conversion = (char*)MALLOC((strlen("string") + 1) * sizeof(char));
-            strcpy(conversion, "string");
+            conversion = to_wide_string("string");
         }
         else
         {
-            conversion = os_strdup(getCsvDefaultConversion());
+            conversion = to_wide_string(getCsvDefaultConversion());
         }
     }
 
     if (Rhs >= 3)
     {
         int iErr = 0;
-        decimal = csv_getArgumentAsStringWithEmptyManagement(pvApiCtx, 3, fname, getCsvDefaultDecimal(), &iErr);
+        decimal = csv_getArgumentAsWideStringWithEmptyManagement(pvApiCtx, 3, fname, getCsvDefaultDecimal(), &iErr);
         if (iErr)
         {
-            freeVar(&filename, &separator, &decimal, &conversion, &iRange, &toreplace, nbElementsToReplace, &regexp);
+            freeVar(&filename, &separator, &decimal, &conversion, &iRange, &toreplace, nbElementsToReplace * 2, &regexp);
             return 0;
         }
     }
     else
     {
-        decimal = os_strdup(getCsvDefaultDecimal());
+        decimal = to_wide_string(getCsvDefaultDecimal());
     }
 
     if (Rhs >= 2)
     {
         int iErr = 0;
-        separator = csv_getArgumentAsStringWithEmptyManagement(pvApiCtx, 2, fname, getCsvDefaultSeparator(), &iErr);
+        separator = csv_getArgumentAsWideStringWithEmptyManagement(pvApiCtx, 2, fname, getCsvDefaultSeparator(), &iErr);
         if (iErr)
         {
-            freeVar(&filename, &separator, &decimal, &conversion, &iRange, &toreplace, nbElementsToReplace, &regexp);
+            freeVar(&filename, &separator, &decimal, &conversion, &iRange, &toreplace, nbElementsToReplace * 2, &regexp);
             return 0;
         }
     }
     else
     {
-        separator = os_strdup(getCsvDefaultSeparator());
+        separator = to_wide_string(getCsvDefaultSeparator());
     }
 
-    if (strcmp(separator, "\\t") == 0)
+    if (wcscmp(separator, L"\\t") == 0)
     {
         /* In Scilab, if the user is providing \t as separator, transform it to a real
            tab. Example: read_csv(filename,"\t");
         */
-        strcpy(separator, "\t");
+        wcscpy(separator, L"\t");
     }
 
 
-    filename = csv_getArgumentAsString(pvApiCtx, 1, fname, &iErr);
+    filename = csv_getArgumentAsWideString(pvApiCtx, 1, fname, &iErr);
     if (iErr)
     {
-        freeVar(&filename, &separator, &decimal, &conversion, &iRange, &toreplace, nbElementsToReplace, &regexp);
+        freeVar(&filename, &separator, &decimal, &conversion, &iRange, &toreplace, nbElementsToReplace * 2, &regexp);
         return 0;
     }
 
-    result = csvRead(filename, separator, decimal, (const char**)toreplace, nbElementsToReplace * 2, regexp, header);
-    freeVar(NULL, &separator, &decimal, NULL, NULL, &toreplace, nbElementsToReplace, &regexp);
+    result = csvRead(filename, separator, decimal, toreplace, nbElementsToReplace * 2, regexp, header);
+    freeVar(NULL, NULL, NULL, NULL, NULL, &toreplace, nbElementsToReplace * 2, &regexp);
 
     if (result)
     {
@@ -282,186 +280,182 @@ int sci_csvRead(char *fname, void* pvApiCtx)
 
             case CSV_READ_NO_ERROR:
             {
-                if (strcmp(conversion, CONVTOSTR) == 0)
+                int m1 = 0;
+                int n1 = 0;
+
+                wchar_t** pstrValues = NULL;
+                double* pDblRealValues = NULL;
+                double* pDblImgValues = NULL;
+
+                char* errorMsg = NULL;
+
+                errorMsg = csvTextScanSize(result->pwstrValues, &result->nbLines, separator, &m1, &n1, haveRange, iRange);
+                if (errorMsg != NULL)
                 {
+                    Scierror(999, errorMsg, fname);
+                    break;
+                }
+
+                /*
+                 * Allocate some memory to store the decoded content
+                 */
+
+                if (wcscmp(conversion, CONVTOSTR) == 0)
+                {
+                    // allocMatrixOfWideString (non existing yet) here will avoid an extra copy
                     if (haveRange)
                     {
-                        int newM = 0;
-                        int newN = 0;
-
-                        char **pStrRange = getRangeAsString((const char**)result->pstrValues, result->m, result->n, iRange, &newM, &newN);
-                        if (pStrRange)
-                        {
-                            sciErr = createMatrixOfString(pvApiCtx, Rhs + 1, newM, newN, pStrRange);
-                            freeArrayOfString(pStrRange, newM * newN);
-                        }
-                        else
-                        {
-                            if ((newM == 0) || (newN == 0))
-                            {
-                                Scierror(999, _("%s: Range row or/and column left indice(s) out of bounds.\n"), fname);
-                            }
-                            else
-                            {
-                                Scierror(999, _("%s: Memory allocation error.\n"), fname);
-                            }
-
-                            freeCsvResult(result);
-                            freeVar(&filename, &separator, &decimal, &conversion, &iRange, &toreplace, nbElementsToReplace, &regexp);
-                            return 0;
-                        }
+                        pstrValues = CALLOC((iRange[2] - iRange[0] + 1) * (iRange[3] - iRange[1] + 1), sizeof(wchar_t*));
                     }
                     else
                     {
-                        sciErr = createMatrixOfString(pvApiCtx, Rhs + 1, result->m, result->n, result->pstrValues);
+                        pstrValues = CALLOC(m1 * n1, sizeof(wchar_t*));
                     }
                 }
-                else /* to double */
+                else
                 {
-                    stringToComplexError ierr = STRINGTOCOMPLEX_ERROR;
-                    complexArray *ptrComplexArray = stringsToComplexArray((const char**)result->pstrValues, result->m * result->n, decimal, TRUE, &ierr);
-
-                    if (ptrComplexArray == NULL)
+                    if (haveRange)
                     {
-                        freeCsvResult(result);
-                        if (ierr == STRINGTOCOMPLEX_ERROR)
-                        {
-                            Scierror(999, _("%s: can not convert data.\n"), fname);
-                        }
-                        else
-                        {
-                            Scierror(999, _("%s: Memory allocation error.\n"), fname);
-                        }
-
-                        freeVar(&filename, &separator, &decimal, &conversion, &iRange, &toreplace, nbElementsToReplace, &regexp);
-                        return 0;
+                        sciErr = allocMatrixOfDouble(pvApiCtx, Rhs + 1, (iRange[2] - iRange[0] + 1), (iRange[3] - iRange[1] + 1), &pDblRealValues);
                     }
-
-                    switch (ierr)
+                    else
+                    {
+                        sciErr = allocMatrixOfDouble(pvApiCtx, Rhs + 1, m1, n1, &pDblRealValues);
+                    }
+                    if (sciErr.iErr)
                     {
-                        case STRINGTOCOMPLEX_NOT_A_NUMBER:
-                        case STRINGTOCOMPLEX_NO_ERROR:
-                        {
-                            if (haveRange)
-                            {
-                                int newM = 0;
-                                int newN = 0;
-                                complexArray *complexRange = getRangeAsComplexArray(ptrComplexArray, result->m, result->n, iRange, &newM, &newN);
-                                if (complexRange)
-                                {
-                                    if (complexRange->isComplex)
-                                    {
-                                        sciErr = createComplexMatrixOfDouble(pvApiCtx, Rhs + 1, newM, newN, ptrComplexArray->realPart, ptrComplexArray->imagPart);
-                                    }
-                                    else
-                                    {
-                                        sciErr = createMatrixOfDouble(pvApiCtx, Rhs + 1, newM, newN, complexRange->realPart);
-                                    }
-                                    freeComplexArray(complexRange);
-                                    complexRange = NULL;
-                                }
-                                else
-                                {
-                                    if ((newM == 0) || (newN == 0))
-                                    {
-                                        Scierror(999, _("%s: Range row or/and column left indice(s) out of bounds.\n"), fname);
-                                    }
-                                    else
-                                    {
-                                        Scierror(999, _("%s: Memory allocation error.\n"), fname);
-                                    }
-
-                                    freeCsvResult(result);
-                                    freeVar(&filename, &separator, &decimal, &conversion, &iRange, &toreplace, nbElementsToReplace, &regexp);
-                                    freeComplexArray(ptrComplexArray);
-                                    ptrComplexArray = NULL;
-                                    return 0;
-                                }
-                            }
-                            else
-                            {
-                                if (ptrComplexArray->isComplex)
-                                {
-                                    sciErr = createComplexMatrixOfDouble(pvApiCtx, Rhs + 1, result->m, result->n, ptrComplexArray->realPart, ptrComplexArray->imagPart);
-                                }
-                                else
-                                {
-                                    sciErr = createMatrixOfDouble(pvApiCtx, Rhs + 1, result->m, result->n, ptrComplexArray->realPart);
-                                }
-                            }
-                            freeComplexArray(ptrComplexArray);
-                            ptrComplexArray = NULL;
-                        }
-                        break;
-
-                        case STRINGTOCOMPLEX_MEMORY_ALLOCATION:
-                        {
-                            Scierror(999, _("%s: Memory allocation error.\n"), fname);
-                            freeCsvResult(result);
-                            freeVar(&filename, &separator, &decimal, &conversion, &iRange, &toreplace, nbElementsToReplace, &regexp);
-                            return 0;
-                        }
-                        default:
-                        case STRINGTOCOMPLEX_ERROR:
-                        {
-                            Scierror(999, _("%s: can not convert data.\n"), fname);
-                            freeCsvResult(result);
-                            freeVar(&filename, &separator, &decimal, &conversion, &iRange, &toreplace, nbElementsToReplace, &regexp);
-                            return 0;
-                        }
+                        printError(&sciErr, 0);
+                        Scierror(17, _("%s: Memory allocation error.\n"), fname);
+                        freeCsvResult(result);
+                        freeVar(&filename, &separator, &decimal, &conversion, &iRange, &toreplace, nbElementsToReplace * 2, &regexp);
+                        return 0;
                     }
                 }
 
-                if (sciErr.iErr)
+
+                if (csvTextScanInPlace(result->pwstrValues, result->nbLines, separator, decimal, haveRange, iRange, m1, n1, pstrValues, pDblRealValues, &pDblImgValues))
                 {
-                    Scierror(999, _("%s: Memory allocation error.\n"), fname);
+                    Scierror(17, _("%s: Memory allocation error.\n"), fname);
                     freeCsvResult(result);
-                    freeVar(&filename, &separator, &decimal, &conversion, &iRange, &toreplace, nbElementsToReplace, &regexp);
+                    freeVar(&filename, &separator, &decimal, &conversion, &iRange, &toreplace, nbElementsToReplace * 2, &regexp);
                     return 0;
                 }
+
+                // push or recreate Scilab variables
+                if (pDblRealValues != NULL && pDblImgValues != NULL)
+                {
+                    // assign the re-allocated complex array
+                    if (haveRange)
+                    {
+                        sciErr = createComplexMatrixOfDouble(pvApiCtx, Rhs + 2, (iRange[2] - iRange[0] + 1), (iRange[3] - iRange[1] + 1), pDblRealValues, pDblImgValues);
+                    }
+                    else
+                    {
+                        sciErr = createComplexMatrixOfDouble(pvApiCtx, Rhs + 2, m1, n1, pDblRealValues, pDblImgValues);
+                    }
+                    if (sciErr.iErr)
+                    {
+                        printError(&sciErr, 0);
+                        Scierror(17, _("%s: Memory allocation error.\n"), fname);
+                        freeCsvResult(result);
+                        freeVar(&filename, &separator, &decimal, &conversion, &iRange, &toreplace, nbElementsToReplace * 2, &regexp);
+                        return 0;
+                    }
+                    LhsVar(1) = Rhs + 2;
+                    // release the allocated on-demand array
+                    FREE(pDblImgValues);
+                }
+                else if (pDblRealValues != NULL)
+                {
+                    // data have been copied in place, just assign !
+                    LhsVar(1) = Rhs + 1;
+                }
                 else
                 {
+                    // string conversion, copy the data back to Scilab
+                    if (haveRange)
+                    {
+                        sciErr = createMatrixOfWideString(pvApiCtx, Rhs + 1, (iRange[2] - iRange[0] + 1), (iRange[3] - iRange[1] + 1), pstrValues);
+                    }
+                    else
+                    {
+                        sciErr = createMatrixOfWideString(pvApiCtx, Rhs + 1, m1, n1, pstrValues);
+                    }
+                    if (sciErr.iErr)
+                    {
+                        printError(&sciErr, 0);
+                        Scierror(17, _("%s: Memory allocation error.\n"), fname);
+                        freeCsvResult(result);
+                        freeVar(&filename, &separator, &decimal, &conversion, &iRange, &toreplace, nbElementsToReplace * 2, &regexp);
+                        FREE(pstrValues);
+                        return 0;
+                    }
                     LhsVar(1) = Rhs + 1;
 
-                    if (Lhs == 2)
+                    FREE(pstrValues);
+                }
+
+                if (result->nbComments > 0)
+                {
+                    sciErr = createMatrixOfWideString(pvApiCtx, Rhs + 3, result->nbComments, 1, result->pwstrComments);
+                    if (sciErr.iErr)
                     {
-                        if (haveRegexp == 0)
-                        {
-                            char **emptyStringMatrix = NULL;
-                            emptyStringMatrix = (char**)MALLOC(sizeof(char*));
-                            emptyStringMatrix[0] = "";
-                            sciErr = createMatrixOfString(pvApiCtx, Rhs + 2, 1, 1, emptyStringMatrix);
-                            FREE(emptyStringMatrix);
-                        }
-                        else
-                        {
-                            if (result->nbComments > 0)
-                            {
-                                sciErr = createMatrixOfString(pvApiCtx, Rhs + 2, result->nbComments, 1, result->pstrComments);
-                            }
-                            else
-                            {
-                                iErrEmpty = createEmptyMatrix(pvApiCtx, Rhs + 2);
-                                sciErr.iErr = iErrEmpty;
-                            }
-                        }
-                        if (sciErr.iErr)
-                        {
-                            Scierror(999, _("%s: Memory allocation error.\n"), fname);
-                            freeCsvResult(result);
-                            freeVar(&filename, &separator, &decimal, &conversion, &iRange, &toreplace, nbElementsToReplace, &regexp);
-                            return 0;
-                        }
-                        LhsVar(2) = Rhs + 2;
+                        printError(&sciErr, 0);
+                        Scierror(17, _("%s: Memory allocation error.\n"), fname);
+                        freeCsvResult(result);
+                        freeVar(&filename, &separator, &decimal, &conversion, &iRange, &toreplace, nbElementsToReplace * 2, &regexp);
+                        return 0;
                     }
-                    PutLhsVar();
+
+                    LhsVar(2) = Rhs + 3;
                 }
+
+                if (result->nbHeader > 0)
+                {
+
+                    sciErr = createMatrixOfWideString(pvApiCtx, Rhs + 4, result->nbHeader, 1, result->pwstrHeader);
+                    if (sciErr.iErr)
+                    {
+                        printError(&sciErr, 0);
+                        Scierror(17, _("%s: Memory allocation error.\n"), fname);
+                        freeCsvResult(result);
+                        freeVar(&filename, &separator, &decimal, &conversion, &iRange, &toreplace, nbElementsToReplace * 2, &regexp);
+                        return 0;
+                    }
+
+                    if (result->nbComments > 0)
+                    {
+                        LhsVar(3) = Rhs + 4;
+                    }
+                    else
+                    {
+                        LhsVar(2) = Rhs + 4;
+                    }
+                }
+
+                if (*getNbOutputArgument(pvApiCtx) > 1 && result->nbComments == 0 && result->nbHeader == 0)
+                {
+                    wchar_t* emptystr = L"";
+                    sciErr = createMatrixOfWideString(pvApiCtx, Rhs + 3, 1, 1, &emptystr);
+                    if (sciErr.iErr)
+                    {
+                        printError(&sciErr, 0);
+                        Scierror(17, _("%s: Memory allocation error.\n"), fname);
+                        freeCsvResult(result);
+                        freeVar(&filename, &separator, &decimal, &conversion, &iRange, &toreplace, nbElementsToReplace * 2, &regexp);
+                        return 0;
+                    }
+                    LhsVar(2) = Rhs + 3;
+                }
+
             }
             break;
 
             case CSV_READ_FILE_NOT_EXIST:
             {
-                Scierror(999, _("%s: %s does not exist.\n"), fname, filename);
+                char* f = wide_string_to_UTF8(filename);
+                Scierror(999, _("%s: %s does not exist.\n"), fname, f);
+                FREE(f);
             }
             break;
 
@@ -498,12 +492,12 @@ int sci_csvRead(char *fname, void* pvApiCtx)
 
     freeCsvResult(result);
 
-    freeVar(&filename, &separator, &decimal, &conversion, &iRange, &toreplace, nbElementsToReplace, &regexp);
+    freeVar(&filename, &separator, &decimal, &conversion, &iRange, &toreplace, nbElementsToReplace * 2, &regexp);
 
     return 0;
 }
 /* ==================================================================== */
-static void freeVar(char** filename, char** separator, char** decimal, char** conversion, int** iRange, char*** toreplace, int sizeReplace, char** regexp)
+static void freeVar(wchar_t** filename, wchar_t** separator, wchar_t** decimal, wchar_t** conversion, int** iRange, wchar_t*** toreplace, int sizeReplace, wchar_t** regexp)
 {
     if (filename && *filename)
     {
@@ -537,7 +531,7 @@ static void freeVar(char** filename, char** separator, char** decimal, char** co
 
     if (toreplace && *toreplace)
     {
-        freeArrayOfString(*toreplace, sizeReplace);
+        freeArrayOfWideString(*toreplace, sizeReplace);
         *toreplace = NULL;
     }
 
index adba3df..3283716 100644 (file)
  *
  */
 #include <string.h>
-#include "gw_spreadsheet.h"
-#include "api_scilab.h"
-#include "Scierror.h"
-#include "sci_malloc.h"
+#include <wchar.h>
+
 #include "Scierror.h"
-#include "localization.h"
-#include "freeArrayOfString.h"
-#include "stringToComplex.h"
+#include "api_scilab.h"
 #include "csvDefault.h"
 #include "csvRead.h"
+#include "freeArrayOfString.h"
 #include "getRange.h"
 #include "gw_csv_helpers.h"
+#include "gw_spreadsheet.h"
+#include "localization.h"
+#include "charEncoding.h"
 #include "os_string.h"
+#include "sci_malloc.h"
+#include "splitLine.h"
+#include "stringToComplex.h"
 
-static void freeVar(char*** text, int sizeText, int** lengthText, char** separator, char** decimal, char** conversion, int** iRange);
+static void freeVar(wchar_t*** text, int sizeText, int** lengthText, wchar_t** separator, wchar_t** decimal, wchar_t** conversion, int** iRange);
+static void escapeDoubleQuotes(wchar_t* start, wchar_t* end);
 // =============================================================================
-#define CONVTOSTR "string"
-#define CONVTODOUBLE "double"
+#define CONVTOSTR L"string"
+#define CONVTODOUBLE L"double"
 // =============================================================================
-int sci_csvTextScan(char *fname, void* pvApiCtx)
+int sci_csvTextScan(char* fname, void* pvApiCtx)
 {
     SciErr sciErr;
     int iErr = 0;
     int i = 0;
 
-    int *piAddressVarOne = NULL;
+    int* piAddressVarOne = NULL;
     int m1 = 0, n1 = 0;
     int iType1 = 0;
 
-    char **text = NULL;
-    int *lengthText = NULL;
+    wchar_t** text = NULL;
+    int* lengthText = NULL;
     int nbLines = 0;
 
-    char *separator = NULL;
-    char *decimal = NULL;
-    char *conversion = NULL;
+    wchar_t* separator = NULL;
+    wchar_t* decimal = NULL;
+    wchar_t* conversion = NULL;
 
-    double * dRealValues = NULL;
+    double* dRealValues = NULL;
 
-    int *iRange = NULL;
+    int* iRange = NULL;
     int haveRange = 0;
 
-    csvResult *result = NULL;
+    wchar_t** pstrValues = NULL;
+    double* pDblRealValues = NULL;
+    double* pDblImgValues = NULL;
+    csvResult* result = NULL;
+    stringToComplexError ierr = STRINGTOCOMPLEX_ERROR;
+
+    char* errorMsg = NULL;
 
     CheckRhs(1, 5);
     CheckLhs(0, 1);
@@ -74,7 +84,7 @@ int sci_csvTextScan(char *fname, void* pvApiCtx)
             return 0;
         }
 
-        if ((m5 * n5 != SIZE_RANGE_SUPPORTED) )
+        if ((m5 * n5 != SIZE_RANGE_SUPPORTED))
         {
             freeVar(&text, nbLines, &lengthText, &separator, &decimal, &conversion, &iRange);
             Scierror(999, _("%s: Wrong size for input argument #%d: Four entries expected.\n"), fname, 5);
@@ -102,14 +112,14 @@ int sci_csvTextScan(char *fname, void* pvApiCtx)
 
     if (Rhs >= 4)
     {
-        conversion = csv_getArgumentAsStringWithEmptyManagement(pvApiCtx, 4, fname, getCsvDefaultConversion(), &iErr);
+        conversion = csv_getArgumentAsWideStringWithEmptyManagement(pvApiCtx, 4, fname, getCsvDefaultConversion(), &iErr);
         if (iErr)
         {
             freeVar(&text, nbLines, &lengthText, &separator, &decimal, &conversion, &iRange);
             return 0;
         }
 
-        if (!((strcmp(conversion, CONVTOSTR) == 0) || (strcmp(conversion, CONVTODOUBLE) == 0)))
+        if (!((wcscmp(conversion, CONVTOSTR) == 0) || (wcscmp(conversion, CONVTODOUBLE) == 0)))
         {
             freeVar(&text, nbLines, &lengthText, &separator, &decimal, &conversion, &iRange);
             Scierror(999, _("%s: Wrong value for input argument #%d: '%s' or '%s' string expected.\n"), fname, 4, "double", "string");
@@ -118,12 +128,12 @@ int sci_csvTextScan(char *fname, void* pvApiCtx)
     }
     else
     {
-        conversion = os_strdup(getCsvDefaultConversion());
+        conversion = to_wide_string(getCsvDefaultConversion());
     }
 
     if (Rhs >= 3)
     {
-        decimal = csv_getArgumentAsStringWithEmptyManagement(pvApiCtx, 3, fname, getCsvDefaultDecimal(), &iErr);
+        decimal = csv_getArgumentAsWideStringWithEmptyManagement(pvApiCtx, 3, fname, getCsvDefaultDecimal(), &iErr);
         if (iErr)
         {
             freeVar(&text, nbLines, &lengthText, &separator, &decimal, &conversion, &iRange);
@@ -139,12 +149,12 @@ int sci_csvTextScan(char *fname, void* pvApiCtx)
     }
     else
     {
-        decimal = os_strdup(getCsvDefaultDecimal());
+        decimal = to_wide_string(getCsvDefaultDecimal());
     }
 
     if (Rhs >= 2)
     {
-        separator = csv_getArgumentAsStringWithEmptyManagement(pvApiCtx, 2, fname, getCsvDefaultSeparator(), &iErr);
+        separator = csv_getArgumentAsWideStringWithEmptyManagement(pvApiCtx, 2, fname, getCsvDefaultSeparator(), &iErr);
         if (iErr)
         {
             freeVar(&text, nbLines, &lengthText, &separator, &decimal, &conversion, &iRange);
@@ -153,7 +163,7 @@ int sci_csvTextScan(char *fname, void* pvApiCtx)
     }
     else
     {
-        separator = os_strdup(getCsvDefaultSeparator());
+        separator = to_wide_string(getCsvDefaultSeparator());
     }
 
     if (!csv_isRowVector(pvApiCtx, 1) &&
@@ -165,183 +175,145 @@ int sci_csvTextScan(char *fname, void* pvApiCtx)
         return 0;
     }
 
-    text = csv_getArgumentAsMatrixOfString(pvApiCtx, 1, fname, &m1, &n1, &iErr);
+    text = csv_getArgumentAsMatrixOfWideString(pvApiCtx, 1, fname, &m1, &n1, &iErr);
+    nbLines = m1 * n1;
     if (iErr)
     {
         freeVar(&text, nbLines, &lengthText, &separator, &decimal, &conversion, &iRange);
         return 0;
     }
 
-    nbLines = m1 * n1;
-    result = csvTextScan((const char**)text, nbLines, separator, decimal);
+    /*
+     * Preconditions
+     */
 
-    if (result)
+    // decimal and separator should be different
+    if (wcscmp(separator, decimal) == 0)
     {
-        switch (result->err)
+        freeVar(&text, nbLines, &lengthText, &separator, &decimal, &conversion, &iRange);
+        Scierror(999, _("%s: separator and decimal must have different values.\n"), fname);
+        return 0;
+    }
+
+    // validate size
+    errorMsg = csvTextScanSize(text, &nbLines, separator, &m1, &n1, haveRange, iRange);
+    if (errorMsg != NULL)
+    {
+        freeVar(&text, nbLines, &lengthText, &separator, &decimal, &conversion, &iRange);
+        Scierror(999, errorMsg, fname);
+        return 0;
+    }
+
+
+    /*
+     * Allocate some memory to store the decoded content
+     */
+
+    if (wcscmp(conversion, CONVTOSTR) == 0)
+    {
+        // allocMatrixOfWideString (non existing yet) here will avoid an extra copy
+        if (haveRange)
         {
-            case CSV_READ_SEPARATOR_DECIMAL_EQUAL:
-            {
-                Scierror(999, _("%s: separator and decimal must have different values.\n"), fname);
-            }
-            break;
-
-            case CSV_READ_NO_ERROR:
-            {
-                if (strcmp(conversion, CONVTOSTR) == 0)
-                {
-                    if (haveRange)
-                    {
-                        int newM = 0;
-                        int newN = 0;
-
-                        char **pStrRange = getRangeAsString((const char**)result->pstrValues, result->m, result->n, iRange, &newM, &newN);
-                        if (pStrRange)
-                        {
-                            sciErr = createMatrixOfString(pvApiCtx, Rhs + 1, newM, newN, pStrRange);
-                            freeArrayOfString(pStrRange, newM * newN);
-                        }
-                        else
-                        {
-                            Scierror(999, _("%s: Memory allocation error.\n"), fname);
-                        }
-                    }
-                    else
-                    {
-                        sciErr = createMatrixOfString(pvApiCtx, Rhs + 1, result->m, result->n, result->pstrValues);
-                    }
-                }
-                else /* to double */
-                {
-                    stringToComplexError ierr = STRINGTOCOMPLEX_ERROR;
-                    complexArray *ptrComplexArray = stringsToComplexArray((const char**)result->pstrValues, result->m * result->n, decimal, TRUE, &ierr);
-                    if (ptrComplexArray == NULL)
-                    {
-                        if (ierr == STRINGTOCOMPLEX_ERROR)
-                        {
-                            Scierror(999, _("%s: can not convert data.\n"), fname);
-                        }
-                        else
-                        {
-                            Scierror(999, _("%s: Memory allocation error.\n"), fname);
-                        }
-                        freeCsvResult(result);
-                        freeVar(&text, nbLines, &lengthText, &separator, &decimal, &conversion, &iRange);
-                        return 0;
-                    }
-
-                    switch (ierr)
-                    {
-                        case STRINGTOCOMPLEX_NOT_A_NUMBER:
-                        case STRINGTOCOMPLEX_NO_ERROR:
-                        {
-                            if (haveRange)
-                            {
-                                int newM = 0;
-                                int newN = 0;
-                                complexArray *csvComplexRange = getRangeAsComplexArray(ptrComplexArray, result->m, result->n, iRange, &newM, &newN);
-                                if (csvComplexRange)
-                                {
-                                    if (csvComplexRange->isComplex)
-                                    {
-                                        sciErr = createComplexMatrixOfDouble(pvApiCtx, Rhs + 1, newM, newN, ptrComplexArray->realPart, ptrComplexArray->imagPart);
-                                    }
-                                    else
-                                    {
-                                        sciErr = createMatrixOfDouble(pvApiCtx, Rhs + 1, newM, newN, csvComplexRange->realPart);
-                                    }
-                                    freeComplexArray(csvComplexRange);
-                                    csvComplexRange = NULL;
-                                }
-                                else
-                                {
-                                    Scierror(999, _("%s: Memory allocation error.\n"), fname);
-                                }
-                            }
-                            else
-                            {
-                                if (ptrComplexArray->isComplex)
-                                {
-                                    sciErr = createComplexMatrixOfDouble(pvApiCtx, Rhs + 1, result->m, result->n, ptrComplexArray->realPart, ptrComplexArray->imagPart);
-                                }
-                                else
-                                {
-                                    sciErr = createMatrixOfDouble(pvApiCtx, Rhs + 1, result->m, result->n, ptrComplexArray->realPart);
-                                }
-                            }
-                            freeComplexArray(ptrComplexArray);
-                            ptrComplexArray = NULL;
-                        }
-                        break;
-
-                        case STRINGTOCOMPLEX_MEMORY_ALLOCATION:
-                        {
-                            Scierror(999, _("%s: Memory allocation error.\n"), fname);
-                        }
-                        break;
-
-                        default:
-                        case STRINGTOCOMPLEX_ERROR:
-                        {
-                            Scierror(999, _("%s: can not convert data.\n"), fname);
-                        }
-                        break;
-                    }
-                }
-
-                if (sciErr.iErr)
-                {
-                    printError(&sciErr, 0);
-                    Scierror(17, _("%s: Memory allocation error.\n"), fname);
-                    freeCsvResult(result);
-                    freeVar(&text, nbLines, &lengthText, &separator, &decimal, &conversion, &iRange);
-                    return 0;
-                }
-                else
-                {
-                    LhsVar(1) = Rhs + 1;
-                    PutLhsVar();
-                }
-            }
-            break;
-
-            case CSV_READ_MEMORY_ALLOCATION:
-            {
-                Scierror(999, _("%s: Memory allocation error.\n"), fname);
-            }
-            break;
-
-            case CSV_READ_COLUMNS_ERROR:
-            {
-                Scierror(999, _("%s: can not read text: Error in the column structure\n"), fname);
-            }
-            break;
-
-            case CSV_READ_READLINES_ERROR:
-            case CSV_READ_ERROR:
-            case CSV_READ_MOPEN_ERROR:
-            case CSV_READ_FILE_NOT_EXIST:
-            case CSV_READ_REGEXP_ERROR:
-            {
-                Scierror(999, _("%s: can not read text.\n"), fname);
-            }
-            break;
+            pstrValues = CALLOC((iRange[2] - iRange[0] + 1) * (iRange[3] - iRange[1] + 1), sizeof(wchar_t*));
+        }
+        else
+        {
+            pstrValues = CALLOC(m1 * n1, sizeof(wchar_t*));
         }
     }
     else
     {
-        Scierror(999, _("%s: Memory allocation error.\n"), fname);
+        if (haveRange)
+        {
+            sciErr = allocMatrixOfDouble(pvApiCtx, Rhs + 1, (iRange[2] - iRange[0] + 1), (iRange[3] - iRange[1] + 1), &pDblRealValues);
+        }
+        else
+        {
+            sciErr = allocMatrixOfDouble(pvApiCtx, Rhs + 1, m1, n1, &pDblRealValues);
+        }
+        if (sciErr.iErr)
+        {
+            printError(&sciErr, 0);
+            Scierror(17, _("%s: Memory allocation error.\n"), fname);
+            freeVar(&text, nbLines, &lengthText, &separator, &decimal, &conversion, &iRange);
+            return 0;
+        }
+    }
+
+    /*
+     * Decode each cell into the previously allocated memory, this code should not allocate per-cell
+     * but rather manipulate the input lines to speed the decoding.
+     *
+     * Note: some global allocation are also performed depending in some parsing condition. For example,
+     * the image buffer of complex numbers is allocated only when a complex number is detected.
+     */
+    if (csvTextScanInPlace(text, nbLines, separator, decimal, haveRange, iRange, m1, n1, pstrValues, pDblRealValues, &pDblImgValues))
+    {
+        Scierror(17, _("%s: Memory allocation error.\n"), fname);
+        freeVar(&text, nbLines, &lengthText, &separator, &decimal, &conversion, &iRange);
+        return 0;
+    }
+
+    // push or recreate Scilab variables
+    if (pDblRealValues != NULL && pDblImgValues != NULL)
+    {
+        // assign the re-allocated complex array
+        if (haveRange)
+        {
+            sciErr = createComplexMatrixOfDouble(pvApiCtx, Rhs + 2, (iRange[2] - iRange[0] + 1), (iRange[3] - iRange[1] + 1), pDblRealValues, pDblImgValues);
+        }
+        else
+        {
+            sciErr = createComplexMatrixOfDouble(pvApiCtx, Rhs + 2, m1, n1, pDblRealValues, pDblImgValues);
+        }
+        if (sciErr.iErr)
+        {
+            printError(&sciErr, 0);
+            Scierror(17, _("%s: Memory allocation error.\n"), fname);
+            freeVar(&text, nbLines, &lengthText, &separator, &decimal, &conversion, &iRange);
+            FREE(pDblImgValues);
+            return 0;
+        }
+        FREE(pDblImgValues);
+        LhsVar(1) = Rhs + 2;
+    }
+    else if (pDblRealValues != NULL)
+    {
+        // data have been copied in place, just assign !
+        LhsVar(1) = Rhs + 1;
+    }
+    else
+    {
+        // string conversion, copy the data back to Scilab
+        if (haveRange)
+        {
+            sciErr = createMatrixOfWideString(pvApiCtx, Rhs + 1, (iRange[2] - iRange[0] + 1), (iRange[3] - iRange[1] + 1), pstrValues);
+        }
+        else
+        {
+            sciErr = createMatrixOfWideString(pvApiCtx, Rhs + 1, m1, n1, pstrValues);
+        }
+        if (sciErr.iErr)
+        {
+            printError(&sciErr, 0);
+            Scierror(17, _("%s: Memory allocation error.\n"), fname);
+            freeVar(&text, nbLines, &lengthText, &separator, &decimal, &conversion, &iRange);
+            return 0;
+        }
+        LhsVar(1) = Rhs + 1;
+
+        FREE(pstrValues);
     }
 
     freeVar(&text, nbLines, &lengthText, &separator, &decimal, &conversion, &iRange);
-    freeCsvResult(result);
     return 0;
 }
 // =============================================================================
-static void freeVar(char*** text, int sizeText, int** lengthText, char** separator, char** decimal, char** conversion, int** iRange)
+static void freeVar(wchar_t*** text, int sizeText, int** lengthText, wchar_t** separator, wchar_t** decimal, wchar_t** conversion, int** iRange)
 {
     if (text && *text)
     {
-        freeArrayOfString(*text, sizeText);
+        freeArrayOfWideString(*text, sizeText);
         *text = NULL;
     }
 
index 1de4b91..4ed6da0 100644 (file)
@@ -134,6 +134,9 @@ types::Function::ReturnValue sci_xls_read(types::typed_list &in, int _iRetCount,
     {
         out.push_back(types::Double::Empty());
         out.push_back(types::Double::Empty());
+
+        free(data);
+        free(ind);
     }
 
     return types::Function::OK;
index e5d458c..8a0baf7 100644 (file)
@@ -293,6 +293,12 @@ static int initializeCsvDefaultValues(void)
 // =============================================================================
 int setCsvDefaultReset(void)
 {
+    setCsvDefaultClear();
+    return initializeCsvDefaultValues();
+}
+// =============================================================================
+void setCsvDefaultClear(void)
+{
     if (defaultCsvSeparator)
     {
         FREE(defaultCsvSeparator);
@@ -333,7 +339,6 @@ int setCsvDefaultReset(void)
         FREE(defaultCsvIgnoreBlankLine);
         defaultCsvIgnoreBlankLine = NULL;
     }
-    return initializeCsvDefaultValues();
 }
 // =============================================================================
 int setCsvDefaultCommentsRegExp(const char *commentsRegExp)
index d1db12f..94d1c20 100644 (file)
@@ -38,6 +38,7 @@ int setCsvDefaultEncoding(const char *encoding);
 int setCsvDefaultCsvIgnoreBlankLine(const char *blankMode);
 
 int setCsvDefaultReset(void);
+void setCsvDefaultClear(void);
 
 #ifdef __cplusplus
 }
index 7c2d61d..aec92ca 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
  * Copyright (C) 2010-2011 - DIGITEO - Allan CORNET
+ * Copyright (C) 2019-2019 - ESI Group - Clement DAVID
  *
  * Copyright (C) 2012 - 2016 - Scilab Enterprises
  *
  * along with this program.
  *
  */
-#include <string.h>
-#include <stdio.h>
 #include "csvRead.h"
-#include "sci_malloc.h"
+#include "FileExist.h"
+#include "Sciwarning.h"
+#include "configvariable_interface.h"
+#include "csvDefault.h"
+#include "expandPathVariable.h"
 #include "freeArrayOfString.h"
-#include "mopen.h"
-#include "mgetl.h"
 #include "localization.h"
-#include "expandPathVariable.h"
-#include "FileExist.h"
+#include "stringToComplex.h"
 #include "mclose.h"
-#include "configvariable_interface.h"
+#include "mgetl.h"
+#include "mopen.h"
+#include "os_string.h"
 #include "pcre_private.h"
+#include "sci_malloc.h"
 #include "sciprint.h"
 #include "splitLine.h"
-#include "os_string.h"
-#include "csvDefault.h"
 #include "strsubst.h"
-#include "Sciwarning.h"
+#include <stdio.h>
+#include <string.h>
 // =============================================================================
 #if _MSC_VER
 #define READ_ONLY_TEXT_MODE "rt"
 #define READ_ONLY_TEXT_MODE "r"
 #endif
 // =============================================================================
-static int getNumbersOfColumnsInLines(const char **lines, int sizelines,
-                                      const char *separator);
-static int getNumbersOfColumnsInLine(const char *line, const char *separator);
-static char **getStringsFromLines(const char **lines, int sizelines,
-                                  const char *separator, const char *decimal,
-                                  int m, int n);
-static char **removeEmptyLinesAtTheEnd(const char **lines, int *sizelines);
-static char *stripCharacters(const char *line);
-static char **replaceStrings(const char **lines, int nbLines, const char **toreplace, int sizetoreplace);
-static char **extractComments(const char **lines, int nbLines, const char *regexpcomments, int *nbcomments, int *iErr);
-static char **removeComments(const char **lines, int nbLines, const char *regexpcomments, int *nbNewLine, int *iErr);
-static char **removeAllBlankLines(const char **lines, int *sizelines);
+wchar_t* EMPTY_STR = L"";
+// =============================================================================
+static char* getNumbersOfColumnsInLines(wchar_t** lines, int sizelines,
+                                        const wchar_t* separator, int* cols);
+static int getNumbersOfColumnsInLine(wchar_t* line, const wchar_t* separator);
+static void removeEmptyLinesAtEnd(wchar_t** lines, int* nonEmptyLines);
+static void moveEmptyLinesToEnd(wchar_t** lines, int* nonEmptyLines);
+static void replaceDoubleQuotes(wchar_t** lines, int* nbLines);
+static int hasOnlyBlankCharacters(wchar_t** line);
+static void replaceStrings(wchar_t** lines, int* nbLines, wchar_t** toreplace, int sizetoreplace);
+static wchar_t** extractComments(wchar_t** lines, int* nbLines, const wchar_t* regexpcomments, int* nbcomments, int* iErr);
 // =============================================================================
-csvResult* csvRead(const char *filename, const char *separator, const char *decimal, const char **toreplace, int sizetoreplace, const char *regexpcomments, int header)
+csvResult* csvRead(const wchar_t* filename, const wchar_t* separator, const wchar_t* decimal, wchar_t** toreplace, int sizetoreplace, const wchar_t* regexpcomments, int header)
 {
-    wchar_t *expandedFilename = NULL;
-    wchar_t *wideFilename = NULL;
-    csvResult *result = NULL;
+    wchar_t* expandedFilename = NULL;
+    csvResult* result = NULL;
     int fd = 0;
     int f_swap = 0;
     double res = 0.0;
     int errMOPEN = MOPEN_INVALID_STATUS;
-    wchar_t **pwstLines = NULL;
-    char **pstLines = NULL;
+    wchar_t** pwstLines = NULL;
     int nbLines = 0;
-    char **replacedInLines = NULL;
-    char **pComments = NULL;
+    wchar_t** replacedInLines = NULL;
+    wchar_t** pComments = NULL;
     int nbComments = 0;
+    wchar_t** pHeader = NULL;
+    int nbHeader = 0;
 
     if ((filename == NULL) || (separator == NULL) || (decimal == NULL))
     {
         return NULL;
     }
 
-    wideFilename = to_wide_string((char*)filename);
-    expandedFilename = expandPathVariableW(wideFilename);
-    FREE(wideFilename);
-
+    expandedFilename = expandPathVariableW(filename);
     if (!FileExistW(expandedFilename))
     {
-        result = (csvResult*)(MALLOC(sizeof(csvResult)));
+        result = (csvResult*)(CALLOC(1, sizeof(csvResult)));
         if (result)
         {
             result->err = CSV_READ_FILE_NOT_EXIST;
-            result->m = 0;
-            result->n = 0;
-            result->pstrValues = NULL;
-            result->pstrComments = NULL;
-            result->nbComments = 0;
         }
 
         FREE(expandedFilename);
@@ -102,53 +95,30 @@ csvResult* csvRead(const char *filename, const char *separator, const char *deci
 
     if (errMOPEN != MOPEN_NO_ERROR)
     {
-        result = (csvResult*)(MALLOC(sizeof(csvResult)));
+        result = (csvResult*)(CALLOC(1, sizeof(csvResult)));
         if (result)
         {
             result->err = CSV_READ_MOPEN_ERROR;
-            result->m = 0;
-            result->n = 0;
-            result->pstrValues = NULL;
-            result->pstrComments = NULL;
-            result->nbComments = 0;
-
         }
         return result;
     }
 
     if (header != 0)
     {
-        wchar_t **pwstHeaderLines = NULL;
-        mgetl(fd, header, &pwstHeaderLines);
-        FREE(pwstHeaderLines);
+        nbHeader = mgetl(fd, header, &pHeader);
     }
 
     nbLines = mgetl(fd, -1, &pwstLines);
     mclose(fd);
 
-    if (nbLines >= 0)
+    if (nbLines < 0)
     {
-        int i = 0;
-        pstLines = (char**)MALLOC(sizeof(char*) * nbLines);
-        for (i = 0 ; i < nbLines ; i++)
-        {
-            pstLines[i] = wide_string_to_UTF8(pwstLines[i]);
-        }
-        freeArrayOfWideString(pwstLines, nbLines);
-        pwstLines = NULL;
-    }
-    else
-    {
-        result = (csvResult*)(MALLOC(sizeof(csvResult)));
+        result = (csvResult*)(CALLOC(1, sizeof(csvResult)));
         if (result)
         {
             result->err = CSV_READ_READLINES_ERROR;
-            result->m = 0;
-            result->n = 0;
-            result->pstrValues = NULL;
-            result->pstrComments = NULL;
-            result->nbComments = 0;
         }
+        freeArrayOfWideString(pHeader, nbHeader);
         return result;
     }
 
@@ -156,11 +126,11 @@ csvResult* csvRead(const char *filename, const char *separator, const char *deci
     {
         int iErr = 0;
 
-        pComments = extractComments((const char**)pstLines, nbLines, regexpcomments, &nbComments, &iErr);
+        pComments = extractComments(pwstLines, &nbLines, regexpcomments, &nbComments, &iErr);
 
         if ((iErr == CAN_NOT_COMPILE_PATTERN) || (iErr == DELIMITER_NOT_ALPHANUMERIC))
         {
-            result = (csvResult*)(MALLOC(sizeof(csvResult)));
+            result = (csvResult*)(CALLOC(1, sizeof(csvResult)));
             if (result)
             {
                 if ((iErr == CAN_NOT_COMPILE_PATTERN) || (iErr == DELIMITER_NOT_ALPHANUMERIC))
@@ -168,180 +138,282 @@ csvResult* csvRead(const char *filename, const char *separator, const char *deci
                     iErr = CSV_READ_REGEXP_ERROR;
                 }
                 result->err = (csvReadError)iErr;
-                result->m = 0;
-                result->n = 0;
-                result->pstrValues = NULL;
-                result->pstrComments = NULL;
-                result->nbComments = 0;
             }
-            freeArrayOfString(pstLines, nbLines);
+            freeArrayOfWideString(pHeader, nbHeader);
+            freeArrayOfWideString(pwstLines, nbLines);
             return result;
         }
-
-        if (pComments)
-        {
-            char **pCleanedLines = NULL;
-            int nbCleanedLines = 0;
-            int i = 0;
-
-            pCleanedLines = removeComments((const char**)pstLines, nbLines, (const char*)regexpcomments, &nbCleanedLines, &iErr);
-            if (pCleanedLines)
-            {
-                FREE(pstLines);
-                pstLines = pCleanedLines;
-                nbLines = nbCleanedLines;
-            }
-
-        }
     }
 
     if (toreplace && (sizetoreplace > 0))
     {
-        replacedInLines = replaceStrings((const char**)pstLines, nbLines, toreplace, sizetoreplace);
-        if (replacedInLines)
-        {
-            freeArrayOfString(pstLines, nbLines);
-            pstLines = replacedInLines;
-        }
+        replaceStrings(pwstLines, &nbLines, toreplace, sizetoreplace);
     }
 
-    result = csvTextScan((const char**)pstLines, nbLines, (const char*)separator, (const char*)decimal);
-    freeArrayOfString(pstLines, nbLines);
-    freeArrayOfWideString(pwstLines, nbLines);
-
+    result = (csvResult*)(CALLOC(1, sizeof(csvResult)));
     if (result)
     {
-        result->pstrComments = pComments;
+        result->err = CSV_READ_NO_ERROR;
+        result->nbLines = nbLines;
+        result->pwstrValues = pwstLines;
         result->nbComments = nbComments;
+        result->pwstrComments = pComments;
+        result->nbHeader = nbHeader;
+        result->pwstrHeader = pHeader;
     }
     else
     {
-        freeArrayOfString(pComments, nbComments);
+        freeArrayOfWideString(pComments, nbComments);
+        freeArrayOfWideString(pHeader, nbHeader);
+        freeArrayOfWideString(pwstLines, nbLines);
     }
-
     return result;
 }
 // =============================================================================
-csvResult* csvTextScan(const char **lines, int numberOfLines, const char *separator, const char *decimal)
+/*
+ * Decode each cell into the previously allocated memory, this code should not allocate per-cell
+ * but rather manipulate the input lines to speed the decoding.
+ *
+ * Note: some global allocation are also performed depending in some parsing condition. For example,
+ * the image buffer of complex numbers is allocated only when a complex number is detected.
+ */
+
+int csvTextScanInPlace(wchar_t** text, int nbLines, const wchar_t* separator,
+                       const wchar_t* decimal, int haveRange, const int* iRange, int m1, int n1,
+                       wchar_t** pstrValues, double* pDblRealValues, double** pDblImgValues)
 {
-    csvResult *result = NULL;
-    int nbRows = 0;
-    int nbColumns = 0;
-    char **cellsStrings = NULL;
-    char **cleanedLines = NULL;
-    int nbLines = numberOfLines;
-
-    if (strcmp(separator, decimal) == 0)
+    stringToComplexError ierr = STRINGTOCOMPLEX_ERROR;
+
+
+    // per line
+    for (int i = 0; i < nbLines; i++)
     {
-        result = (csvResult*)(MALLOC(sizeof(csvResult)));
-        if (result)
+        wchar_t* start = NULL;
+        wchar_t* end = NULL;
+        wchar_t* previousEnd = NULL;
+        wchar_t* iter = text[i];
+
+        // skip some values to be within the range
+        if (haveRange)
         {
-            result->err = CSV_READ_SEPARATOR_DECIMAL_EQUAL;
-            result->m = 0;
-            result->n = 0;
-            result->pstrValues = NULL;
-            result->pstrComments = NULL;
-            result->nbComments = 0;
+            if (i < iRange[0] - 1)
+            {
+                continue;
+            }
+            if (i >= iRange[2])
+            {
+                break;
+            }
         }
-        return result;
-    }
 
-    // ticket 472
+        // per cell (column)
+        for (int j = 0; iter != NULL; j++)
+        {
+            int zeroIndex = i + nbLines * j;
+
+            iter = splitLineCSVNext(iter, separator, &start, &end);
+
+            // skip some values to be within the range
+            if (haveRange)
+            {
+                if (j < iRange[1] - 1)
+                {
+                    continue;
+                }
+                if (j >= iRange[3])
+                {
+                    break;
+                }
+                // adapt zeroIndex to be within the range
+                zeroIndex = i - iRange[0] + 1
+                            + (iRange[2] - iRange[0] + 1) * (j - iRange[1] + 1);
+            }
+
+            // decode in double or string
+            if (pDblRealValues != NULL)
+            {
+                doublecomplex v = stringToComplexWInPlace(start, end, decimal,
+                                  TRUE, &ierr);
+                if (ierr == STRINGTOCOMPLEX_NO_ERROR)
+                {
+                    // the imag part of a complex number is allocated on demand
+                    if (v.i != 0. && *pDblImgValues == NULL)
+                    {
+                        size_t n;
+                        if (haveRange)
+                        {
+                            n = (iRange[2] - iRange[0] + 1)
+                                * (iRange[3] - iRange[1] + 1)
+                                * sizeof(double);
+                        }
+                        else
+                        {
+                            n = m1 * n1 * sizeof(double);
+                        }
+                        *pDblImgValues = CALLOC(1, n);
+                        if (*pDblImgValues == NULL)
+                        {
+                            return -1;
+                        }
+                    }
+                    if (v.i != 0.)
+                    {
+                        (*pDblImgValues)[zeroIndex] = v.i;
+                    }
+                    pDblRealValues[zeroIndex] = v.r;
+                }
+            }
+            else
+            {
+                // finish a previously stored "end" by a trailing '\0', needed for further iteration *BUT* easy strdup() at the end
+                if (previousEnd)
+                {
+                    *previousEnd = '\0';
+                }
+                previousEnd = end;
+
+                // convert the passed decimal to a dot
+                convertDecimalToDotInPlace(start, decimal);
+
+                // escape double quotes
+                escapeDoubleQuotesInPlace(start, end);
+
+                pstrValues[zeroIndex] = start;
+            }
+        }
+    }
+    return 0;
+}
+// =============================================================================
+static void replaceDoubleQuotes(wchar_t** lines, int* nbLines)
+{
+    int dest = 0;
+    wchar_t* it = NULL;
+    for (int next = dest; next < *nbLines; dest++, next++)
     {
-        const char *blankMode = getCsvDefaultCsvIgnoreBlankLine();
-        if (strcmp(blankMode, "on") == 0)
+        int quoteCount = 0;
+        lines[dest] = lines[next];
+
+        it = lines[dest];
+        for (; *it != L'\0'; it++)
         {
-            char **tmpLines = removeAllBlankLines(lines, &nbLines);
-            if (tmpLines)
+            if (*it == L'"')
             {
-                freeArrayOfString(cleanedLines, nbLines);
-                cleanedLines = tmpLines;
+                quoteCount++;
             }
         }
-        else
+
+        // if at the end of this line, we still have an open double quote.
+        // merge this line and the followings.
+        for (; quoteCount % 2 == 1 && next + 1 < *nbLines; next++)
         {
-            /* remove last lines empty (bug 7003 in scilab)*/
-            cleanedLines = removeEmptyLinesAtTheEnd(lines, &nbLines);
+            wchar_t* currentLine = lines[dest];
+            wchar_t* nextLine = lines[next + 1];
+
+            size_t currentLen = it - lines[dest];
+            size_t nextLen = wcslen(nextLine);
+            size_t newLen = currentLen + nextLen + 2; // includes 'LF' and '\0'
+
+            lines[dest] = MALLOC(newLen * sizeof(wchar_t));
+            memcpy(lines[dest], currentLine, currentLen * sizeof(wchar_t));
+            *(lines[dest] + currentLen) = 0x0A; // LF
+            memcpy(lines[dest] + currentLen + 1, nextLine, nextLen * sizeof(wchar_t));
+            *(lines[dest] + currentLen + 1 + nextLen) = L'\0';
+
+            FREE(currentLine);
+            FREE(nextLine);
+
+            it = lines[dest] + currentLen;
+            for (; *it != L'\0'; it++)
+            {
+                if (*it == L'"')
+                {
+                    quoteCount++;
+                }
+            }
         }
     }
 
-    nbColumns = getNumbersOfColumnsInLines((const char **)cleanedLines, nbLines, separator);
-    if (nbColumns == 0)
+    *nbLines = dest;
+}
+// =============================================================================
+char* csvTextScanSize(wchar_t** lines, int* nbLines, const wchar_t* separator, int* rows, int* cols, int haveRange, int* iRange)
+{
+    char* errorMsg = NULL;
+
+    // ticket 472
     {
-        result = (csvResult*)(MALLOC(sizeof(csvResult)));
-        if (result)
+        const char* blankMode = getCsvDefaultCsvIgnoreBlankLine();
+        if (strcmp(blankMode, "on") == 0)
         {
-            result->err = CSV_READ_COLUMNS_ERROR;
-            result->m = 0;
-            result->n = 0;
-            result->pstrValues = NULL;
-            result->pstrComments = NULL;
-            result->nbComments = 0;
+            moveEmptyLinesToEnd(lines, nbLines);
+        }
+        else
+        {
+            /* remove last lines empty (bug 7003 in scilab)*/
+            removeEmptyLinesAtEnd(lines, nbLines);
         }
-        FREE(cleanedLines);
-        return result;
-    }
-    else
-    {
-        nbRows = nbLines;
     }
 
-    cellsStrings = getStringsFromLines((const char **)cleanedLines, nbLines, separator, decimal, nbColumns, nbRows);
-    if (cleanedLines)
+    // escape line breaks (CRLF) inside double quotes
+    // Note: this reallocate and change the number of lines to restore valid
+    //       lines and number of lines.
+    replaceDoubleQuotes(lines, nbLines);
+
+    errorMsg = getNumbersOfColumnsInLines(lines, *nbLines, separator, cols);
+    *rows = *nbLines;
+    if (errorMsg != NULL)
     {
-        freeArrayOfString(cleanedLines, nbLines);
-        cleanedLines = NULL;
+        return errorMsg;
     }
 
-    if (cellsStrings)
+    // update the expected range if needed
+    if (haveRange)
     {
-        result = (csvResult*)(MALLOC(sizeof(csvResult)));
-        if (result)
+        // error
+        if (iRange[0] > *rows)
         {
-            result->err = CSV_READ_NO_ERROR;
-            result->m = nbRows;
-            result->n = nbColumns;
-            result->pstrValues = cellsStrings;
-            result->pstrComments = NULL;
-            result->nbComments = 0;
+            return gettext("%s: Range row or/and column left indice(s) out of bounds.\n");
         }
-        else
+        if (iRange[1] > *cols)
         {
-            FREE(cellsStrings);
+            return gettext("%s: Range row or/and column left indice(s) out of bounds.\n");
         }
-    }
-    else
-    {
-        result = (csvResult*)(MALLOC(sizeof(csvResult)));
-        if (result)
+
+        // truncate
+        if (iRange[2] > *rows)
+        {
+            iRange[2] = *rows;
+        }
+        if (iRange[3] > *cols)
         {
-            result->err = CSV_READ_COLUMNS_ERROR;
-            result->m = 0;
-            result->n = 0;
-            result->pstrValues = NULL;
-            result->pstrComments = NULL;
-            result->nbComments = 0;
+            iRange[3] = *cols;
         }
     }
-    return result;
+
+    return NULL;
 }
 // =============================================================================
-void freeCsvResult(csvResult *result)
+void freeCsvResult(csvResult* result)
 {
     if (result)
     {
-        if (result->pstrValues)
+        if (result->pwstrValues)
         {
-            freeArrayOfString(result->pstrValues, result->m * result->n);
-            result->pstrValues = NULL;
+            freeArrayOfWideString(result->pwstrValues, result->nbLines);
+            result->pwstrValues = NULL;
         }
-        result->m = 0;
-        result->n = 0;
+        result->nbLines = 0;
 
-        if (result->pstrComments)
+        if (result->pwstrComments)
         {
-            freeArrayOfString(result->pstrComments, result->nbComments);
-            result->pstrComments = NULL;
+            freeArrayOfWideString(result->pwstrComments, result->nbComments);
+            result->pwstrComments = NULL;
+        }
+        if (result->pwstrHeader)
+        {
+            freeArrayOfWideString(result->pwstrHeader, result->nbHeader);
+            result->pwstrHeader = NULL;
         }
         result->err = CSV_READ_ERROR;
         FREE(result);
@@ -349,8 +421,8 @@ void freeCsvResult(csvResult *result)
     }
 }
 // =============================================================================
-static int getNumbersOfColumnsInLines(const char **lines, int sizelines,
-                                      const char *separator)
+static char* getNumbersOfColumnsInLines(wchar_t** lines, int sizelines,
+                                        const wchar_t* separator, int* cols)
 {
     int previousNbColumns = 0;
     int NbColumns = 0;
@@ -371,293 +443,185 @@ static int getNumbersOfColumnsInLines(const char **lines, int sizelines,
                 if (previousNbColumns != NbColumns)
                 {
                     Sciwarning(_("%s: Inconsistency found in the columns. At line %d, found %d columns while the previous had %d.\n"), _("Warning"), i + 1, NbColumns, previousNbColumns);
-                    return 0;
+                    return gettext("%s: can not read file, error in the column structure\n");
                 }
             }
         }
     }
-    return NbColumns;
+    *cols = NbColumns;
+    return NULL;
 }
 // =============================================================================
-static int getNumbersOfColumnsInLine(const char *line, const char *separator)
+static int getNumbersOfColumnsInLine(wchar_t* line, const wchar_t* separator)
 {
+    int nbTokens = 0;
+
     if (line && separator)
     {
-        int i = 0;
-        int nbTokens = 0;
-        char **splittedStr = splitLineCSV(line, separator, &nbTokens);
-        if (splittedStr)
-        {
-            freeArrayOfString(splittedStr, nbTokens);
-            return nbTokens;
-        }
-        else
+        wchar_t* start = NULL;
+        wchar_t* end = NULL;
+
+        wchar_t* iter = line;
+        while (iter != NULL)
         {
-            int len = (int)strlen(line);
-            if (len > 0)
-            {
-                nbTokens = 1;
-                return nbTokens;
-            }
+            nbTokens++;
+
+            iter = splitLineCSVNext(iter, separator, &start, &end);
         }
     }
-    return 0;
+    return nbTokens;
 }
 // =============================================================================
-static char **getStringsFromLines(const char **lines, int sizelines,
-                                  const char *separator,
-                                  const char *decimal,
-                                  int m, int n)
+static void removeEmptyLinesAtEnd(wchar_t** lines, int* nonEmptyLines)
 {
-    char **results = NULL;
+    const int len = *nonEmptyLines;
 
-    if (lines == NULL)
-    {
-        return NULL;
-    }
-    if (separator == NULL)
-    {
-        return NULL;
-    }
-    if (m == 0 || n == 0)
-    {
-        return NULL;
-    }
-
-    results = (char**) MALLOC(sizeof(char*) * (m * n));
-    if (results)
+    if (lines)
     {
-        int i = 0;
-        for (i = 0; i < sizelines; i++)
+        int i = len - 1;
+        for (; i >= 0; i--)
         {
-            int nbTokens = 0;
-            char **lineStrings = splitLineCSV(lines[i], separator, &nbTokens);
-            int j = 0;
-
-            if (lineStrings == NULL)
+            if (!hasOnlyBlankCharacters(&lines[i]))
             {
-                lineStrings = (char**)MALLOC(sizeof(char*) * 1);
-                lineStrings[0] = os_strdup(lines[i]);
-                nbTokens = 1;
-            }
-
-            if (m != nbTokens)
-            {
-                freeArrayOfString(results, nbTokens * n);
-                FREE(lineStrings);
-                return NULL;
-            }
-
-            for (j = 0; j < m; j++)
-            {
-
-                if (!decimal)
-                {
-                    results[i + n * j] = os_strdup(lineStrings[j]);
-                }
-                else
-                {
-                    /* Proceed to the remplacement of the provided decimal to the default on
-                     * usually, it converts "," => "." */
-                    results[i + n * j] = strsub(lineStrings[j], decimal, getCsvDefaultDecimal());
-                }
-
-                if (lineStrings[j])
-                {
-                    FREE(lineStrings[j]);
-                    lineStrings[j] = NULL;
-                }
+                break;
             }
-            FREE(lineStrings);
         }
+
+        *nonEmptyLines = i + 1;
     }
-    return results;
 }
 // =============================================================================
-static char **removeEmptyLinesAtTheEnd(const char **lines, int *sizelines)
+static void moveEmptyLinesToEnd(wchar_t** lines, int* nonEmptyLines)
 {
-    char **returnedLines = NULL;
+    const int len = *nonEmptyLines;
     int nbLinesToRemove = 0;
 
     if (lines)
     {
-        int i = 0;
-        if (*sizelines >= 1)
+        for (int i = 0; i < len; i++)
         {
-            for (i = *sizelines - 1; i >= 0; i--)
+            if (hasOnlyBlankCharacters(&lines[i]))
             {
-                char *cleanedLine = stripCharacters(lines[i]);
-                if (cleanedLine)
+                nbLinesToRemove++;
+
+                // move the lines at the end
+                for (int j = i + 1; j < len; i++, j++)
                 {
-                    int len = (int) strlen(cleanedLine);
-                    FREE(cleanedLine);
-                    cleanedLine = NULL;
-                    if (len == 0)
-                    {
-                        nbLinesToRemove++;
-                        FREE((char*)lines[i]);
-                        lines[i] = NULL;
-                    }
-                    else
+                    // hopefully, empty lines have been flagged by hasOnlyBlankCharacters
+                    if (*(lines[j]) != L'\0')
                     {
-                        break;
+                        // swap
+                        wchar_t* str = lines[i];
+                        lines[i] = lines[j];
+                        lines[j] = str;
                     }
                 }
-            }
 
-            if (nbLinesToRemove > 0)
-            {
-                *sizelines = *sizelines - nbLinesToRemove;
-            }
-            returnedLines = (char **)MALLOC(sizeof(char *) * (*sizelines));
-            if (returnedLines)
-            {
-                for (i = 0; i < *sizelines; i++)
-                {
-                    returnedLines[i] = os_strdup(lines[i]);
-                }
             }
         }
     }
 
-    return returnedLines;
+    *nonEmptyLines = len - nbLinesToRemove;
 }
 // =============================================================================
-static char **removeAllBlankLines(const char **lines, int *sizelines)
+static int hasOnlyBlankCharacters(wchar_t** line)
 {
-    char **returnedLines = NULL;
-    int nbLines = 0;
-    if (lines)
+    const wchar_t* iter = *line;
+    while (*iter == L'\t' || *iter == L'\r' || *iter == L'\n' || *iter == L' ')
     {
-        int i = 0;
-        for (i = 0; i < *sizelines; i++)
-        {
-            char *cleanedLine = stripCharacters(lines[i]);
-            if (cleanedLine)
-            {
-                int len = (int) strlen(cleanedLine);
-                FREE(cleanedLine);
-                cleanedLine = NULL;
-                if (len != 0)
-                {
-                    if (nbLines == 0)
-                    {
-                        nbLines++;
-                        returnedLines = (char**)MALLOC(sizeof(char*) * nbLines);
-                    }
-                    else
-                    {
-                        nbLines++;
-                        returnedLines = (char**)REALLOC(returnedLines, sizeof(char*) * nbLines);
-                    }
+        iter++;
+    }
 
-                    if (returnedLines)
-                    {
-                        returnedLines[nbLines - 1] = os_strdup(lines[i]);
-                    }
-                    else
-                    {
-                        *sizelines = 0;
-                        return NULL;
-                    }
-                }
-            }
-        }
-        *sizelines = nbLines;
+    if (*iter == L'\0')
+    {
+        // flag the empty line as really empty, further comparisons will be cheap
+        FREE(*line);
+        *line = EMPTY_STR;
+        return 1;
     }
-    return returnedLines;
-}
-// =============================================================================
-static char *stripCharacters(const char *line)
-{
-    char *returnedLine = NULL;
-    if (line)
+    else
     {
-        char *tmpLineWithoutTab = strsub((char*)line, "\t", "");
-        if (tmpLineWithoutTab)
-        {
-            char *tmpLineWithoutLF = strsub(tmpLineWithoutTab, "\r", "");
-            if (tmpLineWithoutLF)
-            {
-                char *tmpLineWithoutCR = strsub(tmpLineWithoutTab, "\n", "");
-                if (tmpLineWithoutCR)
-                {
-                    returnedLine = strsub(tmpLineWithoutCR, " ", "");
-                    FREE(tmpLineWithoutCR);
-                }
-                else
-                {
-                    returnedLine = os_strdup(line);
-                }
-                FREE(tmpLineWithoutLF);
-                tmpLineWithoutLF = NULL;
-            }
-            else
-            {
-                returnedLine = os_strdup(line);
-            }
-            FREE(tmpLineWithoutTab);
-            tmpLineWithoutTab = NULL;
-        }
-        else
-        {
-            returnedLine = os_strdup(line);
-        }
+        return 0;
     }
-
-    return returnedLine;
 }
 // =============================================================================
-static char **replaceStrings(const char **lines, int nbLines, const char **toreplace, int sizetoreplace)
+static void replaceStrings(wchar_t** lines, int* nbLines, wchar_t** toreplace, int sizetoreplace)
 {
-    char **replacedStrings = NULL;
-    int nr = 0;
+    // number of string to compare and replace
+    int nr = sizetoreplace / 2;
 
-    nr = sizetoreplace / 2;
-
-    if (lines)
+    if (nbLines == NULL || *nbLines == 0 || sizetoreplace == 0)
     {
-        int i = 0;
+        return;
+    }
+    if (lines == NULL || toreplace == NULL)
+    {
+        return;
+    }
 
-        replacedStrings = (char**)MALLOC(sizeof(char*) * nbLines);
-        if (replacedStrings)
+    // for each line
+    for (int i = 0; i < *nbLines; i++)
+    {
+        // for each string to compare with
+        for (int j = 0; j < nr; j++)
         {
-            // Copy the source lines to the target replacedStrings.
-            int j = 0;
-            for (j = 0; j < nbLines; j++)
+            wchar_t* found = wcsstr(lines[i], toreplace[j]);
+            if (found)
             {
-                replacedStrings[j] = os_strdup(lines[j]);
-            }
-            // Make replacements within the target replacedStrings.
-            for (i = 0; i < nr; i++)
-            {
-                for (j = 0; j < nbLines; j++)
+                // we found a matching string, either reallocate and copy OR
+                // copy in place if there is enough room for the replacement
+                size_t lineLen = wcslen(lines[i]);
+                size_t foundLen = wcslen(found);
+                size_t matchLen = wcslen(toreplace[j]);
+                size_t replaceLen = wcslen(toreplace[j + nr]);
+                if (replaceLen > matchLen)
+                {
+                    wchar_t* previousLine = lines[i];
+                    size_t allocatedLen = lineLen - matchLen + replaceLen + 1;
+                    size_t foundIndex = found - previousLine;
+
+                    lines[i] = MALLOC(allocatedLen * sizeof(wchar_t));
+                    // copy up to the found string
+                    memcpy(lines[i], previousLine, foundIndex * sizeof(wchar_t));
+                    // copy the replacement string
+                    memcpy(&lines[i][foundIndex], toreplace[j + nr], replaceLen * sizeof(wchar_t));
+                    // copy from the end of the match up to the end of line
+                    memcpy(&lines[i][foundIndex + replaceLen], &previousLine[foundIndex + matchLen], (allocatedLen - foundIndex - replaceLen) * sizeof(wchar_t));
+
+                    FREE(previousLine);
+                }
+                else
                 {
-                    replacedStrings[j] = strsub(replacedStrings[j], toreplace[i], toreplace[nr + i]);
+                    // copy the replacement string
+                    memcpy(found, toreplace[j + nr], replaceLen * sizeof(wchar_t));
+                    // move the remaining string next to the replaced string (including the trailing 0)
+                    memmove(&found[replaceLen], &found[matchLen], (foundLen - matchLen + 1) * sizeof(wchar_t));
                 }
+
+                // continue to replace
+                j--;
             }
         }
     }
-    return replacedStrings;
 }
 // =============================================================================
-static char **extractComments(const char **lines, int nbLines,
-                              const char *regexpcomments, int *nbcomments, int *iErr)
+static wchar_t** extractComments(wchar_t** lines, int* nbLines,
+                                 const wchar_t* regexpcomments, int* nbcomments, int* iErr)
 {
-    char **pComments = NULL;
+    wchar_t** pComments = NULL;
     int i = 0;
 
-    for (i = 0; i < nbLines; i++)
+    for (i = 0; i < *nbLines; i++)
     {
         int Output_Start = 0;
         int Output_End = 0;
-        pcre_error_code answer = pcre_private((char*)lines[i], (char*)regexpcomments, &Output_Start, &Output_End, NULL, NULL);
+        pcre_error_code answer = wide_pcre_private(lines[i], regexpcomments, &Output_Start, &Output_End, NULL, NULL);
 
-        if ( (answer == CAN_NOT_COMPILE_PATTERN) || (answer == DELIMITER_NOT_ALPHANUMERIC))
+        if ((answer == CAN_NOT_COMPILE_PATTERN) || (answer == DELIMITER_NOT_ALPHANUMERIC))
         {
             if (pComments)
             {
-                freeArrayOfString(pComments, *nbcomments);
+                freeArrayOfWideString(pComments, *nbcomments);
             }
 
             *nbcomments = 0;
@@ -666,16 +630,16 @@ static char **extractComments(const char **lines, int nbLines,
             return NULL;
         }
 
-        if ( answer == PCRE_FINISHED_OK )
+        if (answer == PCRE_FINISHED_OK)
         {
             (*nbcomments)++;
             if (pComments == NULL)
             {
-                pComments = (char **)MALLOC(sizeof(char*) * (*nbcomments));
+                pComments = (wchar_t**)MALLOC(sizeof(wchar_t*) * (*nbcomments));
             }
             else
             {
-                pComments = (char **)REALLOC(pComments, sizeof(char*) * (*nbcomments));
+                pComments = (wchar_t**)REALLOC(pComments, sizeof(wchar_t*) * (*nbcomments));
             }
 
             if (pComments == NULL)
@@ -684,53 +648,15 @@ static char **extractComments(const char **lines, int nbLines,
                 *iErr = 1;
                 return NULL;
             }
-            pComments[(*nbcomments) - 1] = os_strdup(lines[i]);
+
+            // move lines[i] to comments and continue
+            pComments[(*nbcomments) - 1] = lines[i];
+            memmove(lines + i, lines + i + 1, sizeof(wchar_t*) * (*nbLines - i - 1));
+            (*nbLines)--;
+            i--;
         }
     }
 
     return pComments;
 }
 // =============================================================================
-static char **removeComments(const char **lines, int nbLines,
-                             const char *regexpcomments, int *newNbLines, int *iErr)
-{
-    char **pLinesCleaned = NULL;
-
-    int i = 0;
-    *newNbLines = 0;
-
-    for (i = 0; i < nbLines; i++)
-    {
-        int Output_Start = 0;
-        int Output_End = 0;
-        pcre_error_code answer = pcre_private((char*)lines[i], (char*)regexpcomments, &Output_Start, &Output_End, NULL, NULL);
-        if ( answer == PCRE_FINISHED_OK )
-        {
-            FREE((char*)lines[i]);
-            lines[i] = NULL;
-        }
-        else
-        {
-            (*newNbLines)++;
-            if (pLinesCleaned == NULL)
-            {
-                pLinesCleaned = (char **)MALLOC(sizeof(char*) * (*newNbLines));
-            }
-            else
-            {
-                pLinesCleaned = (char **)REALLOC(pLinesCleaned, sizeof(char*) * (*newNbLines));
-            }
-
-            if (pLinesCleaned == NULL)
-            {
-                *newNbLines = 0;
-                *iErr = 1;
-                return NULL;
-            }
-
-            pLinesCleaned[(*newNbLines) - 1] = (char*)lines[i];
-        }
-    }
-    return pLinesCleaned;
-}
-// =============================================================================
index 3799ec6..a4aa546 100644 (file)
@@ -15,6 +15,8 @@
 #ifndef __CSV_READ_H__
 #define __CSV_READ_H__
 
+#include <wchar.h>
+
 typedef enum
 {
     CSV_READ_NO_ERROR = 0,
@@ -30,11 +32,12 @@ typedef enum
 
 typedef struct
 {
-    char **pstrValues;
-    int m;
-    int n;
-    char **pstrComments;
+    wchar_t **pwstrValues;
+    int nbLines;
+    wchar_t **pwstrComments;
     int nbComments;
+    wchar_t **pwstrHeader;
+    int nbHeader;
     csvReadError err;
 } csvResult;
 
@@ -42,10 +45,14 @@ typedef struct
 extern "C" {
 #endif
 
-csvResult* csvRead(const char *filename, const char *separator, const char *decimal,
-                   const char **toreplace, int sizetoreplace, const char *regexpcomments, int header);
+csvResult* csvRead(const wchar_t *filename, const wchar_t *separator, const wchar_t *decimal,
+                   wchar_t **toreplace, int sizetoreplace, const wchar_t *regexpcomments, int header);
+
+int csvTextScanInPlace(wchar_t** text, int nbLines, const wchar_t* separator,
+                       const wchar_t* decimal, int haveRange, const int* iRange, int m1, int n1,
+                       wchar_t** pstrValues, double* pDblRealValues, double** pDblImgValues);
 
-csvResult* csvTextScan(const char **lines, int numberOfLines, const char *separator, const char *decimal);
+char* csvTextScanSize(wchar_t** lines, int* numberOfLines, const wchar_t* separator, int *rows, int *cols, int haveRange, int* iRange);
 
 void freeCsvResult(csvResult *result);
 
index b352565..8846eb7 100644 (file)
@@ -244,3 +244,66 @@ char **splitLineCSV(const char *str, const char *sep, int *toks)
     return retstr;
 }
 /* ==================================================================== */
+wchar_t* splitLineCSVNext(wchar_t* previousToken, const wchar_t* separator, wchar_t** start, wchar_t** end)
+{
+    size_t quoteCount = 0;
+    wchar_t* it = NULL;
+    if (previousToken == NULL)
+    {
+        return NULL;
+    }
+
+    // string separator might be a string, the management is also more complex due to some mix between " and *separator
+
+    // initial values
+    *start = previousToken;
+    *end = NULL;
+
+    it = previousToken;
+    for (; *it != L'\0'; it++)
+    {
+        if (*it == L'\"')
+        {
+            quoteCount++;
+        }
+        if (*it == *separator && quoteCount % 2 == 0)
+        {
+            // look for the next separator
+            const wchar_t* st = separator;
+            for (wchar_t* iit = it; *iit != L'\0'; iit++)
+            {
+                if (*iit == *st)
+                {
+                    // found! iterate on both strings
+                    st++;
+                }
+                else if (iit != it)
+                {
+                    // reset a previously started match
+                    break;
+                }
+
+                // last iteration
+                if (*st == L'\0')
+                {
+                    *end = iit;
+                    break;
+                }
+            }
+
+            if (*end != NULL)
+            {
+                break;
+            }
+        }
+    }
+
+    // last iteration, set the end to the last '\0' char and the iterator to NULL
+    if (*end == NULL)
+    {
+        *end = it;
+        return NULL;
+    }
+    return *end + 1;
+}
+
index 39ad968..d890f13 100644 (file)
@@ -15,6 +15,8 @@
 #ifndef __SPLITLINE_H__
 #define __SPLITLINE_H__
 
+#include <wchar.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -22,7 +24,12 @@ extern "C" {
 /**
 * split a line by separator
 */
-char **splitLineCSV(const char *str, const char *sep, int *toks);
+char** splitLineCSV(const char* str, const char* sep, int* toks);
+
+/**
+* split a line by separator, iterator (non-allocating) version
+*/
+wchar_t* splitLineCSVNext(wchar_t* previousToken, const wchar_t* separator, wchar_t** start, wchar_t** end);
 
 #ifdef __cplusplus
 }
diff --git a/scilab/modules/spreadsheet/tests/benchmarks/csvRead.tst b/scilab/modules/spreadsheet/tests/benchmarks/csvRead.tst
new file mode 100644 (file)
index 0000000..9c3a4f3
--- /dev/null
@@ -0,0 +1,33 @@
+// ================================================================================
+// Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+// Copyright (C) 2019 - ESI Group - Clement DAVID
+//
+//  This file is distributed under the same license as the Scilab package.
+// ================================================================================
+
+//=================================================================================
+// Benchmark for csvRead, the algorithm should be linear to the number of lines
+//=================================================================================
+
+// <-- BENCH NB RUN : 5 -->
+// generate some CSV files
+
+N=4;
+space = logspace(0, 3, N);
+R = rand(space($), space($));
+for i=space,
+    for j=space,
+        fprintfMat(fullfile(TMPDIR, msprintf("%dx%d.csv", i, j)), R(1:i, 1:j));
+    end
+end
+
+// <-- BENCH START -->
+for i=space,
+    for j=space,
+        csvRead(fullfile(TMPDIR, msprintf("%dx%d.csv", i, j)));
+    end
+end
+// <-- BENCH END -->
+
+
+
index 3d9b5d0..1e8d5ed 100644 (file)
@@ -19,9 +19,9 @@
 //
 filename = SCI + "/modules/spreadsheet/tests/nonreg_tests/bug_11999.csv";
 csvDefault("blank", "off"); // Default behavior in 5.4.0, changed 5.4.1 to "on"
-errMsg = msprintf(gettext("%s: can not read file %s: Error in the column structure\n"), "csvRead", filename);
+errMsg = msprintf(gettext("%s: can not read file, error in the column structure\n"), "csvRead");
 assert_checkerror("a=csvRead(filename, "";"", [], ""string"");", errMsg, 999);
-Warning: Inconsistency found in the columns. At line 2, found 0 columns while the previous had 3.
+Warning: Inconsistency found in the columns. At line 2, found 1 columns while the previous had 3.
 csvDefault("blank", "on");
 a=csvRead(filename, ";", [], "string");
 assert_checkequal(a,["foo", "bar", "foo"; "foo2", "bar2", "bar3"]);
index be89073..d12c619 100644 (file)
@@ -20,7 +20,7 @@
 filename = SCI + "/modules/spreadsheet/tests/nonreg_tests/bug_11999.csv";
 
 csvDefault("blank", "off"); // Default behavior in 5.4.0, changed 5.4.1 to "on"
-errMsg = msprintf(gettext("%s: can not read file %s: Error in the column structure\n"), "csvRead", filename);
+errMsg = msprintf(gettext("%s: can not read file, error in the column structure\n"), "csvRead");
 assert_checkerror("a=csvRead(filename, "";"", [], ""string"");", errMsg, 999);
 
 csvDefault("blank", "on");
index 1a639f0..812d7c0 100644 (file)
@@ -26,7 +26,7 @@ header = 2;
 refM = [
 0.211324865464121 0.000221134629101 0.665381104219705
 0.756043854169548 0.330327091738582 0.628391788341105 ];
-refC = "";
+refC = comments;
 assert_checkalmostequal(M, refM);
 assert_checkequal(c, refC);
 // Case when csvRead has two output arguments but no 'regexpcomments' argument.
index 15defd7..60aa930 100644 (file)
@@ -29,7 +29,7 @@ header = 2;
 refM = [
 0.211324865464121 0.000221134629101 0.665381104219705
 0.756043854169548 0.330327091738582 0.628391788341105 ];
-refC = "";
+refC = comments;
 
 assert_checkalmostequal(M, refM);
 assert_checkequal(c, refC);
index 34120f1..fc67a2c 100644 (file)
@@ -45,6 +45,6 @@ b=csvRead(filename);
 assert_checkequal(b, [1.1  %inf*(1+%i)]);
 write_csv([ 1.1  1+%i*%inf],filename)
 b=mgetl(filename);
-assert_checkequal(b,"1.1000000000000001,Nan+Infi");
+assert_checkequal(b,"1.1000000000000001,1+Infi");
 b=csvRead(filename);
 assert_checkequal(b, [ 1.1  1+%i*%inf]);
index 4617256..8327484 100644 (file)
@@ -52,6 +52,6 @@ assert_checkequal(b, [1.1  %inf*(1+%i)]);
 
 write_csv([ 1.1  1+%i*%inf],filename)
 b=mgetl(filename);
-assert_checkequal(b,"1.1000000000000001,Nan+Infi");
+assert_checkequal(b,"1.1000000000000001,1+Infi");
 b=csvRead(filename);
 assert_checkequal(b, [ 1.1  1+%i*%inf]);
index b257d2c..cd49c9d 100644 (file)
@@ -3,7 +3,6 @@
 // =============================================================================
 // <-- CLI SHELL MODE -->
 // =============================================================================
-// <-- LONG TIME EXECUTION -->
 // <-- NO CHECK REF -->
 //
 // <-- Non-regression test for bug 194 -->
diff --git a/scilab/modules/spreadsheet/tests/nonreg_tests/ticket_472.dia.ref b/scilab/modules/spreadsheet/tests/nonreg_tests/ticket_472.dia.ref
deleted file mode 100644 (file)
index 8173737..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-// =============================================================================
-// Copyright (C) 2012 - INRIA - Allan CORNET
-// =============================================================================
-// <-- CLI SHELL MODE -->
-// =============================================================================
-// <-- Non-regression test for bug 472 -->
-//
-// <-- URL -->
-//  http://forge.scilab.org/index.php/p/csv-readwrite/issues/472/
-//
-// <-- Short Description -->
-// csvRead, csvTextScan cannot ignore blank lines.
-// =============================================================================
-warning("off");
-txt = ["my data 1";"";"my data 2"];
-ref_res = ["my data 1";"my data 2"];
-assert_checkequal(csvDefault('blank'), 'on');
-assert_checkequal(csvDefault('blank','off'), %t);
-ierr = execstr("res = csvTextScan(txt, [] , [], ""string"")", "errcatch");
-assert_checkequal(ierr, 999);
-assert_checkequal(csvDefault('blank','on'), %t);
-ierr = execstr("res = csvTextScan(txt, [] , [], ""string"")", "errcatch");
-assert_checkequal(ierr, 0);
-assert_checkequal(res, ref_res);
-// =============================================================================
-assert_checkequal(csvDefault('blank','off'), %t);
index e5f1af3..79c9390 100644 (file)
@@ -2,6 +2,7 @@
 // Copyright (C) 2012 - INRIA - Allan CORNET
 // =============================================================================
 // <-- CLI SHELL MODE -->
+// <-- NO CHECK REF -->
 // =============================================================================
 // <-- Non-regression test for bug 472 -->
 //
 // csvRead, csvTextScan cannot ignore blank lines.
 // =============================================================================
 
-warning("off");
 txt = ["my data 1";"";"my data 2"];
 ref_res = ["my data 1";"my data 2"];
 
 assert_checkequal(csvDefault('blank'), 'on');
 assert_checkequal(csvDefault('blank','off'), %t);
-ierr = execstr("res = csvTextScan(txt, [] , [], ""string"")", "errcatch");
-assert_checkequal(ierr, 999);
+res = csvTextScan(txt, [] , [], "string");
+assert_checkequal(res, txt); // handle empty lines
 
 assert_checkequal(csvDefault('blank','on'), %t);
-ierr = execstr("res = csvTextScan(txt, [] , [], ""string"")", "errcatch");
-assert_checkequal(ierr, 0);
+res = csvTextScan(txt, [] , [], "string");
 assert_checkequal(res, ref_res);
 // =============================================================================
 
-assert_checkequal(csvDefault('blank','off'), %t);
\ No newline at end of file
+assert_checkequal(csvDefault('blank','off'), %t);
diff --git a/scilab/modules/spreadsheet/tests/unit_tests/csvRead_multi_line.csv b/scilab/modules/spreadsheet/tests/unit_tests/csvRead_multi_line.csv
new file mode 100644 (file)
index 0000000..b712347
--- /dev/null
@@ -0,0 +1,8 @@
+hello,this,is,"C
+S
+V",!
+on,a,"m
+u
+l
+t
+i",line,sheet
diff --git a/scilab/modules/spreadsheet/tests/unit_tests/csvRead_multi_line.tst b/scilab/modules/spreadsheet/tests/unit_tests/csvRead_multi_line.tst
new file mode 100644 (file)
index 0000000..63fe3af
--- /dev/null
@@ -0,0 +1,34 @@
+// =============================================================================
+// Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+// Copyright (C) 2019 - ESI Group - Clement DAVID
+//
+//  This file is distributed under the same license as the Scilab package.
+// =============================================================================
+//
+// <-- CLI SHELL MODE -->
+// <-- NO CHECK REF -->
+//
+// <-- Short Description -->
+// from RFC4180:
+//  Fields containing line breaks (CRLF), double quotes, and commas
+//  should be enclosed in double-quotes.
+//
+
+path = SCI+"/modules/spreadsheet/tests/unit_tests/";
+
+M = csvRead(fullfile(path, "csvRead_multi_line.csv"));
+assert_checkequal(M, %nan + zeros(2,5));
+
+M = csvRead(fullfile(path, "csvRead_multi_line.csv"), [], [], "string");
+assert_checkequal(M(1, 1), "hello");
+assert_checkequal(M(1, 2), "this");
+assert_checkequal(M(1, 3), "is");
+assert_checkequal(M(1, 4), strcat(["C", "S", "V"], ascii(10)));
+assert_checkequal(M(1, 5), "!");
+assert_checkequal(M(2, 1), "on");
+assert_checkequal(M(2, 2), "a");
+assert_checkequal(M(2, 3), strcat(["m", "u", "l", "t", "i"], ascii(10)));
+assert_checkequal(M(2, 4), "line");
+assert_checkequal(M(2, 5), "sheet");
+
+
index a0516db..d7ac1f1 100644 (file)
@@ -37,21 +37,30 @@ typedef enum
 extern "C" {
 #endif
 
-doublecomplex stringToComplex(const char *pSTR,
-                              const char *decimal,
-                              BOOL bConvertByNAN,
-                              stringToComplexError *ierr);
+STRING_IMPEXP doublecomplex stringToComplexWInPlace(wchar_t* start, wchar_t* end,
+        const wchar_t* decimal,
+        BOOL bConvertByNAN,
+        stringToComplexError* ierr);
 
-doublecomplex stringToComplexW(const wchar_t *pSTR,
-                               const wchar_t *decimal,
-                               BOOL bConvertByNAN,
-                               stringToComplexError *ierr);
+STRING_IMPEXP doublecomplex stringToComplex(const char* pSTR,
+        const char *decimal,
+        BOOL bConvertByNAN,
+        stringToComplexError *ierr);
+
+STRING_IMPEXP doublecomplex stringToComplexW(const wchar_t* pSTR,
+        const wchar_t *decimal,
+        BOOL bConvertByNAN,
+        stringToComplexError *ierr);
 
 STRING_IMPEXP  complexArray *stringsToComplexArray(const char **pSTRs, int nbElements,
         const char *decimal,
         BOOL bConvertByNAN,
         stringToComplexError *ierr);
 
+STRING_IMPEXP void convertDecimalToDotInPlace(wchar_t* str, const wchar_t* decimal);
+
+STRING_IMPEXP void escapeDoubleQuotesInPlace(wchar_t* start, wchar_t* end);
+
 #ifdef __cplusplus
 }
 #endif
index a66c1e0..9748c5d 100644 (file)
@@ -86,7 +86,8 @@ stringToDoubleError;
  * @return <ReturnValue>
  */
 STRING_IMPEXP double stringToDouble(const char *pSTR, BOOL bConvertByNAN, stringToDoubleError *ierr);
-STRING_IMPEXP double stringToDoubleW(const wchar_t *pSTR, BOOL bConvertByNAN, stringToDoubleError *ierr);
+STRING_IMPEXP double stringToDoubleW(const wchar_t* pSTR, BOOL bConvertByNAN, stringToDoubleError* ierr);
+STRING_IMPEXP double stringToDoubleWInPlace(wchar_t* pSTR, BOOL bConvertByNAN, stringToDoubleError* ierr);
 
 #ifdef __cplusplus
 }
index c6b7077..63a7fd8 100644 (file)
  * along with this program.
  *
  */
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <math.h>
-#include <ctype.h>
-#include <wctype.h>
 #include "stringToComplex.h"
-#include "stringToDouble.h"
-#include "sci_malloc.h"
-#include "os_string.h"
 #include "BOOL.h"
+#include "os_string.h"
+#include "sci_malloc.h"
+#include "stringToDouble.h"
 #include "strsubst.h"
 #include "numericconstants_interface.h"
  /* ========================================================================== */
+#include <ctype.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wctype.h>
+/* ========================================================================== */
 #define PlusChar '+'
 #define PlusCharW L'+'
 #define LessChar '-'
 /* ========================================================================== */
 static int ParseNumber(const char* tx);
 static int ParseNumberW(const wchar_t* tx);
-static stringToComplexError ParseComplexValue(const char *tx, BOOL bConvertByNAN, double *real, double *imag);
-static stringToComplexError ParseComplexValueW(const wchar_t *tx, BOOL bConvertByNAN, double *real, double *imag);
-static char* midstring(const char *tx, size_t pos, int nb);
-static wchar_t* midstringW(const wchar_t *tx, size_t pos, int nb);
-static char *leftstring(const char *tx, size_t pos);
+static stringToComplexError ParseComplexValue(const char* tx, BOOL bConvertByNAN, double* real, double* imag);
+static stringToComplexError ParseComplexValueW(const wchar_t* tx, BOOL bConvertByNAN, double* real, double* imag);
+static stringToComplexError ParseComplexValueWInPlace(wchar_t* tx, BOOL bConvertByNAN, double* real, double* imag);
+static char* midstring(const char* tx, size_t pos, int nb);
+static wchar_t* midstringW(const wchar_t* tx, size_t pos, int nb);
+static wchar_t* midstringWInPlace(wchar_t* tx, size_t pos);
+static char* leftstring(const char* tx, size_t pos);
 static wchar_t* leftstringW(const wchar_t* tx, size_t pos);
-static BOOL is_unit_imaginary (const char *src, double *im);
-static BOOL is_unit_imaginaryW (const wchar_t* src, double *im);
+static wchar_t* leftstringWInPlace(wchar_t* tx, size_t pos);
+static BOOL is_unit_imaginary(const char* src, double* im);
+static BOOL is_unit_imaginaryW(const wchar_t* src, double* im);
+static double returnNAN(void);
 /* ========================================================================== */
-complexArray *stringsToComplexArray(const char **pSTRs, int nbElements,
-                                    const char *decimal,
+complexArray* stringsToComplexArray(const char** pSTRs, int nbElements,
+                                    const char* decimal,
                                     BOOL bConvertByNAN,
-                                    stringToComplexError *ierr)
+                                    stringToComplexError* ierr)
 {
-    complexArray *pComplexArray = NULL;
+    complexArray* pComplexArray = NULL;
 
     *ierr = STRINGTOCOMPLEX_ERROR;
     if (nbElements <= 0)
@@ -109,7 +114,125 @@ complexArray *stringsToComplexArray(const char **pSTRs, int nbElements,
     return pComplexArray;
 }
 /* ========================================================================== */
-doublecomplex stringToComplex(const char *pSTR, const char *decimal, BOOL bConvertByNAN, stringToComplexError *ierr)
+void convertDecimalToDotInPlace(wchar_t* str, const wchar_t* decimal)
+{
+
+    // convert decimal to L'.' to use standard parsing
+    if (decimal[0] == L'.' && decimal[1] == L'\0')
+    {
+        // the decimal is the usual one, do nothing
+    }
+    else if (decimal[0] != L'\0' && decimal[1] == L'\0')
+    {
+        // common case, the delimiter is one wchar_t
+        for (wchar_t* it = str; *it != L'\0'; it++)
+        {
+            if (*it == decimal[0])
+            {
+                *it = L'.';
+                break;
+            }
+        }
+    }
+    else
+    {
+        // extra case, the delimiter is a string
+        for (wchar_t *it = str, *jt = str; *it != L'\0'; it++, jt++)
+        {
+            // consume the decimal delimiter
+            for (const wchar_t* dt = decimal, *iit = it; *dt != L'\0' && *iit != L'\0'; dt++, iit++)
+            {
+                if (*iit != *dt)
+                {
+                    break;
+                }
+
+                // last iteration
+                if (dt[1] == L'\0')
+                {
+                    it = (wchar_t*) iit;
+                    break;
+                }
+            }
+
+            // copy the source to destination
+            *jt = *it;
+        }
+    }
+}
+// =============================================================================
+void escapeDoubleQuotesInPlace(wchar_t* start, wchar_t* end)
+{
+    wchar_t* c = start;
+    wchar_t* c2 = start;
+    while (c < end)
+    {
+        if (*c == L'"')
+        {
+            c++;
+            if (*c == L'"')
+            {
+                *c2 = L'"';
+                c++;
+                c2++;
+            }
+        }
+        else
+        {
+            *c2 = *c;
+            c++;
+            c2++;
+        }
+    }
+    *c2 = 0;
+}
+/* ========================================================================== */
+doublecomplex stringToComplexWInPlace(wchar_t* start, wchar_t* end,
+                                      const wchar_t* decimal,
+                                      BOOL bConvertByNAN,
+                                      stringToComplexError* ierr)
+{
+    doublecomplex dComplexValue;
+    *ierr = STRINGTOCOMPLEX_ERROR;
+
+    dComplexValue.r = 0.;
+    dComplexValue.i = 0.;
+
+    if (start)
+    {
+        double real = 0.;
+        double imag = 0.;
+
+        // remove any space
+        wchar_t* withoutLeadingSpaces = start;
+        while (*withoutLeadingSpaces == L' ')
+        {
+            withoutLeadingSpaces++;
+        }
+
+        // convert decimal to '.' to use standard parsing
+        convertDecimalToDotInPlace(withoutLeadingSpaces, decimal);
+
+        // FIXME: handle .4 to 0.4
+        // FIXME: handle +.4 to +0.4
+        // FIXME: handle -.4 to -0.4
+        // FIXME: handle is_unit_imaginary()
+
+        {
+            wchar_t previous = *end;
+            *end = L'\0';
+            *ierr = ParseComplexValueWInPlace(withoutLeadingSpaces, bConvertByNAN, &real, &imag);
+            *end = previous;
+        }
+
+        dComplexValue.r = real;
+        dComplexValue.i = imag;
+    }
+
+    return dComplexValue;
+}
+/* ========================================================================== */
+doublecomplex stringToComplex(const char* pSTR, const char* decimal, BOOL bConvertByNAN, stringToComplexError* ierr)
 {
     doublecomplex dComplexValue;
     *ierr = STRINGTOCOMPLEX_ERROR;
@@ -121,22 +244,22 @@ doublecomplex stringToComplex(const char *pSTR, const char *decimal, BOOL bConve
     {
         double real = 0.;
         double imag = 0.;
-        char *pStrTemp = strsub((char*)pSTR, " ", "");
+        char* pStrTemp = strsub((char*)pSTR, " ", "");
 
         if (pStrTemp)
         {
-            char *pStrFormatted = strsub(pStrTemp, decimal, ".");
+            char* pStrFormatted = strsub(pStrTemp, decimal, ".");
             FREE(pStrTemp);
 
             if (pStrFormatted)
             {
-                int lenStrFormatted = (int) strlen(pStrFormatted);
+                int lenStrFormatted = (int)strlen(pStrFormatted);
 
                 /* case .4 replaced by 0.4 */
                 if (pStrFormatted[0] == '.')
                 {
                     /* case .4 replaced by 0.4 */
-                    char *pstStrTemp = (char*)MALLOC(sizeof(char) * (lenStrFormatted + strlen("0") + 1));
+                    char* pstStrTemp = (char*)MALLOC(sizeof(char) * (lenStrFormatted + strlen("0") + 1));
                     strcpy(pstStrTemp, "0");
                     strcat(pstStrTemp, pStrFormatted);
                     FREE(pStrFormatted);
@@ -149,7 +272,7 @@ doublecomplex stringToComplex(const char *pSTR, const char *decimal, BOOL bConve
                             (pStrFormatted[1] == '.'))
                     {
                         /* case +.4 replaced by +0.4 */
-                        char *pstStrTemp = strsub(pStrFormatted, "+.", "+0.");
+                        char* pstStrTemp = strsub(pStrFormatted, "+.", "+0.");
                         FREE(pStrFormatted);
 
                         /* case -.4 replaced by -0.4 */
@@ -159,7 +282,7 @@ doublecomplex stringToComplex(const char *pSTR, const char *decimal, BOOL bConve
                 }
 
                 /* Case: "i", "+i", "-i", and with "j"  */
-                if (is_unit_imaginary (pStrFormatted, &imag))
+                if (is_unit_imaginary(pStrFormatted, &imag))
                 {
                     *ierr = STRINGTOCOMPLEX_NO_ERROR;
                     dComplexValue.r = 0.;
@@ -178,7 +301,7 @@ doublecomplex stringToComplex(const char *pSTR, const char *decimal, BOOL bConve
     return dComplexValue;
 }
 /* ========================================================================== */
-doublecomplex stringToComplexW(const wchar_t *pSTR, const wchar_t *decimal, BOOL bConvertByNAN, stringToComplexError *ierr)
+doublecomplex stringToComplexW(const wchar_t* pSTR, const wchar_t* decimal, BOOL bConvertByNAN, stringToComplexError* ierr)
 {
     doublecomplex dComplexValue;
     *ierr = STRINGTOCOMPLEX_ERROR;
@@ -190,22 +313,22 @@ doublecomplex stringToComplexW(const wchar_t *pSTR, const wchar_t *decimal, BOOL
     {
         double real = 0.;
         double imag = 0.;
-        wchar_t *pStrTemp = wcssub(pSTR, L" ", L"");
+        wchar_t* pStrTemp = wcssub(pSTR, L" ", L"");
 
         if (pStrTemp)
         {
-            wchar_t *pStrFormatted = wcssub(pStrTemp, decimal, L".");
+            wchar_t* pStrFormatted = wcssub(pStrTemp, decimal, L".");
             FREE(pStrTemp);
 
             if (pStrFormatted)
             {
-                int lenStrFormatted = (int) wcslen(pStrFormatted);
+                int lenStrFormatted = (int)wcslen(pStrFormatted);
 
                 /* case .4 replaced by 0.4 */
                 if (pStrFormatted[0] == '.')
                 {
                     /* case .4 replaced by 0.4 */
-                    wchar_t *pstStrTemp = (wchar_t*)MALLOC(sizeof(wchar_t) * (lenStrFormatted + wcslen(L"0") + 1));
+                    wchar_t* pstStrTemp = (wchar_t*)MALLOC(sizeof(wchar_t) * (lenStrFormatted + wcslen(L"0") + 1));
                     wcscpy(pstStrTemp, L"0");
                     wcscat(pstStrTemp, pStrFormatted);
                     FREE(pStrFormatted);
@@ -218,7 +341,7 @@ doublecomplex stringToComplexW(const wchar_t *pSTR, const wchar_t *decimal, BOOL
                             (pStrFormatted[1] == '.'))
                     {
                         /* case +.4 replaced by +0.4 */
-                        wchar_t *pstStrTemp = wcssub(pStrFormatted, L"+.", L"+0.");
+                        wchar_t* pstStrTemp = wcssub(pStrFormatted, L"+.", L"+0.");
                         FREE(pStrFormatted);
 
                         /* case -.4 replaced by -0.4 */
@@ -253,7 +376,7 @@ static int ParseNumber(const char* tx)
     int lookahead = 0;
     int len = 0;
 
-    if (tx[len] == NULL)
+    if (tx[len] == '\0')
     {
         return lookahead;
     }
@@ -269,7 +392,7 @@ static int ParseNumber(const char* tx)
     }
     else if (strlen(tx) >= 4 && (strncmp(tx, "%eps", 4) == 0 || strncmp(tx, "+%pi", 4) == 0 || strncmp(tx, "-%pi", 4) == 0 ||
                                  strncmp(tx, "+Inf", 4) == 0 || strncmp(tx, "-Inf", 4) == 0 || strncmp(tx, "+Nan", 4) == 0 ||
-                                 strncmp(tx, "-Nan", 4) == 0 || strncmp(tx, "%nan", 4) == 0 || strncmp(tx, "%inf", 4) == 0 ))
+                                 strncmp(tx, "-Nan", 4) == 0 || strncmp(tx, "%nan", 4) == 0 || strncmp(tx, "%inf", 4) == 0))
     {
         return 4;
     }
@@ -330,7 +453,7 @@ static int ParseNumberW(const wchar_t* tx)
     int lookahead = 0;
     int len = 0;
 
-    if (tx[len] == NULL)
+    if (tx[len] == L'0')
     {
         return lookahead;
     }
@@ -382,15 +505,15 @@ static int ParseNumberW(const wchar_t* tx)
     return lookahead;
 }
 /* ========================================================================== */
-static stringToComplexError ParseComplexValue(const char *tx, BOOL bConvertByNAN, double *real, double *imag)
+static stringToComplexError ParseComplexValue(const char* tx, BOOL bConvertByNAN, double* real, double* imag)
 {
     stringToDoubleError ierrDouble = STRINGTODOUBLE_NO_ERROR;
     stringToComplexError ierr = STRINGTOCOMPLEX_NO_ERROR;
-    char *rnum_string = NULL;
-    char *inum_string = NULL;
+    char* rnum_string = NULL;
+    char* inum_string = NULL;
     size_t lnum = 0;
     BOOL haveImagI = FALSE;
-    char *modifiedTxt = NULL;
+    char* modifiedTxt = NULL;
     int i = 0;
 
     *real = stringToDouble(tx, FALSE, &ierrDouble);
@@ -401,7 +524,7 @@ static stringToComplexError ParseComplexValue(const char *tx, BOOL bConvertByNAN
     {
         if (ierrDouble == STRINGTODOUBLE_NO_ERROR)
         {
-            ierr = (stringToComplexError) ierrDouble;
+            ierr = (stringToComplexError)ierrDouble;
         }
         else
         {
@@ -415,7 +538,7 @@ static stringToComplexError ParseComplexValue(const char *tx, BOOL bConvertByNAN
             {
                 *real = 0;
                 *imag = 0;
-                ierr = (stringToComplexError) ierrDouble;
+                ierr = (stringToComplexError)ierrDouble;
             }
         }
     }
@@ -453,27 +576,30 @@ static stringToComplexError ParseComplexValue(const char *tx, BOOL bConvertByNAN
         }
         inum_string = midstring(modifiedTxt, lnum, -1);
 
-        if ((inum_string[strlen(inum_string) - 1] == 'i') ||
-                (inum_string[strlen(inum_string) - 1] == 'j')) // The imaginary part looks like "a*%i"
+        if (*inum_string != '\0')
         {
-            inum_string[strlen(inum_string) - 1] = 0;
-            if (inum_string[strlen(inum_string) - 1] == '*')
+            if ((inum_string[strlen(inum_string) - 1] == 'i') ||
+                    (inum_string[strlen(inum_string) - 1] == 'j')) // The imaginary part looks like "a*%i"
             {
                 inum_string[strlen(inum_string) - 1] = 0;
-            }
+                if (*inum_string != '\0' && inum_string[strlen(inum_string) - 1] == '*')
+                {
+                    inum_string[strlen(inum_string) - 1] = 0;
+                }
 
-            if (strcmp(inum_string, "+") == 0)
-            {
-                FREE(inum_string);
-                inum_string = os_strdup("+1");
-            }
+                if (strcmp(inum_string, "+") == 0)
+                {
+                    FREE(inum_string);
+                    inum_string = os_strdup("+1");
+                }
 
-            if (strcmp(inum_string, "-") == 0)
-            {
-                FREE(inum_string);
-                inum_string = os_strdup("-1");
+                if (strcmp(inum_string, "-") == 0)
+                {
+                    FREE(inum_string);
+                    inum_string = os_strdup("-1");
+                }
+                haveImagI = TRUE;
             }
-            haveImagI = TRUE;
         }
         else if (inum_string[1] == 'i' || inum_string[1] == 'j') // The imaginary part looks like "%i*a". For instance if string() has been used
         {
@@ -482,13 +608,20 @@ static stringToComplexError ParseComplexValue(const char *tx, BOOL bConvertByNAN
             {
                 inum_string[i] = inum_string[i + 1];    // Removing the "i"
             }
-            if (inum_string[1] == '*')
+            if (inum_string[1] == 'i' || inum_string[1] == 'j') // The imaginary part looks like "%i*a". For instance if string() has been used
             {
+                int len_inum_string = strlen(inum_string);
                 for (i = 1; i < len_inum_string; ++i)
                 {
-                    inum_string[i] = inum_string[i + 1];    // Removing the "*"
+                    inum_string[i] = inum_string[i + 1]; // Removing the "i"
+                }
+                if (inum_string[1] == '*')
+                {
+                    for (i = 1; i < len_inum_string; ++i)
+                    {
+                        inum_string[i] = inum_string[i + 1]; // Removing the "*"
+                    }
                 }
-            }
 
             if (strcmp(inum_string, "+") == 0)
             {
@@ -496,12 +629,18 @@ static stringToComplexError ParseComplexValue(const char *tx, BOOL bConvertByNAN
                 inum_string = os_strdup("+1");
             }
 
-            if (strcmp(inum_string, "-") == 0)
+                if (strcmp(inum_string, "-") == 0)
+                {
+                    FREE(inum_string);
+                    inum_string = strdup("-1");
+                }
+                haveImagI = TRUE;
+            }
+            else
             {
                 FREE(inum_string);
                 inum_string = os_strdup("-1");
             }
-            haveImagI = TRUE;
         }
         else
         {
@@ -560,7 +699,8 @@ static stringToComplexError ParseComplexValue(const char *tx, BOOL bConvertByNAN
                     ierr = STRINGTOCOMPLEX_ERROR;
                 }
             }
-        }
+        } 
+        
 
         FREE(rnum_string);
         FREE(inum_string);
@@ -569,15 +709,15 @@ static stringToComplexError ParseComplexValue(const char *tx, BOOL bConvertByNAN
     return ierr;
 }
 /* ========================================================================== */
-static stringToComplexError ParseComplexValueW(const wchar_t *tx, BOOL bConvertByNAN, double *real, double *imag)
+static stringToComplexError ParseComplexValueW(const wchar_t* tx, BOOL bConvertByNAN, double* real, double* imag)
 {
     stringToDoubleError ierrDouble = STRINGTODOUBLE_NO_ERROR;
     stringToComplexError ierr = STRINGTOCOMPLEX_NO_ERROR;
-    wchar_t *rnum_string = NULL;
-    wchar_t *inum_string = NULL;
+    wchar_t* rnum_string = NULL;
+    wchar_t* inum_string = NULL;
     size_t lnum = 0;
     BOOL haveImagI = FALSE;
-    wchar_t *modifiedTxt = NULL;
+    wchar_t* modifiedTxt = NULL;
 
     *real = stringToDoubleW(tx, FALSE, &ierrDouble);
     *imag = 0;
@@ -587,7 +727,7 @@ static stringToComplexError ParseComplexValueW(const wchar_t *tx, BOOL bConvertB
     {
         if (ierrDouble == STRINGTODOUBLE_NO_ERROR)
         {
-            ierr = (stringToComplexError) ierrDouble;
+            ierr = (stringToComplexError)ierrDouble;
         }
         else
         {
@@ -601,7 +741,7 @@ static stringToComplexError ParseComplexValueW(const wchar_t *tx, BOOL bConvertB
             {
                 *real = 0;
                 *imag = 0;
-                ierr = (stringToComplexError) ierrDouble;
+                ierr = (stringToComplexError)ierrDouble;
             }
         }
     }
@@ -794,14 +934,201 @@ static stringToComplexError ParseComplexValueW(const wchar_t *tx, BOOL bConvertB
         modifiedTxt = NULL;
     }
     return ierr;
+} /* ========================================================================== */
+static stringToComplexError ParseComplexValueWInPlace(wchar_t* tx, BOOL bConvertByNAN, double* real, double* imag)
+{
+    stringToDoubleError ierrDouble = STRINGTODOUBLE_NO_ERROR;
+    stringToComplexError ierr = STRINGTOCOMPLEX_NO_ERROR;
+    wchar_t* rnum_string = NULL;
+    wchar_t* inum_string = NULL;
+    size_t lnum = 0;
+    double gainImagI = 0.;
+    int i = 0;
+
+    *real = stringToDoubleWInPlace(tx, FALSE, &ierrDouble);
+    *imag = 0;
+
+    /* test on strlen(tx) > 1 to remove case 'e' */
+    if ((int)wcslen(tx) < 2)
+    {
+        if (ierrDouble == STRINGTODOUBLE_NO_ERROR)
+        {
+            ierr = (stringToComplexError)ierrDouble;
+        }
+        else
+        {
+            if (bConvertByNAN)
+            {
+                ierrDouble = STRINGTODOUBLE_NOT_A_NUMBER;
+                *real = returnNAN();
+                *imag = 0;
+            }
+            else
+            {
+                *real = 0;
+                *imag = 0;
+                ierr = (stringToComplexError)ierrDouble;
+            }
+        }
+    }
+    else if (ierrDouble != STRINGTODOUBLE_NO_ERROR)
+    {
+        // convert %i to i
+        for (wchar_t *it = tx, *jt = tx; *it != L'\0'; it++, jt++)
+        {
+            if (it[0] == L'%' && it[1] == L'i')
+            {
+                it++;
+            }
+            *jt = *it;
+        }
+
+        lnum = ParseNumberW(tx);
+        if (lnum <= 1)
+        {
+            /* manages special cases nan + nani, ... */
+            if (wcsnicmp(tx, NanStringW, wcslen(NanStringW)) == 0)
+            {
+                lnum = wcslen(NanStringW);
+            }
+            else if (wcsnicmp(tx, InfStringW, wcslen(InfStringW)) == 0)
+            {
+                lnum = wcslen(InfStringW);
+            }
+            else if (wcsnicmp(tx, NegInfStringW, wcslen(NegInfStringW)) == 0)
+            {
+                lnum = wcslen(NegInfStringW);
+            }
+            else if (wcsnicmp(tx, PosInfStringW, wcslen(PosInfStringW)) == 0)
+            {
+                lnum = wcslen(PosInfStringW);
+            }
+            else if (wcsnicmp(tx, NegNanStringW, wcslen(NegNanStringW)) == 0)
+            {
+                lnum = wcslen(NegNanStringW);
+            }
+            else if (wcsnicmp(tx, PosNanStringW, wcslen(PosNanStringW)) == 0)
+            {
+                lnum = wcslen(PosNanStringW);
+            }
+        }
+        inum_string = midstringWInPlace(tx, lnum);
+
+        if ((inum_string[wcslen(inum_string) - 1] == L'i') ||
+                (inum_string[wcslen(inum_string) - 1] == L'j')) // The imaginary part looks like "a*%i"
+        {
+            inum_string[wcslen(inum_string) - 1] = L'\0';
+            if (inum_string[wcslen(inum_string) - 1] == L'*')
+            {
+                inum_string[wcslen(inum_string) - 1] = L'\0';
+            }
+
+            // *inum_string will be set to '\0' on leftstringInPlace, store the sign
+            // somewhere before!
+            gainImagI = 1.;
+            if (*inum_string == L'-')
+            {
+                gainImagI = -1.;
+            }
+            inum_string++;
+        }
+        else if (inum_string[1] == L'i' || inum_string[1] == L'j') // The imaginary part looks like "%i*a". For instance if string() has been used
+        {
+            int len_inum_string = wcslen(inum_string);
+            for (i = 1; i < len_inum_string; ++i)
+            {
+                inum_string[i] = inum_string[i + 1]; // Removing the "i"
+            }
+            if (inum_string[1] == L'*')
+            {
+                for (i = 1; i < len_inum_string; ++i)
+                {
+                    inum_string[i] = inum_string[i + 1]; // Removing the "*"
+                }
+            }
+
+            if (wcscmp(inum_string, L"+") == 0)
+            {
+                inum_string = L"+1";
+            }
+
+            if (wcscmp(inum_string, L"-") == 0)
+            {
+                inum_string = L"-1";
+            }
+            gainImagI = 1.;
+        }
+        else
+        {
+            gainImagI = 0.;
+        }
+        rnum_string = leftstringWInPlace(tx, lnum);
+
+        if (gainImagI != 0. && *rnum_string != L'\0' && *inum_string == L'\0')
+        {
+
+            *imag = stringToDoubleWInPlace(rnum_string, bConvertByNAN, &ierrDouble);
+
+
+            ierr = (stringToComplexError)(ierrDouble);
+            *real = 0.;
+        }
+        else
+        {
+            double dReal = 0.;
+            double dImag = 0.;
+
+            stringToDoubleError ierrReal = STRINGTODOUBLE_NO_ERROR;
+            stringToDoubleError ierrImag = STRINGTODOUBLE_NO_ERROR;
+            dReal = stringToDoubleWInPlace(rnum_string, FALSE, &ierrReal);
+            dImag = stringToDoubleWInPlace(inum_string, FALSE, &ierrImag);
+
+            if ((ierrReal == STRINGTODOUBLE_NO_ERROR) && (ierrImag == STRINGTODOUBLE_NO_ERROR))
+            {
+                if (gainImagI == 0.)
+                {
+                    if (bConvertByNAN)
+                    {
+                        ierr = STRINGTOCOMPLEX_NO_ERROR;
+                        *real = returnNAN();
+                        *imag = 0.;
+                    }
+                    else
+                    {
+                        ierr = STRINGTOCOMPLEX_ERROR;
+                    }
+                }
+                else
+                {
+                    ierr = STRINGTOCOMPLEX_NO_ERROR;
+                    *real = dReal;
+                    *imag = gainImagI * dImag;
+                }
+            }
+            else
+            {
+                if (bConvertByNAN)
+                {
+                    ierr = STRINGTOCOMPLEX_NO_ERROR;
+                    *real = returnNAN();
+                    *imag = 0.;
+                }
+                else
+                {
+                    ierr = STRINGTOCOMPLEX_ERROR;
+                }
+            }
+        }
+    }
+    return ierr;
 }
 /* ========================================================================== */
-static char *midstring(const char *tx, size_t pos, int nb)
+static char* midstring(const char* tx, size_t pos, int nb)
 {
-    char *returnString = NULL;
+    char* returnString = NULL;
     if (tx)
     {
-        int lenTx = (int) strlen(tx);
+        int lenTx = (int)strlen(tx);
         int posEnd = 0;
         int newLen = 0;
 
@@ -826,10 +1153,10 @@ static char *midstring(const char *tx, size_t pos, int nb)
 /* ========================================================================== */
 static wchar_t* midstringW(const wchar_t* tx, size_t pos, int nb)
 {
-    wchar_t *returnString = NULL;
+    wchar_t* returnString = NULL;
     if (tx)
     {
-        int lenTx = (int) wcslen(tx);
+        int lenTx = (int)wcslen(tx);
         int posEnd = 0;
         int newLen = 0;
 
@@ -852,12 +1179,21 @@ static wchar_t* midstringW(const wchar_t* tx, size_t pos, int nb)
     return returnString;
 }
 /* ========================================================================== */
-static char *leftstring(const char *tx, size_t pos)
+static wchar_t* midstringWInPlace(wchar_t* tx, size_t pos)
+{
+    if (tx)
+    {
+        return &tx[pos];
+    }
+    return NULL;
+}
+/* ========================================================================== */
+static char* leftstring(const char* tx, size_t pos)
 {
-    char *returnString = NULL;
+    char* returnString = NULL;
     if (tx)
     {
-        int lenTx = (int) strlen(tx);
+        int lenTx = (int)strlen(tx);
         returnString = os_strdup(tx);
         if (pos > lenTx)
         {
@@ -871,12 +1207,12 @@ static char *leftstring(const char *tx, size_t pos)
     return returnString;
 }
 /* ========================================================================== */
-static wchar_t *leftstringW(const wchar_t *tx, size_t pos)
+static wchar_t* leftstringW(const wchar_t* tx, size_t pos)
 {
-    wchar_t *returnString = NULL;
+    wchar_t* returnString = NULL;
     if (tx)
     {
-        int lenTx = (int) wcslen(tx);
+        int lenTx = (int)wcslen(tx);
         returnString = os_wcsdup(tx);
         if (pos > lenTx)
         {
@@ -890,10 +1226,27 @@ static wchar_t *leftstringW(const wchar_t *tx, size_t pos)
     return returnString;
 }
 /* ========================================================================== */
-static BOOL is_unit_imaginary (const char *src, double *im)
+static wchar_t* leftstringWInPlace(wchar_t* tx, size_t pos)
 {
-    char *modifiedSrc = strsub((char*)src, ComplexScilab, ComplexI);
-    char *nextChar = NULL;
+    if (tx)
+    {
+        int lenTx = (int)wcslen(tx);
+        if (pos > lenTx)
+        {
+            return tx;
+        }
+        else
+        {
+            tx[pos] = L'\0';
+        }
+    }
+    return tx;
+}
+/* ========================================================================== */
+static BOOL is_unit_imaginary(const char* src, double* im)
+{
+    char* modifiedSrc = strsub((char*)src, ComplexScilab, ComplexI);
+    char* nextChar = NULL;
     BOOL isUnitImag = FALSE;
 
     if (modifiedSrc == NULL)
@@ -935,10 +1288,10 @@ static BOOL is_unit_imaginary (const char *src, double *im)
     return isUnitImag;
 }
 /* ========================================================================== */
-static BOOL is_unit_imaginaryW(const wchar_t *src, double *im)
+static BOOL is_unit_imaginaryW(const wchar_t* src, double* im)
 {
-    wchar_t *modifiedSrc = wcssub(src, ComplexScilabW, ComplexIW);
-    wchar_t *nextChar = NULL;
+    wchar_t* modifiedSrc = wcssub(src, ComplexScilabW, ComplexIW);
+    wchar_t* nextChar = NULL;
     BOOL isUnitImag = FALSE;
 
     if (modifiedSrc == NULL)
@@ -980,3 +1333,16 @@ static BOOL is_unit_imaginaryW(const wchar_t *src, double *im)
     return isUnitImag;
 }
 /* ========================================================================== */
+static double returnNAN(void)
+{
+    static int first = 1;
+    static double nan = 1.0;
+
+    if (first)
+    {
+        nan = (nan - (double)first) / (nan - (double)first);
+        first = 0;
+    }
+    return (nan);
+}
+// =============================================================================
index 5433f74..e509677 100644 (file)
 /* ========================================================================== */
 #define DEFAULT_DOUBLE_MAX_DIGIT_FORMAT "%lg"
 /* ========================================================================== */
+static double returnDoubleInPlace(BOOL bConvertByNAN, wchar_t* pSTR, stringToDoubleError* ierr);
+static double returnINF(BOOL bPositive);
+static double returnNAN(void);
+/* ========================================================================== */
+
 static char* replace_D_By_E(const char* _pst)
 {
     //find and replace d and D by E for compatibility with strtod Linux/Mac
@@ -94,6 +99,22 @@ static wchar_t* replace_D_By_EW(const wchar_t* _pst)
     return pstReturn;
 }
 
+void replace_D_By_E_WInPlace(wchar_t* _pst)
+{
+    //find and replace d and D by E for compatibility with strtod Linux/Mac
+    for (wchar_t* it = _pst; *it != '\0'; it++)
+    {
+        if (*it == L'D')
+        {
+            *it = L'E';
+        }
+        else if (*it == L'd')
+        {
+            *it = L'e';
+        }
+    }
+}
+
 double stringToDouble(const char *pSTR, BOOL bConvertByNAN, stringToDoubleError *ierr)
 {
     double dValue = 0.0;
@@ -284,3 +305,141 @@ double stringToDoubleW(const wchar_t *pSTR, BOOL bConvertByNAN, stringToDoubleEr
     return dValue;
 }
 // =============================================================================
+double stringToDoubleWInPlace(wchar_t* pSTR, BOOL bConvertByNAN, stringToDoubleError* ierr)
+{
+    double dValue = 0.0;
+    *ierr = STRINGTODOUBLE_ERROR;
+    if (pSTR)
+    {
+        if ('0' <= *pSTR && *pSTR <= '9')
+        {
+            // this is a regular number, convert it as fast as possible
+            dValue = returnDoubleInPlace(bConvertByNAN, pSTR, ierr);
+        }
+        else if ((wcsicmp(pSTR, NanStringW) == 0) || (wcsicmp(pSTR, NegNanStringW) == 0) ||
+                 (wcsicmp(pSTR, PosNanStringW) == 0) || (wcsicmp(pSTR, ScilabPosNanStringW) == 0) ||
+                 (wcsicmp(pSTR, ScilabNanStringW) == 0) || (wcsicmp(pSTR, ScilabNegNanStringW) == 0))
+        {
+            *ierr = STRINGTODOUBLE_NO_ERROR;
+            dValue = returnNAN();
+        }
+        else if ((wcsicmp(pSTR, InfStringW) == 0) || (wcsicmp(pSTR, PosInfStringW) == 0) ||
+                 (wcsicmp(pSTR, ScilabInfStringW) == 0) || (wcsicmp(pSTR, ScilabPosInfStringW) == 0))
+        {
+            *ierr = STRINGTODOUBLE_NO_ERROR;
+            dValue = returnINF(TRUE);
+        }
+        else if ((wcsicmp(pSTR, NegInfStringW) == 0) || (wcsicmp(pSTR, ScilabNegInfStringW) == 0))
+        {
+            *ierr = STRINGTODOUBLE_NO_ERROR;
+            dValue = returnINF(FALSE);
+        }
+        else if ((wcsicmp(pSTR, ScilabPiStringW) == 0) || (wcsicmp(pSTR, ScilabPosPiStringW) == 0))
+        {
+            *ierr = STRINGTODOUBLE_NO_ERROR;
+            dValue = M_PI;
+        }
+        else if (wcsicmp(pSTR, ScilabNegPiStringW) == 0)
+        {
+            *ierr = STRINGTODOUBLE_NO_ERROR;
+            dValue = -M_PI;
+        }
+        else if ((wcsicmp(pSTR, ScilabEpsStringW) == 0) || (wcsicmp(pSTR, ScilabPosEpsStringW) == 0))
+        {
+            *ierr = STRINGTODOUBLE_NO_ERROR;
+            dValue = EPSILON;
+        }
+        else if (wcsicmp(pSTR, ScilabNegEpsStringW) == 0)
+        {
+            *ierr = STRINGTODOUBLE_NO_ERROR;
+            dValue = -EPSILON;
+        }
+        else if ((wcsicmp(pSTR, ScilabEStringW) == 0) || (wcsicmp(pSTR, ScilabPosEStringW) == 0))
+        {
+            *ierr = STRINGTODOUBLE_NO_ERROR;
+            dValue = exp(1);
+        }
+        else if (wcsicmp(pSTR, ScilabNegEStringW) == 0)
+        {
+            *ierr = STRINGTODOUBLE_NO_ERROR;
+            dValue = -exp(1);
+        }
+        else
+        {
+            dValue = returnDoubleInPlace(bConvertByNAN, pSTR, ierr);
+        }
+    }
+    else
+    {
+        *ierr = STRINGTODOUBLE_MEMORY_ALLOCATION;
+    }
+    return dValue;
+}
+// =============================================================================
+static double returnDoubleInPlace(BOOL bConvertByNAN, wchar_t* pSTR, stringToDoubleError* ierr)
+{
+    double dValue;
+
+    replace_D_By_E_WInPlace(pSTR);
+    wchar_t* pEnd = NULL;
+    double v = wcstod(pSTR, &pEnd);
+    if ((v == 0) && (pEnd == pSTR))
+    {
+        if (bConvertByNAN)
+        {
+            *ierr = STRINGTODOUBLE_NO_ERROR;
+            dValue = returnNAN();
+        }
+        else
+        {
+            *ierr = STRINGTODOUBLE_NOT_A_NUMBER;
+            dValue = 0.0;
+        }
+    }
+    else
+    {
+        if (*pEnd == L'\0')
+        {
+            *ierr = STRINGTODOUBLE_NO_ERROR;
+            dValue = v;
+        }
+        else
+        {
+            if (bConvertByNAN)
+            {
+                *ierr = STRINGTODOUBLE_NO_ERROR;
+                dValue = returnNAN();
+            }
+            else
+            {
+                *ierr = STRINGTODOUBLE_NOT_A_NUMBER;
+                dValue = 0.0;
+            }
+        }
+    }
+
+    return dValue;
+}
+// =============================================================================
+static double returnINF(BOOL bPositive)
+{
+    double dbl1 = 1.0;
+    double dbl0 = dbl1 - dbl1;
+    int iSign = bPositive == 1 ? 1 : -1;
+
+    return iSign * dbl1 / dbl0;
+}
+// =============================================================================
+static double returnNAN(void)
+{
+    static int first = 1;
+    static double nan = 1.0;
+
+    if ( first )
+    {
+        nan = (nan - (double) first) / (nan - (double) first);
+        first = 0;
+    }
+    return (nan);
+}
+// =============================================================================
index 3418759..2d867e8 100644 (file)
    fun:H5F_open
    ...
 }
-
+{
+   gotoblas/gotoblas_affinity_init
+   Memcheck:Param
+   sched_getaffinity(mask)
+   ...
+   fun:gotoblas_affinity_init
+   fun:gotoblas_init
+   ...
+}