fileio: mgetl rewritten for better performance 10/19010/2
Simon Marchetto [Fri, 27 Jan 2017 15:06:12 +0000 (16:06 +0100)]
- use C fgets, less allocations...
- interface changed => csvRead, fscanfMat, readline updated
- benchmarks added
- unit test rewritten

Change-Id: Id4e1cc265606b04532412183eab4b46e02d01cb8

scilab/modules/fileio/includes/mgetl.h
scilab/modules/fileio/sci_gateway/cpp/sci_mgetl.cpp
scilab/modules/fileio/src/c/fscanfMat.c
scilab/modules/fileio/src/c/readline.c
scilab/modules/fileio/src/cpp/mgetl.cpp
scilab/modules/fileio/tests/benchmarks/mgetl_largefile.tst [new file with mode: 0644]
scilab/modules/fileio/tests/benchmarks/mgetl_longfile.tst [new file with mode: 0644]
scilab/modules/fileio/tests/unit_tests/mgetl.dia.ref
scilab/modules/fileio/tests/unit_tests/mgetl.tst
scilab/modules/spreadsheet/src/c/csvRead.c

index b5c243d..99c5596 100644 (file)
 #define __MGETL_H__
 
 #include "dynlib_fileio.h"
-#include "charEncoding.h"
 
-typedef enum
-{
-    MGETL_NO_ERROR = 0,
-    MGETL_EOF = 1,
-    MGETL_MEMORY_ALLOCATION_ERROR = 2,
-    MGETL_ERROR = 3
-} mgetlError;
-
-/* file descriptor id for stdin */
-#define STDIN_ID 5
-/* file descriptor id for stdout */
-#define STDOUT_ID 6
+#include <stddef.h>
 
 /**
- * @fn  char ** mgetl(int fd, int nbLinesIn, int *nbLinesOut, int *ierr) #endif
- *
- * @brief   read lines of a file.
+ * @fn int mgetl(FILE *fd, int iLineCount, wchar_t ***pwstLines)
  *
- * @author  Allan Cornet
- * @date    4/16/2010
+ * @brief reads all the lines (or a part) of a text file.
  *
- * @param   fd                  The file descriptor id.
- * @param   nbLinesIn           The nb lines in .
- * @param [in,out]  nbLinesOut  If non-null, the nb lines out.
- * @param [in,out]  ierr        If non-null, the ierr.
+ * @param [in]  iFileID     the file ID.
+ * @param [in]  iLineCount  the number of lines to read.
+ * @param [out] pwstLines   a wide string array containing the lines
  *
- * @return  null if it fails, else strings readed.
+ * @return the number of lines read, -1 if an error occured
 **/
-FILEIO_IMPEXP wchar_t ** mgetl(int fd, int nbLinesIn, int *nbLinesOut, int *ierr);
+FILEIO_IMPEXP int mgetl(int iFileID, int iLineCount, wchar_t ***pwstLines);
 
 #endif /* __MGETL_H__ */
 /*--------------------------------------------------------------------------*/
index 46c719d..49e991a 100644 (file)
@@ -35,11 +35,11 @@ extern "C"
 /*--------------------------------------------------------------------------*/
 types::Function::ReturnValue sci_mgetl(types::typed_list &in, int _iRetCount, types::typed_list &out)
 {
-    int iFileID                 = 0;
-    int iErr                    = 0;
-    bool bCloseFile             = false;
-    int iLinesExcepted          = -1;
-    int iLinesRead              = -1;
+    int iFileID = 0;
+    int iErr = 0;
+    bool bCloseFile = false;
+    int iLinesExcepted = -1;
+    int iLinesRead = -1;
     wchar_t** wcReadedStrings   = NULL;
 
     if (in.size() < 1 || in.size() > 2)
@@ -134,13 +134,16 @@ types::Function::ReturnValue sci_mgetl(types::typed_list &in, int _iRetCount, ty
                 return types::Function::Error;
             }
 
-            wcReadedStrings = mgetl(iFileID, iLinesExcepted, &iLinesRead, &iErr);
-
-            switch (iErr)
+            if ((iLinesExcepted > 0) && (iFileID == 5))
             {
-                case MGETL_MEMORY_ALLOCATION_ERROR :
-                    break;
+                iLinesExcepted = 1;
+            }
+
+            iLinesRead = mgetl(iFileID, iLinesExcepted, &wcReadedStrings);
 
+            if (iLinesRead < 0)
+            {
+                break;
             }
         }
     }
index 93bdd4a..3b75473 100644 (file)
@@ -78,7 +78,6 @@ fscanfMatResult *fscanfMat(char *filename, char *format, char *separator)
     int f_swap = 0;
     double res = 0.0;
     int errMOPEN = MOPEN_INVALID_STATUS;
-    int errMGETL = MGETL_ERROR;
     int i = 0;
     int nbLinesTextDetected = 0;
     int nbColumns = 0;
@@ -86,7 +85,7 @@ fscanfMatResult *fscanfMat(char *filename, char *format, char *separator)
 
 
     fscanfMatResult *resultFscanfMat = NULL;
-    wchar_t **pwsLines = NULL;
+    wchar_t **pwstLines = NULL;
     char **lines = NULL;
     int nblines = 0;
     double *dValues = NULL;
@@ -130,10 +129,10 @@ fscanfMatResult *fscanfMat(char *filename, char *format, char *separator)
         return resultFscanfMat;
     }
 
-    pwsLines = mgetl(fd, -1, &nblines, &errMGETL);
+    nblines = mgetl(fd, -1, &pwstLines);
     mclose(fd);
 
-    if (errMGETL != MGETL_NO_ERROR)
+    if (nblines < 0)
     {
         resultFscanfMat = (fscanfMatResult*)(MALLOC(sizeof(fscanfMatResult)));
         if (resultFscanfMat)
@@ -145,17 +144,17 @@ fscanfMatResult *fscanfMat(char *filename, char *format, char *separator)
             resultFscanfMat->text = NULL;
             resultFscanfMat->values = NULL;
         }
-        freeArrayOfWideString(pwsLines, nblines);
+        freeArrayOfWideString(pwstLines, nblines);
         return resultFscanfMat;
     }
 
     lines = (char**)MALLOC(sizeof(char*) * nblines);
     for (i = 0; i < nblines; i++)
     {
-        lines[i] = wide_string_to_UTF8(pwsLines[i]);
+        lines[i] = wide_string_to_UTF8(pwstLines[i]);
     }
 
-    freeArrayOfWideString(pwsLines, nblines);
+    freeArrayOfWideString(pwstLines, nblines);
 
     lines = removeEmptyLinesAtTheEnd(lines, &nblines);
     lines = removeTextLinesAtTheEnd(lines, &nblines, format, separator);
index 7a346e6..20eb039 100644 (file)
 /*--------------------------------------------------------------------------*/
 int LineRead(int fd, char buf[], int n, int *cnt, int *nr)
 {
-    int returnedInfo = READNEXTLINE_ERROR_ERROR_UNMANAGED;
-    int nbLinesToRead = 1;
+    int returnedInfo;
     int nbLinesReaded = 0;
-    int mgetIerr = MGETL_ERROR;
+    wchar_t **lines = NULL;
+    char* line = NULL;
 
-    wchar_t **lines = mgetl(fd, nbLinesToRead, &nbLinesReaded, &mgetIerr);
-    char* line = wide_string_to_UTF8(lines[0]);
-    freeArrayOfWideString(lines, nbLinesReaded);
-
-    *cnt = 0;
-    *nr = 0;
+    nbLinesReaded = mgetl(fd, 1, &lines);
+    if (nbLinesReaded == 1)
+    {
+        char* line = wide_string_to_UTF8(lines[0]);
+        freeArrayOfWideString(lines, nbLinesReaded);
 
-    memset(buf, 0, n);
-    strcpy(buf, EMPTYSTR);
+        memset(buf, 0, n);
+        strcpy(buf, EMPTYSTR);
 
-    switch (mgetIerr)
-    {
-        case MGETL_NO_ERROR:
+        /* current limitation (bsiz) of line readed by scilab */
+        if ((int)strlen(line) < bsiz)
         {
-            if (line && nbLinesReaded == 1)
-            {
-                /* current limitation (bsiz) of line readed by scilab */
-                if ((int)strlen(line) < bsiz)
-                {
-                    strcpy(buf, line);
-                    returnedInfo = READNEXTLINE_ERROR_EOL;
-                }
-                else
-                {
-                    strncpy(buf, line, bsiz);
-                    returnedInfo = READNEXTLINE_ERROR_BUFFER_FULL;
-                }
-            }
-            else
-            {
-                returnedInfo = READNEXTLINE_ERROR_EOF_REACHED;
-            }
+            strcpy(buf, line);
+            returnedInfo = READNEXTLINE_ERROR_EOL;
         }
-        break;
-
-        case MGETL_EOF:
+        else
         {
-            if (line)
-            {
-                if (nbLinesReaded == 0)
-                {
-                    returnedInfo = READNEXTLINE_ERROR_EOF_REACHED;
-                }
-                else
-                {
-                    /* current limitation (bsiz) of line readed by scilab */
-                    if ((int)strlen(line) >= bsiz)
-                    {
-                        strcpy(buf, line);
-                        returnedInfo = READNEXTLINE_ERROR_EOF_REACHED_AFTER_EOL;
-                    }
-                    else
-                    {
-                        strncpy(buf, line, bsiz);
-                        returnedInfo = READNEXTLINE_ERROR_BUFFER_FULL;
-                    }
-                }
-            }
-            else
-            {
-                returnedInfo = READNEXTLINE_ERROR_EOF_REACHED_BEFORE_EOL;
-            }
+            strncpy(buf, line, bsiz);
+            returnedInfo = READNEXTLINE_ERROR_BUFFER_FULL;
         }
-        break;
 
-        case MGETL_MEMORY_ALLOCATION_ERROR:
-        case MGETL_ERROR:
-        default:
-        {
-            returnedInfo = READNEXTLINE_ERROR_ERROR_UNMANAGED;
-        }
-        break;
-    }
+        *cnt = (int)strlen(buf) + 1;
+        *nr = *cnt;
 
-    *cnt = (int)strlen(buf) + 1;
-    *nr = *cnt;
-
-    if (line)
-    {
         FREE(line);
     }
+    else if (nbLinesReaded == 0)
+    {
+        *cnt = 0;
+        *nr = 0;
+        returnedInfo = READNEXTLINE_ERROR_EOF_REACHED;
+    }
+    else
+    {
+        *cnt = 0;
+        *nr = 0;
+        returnedInfo = READNEXTLINE_ERROR_ERROR_UNMANAGED;
+    }
 
     return returnedInfo;
 }
index 32ca9f3..57cc4a4 100644 (file)
 *
 */
 /*--------------------------------------------------------------------------*/
-#include <string.h>
-#include "filemanager.hxx"
 
 extern "C"
 {
-#ifdef _MSC_VER
-#include <Windows.h>
-#endif
 #include "mgetl.h"
-#include "mopen.h"
-#include "sci_malloc.h"
-#include "os_string.h"
-#include "mtell.h"
-#include "mseek.h"
-#include "sciprint.h"
 #include "freeArrayOfString.h"
+#include "charEncoding.h"
+#include "sci_malloc.h"
 }
+#include "filemanager.hxx"
 
-#include <iostream>
-#include <fstream>
-/*--------------------------------------------------------------------------*/
-// we do not want to depend on the OS specific LINE_MAX setting
-#ifdef LINE_MAX
-#undef LINE_MAX
+#include <string.h>
+#include <stdio.h>
+
+#ifdef _MSC_VER
+#include <Windows.h>
 #endif
-#define LINE_MAX 4096
 
-#define CR L'\r'
-#define LF L'\n'
-#define EMPTYSTRW L""
-#define EMPTYSTR ""
-/*--------------------------------------------------------------------------*/
-static wchar_t *removeEOL(wchar_t *_inString);
-static char *convertAnsiToUtf(char *_inString);
-static wchar_t* getLine(wchar_t* _pstLine, int _iLineSize, types::File* _pFile);
-/*--------------------------------------------------------------------------*/
-#define UTF_16BE_BOM 0xFEFF // 0xFEFF = to_wide_string(0xEFBBBF)
-/*--------------------------------------------------------------------------*/
-wchar_t **mgetl(int fd, int nbLinesIn, int *nbLinesOut, int *ierr)
-{
-    wchar_t **strLines = NULL;
-    types::File* pFile = NULL;
-    int iLineSizeMult = 1;
-    *ierr = MGETL_ERROR;
-    *nbLinesOut = 0;
+#ifdef BUFFER_SIZE
+#undef BUFFER_SIZE
+#endif
+#define BUFFER_SIZE 4096
+
+static const char UTF8_BOM[] = { 0xEF, 0xBB, 0xBF, 0x00 };
 
-    pFile = FileManager::getFile(fd);
+int mgetl(int iFileID, int iLineCount, wchar_t ***pwstLines)
+{
+    *pwstLines = NULL;
 
-    if (nbLinesIn < 0 && fd == 5)
+    // get file descriptor
+    types::File* pFile = FileManager::getFile(iFileID);
+    FILE *fd;
+    if (pFile != NULL)
     {
-        nbLinesIn = 1;
+        fd = pFile->getFiledesc();
+    }
+    else
+    {
+        return -1;
     }
 
-    /*try std version*/
-    //{
-    //    int posix_handle = ::_fileno(pFile->getFiledesc());
-
-    //    std::ifstream ifs(::_wfdopen(posix_handle, pFile->getFileMode().c_str()));
-    //    std::list<string> lst;
-    //    std::string str;
-
-    //    while(ifs.eof() == false && lst.size() < nbLinesIn)
-    //    {
-    //        std::getline(ifs, str);
-    //        lst.push_back(str);
-    //    }
-
-    //    sciprint("size : %d\n", lst.size());
-
-    //    *nbLinesOut =  (int)lst.size();
-    //    if(*nbLinesOut == 0)
-    //    {
-    //        return NULL;
-    //    }
-
-    //    strLines = (wchar_t**)MALLOC(sizeof(wchar_t*) * *nbLinesOut);
-    //    for(int i = 0 ; i < *nbLinesOut ; i++)
-    //    {
-    //        strLines[i] = to_wide_string(lst.front().c_str());
-    //        lst.pop_front();
-    //    }
-
-    //    return strLines;
-    //}
+    if (iLineCount == 0)
+    {
+        return 0;
+    }
 
-    if (pFile)
+    // check file is not empty
+    if (ftell(fd) == 0)
     {
-        wchar_t* Line = (wchar_t*)MALLOC(LINE_MAX * iLineSizeMult * sizeof(wchar_t));
-        int nbLines = 0;
-        long long iPos = 0;
-        if (nbLinesIn < 0)
+        char cValues[4] = { 0x00, 0x00, 0x00, 0x00 };
+        if (fgets(cValues, 4 * sizeof(char), fd) != NULL)
         {
-            strLines = (wchar_t **)MALLOC(sizeof(wchar_t *));
-            if (strLines == NULL)
+            // skip BOM
+            if (strcmp(cValues, UTF8_BOM) != 0)
             {
-                *nbLinesOut = 0;
-                *ierr = MGETL_MEMORY_ALLOCATION_ERROR;
-                FREE(Line);
-                return NULL;
+                rewind(fd);
             }
-            while ( getLine ( Line, LINE_MAX * iLineSizeMult, pFile ) != NULL )
-            {
-                if (((int) wcslen(Line)) >= (LINE_MAX * iLineSizeMult) - 1 && iPos >= 0)
-                {
-                    FREE(Line);
-                    iLineSizeMult++;
-                    Line = (wchar_t*)MALLOC(LINE_MAX * iLineSizeMult * sizeof(wchar_t));
-                    mseek(fd, iPos, SEEK_SET);
-
-                    continue;
-                }
-
-                iPos = mtell(fd);
-                /* UTF-16 BOM */
-                if ((nbLines == 0) && (Line[0] == UTF_16BE_BOM))
-                {
-                    wchar_t* tmpLine = os_wcsdup(Line);
-                    memset(Line, 0x00, LINE_MAX * iLineSizeMult);
-                    wcscpy(Line, &tmpLine[1]);
-                    FREE(tmpLine);
-                }
-
-                nbLines++;
-                strLines = (wchar_t **)REALLOC(strLines, nbLines * sizeof(wchar_t *));
-                if (strLines == NULL)
-                {
-                    *nbLinesOut = 0;
-                    *ierr = MGETL_MEMORY_ALLOCATION_ERROR;
-                    FREE(Line);
-                    return NULL;
-                }
-
-                strLines[nbLines - 1] = os_wcsdup(removeEOL(Line));
-                if (strLines[nbLines - 1] == NULL)
-                {
-                    *nbLinesOut = 0;
-                    *ierr = MGETL_MEMORY_ALLOCATION_ERROR;
-                    freeArrayOfWideString(strLines, nbLines);
-                    FREE(Line);
-                    return NULL;
-                }
-                wcscpy(Line, EMPTYSTRW);
-            }
-            *nbLinesOut = nbLines;
-            *ierr = MGETL_NO_ERROR;
         }
-        else
-        {
-            if (nbLinesIn == 0)
-            {
-                *ierr = MGETL_EOF;
-                *nbLinesOut = 0;
-            }
-            else
-            {
-                BOOL bContinue = TRUE;
-                BOOL bEOF = FALSE;
-                strLines = (wchar_t **)MALLOC(sizeof(wchar_t *) * nbLinesIn);
-                if (strLines == NULL)
-                {
-                    *nbLinesOut = 0;
-                    *ierr = MGETL_MEMORY_ALLOCATION_ERROR;
-                    FREE(Line);
-                    return NULL;
-                }
-
-                do
-                {
-                    if (nbLines < nbLinesIn)
-                    {
-                        bool header = false;
-                        /* UTF-16 BOM */
-                        if ((ftell(pFile->getFiledesc()) == 0) && (nbLines == 0))
-                        {
-                            header = true;
-                        }
-
-                        if ( getLine ( Line, LINE_MAX * iLineSizeMult, pFile) != NULL)
-                        {
-                            if (((int) wcslen(Line)) >= (LINE_MAX * iLineSizeMult) - 1)
-                            {
-                                FREE(Line);
-                                iLineSizeMult++;
-                                Line = (wchar_t*)MALLOC(LINE_MAX * iLineSizeMult * sizeof(wchar_t));
-                                mseek(fd, iPos, SEEK_SET);
-
-                                continue;
-                            }
-
-                            iPos = mtell(fd);
-
-                            if (header && (Line[0] == UTF_16BE_BOM))
-                            {
-                                wchar_t* tmpLine = os_wcsdup(Line);
-                                memset(Line, 0x00, LINE_MAX * iLineSizeMult);
-                                wcscpy(Line, &tmpLine[1]);
-                                FREE(tmpLine);
-                            }
-                            nbLines++;
-                            strLines[nbLines - 1] = os_wcsdup(removeEOL(Line));
-                            if (strLines[nbLines - 1] == NULL)
-                            {
-                                *nbLinesOut = 0;
-                                *ierr = MGETL_MEMORY_ALLOCATION_ERROR;
-                                FREE(Line);
-                                freeArrayOfWideString(strLines, nbLines);
-                                return NULL;
-                            }
-                            wcscpy(Line, EMPTYSTRW);
-                        }
-                        else
-                        {
-                            /* EOF */
-                            if (feof(pFile->getFiledesc()))
-                            {
-                                bEOF = TRUE;
-                            }
-                            bContinue = FALSE;
-                        }
-                    }
-                    else
-                    {
-                        bContinue = FALSE;
-                    }
-                }
-                while (bContinue);
-
-                *nbLinesOut = nbLines;
-                if (bEOF)
-                {
-                    *ierr = MGETL_EOF;
-                }
-                else
-                {
-                    *ierr = MGETL_NO_ERROR;
-                }
-            }
-        }
-        FREE(Line);
-    }
-    return strLines;
-}
-/*--------------------------------------------------------------------------*/
-wchar_t* getLine(wchar_t* _pstLine, int _iLineSize, types::File* _pFile)
-{
-    char* pstTemp = (char*)MALLOC(sizeof(char) * _iLineSize);
-    if (fgets(pstTemp, _iLineSize, _pFile->getFiledesc()) == NULL)
-    {
-        FREE(pstTemp);
-        return NULL;
     }
 
-    wchar_t* pstTempWide = to_wide_string(pstTemp);
-    wcscpy(_pstLine, pstTempWide);
-    FREE(pstTemp);
-    FREE(pstTempWide);
-    return _pstLine;
-}
-/*--------------------------------------------------------------------------*/
-wchar_t *removeEOL(wchar_t *_inString)
-{
-    if (_inString)
+    if (iLineCount > 0)
     {
-        wchar_t *pos = wcschr(_inString, LF);
-        if (pos)
+        *pwstLines = (wchar_t**)MALLOC(iLineCount * sizeof(wchar_t*));
+        if (pwstLines == NULL)
         {
-            *pos = 0;
+            return -1;
         }
+    }
 
-        pos = wcschr(_inString, CR);
-        if (pos)
-        {
-            *pos = 0;
-        }
+    // allocate initial reading buffer, it will grow depending on line size
+    int iBufferSize = BUFFER_SIZE;
+    char *pstBuffer = (char *) malloc(iBufferSize * sizeof(char));
+    if (pstBuffer == NULL)
+    {
+        freeArrayOfWideString(*pwstLines, iLineCount);
+        *pwstLines = NULL;
+        return -1;
     }
-    return _inString;
-}
-/*--------------------------------------------------------------------------*/
-/*
-* convert ansi to Utf
-*/
-static char *convertAnsiToUtf(char *_inString)
-{
-    char *outString = NULL;
-    if (_inString)
+
+    int iReadLineCount = 0;
+    while (fgets(pstBuffer, iBufferSize * sizeof(char), fd) != NULL)
     {
-#ifdef _MSC_VER
-        if (IsValidUTF8(_inString))
+        iReadLineCount++;
+        *pwstLines = (wchar_t**)REALLOC(*pwstLines, iReadLineCount * sizeof(wchar_t*));
+        if (*pwstLines == NULL)
         {
-            outString = os_strdup(_inString);
+            free(pstBuffer);
+            return -1;
         }
-        else
-        {
-            /* conversion ANSI to UTF */
-            int Len = 0;
-            int newLen = 0;
-            BSTR bstrCode = NULL;
 
-            Len = MultiByteToWideChar(CP_ACP, 0, _inString, lstrlen(_inString), NULL, NULL);
-            bstrCode = SysAllocStringLen(NULL, Len);
-            if (bstrCode)
-            {
-                MultiByteToWideChar(CP_ACP, 0, _inString, lstrlen(_inString), bstrCode, Len);
-                newLen = WideCharToMultiByte(CP_UTF8, 0, bstrCode, -1, outString, 0, NULL, NULL);
-                outString = (char*) MALLOC(sizeof(char) * (newLen + 1));
-                if (outString)
-                {
-                    WideCharToMultiByte(CP_UTF8, 0, bstrCode, -1, outString, newLen, NULL, NULL);
-                }
-                else
-                {
-                    outString = os_strdup(_inString);
-                }
-                SysFreeString(bstrCode);
-                bstrCode = NULL;
-            }
-            else
-            {
-                outString = os_strdup(_inString);
-            }
-        }
-#else
-        if (IsValidUTF8(_inString))
+        // is the line complete in the buffer (= zero terminal found) ?
+        int len = strnlen(pstBuffer, iBufferSize);
+        int totalLen = len;
+        if (len >= iBufferSize - 1)
         {
-            outString = os_strdup(_inString);
-        }
-        else
-        {
-            int len = (int)strlen(_inString);
-            int i = 0;
-
-            outString = (char*)MALLOC(((len * 3) + 1) * sizeof(char));
-            if (outString == NULL)
+            // no, there is another data to read for this line
+            // allocate a temporary buffer for reading it
+            char *pstBufferTmp = (char*) malloc(BUFFER_SIZE * sizeof(char));
+            if (pstBufferTmp == NULL)
             {
-                return NULL;
+                freeArrayOfWideString(*pwstLines, iReadLineCount);
+                *pwstLines = NULL;
+                free(pstBuffer);
+                return -1;
             }
-
-            strcpy(outString, EMPTYSTR);
-
-            for (i = 0; i < len; i++)
+            char *pstNewBuffer = pstBuffer;
+            // loop until line is complete
+            do
             {
-                char *outUtfChar = NULL;
-                unsigned char inAnsiChar = 0;
-
-                if (_inString[i] < 0)
+                // reallocate a new bigger buffer for the line
+                iBufferSize += BUFFER_SIZE;
+                pstNewBuffer = (char*) REALLOC(pstNewBuffer, iBufferSize * sizeof(char));
+                if (pstNewBuffer == NULL)
                 {
-                    inAnsiChar = 256 + _inString[i];
-                }
-                else
-                {
-                    inAnsiChar = _inString[i];
+                    freeArrayOfWideString(*pwstLines, iReadLineCount);
+                    *pwstLines = NULL;
+                    free(pstBufferTmp);
+                    return -1;
                 }
 
-                if (inAnsiChar < 128)
+                // read the remaining data and copy it in the new buffer
+                if (fgets(pstBufferTmp, BUFFER_SIZE * sizeof(char), fd) != NULL)
                 {
-                    outUtfChar = (char *)CALLOC(2, sizeof(char));
-                    if (outUtfChar)
-                    {
-                        outUtfChar[0] = inAnsiChar;
-                        outUtfChar[1] = 0;
-                    }
+                    len = strnlen(pstBufferTmp, BUFFER_SIZE);
+                    totalLen += len;
+                    strncat(pstNewBuffer, pstBufferTmp, BUFFER_SIZE);
                 }
                 else
                 {
-                    outUtfChar = (char *)CALLOC(3, sizeof(char));
-                    if (outUtfChar)
-                    {
-                        outUtfChar[0] = (inAnsiChar >> 6) | 0xC0;
-                        outUtfChar[1] = (inAnsiChar & 0x3F) | 0x80;
-                        outUtfChar[2] = 0;
-                    }
+                    break;
                 }
+            }
+            while (len >= BUFFER_SIZE - 1);
 
-                if (outUtfChar)
-                {
-                    strcat(outString, outUtfChar);
-                    FREE(outUtfChar);
-                    outUtfChar = NULL;
-                }
+            free(pstBufferTmp);
+            // the bigger buffer becomes the current buffer
+            pstBuffer = pstNewBuffer;
+        }
+        if ((totalLen > 0) && (pstBuffer[totalLen - 1] == '\n'))
+        {
+            pstBuffer[totalLen - 1] = '\0';
+            if ((totalLen > 1) && (pstBuffer[totalLen - 2] == '\r'))
+            {
+                pstBuffer[totalLen - 2] = '\0';
             }
         }
-#endif
+        // add the line in the array
+        (*pwstLines)[iReadLineCount - 1] = to_wide_string(pstBuffer);
+
+        if ((iLineCount > 0) && (iReadLineCount >= iLineCount))
+        {
+            break;
+        }
     }
-    return outString;
+
+    free(pstBuffer);
+    return iReadLineCount;
 }
-/*--------------------------------------------------------------------------*/
+
diff --git a/scilab/modules/fileio/tests/benchmarks/mgetl_largefile.tst b/scilab/modules/fileio/tests/benchmarks/mgetl_largefile.tst
new file mode 100644 (file)
index 0000000..544f3c4
--- /dev/null
@@ -0,0 +1,19 @@
+// ================================================================================
+// Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+// Copyright (C) 2016 - Scilab Enterprises
+//
+//  This file is distributed under the same license as the Scilab package.
+// ================================================================================
+
+//=================================================================================
+// Benchmark for mgetl function
+//==============================================================================
+
+// <-- BENCH NB RUN : 10 -->
+filename = fullfile(TMPDIR, "largefile.txt");
+mat = rand(2000, 1000);
+fprintfMat(filename, mat, "%0.6f");
+
+// <-- BENCH START -->
+M = mgetl(filename);
+// <-- BENCH END -->
diff --git a/scilab/modules/fileio/tests/benchmarks/mgetl_longfile.tst b/scilab/modules/fileio/tests/benchmarks/mgetl_longfile.tst
new file mode 100644 (file)
index 0000000..efb47d7
--- /dev/null
@@ -0,0 +1,39 @@
+// ================================================================================
+// Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+// Copyright (C) 2016 - Scilab Enterprises
+//
+//  This file is distributed under the same license as the Scilab package.
+// ================================================================================
+
+//=================================================================================
+// Benchmark for mgetl function
+//==============================================================================
+
+// <-- BENCH NB RUN : 10 -->
+function a = randInt(start, stop, count)
+    a = int(rand(count, 1) * ((stop-1) - start) + start);
+endfunction
+
+function a = randStr(pool, count)
+    s = size(pool, "*");
+    i = rand(count, 1) * (s-1) + 1;
+    a = matrix(pool(i), -1, 1);
+endfunction
+
+filename = fullfile(TMPDIR, "longfile.txt");
+
+COLS3 = ["ALACHUA COUNTY", "BAKER COUNTY", "BAY COUNTY", "BRADFORD COUNTY", "BREVARD COUNTY", "BROWARD COUNTY", "CALHO UN COUNTY", "CHARLOTTE COUNTY", "CITRUS COUNTY", "CLAY COUNTY", "COLLIER COUNTY", "COLUMBIA COUNTY", "DESOTO COUNTY", "DIXIE COUNTY", "DUVAL COUNTY", "ESCAMBIA COUNTY", "FLAGLER COUNTY", "FRANKLIN COUNTY", "GADSDEN COUNTY", "GILCHRIST COUNTY", "GLADES COUNTY", "GULF COUNTY", "HAMILTON COUNTY", "HARDEE COUNTY", "HENDRY COUNTY", ... 
+    "HERNANDO COUNTY", "HIGHLANDS COUNTY", "HILLSBOROUGH COUNTY", "HOLMES COUNTY", "INDIAN RIVER COUNTY", "JACKSON COUNTY", "JEFFERSON COUNTY", "LAFAYETTE COUNTY", "LAKE COUNTY", "LEE COUNTY", "LEON COUNTY", "LEVY COUNTY", "LIBERTY COUNTY", "MADISON COUNTY", "MANATEE COUNTY", "MARION COUNTY", "MARTIN COUNTY", "MIAMI DADE COUNTY", "MONROE COUNTY", "NASSAU COUNTY", "North Fort Myers", "OKALOOSA COUNTY", "ORANGE COUNTY", "OSCEOLA COUNTY", "Orlando", ...
+    "PALM BEACH COUNTY", "PASCO COUNTY", "PINELLAS COUNTY", "POLK COUNTY", "PUTNAM COUNTY", "SANTA ROSA COUNTY", "SARASOTA COUNTY", "SEMINOLE COUNTY", "ST  JOHNS COUNTY", "SUMTER COUNTY", "SUWANNEE COUNTY", "TAYLOR COUNTY", "UNION COUNTY", "VOLUSIA COUNTY", "WAKULLA COUNTY", "WALTON COUNTY", "WASHINGTON COUNTY"];
+
+header = "policyID,statecode,county,eq_site_limit,hu_site_limit,fl_site_limit,fr_site_limit,tiv_2011,tiv_2012,eq_site_deductible,hu_site_deductible,fl_site_deductible,fr_site_deductible,point_latitude,point_longitude,line,construction,point_granularity";
+
+nb = 100000;
+rI = randInt(1d5, 1d6, nb);
+rS = randStr(COLS3, nb);
+strs = msprintf("%d,%s,%s,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%s,%s,%d\n", rI, rS, rS, rI, rI, rI, rI, rI, rI, rI, rI, rI, rI, rI, rI, rS, rS, rI);
+mputl(strs, filename);
+
+// <-- BENCH START -->
+M = mgetl(filename);
+// <-- BENCH END -->
\ No newline at end of file
index c11ac17..6b430ea 100644 (file)
@@ -8,83 +8,97 @@
 // =============================================================================
 // Unitary tests for mgetl function
 //==============================================================================
-if mgetl('SCI/etc/scilab.start', 0) <> [] then bugmes();quit;end
-//==============================================================================
-fd = mopen('SCI/etc/scilab.start', 'rt');
-if mgetl(fd, 0) <> [] then bugmes();quit;end
+function [filename, txt] = create_file(arg)
+    if isempty(arg) then
+        txt = [];
+        filename = tempname();
+    elseif typeof(arg) == "string" then
+        txt = arg;
+        filename = tempname();
+        if arg <> [] then
+            mputl(arg, filename);
+        end
+    elseif typeof(arg) == "constant" then
+        txt = "";
+        for i=1:size(arg, '*')
+            txt = [txt; strcat(repmat(ascii(96+i), 1, arg(i)))];
+        end
+        filename = tempname();
+        mputl(txt, filename);
+    end
+end
+function fd = open_create_file(txt)
+    fd = mopen(create_file(txt), "rt");
+endfunction
+function check_mgetl(f, expected, varargin)
+    txt = mgetl(f, varargin(:));
+    assert_checkequal(txt, expected);
+endfunction
+ref = ["1 Scilab"; ..
+        "2 Puffin"; ..
+        "3 "; ..
+        "4 Puffin"; ..
+        "5 Scilab"];
+// test simple
+check_mgetl(create_file("a"), "a");
+check_mgetl(create_file(ref), ref);
+// test file argument: file descriptor
+fd = open_create_file(ref);
+check_mgetl(fd, [], 0)
 mclose(fd);
-//==============================================================================
-ref = ["1 Scilab";"2 Puffin";"3 ";"4 Puffin";"5 Scilab"];
-mputl(ref, TMPDIR + "/text.txt");
-//==============================================================================
-txt = mgetl(TMPDIR + "/text.txt");
-if or(ref <> txt) then bugmes();quit;end
-//==============================================================================
-txt = mgetl(TMPDIR + "/text.txt", -10);
-if or(ref <> txt) then bugmes();quit;end
-//==============================================================================
-txt = mgetl(TMPDIR + "/text.txt", -1);
-if or(ref <> txt) then bugmes();quit;end
-//==============================================================================
-txt = mgetl(TMPDIR + "/text.txt", 1);
-if txt <> ref(1) then bugmes();quit;end
-//==============================================================================
-txt = mgetl(TMPDIR + "/text.txt", 2);
-if or(txt <> ref(1:2)) then bugmes();quit;end
-//==============================================================================
-txt = mgetl(TMPDIR + "/text.txt", 100);
-if or(txt <> ref) then bugmes();quit;end
-//==============================================================================
-fd = mopen(TMPDIR + "/text2.txt","wt");
-r = mgetl(fd);
+// test line count argument: read all lines
+check_mgetl(create_file(ref), ref, -1);
+check_mgetl(create_file(ref), ref, -10);
+// test line count argument: read zero lines
+check_mgetl(create_file(ref), [], 0);
+// test line count argument: read some lines
+check_mgetl(create_file(ref), ref(1), 1);
+check_mgetl(create_file(ref), ref(1:2), 2);
+check_mgetl(create_file(ref), ref, 100);
+// read all lines in several calls
+fd = open_create_file(ref);
+check_mgetl(fd, ref(1), 1);
+check_mgetl(fd, ref(2:3), 2);
+check_mgetl(fd, ref(4:5), 3);
 mclose(fd);
-if r <> [] then bugmes();quit;end
-//==============================================================================
-fd = mopen(TMPDIR + "/text.txt","rt");
-r = mgetl(fd, 1);
-if r <> ref(1) then bugmes();quit;end
-//==============================================================================
-r = mgetl(fd, 2);
-if r <> ref(2:3) then bugmes();quit;end
-//==============================================================================
-r = mgetl(fd, 3);
-if r <> ref(4:5) then bugmes();quit;end
-//==============================================================================
+// test empty file
+check_mgetl(create_file([]), []);
+// test file empty lines
+filename = tempname();
+fd = mopen(filename, "wb");
+mfprintf(fd, ascii(10));
 mclose(fd);
-//==============================================================================
+check_mgetl(filename, "");
 txt = mgetl("SCI/modules/fileio/tests/unit_tests/text.txt");
-if and(size(txt) <> [6 1]) then bugmes();quit;end
-//==============================================================================
-// creates a file with some differents end of line
-ref = ['A text with different end of line';
-'text with LF:';
-'text with CRLF:';
-'text no EOL.'];
-CR = '\r';
-LF = '\n';
-fd = mopen(TMPDIR + '/mgetl_text_tst.txt', 'wt');
-mfprintf(fd, ref(1) + CR + LF);
-mfprintf(fd, ref(2) + LF);
-mfprintf(fd, ref(3) + CR + LF);
-mfprintf(fd, ref(4));
+assert_checkequal(size(txt), [6 1]);
+assert_checkequal(txt(6), "");
+// test file with different EOL (end of line)
+ref_EOL = ["line with CR LF"; ..
+    "line with LF"; ..
+    "line with no EOL"];
+filename = tempname();
+fd = mopen(filename, "wb");
+mfprintf(fd, "%s" + ascii(13) + ascii(10), ref_EOL(1));
+mfprintf(fd, "%s" + ascii(10), ref_EOL(2));
+mfprintf(fd, "%s", ref_EOL(3));
 mclose(fd);
-r = mgetl(TMPDIR + '/mgetl_text_tst.txt');
-if ~and(r == ref) then bugmes();quit;end
-//==============================================================================
+check_mgetl(filename, ref_EOL);
+// test file with BOM
 txt = mgetl("SCI/modules/fileio/tests/unit_tests/text-UTF8BOM.txt");
-if and(size(txt) <> [13 1]) then bugmes();quit;end
+assert_checkequal(size(txt), [13 1]);
 r = "Scilab is a numerical computational package developed since 1990 by researchers from the INRIA and the Ecole nationale des ponts et chaussees (ENPC). It is, since the creation of the Scilab consortium in May 2003, developed and maintained by the INRIA.";
-if r <> txt(1) then bugmes();quit;end
-ierr = execstr('mgetl(0,1)','errcatch');
-if ierr <> 999 then bugmes();quit;end
-ierr = execstr('mgetl(6,1)','errcatch');
-if ierr <> 999 then bugmes();quit;end
-file_1 = TMPDIR+'/test_binary_1.bin';
-fid = mopen(file_1,'wb');
-mput(1996,'l');
-mputstr('Scilab');
-mclose(fid);
-fid = mopen(file_1,'rb');
-assert_checkequal(mget(1,'l'),1996);
-assert_checkequal(mgetstr(6),"Scilab");
-mclose(fid);
+assert_checkequal(txt(1), r);
+// test when line size exceeeds reading buffer size (currently 4096 characters per line)
+[filename, ref2] = create_file([5000, 5000]);
+check_mgetl(filename, ref2);
+[filename, ref2] = create_file([100, 5000, 15000]);
+check_mgetl(filename, ref2);
+[filename, ref2] = create_file([4095, 8191, 16383]);
+check_mgetl(filename, ref2);
+[filename, ref2] = create_file([4096, 8192, 16384]);
+check_mgetl(filename, ref2);
+// test error management
+ierr = execstr("mgetl(1000, 1)", "errcatch");
+assert_checkequal(ierr, 999);
+ierr = execstr("mgetl(TMPDIR + ""notfound.txt"",1)", "errcatch");
+assert_checkequal(ierr, 999);
index eb72ffa..b48c729 100644 (file)
 // =============================================================================
 // Unitary tests for mgetl function
 //==============================================================================
-if mgetl('SCI/etc/scilab.start', 0) <> [] then pause,end
-//==============================================================================
-fd = mopen('SCI/etc/scilab.start', 'rt');
-if mgetl(fd, 0) <> [] then pause,end
+
+function [filename, txt] = create_file(arg)
+    if isempty(arg) then
+        txt = [];
+        filename = tempname();
+    elseif typeof(arg) == "string" then
+        txt = arg;
+        filename = tempname();
+        if arg <> [] then
+            mputl(arg, filename);
+        end
+    elseif typeof(arg) == "constant" then
+        txt = "";
+        for i=1:size(arg, '*')
+            txt = [txt; strcat(repmat(ascii(96+i), 1, arg(i)))];
+        end
+        filename = tempname();
+        mputl(txt, filename);
+    end
+end
+
+function fd = open_create_file(txt)
+    fd = mopen(create_file(txt), "rt");
+endfunction
+
+function check_mgetl(f, expected, varargin)
+    txt = mgetl(f, varargin(:));
+    assert_checkequal(txt, expected);
+endfunction
+
+
+ref = ["1 Scilab"; ..
+        "2 Puffin"; ..
+        "3 "; ..
+        "4 Puffin"; ..
+        "5 Scilab"];
+
+// test simple
+check_mgetl(create_file("a"), "a");
+check_mgetl(create_file(ref), ref);
+
+// test file argument: file descriptor
+fd = open_create_file(ref);
+check_mgetl(fd, [], 0)
 mclose(fd);
-//==============================================================================
-ref = ["1 Scilab";"2 Puffin";"3 ";"4 Puffin";"5 Scilab"];
-mputl(ref, TMPDIR + "/text.txt");
-//==============================================================================
-txt = mgetl(TMPDIR + "/text.txt");
-if or(ref <> txt) then pause,end
-//==============================================================================
-txt = mgetl(TMPDIR + "/text.txt", -10);
-if or(ref <> txt) then pause,end
-//==============================================================================
-txt = mgetl(TMPDIR + "/text.txt", -1);
-if or(ref <> txt) then pause,end
-//==============================================================================
-txt = mgetl(TMPDIR + "/text.txt", 1);
-if txt <> ref(1) then pause,end
-//==============================================================================
-txt = mgetl(TMPDIR + "/text.txt", 2);
-if or(txt <> ref(1:2)) then pause,end
-//==============================================================================
-txt = mgetl(TMPDIR + "/text.txt", 100);
-if or(txt <> ref) then pause,end
-//==============================================================================
-fd = mopen(TMPDIR + "/text2.txt","wt");
-r = mgetl(fd);
+
+// test line count argument: read all lines
+check_mgetl(create_file(ref), ref, -1);
+check_mgetl(create_file(ref), ref, -10);
+
+// test line count argument: read zero lines
+check_mgetl(create_file(ref), [], 0);
+
+// test line count argument: read some lines
+check_mgetl(create_file(ref), ref(1), 1);
+check_mgetl(create_file(ref), ref(1:2), 2);
+check_mgetl(create_file(ref), ref, 100);
+
+// read all lines in several calls
+fd = open_create_file(ref);
+check_mgetl(fd, ref(1), 1);
+check_mgetl(fd, ref(2:3), 2);
+check_mgetl(fd, ref(4:5), 3);
 mclose(fd);
-if r <> [] then pause,end
-//==============================================================================
-fd = mopen(TMPDIR + "/text.txt","rt");
-r = mgetl(fd, 1);
-if r <> ref(1) then pause,end
-//==============================================================================
-r = mgetl(fd, 2);
-if r <> ref(2:3) then pause,end
-//==============================================================================
-r = mgetl(fd, 3);
-if r <> ref(4:5) then pause,end
-//==============================================================================
+
+// test empty file
+check_mgetl(create_file([]), []);
+
+// test file empty lines
+filename = tempname();
+fd = mopen(filename, "wb");
+mfprintf(fd, ascii(10));
 mclose(fd);
-//==============================================================================
+check_mgetl(filename, "");
 txt = mgetl("SCI/modules/fileio/tests/unit_tests/text.txt");
-if and(size(txt) <> [6 1]) then pause,end
-//==============================================================================
-// creates a file with some differents end of line
-ref = ['A text with different end of line';
-'text with LF:';
-'text with CRLF:';
-'text no EOL.'];
-
-CR = '\r';
-LF = '\n';
-
-fd = mopen(TMPDIR + '/mgetl_text_tst.txt', 'wt');
-mfprintf(fd, ref(1) + CR + LF);
-mfprintf(fd, ref(2) + LF);
-mfprintf(fd, ref(3) + CR + LF);
-mfprintf(fd, ref(4));
+assert_checkequal(size(txt), [6 1]);
+assert_checkequal(txt(6), "");
+
+// test file with different EOL (end of line)
+ref_EOL = ["line with CR LF"; ..
+    "line with LF"; ..
+    "line with no EOL"];
+filename = tempname();
+fd = mopen(filename, "wb");
+mfprintf(fd, "%s" + ascii(13) + ascii(10), ref_EOL(1));
+mfprintf(fd, "%s" + ascii(10), ref_EOL(2));
+mfprintf(fd, "%s", ref_EOL(3));
 mclose(fd);
-r = mgetl(TMPDIR + '/mgetl_text_tst.txt');
-if ~and(r == ref) then pause,end
-//==============================================================================
+check_mgetl(filename, ref_EOL);
+
+
+// test file with BOM
 txt = mgetl("SCI/modules/fileio/tests/unit_tests/text-UTF8BOM.txt");
-if and(size(txt) <> [13 1]) then pause,end
+assert_checkequal(size(txt), [13 1]);
 r = "Scilab is a numerical computational package developed since 1990 by researchers from the INRIA and the Ecole nationale des ponts et chaussees (ENPC). It is, since the creation of the Scilab consortium in May 2003, developed and maintained by the INRIA.";
-if r <> txt(1) then pause, end
-
-ierr = execstr('mgetl(0,1)','errcatch');
-if ierr <> 999 then pause,end
-ierr = execstr('mgetl(6,1)','errcatch');
-if ierr <> 999 then pause,end
-
-file_1 = TMPDIR+'/test_binary_1.bin';
-fid = mopen(file_1,'wb');
-mput(1996,'l');
-mputstr('Scilab');
-mclose(fid);
-fid = mopen(file_1,'rb');
-assert_checkequal(mget(1,'l'),1996);
-assert_checkequal(mgetstr(6),"Scilab");
-mclose(fid);
+assert_checkequal(txt(1), r);
+
+// test when line size exceeeds reading buffer size (currently 4096 characters per line)
+[filename, ref2] = create_file([5000, 5000]);
+check_mgetl(filename, ref2);
+[filename, ref2] = create_file([100, 5000, 15000]);
+check_mgetl(filename, ref2);
+[filename, ref2] = create_file([4095, 8191, 16383]);
+check_mgetl(filename, ref2);
+[filename, ref2] = create_file([4096, 8192, 16384]);
+check_mgetl(filename, ref2);
+
+// test error management
+ierr = execstr("mgetl(1000, 1)", "errcatch");
+assert_checkequal(ierr, 999);
+ierr = execstr("mgetl(TMPDIR + ""notfound.txt"",1)", "errcatch");
+assert_checkequal(ierr, 999);
+
+
+
index 2283e44..c29cfec 100644 (file)
@@ -60,10 +60,9 @@ csvResult* csvRead(const char *filename, const char *separator, const char *deci
     int f_swap = 0;
     double res = 0.0;
     int errMOPEN = MOPEN_INVALID_STATUS;
-    int errMGETL = MGETL_ERROR;
     wchar_t **pwstLines = NULL;
     char **pstLines = NULL;
-    int nblines = 0;
+    int nbLines = 0;
     char **replacedInLines = NULL;
     char **pComments = NULL;
     int nbComments = 0;
@@ -119,17 +118,26 @@ csvResult* csvRead(const char *filename, const char *separator, const char *deci
 
     if (header != 0)
     {
-        // Ignoring the header
-        pstLines = mgetl(fd, header, &nblines, &errMGETL);
-        freeArrayOfWideString(pstLines, nblines);
-        pstLines = NULL;
+        wchar_t **pwstHeaderLines = NULL;
+        mgetl(fd, header, &pwstHeaderLines);
+        FREE(pwstHeaderLines);
     }
 
-    pwstLines = mgetl(fd, -1, &nblines, &errMGETL);
-
+    nbLines = mgetl(fd, -1, &pwstLines);
     mclose(fd);
 
-    if (errMGETL != MGETL_NO_ERROR)
+    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)));
         if (result)
@@ -144,24 +152,11 @@ csvResult* csvRead(const char *filename, const char *separator, const char *deci
         return result;
     }
 
-    pstLines = (char**)MALLOC(sizeof(char*) * nblines);
-
-    {
-        int i = 0;
-        for (i = 0 ; i < nblines ; i++)
-        {
-            pstLines[i] = wide_string_to_UTF8(pwstLines[i]);
-        }
-
-    }
-    freeArrayOfWideString(pwstLines, nblines);
-    pwstLines = NULL;
-
     if (regexpcomments)
     {
         int iErr = 0;
 
-        pComments = extractComments((const char**)pstLines, nblines, regexpcomments, &nbComments, &iErr);
+        pComments = extractComments((const char**)pstLines, nbLines, regexpcomments, &nbComments, &iErr);
 
         if ((iErr == CAN_NOT_COMPILE_PATTERN) || (iErr == DELIMITER_NOT_ALPHANUMERIC))
         {
@@ -179,7 +174,7 @@ csvResult* csvRead(const char *filename, const char *separator, const char *deci
                 result->pstrComments = NULL;
                 result->nbComments = 0;
             }
-            freeArrayOfString(pstLines, nblines);
+            freeArrayOfString(pstLines, nbLines);
             return result;
         }
 
@@ -189,12 +184,17 @@ csvResult* csvRead(const char *filename, const char *separator, const char *deci
             int nbCleanedLines = 0;
             int i = 0;
 
-            pCleanedLines = removeComments((const char**)pstLines, nblines, (const char*)regexpcomments, &nbCleanedLines, &iErr);
+            pCleanedLines = removeComments((const char**)pstLines, nbLines, (const char*)regexpcomments, &nbCleanedLines, &iErr);
             if (pCleanedLines)
             {
+                if (pwstLines)
+                {
+                    freeArrayOfWideString(pwstLines, nbLines);
+                    pwstLines = NULL;
+                }
                 FREE(pstLines);
                 pstLines = pCleanedLines;
-                nblines = nbCleanedLines;
+                nbLines = nbCleanedLines;
             }
 
         }
@@ -202,16 +202,17 @@ csvResult* csvRead(const char *filename, const char *separator, const char *deci
 
     if (toreplace && (sizetoreplace > 0))
     {
-        replacedInLines = replaceStrings((const char**)pstLines, nblines, toreplace, sizetoreplace);
+        replacedInLines = replaceStrings((const char**)pstLines, nbLines, toreplace, sizetoreplace);
         if (replacedInLines)
         {
-            freeArrayOfString(pstLines, nblines);
+            freeArrayOfString(pstLines, nbLines);
             pstLines = replacedInLines;
         }
     }
 
-    result = csvTextScan((const char**)pstLines, nblines, (const char*)separator, (const char*)decimal);
-    freeArrayOfString(pstLines, nblines);
+    result = csvTextScan((const char**)pstLines, nbLines, (const char*)separator, (const char*)decimal);
+    freeArrayOfString(pstLines, nbLines);
+    freeArrayOfWideString(pwstLines, nbLines);
 
     if (result)
     {
@@ -223,7 +224,6 @@ csvResult* csvRead(const char *filename, const char *separator, const char *deci
         freeArrayOfString(pComments, nbComments);
     }
 
-
     return result;
 }
 // =============================================================================