dead lock fixed when the parser fails to open file
[scilab.git] / scilab / modules / ast / src / cpp / parse / parser.cpp
1 /*
2  *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  *  Copyright (C) 2008-2008 - INRIA - Bruno JOFRET
4  *  Copyright (C) 2010-2010 - DIGITEO - Bruno JOFRET
5  *
6  *  This file must be used under the terms of the CeCILL.
7  *  This source file is licensed as described in the file COPYING, which
8  *  you should have received as part of this distribution.  The terms
9  *  are also available at
10  *  http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
11  *
12  */
13
14 #include <fstream>
15 #include <string>
16 #include <string.h>
17 #include "parser.hxx"
18 #include "parser_private.hxx"
19
20 #ifdef _MSC_VER
21 #include "windows.h"
22 #include "charEncoding.h"
23 #include "sci_malloc.h"
24 #endif
25
26 extern "C"
27 {
28 #include "sci_tmpdir.h"
29 #include "Scierror.h"
30 #include "localization.h"
31 #include "os_string.h"
32 #ifdef __APPLE__
33 #include "PATH_MAX.h"
34 #endif
35 #include "os_wfopen.h"
36 }
37
38 extern FILE*    yyin;
39 extern int      yyparse();
40 extern int      yydebug;
41 extern int      yylex_destroy();
42
43 void Parser::cleanup()
44 {
45     yylex_destroy();
46 }
47
48 void Parser::parseFile(const std::wstring& fileName, const std::wstring& progName)
49 {
50     // Calling Parse state machine in C with global values
51     // Must be locked to avoid concurrent access
52     // FIXME : LOCK
53     if (getParseTrace() == true)
54     {
55         ParserSingleInstance::enableParseTrace();
56     }
57     else
58     {
59         ParserSingleInstance::disableParseTrace();
60     }
61
62     try
63     {
64         ParserSingleInstance::parseFile(fileName, progName);
65     }
66     catch (const ast::InternalError& ie)
67     {
68         ParserSingleInstance::setTree(nullptr);
69         ParserSingleInstance::setExitStatus(Parser::Failed);
70     }
71
72     this->setExitStatus(ParserSingleInstance::getExitStatus());
73     this->setControlStatus(ParserSingleInstance::getControlStatus());
74     if (getExitStatus() == Parser::Succeded)
75     {
76         this->setTree(ParserSingleInstance::getTree());
77     }
78     else
79     {
80         this->setErrorMessage(ParserSingleInstance::getErrorMessage());
81     }
82
83     if (getExitStatus() != Parser::Succeded)
84     {
85         delete ParserSingleInstance::getTree();
86         ParserSingleInstance::setTree(nullptr);
87     }
88
89     // FIXME : UNLOCK
90 }
91
92
93 /** \brief parse the given file name */
94 void ParserSingleInstance::parseFile(const std::wstring& fileName, const std::wstring& progName)
95 {
96     yylloc.first_line = yylloc.last_line = 1;
97     yylloc.first_column = yylloc.last_column = 1;
98 #ifdef _MSC_VER
99     yyin = os_wfopen(fileName.c_str(), L"r");
100 #else
101     char* pstTemp = wide_string_to_UTF8(fileName.c_str());
102     yyin = fopen(pstTemp, "r");
103     FREE(pstTemp);
104 #endif
105
106     if (!yyin)
107     {
108         wchar_t szError[bsiz];
109         os_swprintf(szError, bsiz, _W("%ls: Cannot open file %ls.\n").c_str(), L"parser", fileName.c_str());
110         throw ast::InternalError(szError);
111     }
112
113
114     ParserSingleInstance::disableStrictMode();
115     //  Parser::getInstance()->enableStrictMode();
116     ParserSingleInstance::setFileName(fileName);
117     ParserSingleInstance::setProgName(progName);
118
119     ParserSingleInstance::setTree(nullptr);
120     ParserSingleInstance::setExitStatus(Parser::Succeded);
121     ParserSingleInstance::resetControlStatus();
122     ParserSingleInstance::resetErrorMessage();
123     yyparse();
124     fclose(yyin);
125 }
126
127 void Parser::parse(const char *command)
128 {
129     // Calling Parse state machine in C with global values
130     // Must be locked to avoid concurrent access
131     // FIXME : LOCK
132     if (getParseTrace() == true)
133     {
134         ParserSingleInstance::enableParseTrace();
135     }
136     else
137     {
138         ParserSingleInstance::disableParseTrace();
139     }
140
141     ParserSingleInstance::parse(command);
142     this->setExitStatus(ParserSingleInstance::getExitStatus());
143     this->setControlStatus(ParserSingleInstance::getControlStatus());
144     if (getExitStatus() == Parser::Succeded)
145     {
146         this->setTree(ParserSingleInstance::getTree());
147     }
148     else
149     {
150         this->setErrorMessage(ParserSingleInstance::getErrorMessage());
151     }
152
153     if (getControlStatus() == AllControlClosed && get_last_token() != YYEOF)
154     {
155         //set parser last token to EOF
156         scan_throw(YYEOF);
157     }
158
159     if (getExitStatus() != Parser::Succeded)
160     {
161         delete ParserSingleInstance::getTree();
162         ParserSingleInstance::setTree(nullptr);
163     }
164
165     // FIXME : UNLOCK
166 }
167
168 void Parser::parse(const wchar_t *command)
169 {
170     char* pstCommand = wide_string_to_UTF8(command);
171     parse(pstCommand);
172     FREE(pstCommand);
173 }
174
175 /** \brief parse the given file command */
176 void ParserSingleInstance::parse(const char *command)
177 {
178     size_t len = strlen(command);
179
180     yylloc.first_line = yylloc.last_line = 1;
181     yylloc.first_column = yylloc.last_column = 1;
182 #ifdef _MSC_VER
183     char szFile[MAX_PATH];
184     char* pstTmpDIr = getTMPDIR();
185     os_sprintf(szFile, "%s\\%s", pstTmpDIr, "command.temp");
186     FREE(pstTmpDIr);
187     if (fileLocker)
188     {
189         fclose(fileLocker);
190         fileLocker = nullptr;
191     }
192
193     errno_t err;
194     err = fopen_s(&yyin, szFile, "w");
195     if (err)
196     {
197         ParserSingleInstance::setExitStatus(Parser::Failed);
198         ParserSingleInstance::resetErrorMessage();
199         wchar_t szError[bsiz];
200         wchar_t* wszFile = to_wide_string(szFile);
201         os_swprintf(szError, bsiz, _W("%ls: Cannot open file %ls.\n").c_str(), L"parser", wszFile);
202         FREE(wszFile);
203         appendErrorMessage(szError);
204         return;
205     }
206
207     fwrite(command, sizeof(char), len, yyin);
208     fclose(yyin);
209     fopen_s(&yyin, szFile, "r");
210 #endif
211
212 #ifdef __APPLE__
213     char szFile[PATH_MAX];
214     char* pstTmpDIr = "/tmp";
215     sprintf(szFile, "%s/%s", getTMPDIR(), "command.temp");
216     //FREE(pstTmpDIr);
217     if (fileLocker)
218     {
219         fclose(fileLocker);
220         fileLocker = nullptr;
221     }
222     yyin = fopen(szFile, "w");
223     fwrite(command, 1, len, yyin);
224     fclose(yyin);
225     yyin = fopen(szFile, "r");
226 #endif
227
228
229 #ifndef _MSC_VER
230 #ifndef __APPLE__
231     yyin = fmemopen((void*)command, len, "r");
232 #endif
233 #endif
234
235     ParserSingleInstance::disableStrictMode();
236     ParserSingleInstance::setFileName(L"prompt");
237     ParserSingleInstance::setTree(nullptr);
238     ParserSingleInstance::setExitStatus(Parser::Succeded);
239     ParserSingleInstance::resetControlStatus();
240     ParserSingleInstance::resetErrorMessage();
241
242     yyparse();
243
244     fclose(yyin);
245 #ifdef _MSC_VER
246     DeleteFileA(szFile);
247 #endif
248
249 #ifdef _MSC_VER
250     //reopen a file to prevents max file opened.
251     fopen_s(&fileLocker, szFile, "w");
252 #endif
253 #ifdef __APPLE__
254     fileLocker = fopen(szFile, "w");
255 #endif
256 }
257
258 /** \brief put the asked line in codeLine */
259 char *ParserSingleInstance::getCodeLine(int line, char **codeLine)
260 {
261     int i = 0;
262
263     rewind(yyin);
264     /*
265     ** WARNING : *codeLine will be allocated by getline
266     ** so it must be manually freed !
267     */
268     for (i = 1 ; i <= line ; ++i)
269     {
270         fgets(*codeLine, 4096, yyin);
271     }
272     return *codeLine;
273 }
274
275 std::wstring& ParserSingleInstance::getErrorMessage(void)
276 {
277     return _error_message;
278 }
279
280 void ParserSingleInstance::appendErrorMessage(const std::wstring& message)
281 {
282     _error_message += message;
283 }
284
285 /** \brief enable Bison trace mode */
286 void ParserSingleInstance::enableParseTrace(void)
287 {
288     yydebug = 1;
289 }
290
291 /** \brief disable Bison trace mode */
292 void ParserSingleInstance::disableParseTrace(void)
293 {
294     yydebug = 0;
295 }
296
297 void Parser::releaseTmpFile()
298 {
299     ParserSingleInstance::releaseTmpFile();
300 }
301
302 void ParserSingleInstance::releaseTmpFile()
303 {
304     if (fileLocker)
305     {
306         //fclose(fileLocker);
307         //fileLocker = nullptr;
308     }
309 }
310
311 std::wstring ParserSingleInstance::_file_name;
312 std::wstring ParserSingleInstance::_prog_name;
313 std::wstring ParserSingleInstance::_error_message;
314 bool ParserSingleInstance::_strict_mode = false;
315 bool ParserSingleInstance::_stop_on_first_error = false;
316 ast::Exp* ParserSingleInstance::_the_program = nullptr;
317 Parser::ParserStatus ParserSingleInstance::_exit_status = Parser::Succeded;
318 std::list<Parser::ControlStatus> ParserSingleInstance::_control_status;
319 FILE* ParserSingleInstance::fileLocker = nullptr;
320