2cf522fcad91a087e65dc818af1800e68518da68
[scilab.git] / scilab / modules / io / sci_gateway / cpp / sci_genlib.cpp
1 /*
2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) 2006 - INRIA - Allan CORNET
4 *
5 7* This file must be used under the terms of the CeCILL.
6 * This source file is licensed as described in the file COPYING, which
7 * you should have received as part of this distribution.  The terms
8 * are also available at
9 * http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
10 *
11 */
12
13 #ifdef _MSC_VER
14 #pragma warning(disable : 4996) //It's not beautifull but that works !
15 #endif
16
17 #define DEFAULT_ENCODING "UTF-8"
18
19 #ifdef _MSC_VER
20 #define FILE_SEPARATOR L"\\"
21 #else
22 #define FILE_SEPARATOR L"/"
23 #endif
24
25 //XML API
26 #include <libxml/xpath.h>
27 #include <libxml/xmlwriter.h>
28
29 #include <string.h>
30 #include "parser.hxx"
31 #include "context.hxx"
32 #include "io_gw.hxx"
33 #include "scilabWrite.hxx"
34 #include "expandPathVariable.h"
35 #include "configvariable.hxx"
36 #include "string.hxx"
37 #include "library.hxx"
38 #include "macrofile.hxx"
39 #include "serializervisitor.hxx"
40 #include "loadlib.hxx"
41
42 extern "C"
43 {
44 #include "setenvvar.h"
45 #include "sci_malloc.h"
46 #include "localization.h"
47 #include "PATH_MAX.h"
48 #include "findfiles.h"
49 #include "FileExist.h"
50 #include "deleteafile.h"
51 #include "os_string.h"
52 #include "splitpath.h"
53 #include "os_wfopen.h"
54 #include "sciprint.h"
55 #include "freeArrayOfString.h"
56 #include "Scierror.h"
57 #include "scicurdir.h"
58 #include "md5.h"
59 }
60
61
62 xmlTextWriterPtr openXMLFile(const wchar_t *_pstFilename, const wchar_t* _pstLibName);
63 void closeXMLFile(xmlTextWriterPtr _pWriter);
64 bool AddMacroToXML(xmlTextWriterPtr _pWriter, const wstring& name, const wstring& file, const wstring& md5);
65
66
67 using namespace types;
68 /*--------------------------------------------------------------------------*/
69 Function::ReturnValue sci_genlib(types::typed_list &in, int _iRetCount, types::typed_list &out)
70 {
71     wchar_t pstParseFile[PATH_MAX + FILENAME_MAX];
72     wchar_t pstVerbose[65535];
73
74     int iNbFile             = 0;
75     wchar_t *pstParsePath      = NULL;
76     int iParsePathLen           = 0;
77     wchar_t* pstLibName         = NULL;
78     bool bVerbose           = false;
79
80     if (in.size() < 1 || in.size() > 4)
81     {
82         Scierror(78, _("%s: Wrong number of input argument(s): %d to %d expected.\n"), "genlib", 1, 4);
83         return Function::Error;
84     }
85
86     //param 1, library name
87     InternalType* pIT = in[0];
88     if (pIT->isString() == false)
89     {
90         Scierror(999, _("%s: Wrong type for input argument #%d: A string expected.\n"), "genlib", 1);
91         return Function::Error;
92     }
93
94     String *pS = pIT->getAs<types::String>();
95     if (pS->getSize() != 1)
96     {
97         Scierror(999, _("%s: Wrong size for input argument #%d: A string expected.\n"), "genlib", 1);
98         return Function::Error;
99     }
100     pstLibName = pS->get(0);
101
102     //param 2, library path
103     if (in.size() > 1)
104     {
105         pIT = in[1];
106         if (pIT->isString() == false)
107         {
108             Scierror(999, _("%s: Wrong type for input argument #%d: A string expected.\n"), "genlib", 2);
109             return Function::Error;
110         }
111     }
112     else
113     {
114         int ierr = 0;
115         pIT = new types::String(scigetcwd(&ierr));
116     }
117
118     pS = pIT->getAs<types::String>();
119     if (pS->isScalar() == false)
120     {
121         Scierror(999, _("%s: Wrong size for input argument #%d: A string expected.\n"), "genlib", 2);
122         return Function::Error;
123     }
124
125     if (in.size() > 2)
126     {
127         //force flag, do nothing but keep for compatibility
128     }
129
130     if (in.size() > 3)
131     {
132         //verbose flag
133         pIT = in[3];
134         if (pIT->isBool() == false)
135         {
136             return Function::Error;
137         }
138
139         bVerbose = pIT->getAs<types::Bool>()->get()[0] == 1;
140     }
141
142     wchar_t* pstFile = pS->get(0);
143     pstParsePath = expandPathVariableW(pstFile);
144
145     os_swprintf(pstParseFile, PATH_MAX + FILENAME_MAX, L"%ls%lslib", pstParsePath, FILE_SEPARATOR);
146
147     if (bVerbose)
148     {
149         os_swprintf(pstVerbose, 65535, _W("-- Creation of [%ls] (Macros) --\n").c_str(), pstLibName);
150
151         //save current prompt mode
152         int oldVal = ConfigVariable::getPromptMode();
153         //set mode silent for errors
154         ConfigVariable::setPromptMode(0);
155         scilabWriteW(pstVerbose);
156         //restore previous prompt mode
157         ConfigVariable::setPromptMode(oldVal);
158     }
159
160     MacroInfoList lstOld;
161     if (FileExistW(pstParseFile))
162     {
163         //read it to get previous information like md5
164         std::wstring libname;
165         parseLibFile(pstParseFile, lstOld, libname);
166         deleteafileW(pstParseFile);
167     }
168
169     xmlTextWriterPtr pWriter = openXMLFile(pstParseFile, pstLibName);
170
171     if (pWriter == NULL)
172     {
173         os_swprintf(pstVerbose, 65535, _W("%ls: Cannot open file ''%ls''.\n").c_str(), L"genlib", pstParseFile);
174         scilabWriteW(pstVerbose);
175
176         out.push_back(new Bool(0));
177         FREE(pstParsePath);
178         return Function::OK;
179     }
180
181
182     wchar_t **pstPath = findfilesW(pstParsePath, L"*.sci", &iNbFile, FALSE);
183
184     if (pstPath)
185     {
186         types::Library* pLib = new types::Library(pstParsePath);
187         for (int k = 0 ; k < iNbFile ; k++)
188         {
189             //version with direct parsing
190             //parse the file to find all functions
191             wstring stFullPath = wstring(pstParsePath) + wstring(FILE_SEPARATOR) + wstring(pstPath[k]);
192             wstring stFullPathBin(stFullPath);
193             stFullPathBin.replace(stFullPathBin.end() - 3, stFullPathBin.end(), L"bin");
194             wstring pstPathBin(pstPath[k]);
195             pstPathBin.replace(pstPathBin.end() - 3, pstPathBin.end(), L"bin");
196
197             //compute file md5
198             FILE* fmdf5 = os_wfopen(stFullPath.data(), L"rb");
199             char* md5 = md5_file(fmdf5);
200             fclose(fmdf5);
201
202             wchar_t* wmd5 = to_wide_string(md5);
203             FREE(md5);
204             std::wstring wide_md5(wmd5);
205             FREE(wmd5);
206
207             //check if is exist in old file
208
209             MacroInfoList::iterator it = lstOld.find(pstPathBin);
210             if (it != lstOld.end())
211             {
212                 if (wide_md5 == (*it).second.md5)
213                 {
214                     //file not change, we can skip it
215                     AddMacroToXML(pWriter, (*it).second.name, pstPathBin, wide_md5);
216                     pLib->add((*it).second.name, new types::MacroFile((*it).second.name, stFullPathBin, pstLibName));
217                     continue;
218                 }
219             }
220
221             if (bVerbose)
222             {
223                 sciprint(_("%ls: Processing file: %ls\n"), L"genlib", pstPath[k]);
224             }
225
226             Parser parser;
227             parser.parseFile(stFullPath, ConfigVariable::getSCIPath());
228             if (parser.getExitStatus() !=  Parser::Succeded)
229             {
230                 scilabWriteW(parser.getErrorMessage());
231                 Scierror(999, _("%ls: Error in file %ls.\n"), L"genlib", stFullPath.data());
232                 return Function::Error;
233             }
234
235             //serialize ast
236             ast::SerializeVisitor* s = new ast::SerializeVisitor(parser.getTree());
237
238             unsigned char* serialAst = s->serialize();
239             // Header is : buffer size (4 bytes) + scilab version (4 bytes)
240             unsigned int size = *((unsigned int*)serialAst);
241
242             FILE* f = os_wfopen(stFullPathBin.c_str(), L"wb");
243             fwrite(serialAst, 1, size, f);
244             fclose(f);
245
246             ast::exps_t LExp = parser.getTree()->getAs<ast::SeqExp>()->getExps();
247             for (ast::exps_t::iterator j = LExp.begin(), itEnd = LExp.end() ; j != itEnd ; ++j)
248             {
249                 if ((*j)->isFunctionDec())
250                 {
251                     ast::FunctionDec* pFD = (*j)->getAs<ast::FunctionDec>();
252                     const wstring& name = pFD->getSymbol().getName();
253                     if (name + L".sci" == pstPath[k])
254                     {
255                         if (AddMacroToXML(pWriter, name, pstPathBin, wide_md5) == false)
256                         {
257                             os_swprintf(pstVerbose, 65535, _W("%ls: Warning: %ls information cannot be added to file %ls. File ignored\n").c_str(), L"genlib", pFD->getSymbol().getName().c_str(), pstPath[k]);
258                             scilabWriteW(pstVerbose);
259                         }
260
261                         pLib->add(name, new types::MacroFile(name, stFullPathBin, pstLibName));
262                         break;
263                     }
264                 }
265             }
266
267             delete s;
268             free(serialAst);
269             delete parser.getTree();
270         }
271
272         symbol::Context* ctx = symbol::Context::getInstance();
273         symbol::Symbol sym = symbol::Symbol(pstLibName);
274         if (ctx->isprotected(sym) == false)
275         {
276             ctx->put(symbol::Symbol(pstLibName), pLib);
277         }
278         else
279         {
280             Scierror(999, _("Redefining permanent variable.\n"));
281             return Function::Error;
282         }
283     }
284
285     freeArrayOfWideString(pstPath, iNbFile);
286     out.push_back(new Bool(1));
287     FREE(pstParsePath);
288     closeXMLFile(pWriter);
289     return Function::OK;
290 }
291
292 void closeXMLFile(xmlTextWriterPtr _pWriter)
293 {
294     int iLen;
295
296     //close opened nodes
297     iLen = xmlTextWriterEndElement(_pWriter);
298     if (iLen < 0)
299     {
300         return;
301     }
302
303     //close document
304     iLen = xmlTextWriterEndDocument(_pWriter);
305     if (iLen < 0)
306     {
307         return;
308     }
309
310     //close xml writer
311     xmlFreeTextWriter(_pWriter);
312 }
313
314 xmlTextWriterPtr openXMLFile(const wchar_t *_pstFilename, const wchar_t* _pstLibName)
315 {
316     int iLen;
317     xmlTextWriterPtr pWriter = NULL;;
318     char *pstFilename = wide_string_to_UTF8(_pstFilename);
319     char *pstLibName = wide_string_to_UTF8(_pstLibName);
320
321
322     //create a writer
323     pWriter = xmlNewTextWriterFilename(pstFilename, 0);
324     if (pWriter == NULL)
325     {
326         return NULL;
327     }
328
329     //setup indentation
330     xmlTextWriterSetIndent (pWriter, 1);
331     xmlTextWriterSetIndentString (pWriter, (xmlChar*)"  ");
332
333     //create a new document
334     iLen = xmlTextWriterStartDocument(pWriter, NULL, DEFAULT_ENCODING, "no");
335     if (iLen < 0)
336     {
337         return NULL;
338     }
339
340     //add a node "scilablib"
341     iLen = xmlTextWriterStartElement(pWriter, (xmlChar*)"scilablib");
342     if (iLen < 0)
343     {
344         return NULL;
345     }
346
347     //Add attribute "name"
348     iLen = xmlTextWriterWriteAttribute(pWriter, (xmlChar*)"name", (xmlChar*)pstLibName);
349     if (iLen < 0)
350     {
351         return NULL;
352     }
353
354     FREE(pstFilename);
355     FREE(pstLibName);
356
357     return pWriter;
358 }
359
360 bool AddMacroToXML(xmlTextWriterPtr _pWriter, const wstring& name, const wstring& file, const wstring& md5)
361 {
362     int iLen;
363
364     if (_pWriter == NULL)
365     {
366         return false;
367     }
368
369     //create node "macro"
370     iLen = xmlTextWriterStartElement(_pWriter, (xmlChar*)"macro");
371     if (iLen < 0)
372     {
373         return false;
374     }
375
376     //Add attribute "name"
377     char* pst1 = wide_string_to_UTF8(name.data());
378     iLen = xmlTextWriterWriteAttribute(_pWriter, (xmlChar*)"name", (xmlChar*)pst1);
379     if (iLen < 0)
380     {
381         return false;
382     }
383     FREE(pst1);
384
385     //Add attribute "file"
386     char* pst2 = wide_string_to_UTF8(file.data());
387     iLen = xmlTextWriterWriteAttribute(_pWriter, (xmlChar*)"file", (xmlChar*)pst2);
388     if (iLen < 0)
389     {
390         return false;
391     }
392     FREE(pst2);
393
394     //Add attribute "md5"
395     char* pst3 = wide_string_to_UTF8(md5.data());
396     iLen = xmlTextWriterWriteAttribute(_pWriter, (xmlChar*)"md5", (xmlChar*)pst3);
397     if (iLen < 0)
398     {
399         return false;
400     }
401     FREE(pst3);
402
403     //close "macro" node
404     iLen = xmlTextWriterEndElement(_pWriter);
405     if (iLen < 0)
406     {
407         return false;
408     }
409
410     return true;
411 }