mgetl: fix trouble with long file and LF on Windows
[scilab.git] / scilab / modules / fileio / src / cpp / mgetl.cpp
1 /*
2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) 2010 - DIGITEO - Allan CORNET
4 * Copyright (C) 2010 - DIGITEO - Antoine ELIAS
5 * Copyright (C) 2019 - ESI - Antoine ELIAS
6 *
7 * Copyright (C) 2012 - 2016 - Scilab Enterprises
8 *
9 * This file is hereby licensed under the terms of the GNU GPL v2.0,
10 * pursuant to article 5.3.4 of the CeCILL v.2.1.
11 * This file was originally licensed under the terms of the CeCILL v2.1,
12 * and continues to be available under such terms.
13 * For more information, see the COPYING file which you should have received
14 * along with this program.
15 *
16 */
17
18 #include <fstream>
19 #include <iostream>
20
21 extern "C"
22 {
23 #include "charEncoding.h"
24 #include "freeArrayOfString.h"
25 #include "mgetl.h"
26 #include "sci_malloc.h"
27 #include "sciprint.h"
28 }
29 #include "filemanager.hxx"
30
31 #include <stdio.h>
32 #include <string.h>
33
34 #ifdef _MSC_VER
35 #include <Windows.h>
36 #endif
37
38 static const unsigned char UTF8_BOM[] = {0xEF, 0xBB, 0xBF, 0x00};
39
40 //remove \r
41 inline void rtrim(char* s)
42 {
43     size_t n = strlen(s);
44     if (n && s[n - 1] == '\r')
45     {
46         s[n - 1] = 0;
47     }
48 }
49
50 int mgetl(int iFileID, int iLineCount, wchar_t*** pwstLines)
51 {
52     *pwstLines = NULL;
53
54     // get file descriptor
55     types::File* pFile = FileManager::getFile(iFileID);
56     FILE* fd;
57     if (pFile != NULL)
58     {
59         fd = pFile->getFiledesc();
60     }
61     else
62     {
63         return -1;
64     }
65
66     if (iLineCount == 0)
67     {
68         return 0;
69     }
70
71     // check file is not empty
72     if (ftell(fd) == 0)
73     {
74         char cValues[4] = {0x00, 0x00, 0x00, 0x00};
75         if (fgets(cValues, 4 * sizeof(char), fd) != NULL)
76         {
77             // skip BOM
78             if (strcmp(cValues, (const char*)UTF8_BOM) != 0)
79             {
80                 rewind(fd);
81             }
82         }
83     }
84
85     int orig = ftell(fd);
86
87 #ifndef _MSC_VER
88     //must reopen the file
89     std::wstring wname = pFile->getFilename();
90     char* name = wide_string_to_UTF8(wname.data());
91     std::ifstream ifs(name);
92     FREE(name);
93 #else
94     std::ifstream ifs(fd);
95 #endif
96     //seek to same position
97     ifs.seekg(orig);
98
99 #define MAX_READ_LEN 262144
100     char str[MAX_READ_LEN];
101     std::vector<wchar_t*> lst;
102
103     while ((iLineCount == -1 || lst.size() < iLineCount) && ifs.getline(str, MAX_READ_LEN))
104     {
105         rtrim(str);
106         lst.push_back(to_wide_string(str));
107     }
108
109     int nbLinesOut = (int)lst.size();
110     if (nbLinesOut == 0)
111     {
112         return 0;
113     }
114
115     *pwstLines = (wchar_t**)MALLOC(nbLinesOut * sizeof(wchar_t*));
116
117     if (*pwstLines == NULL)
118     {
119         return -1;
120     }
121
122     for (int i = 0; i < nbLinesOut; ++i)
123     {
124         (*pwstLines)[i] = lst[i];
125     }
126
127 #ifndef _MSC_VER
128     auto pos = ifs.tellg();
129     if (pos == -1)
130     {
131         fseek(fd, 0, SEEK_END);
132     }
133     else
134     {
135         fseek(fd, pos, SEEK_SET);
136     }
137
138     ifs.close();
139 #endif
140
141     return nbLinesOut;
142 }